diff options
author | John W. Linville <linville@tuxdriver.com> | 2011-04-12 16:18:44 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-04-12 16:18:44 -0400 |
commit | 252f4bf400df1712408fe83ba199a66a1b57ab1d (patch) | |
tree | e07fa00abdd55b31e22567786c78635f32c6a66c /drivers/net | |
parent | 6ba1037c3d871ab70e342631516dbf841c35b086 (diff) | |
parent | b37e3b6d64358604960b35e8ecbb7aed22e0926e (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6 into for-davem
Conflicts:
drivers/net/wireless/ath/ar9170/main.c
drivers/net/wireless/ath/ar9170/phy.c
drivers/net/wireless/zd1211rw/zd_rf_rf2959.c
Diffstat (limited to 'drivers/net')
182 files changed, 28444 insertions, 12306 deletions
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 7aeb113cbb90..f354bd4e121e 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig | |||
@@ -284,5 +284,6 @@ source "drivers/net/wireless/rtlwifi/Kconfig" | |||
284 | source "drivers/net/wireless/wl1251/Kconfig" | 284 | source "drivers/net/wireless/wl1251/Kconfig" |
285 | source "drivers/net/wireless/wl12xx/Kconfig" | 285 | source "drivers/net/wireless/wl12xx/Kconfig" |
286 | source "drivers/net/wireless/zd1211rw/Kconfig" | 286 | source "drivers/net/wireless/zd1211rw/Kconfig" |
287 | source "drivers/net/wireless/mwifiex/Kconfig" | ||
287 | 288 | ||
288 | endif # WLAN | 289 | endif # WLAN |
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index ddd3fb6ba1d3..7bba6a82b875 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile | |||
@@ -56,3 +56,5 @@ obj-$(CONFIG_WL12XX) += wl12xx/ | |||
56 | obj-$(CONFIG_WL12XX_PLATFORM_DATA) += wl12xx/ | 56 | obj-$(CONFIG_WL12XX_PLATFORM_DATA) += wl12xx/ |
57 | 57 | ||
58 | obj-$(CONFIG_IWM) += iwmc3200wifi/ | 58 | obj-$(CONFIG_IWM) += iwmc3200wifi/ |
59 | |||
60 | obj-$(CONFIG_MWIFIEX) += mwifiex/ | ||
diff --git a/drivers/net/wireless/ath/Kconfig b/drivers/net/wireless/ath/Kconfig index 92c216263ee9..d1b23067619f 100644 --- a/drivers/net/wireless/ath/Kconfig +++ b/drivers/net/wireless/ath/Kconfig | |||
@@ -24,7 +24,6 @@ config ATH_DEBUG | |||
24 | 24 | ||
25 | source "drivers/net/wireless/ath/ath5k/Kconfig" | 25 | source "drivers/net/wireless/ath/ath5k/Kconfig" |
26 | source "drivers/net/wireless/ath/ath9k/Kconfig" | 26 | source "drivers/net/wireless/ath/ath9k/Kconfig" |
27 | source "drivers/net/wireless/ath/ar9170/Kconfig" | ||
28 | source "drivers/net/wireless/ath/carl9170/Kconfig" | 27 | source "drivers/net/wireless/ath/carl9170/Kconfig" |
29 | 28 | ||
30 | endif | 29 | endif |
diff --git a/drivers/net/wireless/ath/Makefile b/drivers/net/wireless/ath/Makefile index 6d711ec97ec2..0e8f528c81c0 100644 --- a/drivers/net/wireless/ath/Makefile +++ b/drivers/net/wireless/ath/Makefile | |||
@@ -1,6 +1,5 @@ | |||
1 | obj-$(CONFIG_ATH5K) += ath5k/ | 1 | obj-$(CONFIG_ATH5K) += ath5k/ |
2 | obj-$(CONFIG_ATH9K_HW) += ath9k/ | 2 | obj-$(CONFIG_ATH9K_HW) += ath9k/ |
3 | obj-$(CONFIG_AR9170_USB) += ar9170/ | ||
4 | obj-$(CONFIG_CARL9170) += carl9170/ | 3 | obj-$(CONFIG_CARL9170) += carl9170/ |
5 | 4 | ||
6 | obj-$(CONFIG_ATH_COMMON) += ath.o | 5 | obj-$(CONFIG_ATH_COMMON) += ath.o |
diff --git a/drivers/net/wireless/ath/ar9170/Kconfig b/drivers/net/wireless/ath/ar9170/Kconfig deleted file mode 100644 index 7b9672b0d090..000000000000 --- a/drivers/net/wireless/ath/ar9170/Kconfig +++ /dev/null | |||
@@ -1,20 +0,0 @@ | |||
1 | config AR9170_USB | ||
2 | tristate "Atheros AR9170 802.11n USB support (OBSOLETE)" | ||
3 | depends on USB && MAC80211 | ||
4 | select FW_LOADER | ||
5 | help | ||
6 | This driver is going to get replaced by carl9170. | ||
7 | |||
8 | This is a driver for the Atheros "otus" 802.11n USB devices. | ||
9 | |||
10 | These devices require additional firmware (2 files). | ||
11 | For now, these files can be downloaded from here: | ||
12 | |||
13 | http://wireless.kernel.org/en/users/Drivers/ar9170 | ||
14 | |||
15 | If you choose to build a module, it'll be called ar9170usb. | ||
16 | |||
17 | config AR9170_LEDS | ||
18 | bool | ||
19 | depends on AR9170_USB && MAC80211_LEDS && (LEDS_CLASS = y || LEDS_CLASS = AR9170_USB) | ||
20 | default y | ||
diff --git a/drivers/net/wireless/ath/ar9170/Makefile b/drivers/net/wireless/ath/ar9170/Makefile deleted file mode 100644 index 8d91c7ee3215..000000000000 --- a/drivers/net/wireless/ath/ar9170/Makefile +++ /dev/null | |||
@@ -1,3 +0,0 @@ | |||
1 | ar9170usb-objs := usb.o main.o cmd.o mac.o phy.o led.o | ||
2 | |||
3 | obj-$(CONFIG_AR9170_USB) += ar9170usb.o | ||
diff --git a/drivers/net/wireless/ath/ar9170/ar9170.h b/drivers/net/wireless/ath/ar9170/ar9170.h deleted file mode 100644 index 371e4ce49528..000000000000 --- a/drivers/net/wireless/ath/ar9170/ar9170.h +++ /dev/null | |||
@@ -1,258 +0,0 @@ | |||
1 | /* | ||
2 | * Atheros AR9170 driver | ||
3 | * | ||
4 | * Driver specific definitions | ||
5 | * | ||
6 | * Copyright 2008, Johannes Berg <johannes@sipsolutions.net> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; see the file COPYING. If not, see | ||
20 | * http://www.gnu.org/licenses/. | ||
21 | * | ||
22 | * This file incorporates work covered by the following copyright and | ||
23 | * permission notice: | ||
24 | * Copyright (c) 2007-2008 Atheros Communications, Inc. | ||
25 | * | ||
26 | * Permission to use, copy, modify, and/or distribute this software for any | ||
27 | * purpose with or without fee is hereby granted, provided that the above | ||
28 | * copyright notice and this permission notice appear in all copies. | ||
29 | * | ||
30 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
31 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
32 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
33 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
34 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
35 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
36 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
37 | */ | ||
38 | #ifndef __AR9170_H | ||
39 | #define __AR9170_H | ||
40 | |||
41 | #include <linux/completion.h> | ||
42 | #include <linux/spinlock.h> | ||
43 | #include <net/cfg80211.h> | ||
44 | #include <net/mac80211.h> | ||
45 | #ifdef CONFIG_AR9170_LEDS | ||
46 | #include <linux/leds.h> | ||
47 | #endif /* CONFIG_AR9170_LEDS */ | ||
48 | #include "eeprom.h" | ||
49 | #include "hw.h" | ||
50 | |||
51 | #include "../regd.h" | ||
52 | |||
53 | #define PAYLOAD_MAX (AR9170_MAX_CMD_LEN/4 - 1) | ||
54 | |||
55 | enum ar9170_bw { | ||
56 | AR9170_BW_20, | ||
57 | AR9170_BW_40_BELOW, | ||
58 | AR9170_BW_40_ABOVE, | ||
59 | |||
60 | __AR9170_NUM_BW, | ||
61 | }; | ||
62 | |||
63 | static inline enum ar9170_bw nl80211_to_ar9170(enum nl80211_channel_type type) | ||
64 | { | ||
65 | switch (type) { | ||
66 | case NL80211_CHAN_NO_HT: | ||
67 | case NL80211_CHAN_HT20: | ||
68 | return AR9170_BW_20; | ||
69 | case NL80211_CHAN_HT40MINUS: | ||
70 | return AR9170_BW_40_BELOW; | ||
71 | case NL80211_CHAN_HT40PLUS: | ||
72 | return AR9170_BW_40_ABOVE; | ||
73 | default: | ||
74 | BUG(); | ||
75 | } | ||
76 | } | ||
77 | |||
78 | enum ar9170_rf_init_mode { | ||
79 | AR9170_RFI_NONE, | ||
80 | AR9170_RFI_WARM, | ||
81 | AR9170_RFI_COLD, | ||
82 | }; | ||
83 | |||
84 | #define AR9170_MAX_RX_BUFFER_SIZE 8192 | ||
85 | |||
86 | #ifdef CONFIG_AR9170_LEDS | ||
87 | struct ar9170; | ||
88 | |||
89 | struct ar9170_led { | ||
90 | struct ar9170 *ar; | ||
91 | struct led_classdev l; | ||
92 | char name[32]; | ||
93 | unsigned int toggled; | ||
94 | bool last_state; | ||
95 | bool registered; | ||
96 | }; | ||
97 | |||
98 | #endif /* CONFIG_AR9170_LEDS */ | ||
99 | |||
100 | enum ar9170_device_state { | ||
101 | AR9170_UNKNOWN_STATE, | ||
102 | AR9170_STOPPED, | ||
103 | AR9170_IDLE, | ||
104 | AR9170_STARTED, | ||
105 | }; | ||
106 | |||
107 | struct ar9170_rxstream_mpdu_merge { | ||
108 | struct ar9170_rx_head plcp; | ||
109 | bool has_plcp; | ||
110 | }; | ||
111 | |||
112 | struct ar9170_tx_queue_stats { | ||
113 | unsigned int len; | ||
114 | unsigned int limit; | ||
115 | unsigned int count; | ||
116 | }; | ||
117 | |||
118 | #define AR9170_QUEUE_TIMEOUT 64 | ||
119 | #define AR9170_TX_TIMEOUT 8 | ||
120 | #define AR9170_JANITOR_DELAY 128 | ||
121 | #define AR9170_TX_INVALID_RATE 0xffffffff | ||
122 | |||
123 | #define AR9170_NUM_TX_LIMIT_HARD AR9170_TXQ_DEPTH | ||
124 | #define AR9170_NUM_TX_LIMIT_SOFT (AR9170_TXQ_DEPTH - 10) | ||
125 | |||
126 | struct ar9170 { | ||
127 | struct ieee80211_hw *hw; | ||
128 | struct ath_common common; | ||
129 | struct mutex mutex; | ||
130 | enum ar9170_device_state state; | ||
131 | bool registered; | ||
132 | unsigned long bad_hw_nagger; | ||
133 | |||
134 | int (*open)(struct ar9170 *); | ||
135 | void (*stop)(struct ar9170 *); | ||
136 | int (*tx)(struct ar9170 *, struct sk_buff *); | ||
137 | int (*exec_cmd)(struct ar9170 *, enum ar9170_cmd, u32 , | ||
138 | void *, u32 , void *); | ||
139 | void (*callback_cmd)(struct ar9170 *, u32 , void *); | ||
140 | int (*flush)(struct ar9170 *); | ||
141 | |||
142 | /* interface mode settings */ | ||
143 | struct ieee80211_vif *vif; | ||
144 | |||
145 | /* beaconing */ | ||
146 | struct sk_buff *beacon; | ||
147 | struct work_struct beacon_work; | ||
148 | bool enable_beacon; | ||
149 | |||
150 | /* cryptographic engine */ | ||
151 | u64 usedkeys; | ||
152 | bool rx_software_decryption; | ||
153 | bool disable_offload; | ||
154 | |||
155 | /* filter settings */ | ||
156 | u64 cur_mc_hash; | ||
157 | u32 cur_filter; | ||
158 | unsigned int filter_state; | ||
159 | bool sniffer_enabled; | ||
160 | |||
161 | /* PHY */ | ||
162 | struct ieee80211_channel *channel; | ||
163 | int noise[4]; | ||
164 | |||
165 | /* power calibration data */ | ||
166 | u8 power_5G_leg[4]; | ||
167 | u8 power_2G_cck[4]; | ||
168 | u8 power_2G_ofdm[4]; | ||
169 | u8 power_5G_ht20[8]; | ||
170 | u8 power_5G_ht40[8]; | ||
171 | u8 power_2G_ht20[8]; | ||
172 | u8 power_2G_ht40[8]; | ||
173 | |||
174 | u8 phy_heavy_clip; | ||
175 | |||
176 | #ifdef CONFIG_AR9170_LEDS | ||
177 | struct delayed_work led_work; | ||
178 | struct ar9170_led leds[AR9170_NUM_LEDS]; | ||
179 | #endif /* CONFIG_AR9170_LEDS */ | ||
180 | |||
181 | /* qos queue settings */ | ||
182 | spinlock_t tx_stats_lock; | ||
183 | struct ar9170_tx_queue_stats tx_stats[5]; | ||
184 | struct ieee80211_tx_queue_params edcf[5]; | ||
185 | |||
186 | spinlock_t cmdlock; | ||
187 | __le32 cmdbuf[PAYLOAD_MAX + 1]; | ||
188 | |||
189 | /* MAC statistics */ | ||
190 | struct ieee80211_low_level_stats stats; | ||
191 | |||
192 | /* EEPROM */ | ||
193 | struct ar9170_eeprom eeprom; | ||
194 | |||
195 | /* tx queues - as seen by hw - */ | ||
196 | struct sk_buff_head tx_pending[__AR9170_NUM_TXQ]; | ||
197 | struct sk_buff_head tx_status[__AR9170_NUM_TXQ]; | ||
198 | struct delayed_work tx_janitor; | ||
199 | |||
200 | /* rxstream mpdu merge */ | ||
201 | struct ar9170_rxstream_mpdu_merge rx_mpdu; | ||
202 | struct sk_buff *rx_failover; | ||
203 | int rx_failover_missing; | ||
204 | |||
205 | /* (cached) HW A-MPDU settings */ | ||
206 | u8 global_ampdu_density; | ||
207 | u8 global_ampdu_factor; | ||
208 | }; | ||
209 | |||
210 | struct ar9170_tx_info { | ||
211 | unsigned long timeout; | ||
212 | }; | ||
213 | |||
214 | #define IS_STARTED(a) (((struct ar9170 *)a)->state >= AR9170_STARTED) | ||
215 | #define IS_ACCEPTING_CMD(a) (((struct ar9170 *)a)->state >= AR9170_IDLE) | ||
216 | |||
217 | /* exported interface */ | ||
218 | void *ar9170_alloc(size_t priv_size); | ||
219 | int ar9170_register(struct ar9170 *ar, struct device *pdev); | ||
220 | void ar9170_rx(struct ar9170 *ar, struct sk_buff *skb); | ||
221 | void ar9170_unregister(struct ar9170 *ar); | ||
222 | void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb); | ||
223 | void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len); | ||
224 | int ar9170_nag_limiter(struct ar9170 *ar); | ||
225 | |||
226 | /* MAC */ | ||
227 | void ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb); | ||
228 | int ar9170_init_mac(struct ar9170 *ar); | ||
229 | int ar9170_set_qos(struct ar9170 *ar); | ||
230 | int ar9170_update_multicast(struct ar9170 *ar, const u64 mc_hast); | ||
231 | int ar9170_update_frame_filter(struct ar9170 *ar, const u32 filter); | ||
232 | int ar9170_set_operating_mode(struct ar9170 *ar); | ||
233 | int ar9170_set_beacon_timers(struct ar9170 *ar); | ||
234 | int ar9170_set_dyn_sifs_ack(struct ar9170 *ar); | ||
235 | int ar9170_set_slot_time(struct ar9170 *ar); | ||
236 | int ar9170_set_basic_rates(struct ar9170 *ar); | ||
237 | int ar9170_set_hwretry_limit(struct ar9170 *ar, u32 max_retry); | ||
238 | int ar9170_update_beacon(struct ar9170 *ar); | ||
239 | void ar9170_new_beacon(struct work_struct *work); | ||
240 | int ar9170_upload_key(struct ar9170 *ar, u8 id, const u8 *mac, u8 ktype, | ||
241 | u8 keyidx, u8 *keydata, int keylen); | ||
242 | int ar9170_disable_key(struct ar9170 *ar, u8 id); | ||
243 | |||
244 | /* LEDs */ | ||
245 | #ifdef CONFIG_AR9170_LEDS | ||
246 | int ar9170_register_leds(struct ar9170 *ar); | ||
247 | void ar9170_unregister_leds(struct ar9170 *ar); | ||
248 | #endif /* CONFIG_AR9170_LEDS */ | ||
249 | int ar9170_init_leds(struct ar9170 *ar); | ||
250 | int ar9170_set_leds_state(struct ar9170 *ar, u32 led_state); | ||
251 | |||
252 | /* PHY / RF */ | ||
253 | int ar9170_init_phy(struct ar9170 *ar, enum ieee80211_band band); | ||
254 | int ar9170_init_rf(struct ar9170 *ar); | ||
255 | int ar9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel, | ||
256 | enum ar9170_rf_init_mode rfi, enum ar9170_bw bw); | ||
257 | |||
258 | #endif /* __AR9170_H */ | ||
diff --git a/drivers/net/wireless/ath/ar9170/cmd.c b/drivers/net/wireless/ath/ar9170/cmd.c deleted file mode 100644 index 6452c5055a63..000000000000 --- a/drivers/net/wireless/ath/ar9170/cmd.c +++ /dev/null | |||
@@ -1,127 +0,0 @@ | |||
1 | /* | ||
2 | * Atheros AR9170 driver | ||
3 | * | ||
4 | * Basic HW register/memory/command access functions | ||
5 | * | ||
6 | * Copyright 2008, Johannes Berg <johannes@sipsolutions.net> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; see the file COPYING. If not, see | ||
20 | * http://www.gnu.org/licenses/. | ||
21 | * | ||
22 | * This file incorporates work covered by the following copyright and | ||
23 | * permission notice: | ||
24 | * Copyright (c) 2007-2008 Atheros Communications, Inc. | ||
25 | * | ||
26 | * Permission to use, copy, modify, and/or distribute this software for any | ||
27 | * purpose with or without fee is hereby granted, provided that the above | ||
28 | * copyright notice and this permission notice appear in all copies. | ||
29 | * | ||
30 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
31 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
32 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
33 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
34 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
35 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
36 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
37 | */ | ||
38 | |||
39 | #include "ar9170.h" | ||
40 | #include "cmd.h" | ||
41 | |||
42 | int ar9170_write_mem(struct ar9170 *ar, const __le32 *data, size_t len) | ||
43 | { | ||
44 | int err; | ||
45 | |||
46 | if (unlikely(!IS_ACCEPTING_CMD(ar))) | ||
47 | return 0; | ||
48 | |||
49 | err = ar->exec_cmd(ar, AR9170_CMD_WMEM, len, (u8 *) data, 0, NULL); | ||
50 | if (err) | ||
51 | wiphy_debug(ar->hw->wiphy, "writing memory failed\n"); | ||
52 | return err; | ||
53 | } | ||
54 | |||
55 | int ar9170_write_reg(struct ar9170 *ar, const u32 reg, const u32 val) | ||
56 | { | ||
57 | const __le32 buf[2] = { | ||
58 | cpu_to_le32(reg), | ||
59 | cpu_to_le32(val), | ||
60 | }; | ||
61 | int err; | ||
62 | |||
63 | if (unlikely(!IS_ACCEPTING_CMD(ar))) | ||
64 | return 0; | ||
65 | |||
66 | err = ar->exec_cmd(ar, AR9170_CMD_WREG, sizeof(buf), | ||
67 | (u8 *) buf, 0, NULL); | ||
68 | if (err) | ||
69 | wiphy_debug(ar->hw->wiphy, "writing reg %#x (val %#x) failed\n", | ||
70 | reg, val); | ||
71 | return err; | ||
72 | } | ||
73 | |||
74 | int ar9170_read_mreg(struct ar9170 *ar, int nregs, const u32 *regs, u32 *out) | ||
75 | { | ||
76 | int i, err; | ||
77 | __le32 *offs, *res; | ||
78 | |||
79 | if (unlikely(!IS_ACCEPTING_CMD(ar))) | ||
80 | return 0; | ||
81 | |||
82 | /* abuse "out" for the register offsets, must be same length */ | ||
83 | offs = (__le32 *)out; | ||
84 | for (i = 0; i < nregs; i++) | ||
85 | offs[i] = cpu_to_le32(regs[i]); | ||
86 | |||
87 | /* also use the same buffer for the input */ | ||
88 | res = (__le32 *)out; | ||
89 | |||
90 | err = ar->exec_cmd(ar, AR9170_CMD_RREG, | ||
91 | 4 * nregs, (u8 *)offs, | ||
92 | 4 * nregs, (u8 *)res); | ||
93 | if (err) | ||
94 | return err; | ||
95 | |||
96 | /* convert result to cpu endian */ | ||
97 | for (i = 0; i < nregs; i++) | ||
98 | out[i] = le32_to_cpu(res[i]); | ||
99 | |||
100 | return 0; | ||
101 | } | ||
102 | |||
103 | int ar9170_read_reg(struct ar9170 *ar, u32 reg, u32 *val) | ||
104 | { | ||
105 | return ar9170_read_mreg(ar, 1, ®, val); | ||
106 | } | ||
107 | |||
108 | int ar9170_echo_test(struct ar9170 *ar, u32 v) | ||
109 | { | ||
110 | __le32 echobuf = cpu_to_le32(v); | ||
111 | __le32 echores; | ||
112 | int err; | ||
113 | |||
114 | if (unlikely(!IS_ACCEPTING_CMD(ar))) | ||
115 | return -ENODEV; | ||
116 | |||
117 | err = ar->exec_cmd(ar, AR9170_CMD_ECHO, | ||
118 | 4, (u8 *)&echobuf, | ||
119 | 4, (u8 *)&echores); | ||
120 | if (err) | ||
121 | return err; | ||
122 | |||
123 | if (echobuf != echores) | ||
124 | return -EINVAL; | ||
125 | |||
126 | return 0; | ||
127 | } | ||
diff --git a/drivers/net/wireless/ath/ar9170/cmd.h b/drivers/net/wireless/ath/ar9170/cmd.h deleted file mode 100644 index ec8134b4b949..000000000000 --- a/drivers/net/wireless/ath/ar9170/cmd.h +++ /dev/null | |||
@@ -1,92 +0,0 @@ | |||
1 | /* | ||
2 | * Atheros AR9170 driver | ||
3 | * | ||
4 | * Basic HW register/memory/command access functions | ||
5 | * | ||
6 | * Copyright 2008, Johannes Berg <johannes@sipsolutions.net> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; see the file COPYING. If not, see | ||
20 | * http://www.gnu.org/licenses/. | ||
21 | * | ||
22 | * This file incorporates work covered by the following copyright and | ||
23 | * permission notice: | ||
24 | * Copyright (c) 2007-2008 Atheros Communications, Inc. | ||
25 | * | ||
26 | * Permission to use, copy, modify, and/or distribute this software for any | ||
27 | * purpose with or without fee is hereby granted, provided that the above | ||
28 | * copyright notice and this permission notice appear in all copies. | ||
29 | * | ||
30 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
31 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
32 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
33 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
34 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
35 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
36 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
37 | */ | ||
38 | #ifndef __CMD_H | ||
39 | #define __CMD_H | ||
40 | |||
41 | #include "ar9170.h" | ||
42 | |||
43 | /* basic HW access */ | ||
44 | int ar9170_write_mem(struct ar9170 *ar, const __le32 *data, size_t len); | ||
45 | int ar9170_write_reg(struct ar9170 *ar, const u32 reg, const u32 val); | ||
46 | int ar9170_read_reg(struct ar9170 *ar, u32 reg, u32 *val); | ||
47 | int ar9170_read_mreg(struct ar9170 *ar, int nregs, const u32 *regs, u32 *out); | ||
48 | int ar9170_echo_test(struct ar9170 *ar, u32 v); | ||
49 | |||
50 | /* | ||
51 | * Macros to facilitate writing multiple registers in a single | ||
52 | * write-combining USB command. Note that when the first group | ||
53 | * fails the whole thing will fail without any others attempted, | ||
54 | * but you won't know which write in the group failed. | ||
55 | */ | ||
56 | #define ar9170_regwrite_begin(ar) \ | ||
57 | do { \ | ||
58 | int __nreg = 0, __err = 0; \ | ||
59 | struct ar9170 *__ar = ar; | ||
60 | |||
61 | #define ar9170_regwrite(r, v) do { \ | ||
62 | __ar->cmdbuf[2 * __nreg + 1] = cpu_to_le32(r); \ | ||
63 | __ar->cmdbuf[2 * __nreg + 2] = cpu_to_le32(v); \ | ||
64 | __nreg++; \ | ||
65 | if ((__nreg >= PAYLOAD_MAX/2)) { \ | ||
66 | if (IS_ACCEPTING_CMD(__ar)) \ | ||
67 | __err = ar->exec_cmd(__ar, AR9170_CMD_WREG, \ | ||
68 | 8 * __nreg, \ | ||
69 | (u8 *) &__ar->cmdbuf[1], \ | ||
70 | 0, NULL); \ | ||
71 | __nreg = 0; \ | ||
72 | if (__err) \ | ||
73 | goto __regwrite_out; \ | ||
74 | } \ | ||
75 | } while (0) | ||
76 | |||
77 | #define ar9170_regwrite_finish() \ | ||
78 | __regwrite_out : \ | ||
79 | if (__nreg) { \ | ||
80 | if (IS_ACCEPTING_CMD(__ar)) \ | ||
81 | __err = ar->exec_cmd(__ar, AR9170_CMD_WREG, \ | ||
82 | 8 * __nreg, \ | ||
83 | (u8 *) &__ar->cmdbuf[1], \ | ||
84 | 0, NULL); \ | ||
85 | __nreg = 0; \ | ||
86 | } | ||
87 | |||
88 | #define ar9170_regwrite_result() \ | ||
89 | __err; \ | ||
90 | } while (0); | ||
91 | |||
92 | #endif /* __CMD_H */ | ||
diff --git a/drivers/net/wireless/ath/ar9170/eeprom.h b/drivers/net/wireless/ath/ar9170/eeprom.h deleted file mode 100644 index 6c4663883423..000000000000 --- a/drivers/net/wireless/ath/ar9170/eeprom.h +++ /dev/null | |||
@@ -1,179 +0,0 @@ | |||
1 | /* | ||
2 | * Atheros AR9170 driver | ||
3 | * | ||
4 | * EEPROM layout | ||
5 | * | ||
6 | * Copyright 2008, Johannes Berg <johannes@sipsolutions.net> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; see the file COPYING. If not, see | ||
20 | * http://www.gnu.org/licenses/. | ||
21 | * | ||
22 | * This file incorporates work covered by the following copyright and | ||
23 | * permission notice: | ||
24 | * Copyright (c) 2007-2008 Atheros Communications, Inc. | ||
25 | * | ||
26 | * Permission to use, copy, modify, and/or distribute this software for any | ||
27 | * purpose with or without fee is hereby granted, provided that the above | ||
28 | * copyright notice and this permission notice appear in all copies. | ||
29 | * | ||
30 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
31 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
32 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
33 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
34 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
35 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
36 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
37 | */ | ||
38 | #ifndef __AR9170_EEPROM_H | ||
39 | #define __AR9170_EEPROM_H | ||
40 | |||
41 | #define AR5416_MAX_CHAINS 2 | ||
42 | #define AR5416_MODAL_SPURS 5 | ||
43 | |||
44 | struct ar9170_eeprom_modal { | ||
45 | __le32 antCtrlChain[AR5416_MAX_CHAINS]; | ||
46 | __le32 antCtrlCommon; | ||
47 | s8 antennaGainCh[AR5416_MAX_CHAINS]; | ||
48 | u8 switchSettling; | ||
49 | u8 txRxAttenCh[AR5416_MAX_CHAINS]; | ||
50 | u8 rxTxMarginCh[AR5416_MAX_CHAINS]; | ||
51 | s8 adcDesiredSize; | ||
52 | s8 pgaDesiredSize; | ||
53 | u8 xlnaGainCh[AR5416_MAX_CHAINS]; | ||
54 | u8 txEndToXpaOff; | ||
55 | u8 txEndToRxOn; | ||
56 | u8 txFrameToXpaOn; | ||
57 | u8 thresh62; | ||
58 | s8 noiseFloorThreshCh[AR5416_MAX_CHAINS]; | ||
59 | u8 xpdGain; | ||
60 | u8 xpd; | ||
61 | s8 iqCalICh[AR5416_MAX_CHAINS]; | ||
62 | s8 iqCalQCh[AR5416_MAX_CHAINS]; | ||
63 | u8 pdGainOverlap; | ||
64 | u8 ob; | ||
65 | u8 db; | ||
66 | u8 xpaBiasLvl; | ||
67 | u8 pwrDecreaseFor2Chain; | ||
68 | u8 pwrDecreaseFor3Chain; | ||
69 | u8 txFrameToDataStart; | ||
70 | u8 txFrameToPaOn; | ||
71 | u8 ht40PowerIncForPdadc; | ||
72 | u8 bswAtten[AR5416_MAX_CHAINS]; | ||
73 | u8 bswMargin[AR5416_MAX_CHAINS]; | ||
74 | u8 swSettleHt40; | ||
75 | u8 reserved[22]; | ||
76 | struct spur_channel { | ||
77 | __le16 spurChan; | ||
78 | u8 spurRangeLow; | ||
79 | u8 spurRangeHigh; | ||
80 | } __packed spur_channels[AR5416_MODAL_SPURS]; | ||
81 | } __packed; | ||
82 | |||
83 | #define AR5416_NUM_PD_GAINS 4 | ||
84 | #define AR5416_PD_GAIN_ICEPTS 5 | ||
85 | |||
86 | struct ar9170_calibration_data_per_freq { | ||
87 | u8 pwr_pdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS]; | ||
88 | u8 vpd_pdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS]; | ||
89 | } __packed; | ||
90 | |||
91 | #define AR5416_NUM_5G_CAL_PIERS 8 | ||
92 | #define AR5416_NUM_2G_CAL_PIERS 4 | ||
93 | |||
94 | #define AR5416_NUM_5G_TARGET_PWRS 8 | ||
95 | #define AR5416_NUM_2G_CCK_TARGET_PWRS 3 | ||
96 | #define AR5416_NUM_2G_OFDM_TARGET_PWRS 4 | ||
97 | #define AR5416_MAX_NUM_TGT_PWRS 8 | ||
98 | |||
99 | struct ar9170_calibration_target_power_legacy { | ||
100 | u8 freq; | ||
101 | u8 power[4]; | ||
102 | } __packed; | ||
103 | |||
104 | struct ar9170_calibration_target_power_ht { | ||
105 | u8 freq; | ||
106 | u8 power[8]; | ||
107 | } __packed; | ||
108 | |||
109 | #define AR5416_NUM_CTLS 24 | ||
110 | |||
111 | struct ar9170_calctl_edges { | ||
112 | u8 channel; | ||
113 | #define AR9170_CALCTL_EDGE_FLAGS 0xC0 | ||
114 | u8 power_flags; | ||
115 | } __packed; | ||
116 | |||
117 | #define AR5416_NUM_BAND_EDGES 8 | ||
118 | |||
119 | struct ar9170_calctl_data { | ||
120 | struct ar9170_calctl_edges | ||
121 | control_edges[AR5416_MAX_CHAINS][AR5416_NUM_BAND_EDGES]; | ||
122 | } __packed; | ||
123 | |||
124 | |||
125 | struct ar9170_eeprom { | ||
126 | __le16 length; | ||
127 | __le16 checksum; | ||
128 | __le16 version; | ||
129 | u8 operating_flags; | ||
130 | #define AR9170_OPFLAG_5GHZ 1 | ||
131 | #define AR9170_OPFLAG_2GHZ 2 | ||
132 | u8 misc; | ||
133 | __le16 reg_domain[2]; | ||
134 | u8 mac_address[6]; | ||
135 | u8 rx_mask; | ||
136 | u8 tx_mask; | ||
137 | __le16 rf_silent; | ||
138 | __le16 bluetooth_options; | ||
139 | __le16 device_capabilities; | ||
140 | __le32 build_number; | ||
141 | u8 deviceType; | ||
142 | u8 reserved[33]; | ||
143 | |||
144 | u8 customer_data[64]; | ||
145 | |||
146 | struct ar9170_eeprom_modal | ||
147 | modal_header[2]; | ||
148 | |||
149 | u8 cal_freq_pier_5G[AR5416_NUM_5G_CAL_PIERS]; | ||
150 | u8 cal_freq_pier_2G[AR5416_NUM_2G_CAL_PIERS]; | ||
151 | |||
152 | struct ar9170_calibration_data_per_freq | ||
153 | cal_pier_data_5G[AR5416_MAX_CHAINS][AR5416_NUM_5G_CAL_PIERS], | ||
154 | cal_pier_data_2G[AR5416_MAX_CHAINS][AR5416_NUM_2G_CAL_PIERS]; | ||
155 | |||
156 | /* power calibration data */ | ||
157 | struct ar9170_calibration_target_power_legacy | ||
158 | cal_tgt_pwr_5G[AR5416_NUM_5G_TARGET_PWRS]; | ||
159 | struct ar9170_calibration_target_power_ht | ||
160 | cal_tgt_pwr_5G_ht20[AR5416_NUM_5G_TARGET_PWRS], | ||
161 | cal_tgt_pwr_5G_ht40[AR5416_NUM_5G_TARGET_PWRS]; | ||
162 | |||
163 | struct ar9170_calibration_target_power_legacy | ||
164 | cal_tgt_pwr_2G_cck[AR5416_NUM_2G_CCK_TARGET_PWRS], | ||
165 | cal_tgt_pwr_2G_ofdm[AR5416_NUM_2G_OFDM_TARGET_PWRS]; | ||
166 | struct ar9170_calibration_target_power_ht | ||
167 | cal_tgt_pwr_2G_ht20[AR5416_NUM_2G_OFDM_TARGET_PWRS], | ||
168 | cal_tgt_pwr_2G_ht40[AR5416_NUM_2G_OFDM_TARGET_PWRS]; | ||
169 | |||
170 | /* conformance testing limits */ | ||
171 | u8 ctl_index[AR5416_NUM_CTLS]; | ||
172 | struct ar9170_calctl_data | ||
173 | ctl_data[AR5416_NUM_CTLS]; | ||
174 | |||
175 | u8 pad; | ||
176 | __le16 subsystem_id; | ||
177 | } __packed; | ||
178 | |||
179 | #endif /* __AR9170_EEPROM_H */ | ||
diff --git a/drivers/net/wireless/ath/ar9170/hw.h b/drivers/net/wireless/ath/ar9170/hw.h deleted file mode 100644 index 06f1f3c951a4..000000000000 --- a/drivers/net/wireless/ath/ar9170/hw.h +++ /dev/null | |||
@@ -1,430 +0,0 @@ | |||
1 | /* | ||
2 | * Atheros AR9170 driver | ||
3 | * | ||
4 | * Hardware-specific definitions | ||
5 | * | ||
6 | * Copyright 2008, Johannes Berg <johannes@sipsolutions.net> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; see the file COPYING. If not, see | ||
20 | * http://www.gnu.org/licenses/. | ||
21 | * | ||
22 | * This file incorporates work covered by the following copyright and | ||
23 | * permission notice: | ||
24 | * Copyright (c) 2007-2008 Atheros Communications, Inc. | ||
25 | * | ||
26 | * Permission to use, copy, modify, and/or distribute this software for any | ||
27 | * purpose with or without fee is hereby granted, provided that the above | ||
28 | * copyright notice and this permission notice appear in all copies. | ||
29 | * | ||
30 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
31 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
32 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
33 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
34 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
35 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
36 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
37 | */ | ||
38 | #ifndef __AR9170_HW_H | ||
39 | #define __AR9170_HW_H | ||
40 | |||
41 | #define AR9170_MAX_CMD_LEN 64 | ||
42 | |||
43 | enum ar9170_cmd { | ||
44 | AR9170_CMD_RREG = 0x00, | ||
45 | AR9170_CMD_WREG = 0x01, | ||
46 | AR9170_CMD_RMEM = 0x02, | ||
47 | AR9170_CMD_WMEM = 0x03, | ||
48 | AR9170_CMD_BITAND = 0x04, | ||
49 | AR9170_CMD_BITOR = 0x05, | ||
50 | AR9170_CMD_EKEY = 0x28, | ||
51 | AR9170_CMD_DKEY = 0x29, | ||
52 | AR9170_CMD_FREQUENCY = 0x30, | ||
53 | AR9170_CMD_RF_INIT = 0x31, | ||
54 | AR9170_CMD_SYNTH = 0x32, | ||
55 | AR9170_CMD_FREQ_START = 0x33, | ||
56 | AR9170_CMD_ECHO = 0x80, | ||
57 | AR9170_CMD_TALLY = 0x81, | ||
58 | AR9170_CMD_TALLY_APD = 0x82, | ||
59 | AR9170_CMD_CONFIG = 0x83, | ||
60 | AR9170_CMD_RESET = 0x90, | ||
61 | AR9170_CMD_DKRESET = 0x91, | ||
62 | AR9170_CMD_DKTX_STATUS = 0x92, | ||
63 | AR9170_CMD_FDC = 0xA0, | ||
64 | AR9170_CMD_WREEPROM = 0xB0, | ||
65 | AR9170_CMD_WFLASH = 0xB0, | ||
66 | AR9170_CMD_FLASH_ERASE = 0xB1, | ||
67 | AR9170_CMD_FLASH_PROG = 0xB2, | ||
68 | AR9170_CMD_FLASH_CHKSUM = 0xB3, | ||
69 | AR9170_CMD_FLASH_READ = 0xB4, | ||
70 | AR9170_CMD_FW_DL_INIT = 0xB5, | ||
71 | AR9170_CMD_MEM_WREEPROM = 0xBB, | ||
72 | }; | ||
73 | |||
74 | /* endpoints */ | ||
75 | #define AR9170_EP_TX 1 | ||
76 | #define AR9170_EP_RX 2 | ||
77 | #define AR9170_EP_IRQ 3 | ||
78 | #define AR9170_EP_CMD 4 | ||
79 | |||
80 | #define AR9170_EEPROM_START 0x1600 | ||
81 | |||
82 | #define AR9170_GPIO_REG_BASE 0x1d0100 | ||
83 | #define AR9170_GPIO_REG_PORT_TYPE AR9170_GPIO_REG_BASE | ||
84 | #define AR9170_GPIO_REG_DATA (AR9170_GPIO_REG_BASE + 4) | ||
85 | #define AR9170_NUM_LEDS 2 | ||
86 | |||
87 | |||
88 | #define AR9170_USB_REG_BASE 0x1e1000 | ||
89 | #define AR9170_USB_REG_DMA_CTL (AR9170_USB_REG_BASE + 0x108) | ||
90 | #define AR9170_DMA_CTL_ENABLE_TO_DEVICE 0x1 | ||
91 | #define AR9170_DMA_CTL_ENABLE_FROM_DEVICE 0x2 | ||
92 | #define AR9170_DMA_CTL_HIGH_SPEED 0x4 | ||
93 | #define AR9170_DMA_CTL_PACKET_MODE 0x8 | ||
94 | |||
95 | #define AR9170_USB_REG_MAX_AGG_UPLOAD (AR9170_USB_REG_BASE + 0x110) | ||
96 | #define AR9170_USB_REG_UPLOAD_TIME_CTL (AR9170_USB_REG_BASE + 0x114) | ||
97 | |||
98 | |||
99 | |||
100 | #define AR9170_MAC_REG_BASE 0x1c3000 | ||
101 | |||
102 | #define AR9170_MAC_REG_TSF_L (AR9170_MAC_REG_BASE + 0x514) | ||
103 | #define AR9170_MAC_REG_TSF_H (AR9170_MAC_REG_BASE + 0x518) | ||
104 | |||
105 | #define AR9170_MAC_REG_ATIM_WINDOW (AR9170_MAC_REG_BASE + 0x51C) | ||
106 | #define AR9170_MAC_REG_BCN_PERIOD (AR9170_MAC_REG_BASE + 0x520) | ||
107 | #define AR9170_MAC_REG_PRETBTT (AR9170_MAC_REG_BASE + 0x524) | ||
108 | |||
109 | #define AR9170_MAC_REG_MAC_ADDR_L (AR9170_MAC_REG_BASE + 0x610) | ||
110 | #define AR9170_MAC_REG_MAC_ADDR_H (AR9170_MAC_REG_BASE + 0x614) | ||
111 | #define AR9170_MAC_REG_BSSID_L (AR9170_MAC_REG_BASE + 0x618) | ||
112 | #define AR9170_MAC_REG_BSSID_H (AR9170_MAC_REG_BASE + 0x61c) | ||
113 | |||
114 | #define AR9170_MAC_REG_GROUP_HASH_TBL_L (AR9170_MAC_REG_BASE + 0x624) | ||
115 | #define AR9170_MAC_REG_GROUP_HASH_TBL_H (AR9170_MAC_REG_BASE + 0x628) | ||
116 | |||
117 | #define AR9170_MAC_REG_RX_TIMEOUT (AR9170_MAC_REG_BASE + 0x62C) | ||
118 | |||
119 | #define AR9170_MAC_REG_BASIC_RATE (AR9170_MAC_REG_BASE + 0x630) | ||
120 | #define AR9170_MAC_REG_MANDATORY_RATE (AR9170_MAC_REG_BASE + 0x634) | ||
121 | #define AR9170_MAC_REG_RTS_CTS_RATE (AR9170_MAC_REG_BASE + 0x638) | ||
122 | #define AR9170_MAC_REG_BACKOFF_PROTECT (AR9170_MAC_REG_BASE + 0x63c) | ||
123 | #define AR9170_MAC_REG_RX_THRESHOLD (AR9170_MAC_REG_BASE + 0x640) | ||
124 | #define AR9170_MAC_REG_RX_PE_DELAY (AR9170_MAC_REG_BASE + 0x64C) | ||
125 | |||
126 | #define AR9170_MAC_REG_DYNAMIC_SIFS_ACK (AR9170_MAC_REG_BASE + 0x658) | ||
127 | #define AR9170_MAC_REG_SNIFFER (AR9170_MAC_REG_BASE + 0x674) | ||
128 | #define AR9170_MAC_REG_SNIFFER_ENABLE_PROMISC BIT(0) | ||
129 | #define AR9170_MAC_REG_SNIFFER_DEFAULTS 0x02000000 | ||
130 | #define AR9170_MAC_REG_ENCRYPTION (AR9170_MAC_REG_BASE + 0x678) | ||
131 | #define AR9170_MAC_REG_ENCRYPTION_RX_SOFTWARE BIT(3) | ||
132 | #define AR9170_MAC_REG_ENCRYPTION_DEFAULTS 0x70 | ||
133 | |||
134 | #define AR9170_MAC_REG_MISC_680 (AR9170_MAC_REG_BASE + 0x680) | ||
135 | #define AR9170_MAC_REG_TX_UNDERRUN (AR9170_MAC_REG_BASE + 0x688) | ||
136 | |||
137 | #define AR9170_MAC_REG_FRAMETYPE_FILTER (AR9170_MAC_REG_BASE + 0x68c) | ||
138 | #define AR9170_MAC_REG_FTF_ASSOC_REQ BIT(0) | ||
139 | #define AR9170_MAC_REG_FTF_ASSOC_RESP BIT(1) | ||
140 | #define AR9170_MAC_REG_FTF_REASSOC_REQ BIT(2) | ||
141 | #define AR9170_MAC_REG_FTF_REASSOC_RESP BIT(3) | ||
142 | #define AR9170_MAC_REG_FTF_PRB_REQ BIT(4) | ||
143 | #define AR9170_MAC_REG_FTF_PRB_RESP BIT(5) | ||
144 | #define AR9170_MAC_REG_FTF_BIT6 BIT(6) | ||
145 | #define AR9170_MAC_REG_FTF_BIT7 BIT(7) | ||
146 | #define AR9170_MAC_REG_FTF_BEACON BIT(8) | ||
147 | #define AR9170_MAC_REG_FTF_ATIM BIT(9) | ||
148 | #define AR9170_MAC_REG_FTF_DEASSOC BIT(10) | ||
149 | #define AR9170_MAC_REG_FTF_AUTH BIT(11) | ||
150 | #define AR9170_MAC_REG_FTF_DEAUTH BIT(12) | ||
151 | #define AR9170_MAC_REG_FTF_BIT13 BIT(13) | ||
152 | #define AR9170_MAC_REG_FTF_BIT14 BIT(14) | ||
153 | #define AR9170_MAC_REG_FTF_BIT15 BIT(15) | ||
154 | #define AR9170_MAC_REG_FTF_BAR BIT(24) | ||
155 | #define AR9170_MAC_REG_FTF_BA BIT(25) | ||
156 | #define AR9170_MAC_REG_FTF_PSPOLL BIT(26) | ||
157 | #define AR9170_MAC_REG_FTF_RTS BIT(27) | ||
158 | #define AR9170_MAC_REG_FTF_CTS BIT(28) | ||
159 | #define AR9170_MAC_REG_FTF_ACK BIT(29) | ||
160 | #define AR9170_MAC_REG_FTF_CFE BIT(30) | ||
161 | #define AR9170_MAC_REG_FTF_CFE_ACK BIT(31) | ||
162 | #define AR9170_MAC_REG_FTF_DEFAULTS 0x0700ffff | ||
163 | #define AR9170_MAC_REG_FTF_MONITOR 0xfd00ffff | ||
164 | |||
165 | #define AR9170_MAC_REG_RX_TOTAL (AR9170_MAC_REG_BASE + 0x6A0) | ||
166 | #define AR9170_MAC_REG_RX_CRC32 (AR9170_MAC_REG_BASE + 0x6A4) | ||
167 | #define AR9170_MAC_REG_RX_CRC16 (AR9170_MAC_REG_BASE + 0x6A8) | ||
168 | #define AR9170_MAC_REG_RX_ERR_DECRYPTION_UNI (AR9170_MAC_REG_BASE + 0x6AC) | ||
169 | #define AR9170_MAC_REG_RX_OVERRUN (AR9170_MAC_REG_BASE + 0x6B0) | ||
170 | #define AR9170_MAC_REG_RX_ERR_DECRYPTION_MUL (AR9170_MAC_REG_BASE + 0x6BC) | ||
171 | #define AR9170_MAC_REG_TX_RETRY (AR9170_MAC_REG_BASE + 0x6CC) | ||
172 | #define AR9170_MAC_REG_TX_TOTAL (AR9170_MAC_REG_BASE + 0x6F4) | ||
173 | |||
174 | |||
175 | #define AR9170_MAC_REG_ACK_EXTENSION (AR9170_MAC_REG_BASE + 0x690) | ||
176 | #define AR9170_MAC_REG_EIFS_AND_SIFS (AR9170_MAC_REG_BASE + 0x698) | ||
177 | |||
178 | #define AR9170_MAC_REG_SLOT_TIME (AR9170_MAC_REG_BASE + 0x6F0) | ||
179 | |||
180 | #define AR9170_MAC_REG_POWERMANAGEMENT (AR9170_MAC_REG_BASE + 0x700) | ||
181 | #define AR9170_MAC_REG_POWERMGT_IBSS 0xe0 | ||
182 | #define AR9170_MAC_REG_POWERMGT_AP 0xa1 | ||
183 | #define AR9170_MAC_REG_POWERMGT_STA 0x2 | ||
184 | #define AR9170_MAC_REG_POWERMGT_AP_WDS 0x3 | ||
185 | #define AR9170_MAC_REG_POWERMGT_DEFAULTS (0xf << 24) | ||
186 | |||
187 | #define AR9170_MAC_REG_ROLL_CALL_TBL_L (AR9170_MAC_REG_BASE + 0x704) | ||
188 | #define AR9170_MAC_REG_ROLL_CALL_TBL_H (AR9170_MAC_REG_BASE + 0x708) | ||
189 | |||
190 | #define AR9170_MAC_REG_AC0_CW (AR9170_MAC_REG_BASE + 0xB00) | ||
191 | #define AR9170_MAC_REG_AC1_CW (AR9170_MAC_REG_BASE + 0xB04) | ||
192 | #define AR9170_MAC_REG_AC2_CW (AR9170_MAC_REG_BASE + 0xB08) | ||
193 | #define AR9170_MAC_REG_AC3_CW (AR9170_MAC_REG_BASE + 0xB0C) | ||
194 | #define AR9170_MAC_REG_AC4_CW (AR9170_MAC_REG_BASE + 0xB10) | ||
195 | #define AR9170_MAC_REG_AC1_AC0_AIFS (AR9170_MAC_REG_BASE + 0xB14) | ||
196 | #define AR9170_MAC_REG_AC3_AC2_AIFS (AR9170_MAC_REG_BASE + 0xB18) | ||
197 | |||
198 | #define AR9170_MAC_REG_RETRY_MAX (AR9170_MAC_REG_BASE + 0xB28) | ||
199 | |||
200 | #define AR9170_MAC_REG_FCS_SELECT (AR9170_MAC_REG_BASE + 0xBB0) | ||
201 | #define AR9170_MAC_FCS_SWFCS 0x1 | ||
202 | #define AR9170_MAC_FCS_FIFO_PROT 0x4 | ||
203 | |||
204 | |||
205 | #define AR9170_MAC_REG_TXOP_NOT_ENOUGH_IND (AR9170_MAC_REG_BASE + 0xB30) | ||
206 | |||
207 | #define AR9170_MAC_REG_AC1_AC0_TXOP (AR9170_MAC_REG_BASE + 0xB44) | ||
208 | #define AR9170_MAC_REG_AC3_AC2_TXOP (AR9170_MAC_REG_BASE + 0xB48) | ||
209 | |||
210 | #define AR9170_MAC_REG_AMPDU_FACTOR (AR9170_MAC_REG_BASE + 0xB9C) | ||
211 | #define AR9170_MAC_REG_AMPDU_DENSITY (AR9170_MAC_REG_BASE + 0xBA0) | ||
212 | |||
213 | #define AR9170_MAC_REG_ACK_TABLE (AR9170_MAC_REG_BASE + 0xC00) | ||
214 | #define AR9170_MAC_REG_AMPDU_RX_THRESH (AR9170_MAC_REG_BASE + 0xC50) | ||
215 | |||
216 | #define AR9170_MAC_REG_TXRX_MPI (AR9170_MAC_REG_BASE + 0xD7C) | ||
217 | #define AR9170_MAC_TXRX_MPI_TX_MPI_MASK 0x0000000f | ||
218 | #define AR9170_MAC_TXRX_MPI_TX_TO_MASK 0x0000fff0 | ||
219 | #define AR9170_MAC_TXRX_MPI_RX_MPI_MASK 0x000f0000 | ||
220 | #define AR9170_MAC_TXRX_MPI_RX_TO_MASK 0xfff00000 | ||
221 | |||
222 | #define AR9170_MAC_REG_BCN_ADDR (AR9170_MAC_REG_BASE + 0xD84) | ||
223 | #define AR9170_MAC_REG_BCN_LENGTH (AR9170_MAC_REG_BASE + 0xD88) | ||
224 | #define AR9170_MAC_REG_BCN_PLCP (AR9170_MAC_REG_BASE + 0xD90) | ||
225 | #define AR9170_MAC_REG_BCN_CTRL (AR9170_MAC_REG_BASE + 0xD94) | ||
226 | #define AR9170_MAC_REG_BCN_HT1 (AR9170_MAC_REG_BASE + 0xDA0) | ||
227 | #define AR9170_MAC_REG_BCN_HT2 (AR9170_MAC_REG_BASE + 0xDA4) | ||
228 | |||
229 | |||
230 | #define AR9170_PWR_REG_BASE 0x1D4000 | ||
231 | |||
232 | #define AR9170_PWR_REG_CLOCK_SEL (AR9170_PWR_REG_BASE + 0x008) | ||
233 | #define AR9170_PWR_CLK_AHB_40MHZ 0 | ||
234 | #define AR9170_PWR_CLK_AHB_20_22MHZ 1 | ||
235 | #define AR9170_PWR_CLK_AHB_40_44MHZ 2 | ||
236 | #define AR9170_PWR_CLK_AHB_80_88MHZ 3 | ||
237 | #define AR9170_PWR_CLK_DAC_160_INV_DLY 0x70 | ||
238 | |||
239 | |||
240 | /* put beacon here in memory */ | ||
241 | #define AR9170_BEACON_BUFFER_ADDRESS 0x117900 | ||
242 | |||
243 | |||
244 | struct ar9170_tx_control { | ||
245 | __le16 length; | ||
246 | __le16 mac_control; | ||
247 | __le32 phy_control; | ||
248 | u8 frame_data[0]; | ||
249 | } __packed; | ||
250 | |||
251 | /* these are either-or */ | ||
252 | #define AR9170_TX_MAC_PROT_RTS 0x0001 | ||
253 | #define AR9170_TX_MAC_PROT_CTS 0x0002 | ||
254 | |||
255 | #define AR9170_TX_MAC_NO_ACK 0x0004 | ||
256 | /* if unset, MAC will only do SIFS space before frame */ | ||
257 | #define AR9170_TX_MAC_BACKOFF 0x0008 | ||
258 | #define AR9170_TX_MAC_BURST 0x0010 | ||
259 | #define AR9170_TX_MAC_AGGR 0x0020 | ||
260 | |||
261 | /* encryption is a two-bit field */ | ||
262 | #define AR9170_TX_MAC_ENCR_NONE 0x0000 | ||
263 | #define AR9170_TX_MAC_ENCR_RC4 0x0040 | ||
264 | #define AR9170_TX_MAC_ENCR_CENC 0x0080 | ||
265 | #define AR9170_TX_MAC_ENCR_AES 0x00c0 | ||
266 | |||
267 | #define AR9170_TX_MAC_MMIC 0x0100 | ||
268 | #define AR9170_TX_MAC_HW_DURATION 0x0200 | ||
269 | #define AR9170_TX_MAC_QOS_SHIFT 10 | ||
270 | #define AR9170_TX_MAC_QOS_MASK (3 << AR9170_TX_MAC_QOS_SHIFT) | ||
271 | #define AR9170_TX_MAC_AGGR_QOS_BIT1 0x0400 | ||
272 | #define AR9170_TX_MAC_AGGR_QOS_BIT2 0x0800 | ||
273 | #define AR9170_TX_MAC_DISABLE_TXOP 0x1000 | ||
274 | #define AR9170_TX_MAC_TXOP_RIFS 0x2000 | ||
275 | #define AR9170_TX_MAC_IMM_AMPDU 0x4000 | ||
276 | #define AR9170_TX_MAC_RATE_PROBE 0x8000 | ||
277 | |||
278 | /* either-or */ | ||
279 | #define AR9170_TX_PHY_MOD_MASK 0x00000003 | ||
280 | #define AR9170_TX_PHY_MOD_CCK 0x00000000 | ||
281 | #define AR9170_TX_PHY_MOD_OFDM 0x00000001 | ||
282 | #define AR9170_TX_PHY_MOD_HT 0x00000002 | ||
283 | |||
284 | /* depends on modulation */ | ||
285 | #define AR9170_TX_PHY_SHORT_PREAMBLE 0x00000004 | ||
286 | #define AR9170_TX_PHY_GREENFIELD 0x00000004 | ||
287 | |||
288 | #define AR9170_TX_PHY_BW_SHIFT 3 | ||
289 | #define AR9170_TX_PHY_BW_MASK (3 << AR9170_TX_PHY_BW_SHIFT) | ||
290 | #define AR9170_TX_PHY_BW_20MHZ 0 | ||
291 | #define AR9170_TX_PHY_BW_40MHZ 2 | ||
292 | #define AR9170_TX_PHY_BW_40MHZ_DUP 3 | ||
293 | |||
294 | #define AR9170_TX_PHY_TX_HEAVY_CLIP_SHIFT 6 | ||
295 | #define AR9170_TX_PHY_TX_HEAVY_CLIP_MASK (7 << AR9170_TX_PHY_TX_HEAVY_CLIP_SHIFT) | ||
296 | |||
297 | #define AR9170_TX_PHY_TX_PWR_SHIFT 9 | ||
298 | #define AR9170_TX_PHY_TX_PWR_MASK (0x3f << AR9170_TX_PHY_TX_PWR_SHIFT) | ||
299 | |||
300 | /* not part of the hw-spec */ | ||
301 | #define AR9170_TX_PHY_QOS_SHIFT 25 | ||
302 | #define AR9170_TX_PHY_QOS_MASK (3 << AR9170_TX_PHY_QOS_SHIFT) | ||
303 | |||
304 | #define AR9170_TX_PHY_TXCHAIN_SHIFT 15 | ||
305 | #define AR9170_TX_PHY_TXCHAIN_MASK (7 << AR9170_TX_PHY_TXCHAIN_SHIFT) | ||
306 | #define AR9170_TX_PHY_TXCHAIN_1 1 | ||
307 | /* use for cck, ofdm 6/9/12/18/24 and HT if capable */ | ||
308 | #define AR9170_TX_PHY_TXCHAIN_2 5 | ||
309 | |||
310 | #define AR9170_TX_PHY_MCS_SHIFT 18 | ||
311 | #define AR9170_TX_PHY_MCS_MASK (0x7f << AR9170_TX_PHY_MCS_SHIFT) | ||
312 | |||
313 | #define AR9170_TX_PHY_SHORT_GI 0x80000000 | ||
314 | |||
315 | #define AR5416_MAX_RATE_POWER 63 | ||
316 | |||
317 | struct ar9170_rx_head { | ||
318 | u8 plcp[12]; | ||
319 | } __packed; | ||
320 | |||
321 | struct ar9170_rx_phystatus { | ||
322 | union { | ||
323 | struct { | ||
324 | u8 rssi_ant0, rssi_ant1, rssi_ant2, | ||
325 | rssi_ant0x, rssi_ant1x, rssi_ant2x, | ||
326 | rssi_combined; | ||
327 | } __packed; | ||
328 | u8 rssi[7]; | ||
329 | } __packed; | ||
330 | |||
331 | u8 evm_stream0[6], evm_stream1[6]; | ||
332 | u8 phy_err; | ||
333 | } __packed; | ||
334 | |||
335 | struct ar9170_rx_macstatus { | ||
336 | u8 SAidx, DAidx; | ||
337 | u8 error; | ||
338 | u8 status; | ||
339 | } __packed; | ||
340 | |||
341 | #define AR9170_ENC_ALG_NONE 0x0 | ||
342 | #define AR9170_ENC_ALG_WEP64 0x1 | ||
343 | #define AR9170_ENC_ALG_TKIP 0x2 | ||
344 | #define AR9170_ENC_ALG_AESCCMP 0x4 | ||
345 | #define AR9170_ENC_ALG_WEP128 0x5 | ||
346 | #define AR9170_ENC_ALG_WEP256 0x6 | ||
347 | #define AR9170_ENC_ALG_CENC 0x7 | ||
348 | |||
349 | #define AR9170_RX_ENC_SOFTWARE 0x8 | ||
350 | |||
351 | static inline u8 ar9170_get_decrypt_type(struct ar9170_rx_macstatus *t) | ||
352 | { | ||
353 | return (t->SAidx & 0xc0) >> 4 | | ||
354 | (t->DAidx & 0xc0) >> 6; | ||
355 | } | ||
356 | |||
357 | #define AR9170_RX_STATUS_MODULATION_MASK 0x03 | ||
358 | #define AR9170_RX_STATUS_MODULATION_CCK 0x00 | ||
359 | #define AR9170_RX_STATUS_MODULATION_OFDM 0x01 | ||
360 | #define AR9170_RX_STATUS_MODULATION_HT 0x02 | ||
361 | #define AR9170_RX_STATUS_MODULATION_DUPOFDM 0x03 | ||
362 | |||
363 | /* depends on modulation */ | ||
364 | #define AR9170_RX_STATUS_SHORT_PREAMBLE 0x08 | ||
365 | #define AR9170_RX_STATUS_GREENFIELD 0x08 | ||
366 | |||
367 | #define AR9170_RX_STATUS_MPDU_MASK 0x30 | ||
368 | #define AR9170_RX_STATUS_MPDU_SINGLE 0x00 | ||
369 | #define AR9170_RX_STATUS_MPDU_FIRST 0x20 | ||
370 | #define AR9170_RX_STATUS_MPDU_MIDDLE 0x30 | ||
371 | #define AR9170_RX_STATUS_MPDU_LAST 0x10 | ||
372 | |||
373 | #define AR9170_RX_ERROR_RXTO 0x01 | ||
374 | #define AR9170_RX_ERROR_OVERRUN 0x02 | ||
375 | #define AR9170_RX_ERROR_DECRYPT 0x04 | ||
376 | #define AR9170_RX_ERROR_FCS 0x08 | ||
377 | #define AR9170_RX_ERROR_WRONG_RA 0x10 | ||
378 | #define AR9170_RX_ERROR_PLCP 0x20 | ||
379 | #define AR9170_RX_ERROR_MMIC 0x40 | ||
380 | #define AR9170_RX_ERROR_FATAL 0x80 | ||
381 | |||
382 | struct ar9170_cmd_tx_status { | ||
383 | u8 dst[ETH_ALEN]; | ||
384 | __le32 rate; | ||
385 | __le16 status; | ||
386 | } __packed; | ||
387 | |||
388 | #define AR9170_TX_STATUS_COMPLETE 0x00 | ||
389 | #define AR9170_TX_STATUS_RETRY 0x01 | ||
390 | #define AR9170_TX_STATUS_FAILED 0x02 | ||
391 | |||
392 | struct ar9170_cmd_ba_failed_count { | ||
393 | __le16 failed; | ||
394 | __le16 rate; | ||
395 | } __packed; | ||
396 | |||
397 | struct ar9170_cmd_response { | ||
398 | u8 flag; | ||
399 | u8 type; | ||
400 | __le16 padding; | ||
401 | |||
402 | union { | ||
403 | struct ar9170_cmd_tx_status tx_status; | ||
404 | struct ar9170_cmd_ba_failed_count ba_fail_cnt; | ||
405 | u8 data[0]; | ||
406 | }; | ||
407 | } __packed; | ||
408 | |||
409 | /* QoS */ | ||
410 | |||
411 | /* mac80211 queue to HW/FW map */ | ||
412 | static const u8 ar9170_qos_hwmap[4] = { 3, 2, 0, 1 }; | ||
413 | |||
414 | /* HW/FW queue to mac80211 map */ | ||
415 | static const u8 ar9170_qos_mac80211map[4] = { 2, 3, 1, 0 }; | ||
416 | |||
417 | enum ar9170_txq { | ||
418 | AR9170_TXQ_BE, | ||
419 | AR9170_TXQ_BK, | ||
420 | AR9170_TXQ_VI, | ||
421 | AR9170_TXQ_VO, | ||
422 | |||
423 | __AR9170_NUM_TXQ, | ||
424 | }; | ||
425 | |||
426 | #define AR9170_TXQ_DEPTH 32 | ||
427 | #define AR9170_TX_MAX_PENDING 128 | ||
428 | #define AR9170_RX_STREAM_MAX_SIZE 65535 | ||
429 | |||
430 | #endif /* __AR9170_HW_H */ | ||
diff --git a/drivers/net/wireless/ath/ar9170/led.c b/drivers/net/wireless/ath/ar9170/led.c deleted file mode 100644 index 832d90087f8a..000000000000 --- a/drivers/net/wireless/ath/ar9170/led.c +++ /dev/null | |||
@@ -1,181 +0,0 @@ | |||
1 | /* | ||
2 | * Atheros AR9170 driver | ||
3 | * | ||
4 | * LED handling | ||
5 | * | ||
6 | * Copyright 2008, Johannes Berg <johannes@sipsolutions.net> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; see the file COPYING. If not, see | ||
20 | * http://www.gnu.org/licenses/. | ||
21 | * | ||
22 | * This file incorporates work covered by the following copyright and | ||
23 | * permission notice: | ||
24 | * Copyright (c) 2007-2008 Atheros Communications, Inc. | ||
25 | * | ||
26 | * Permission to use, copy, modify, and/or distribute this software for any | ||
27 | * purpose with or without fee is hereby granted, provided that the above | ||
28 | * copyright notice and this permission notice appear in all copies. | ||
29 | * | ||
30 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
31 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
32 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
33 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
34 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
35 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
36 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
37 | */ | ||
38 | |||
39 | #include "ar9170.h" | ||
40 | #include "cmd.h" | ||
41 | |||
42 | int ar9170_set_leds_state(struct ar9170 *ar, u32 led_state) | ||
43 | { | ||
44 | return ar9170_write_reg(ar, AR9170_GPIO_REG_DATA, led_state); | ||
45 | } | ||
46 | |||
47 | int ar9170_init_leds(struct ar9170 *ar) | ||
48 | { | ||
49 | int err; | ||
50 | |||
51 | /* disable LEDs */ | ||
52 | /* GPIO [0/1 mode: output, 2/3: input] */ | ||
53 | err = ar9170_write_reg(ar, AR9170_GPIO_REG_PORT_TYPE, 3); | ||
54 | if (err) | ||
55 | goto out; | ||
56 | |||
57 | /* GPIO 0/1 value: off */ | ||
58 | err = ar9170_set_leds_state(ar, 0); | ||
59 | |||
60 | out: | ||
61 | return err; | ||
62 | } | ||
63 | |||
64 | #ifdef CONFIG_AR9170_LEDS | ||
65 | static void ar9170_update_leds(struct work_struct *work) | ||
66 | { | ||
67 | struct ar9170 *ar = container_of(work, struct ar9170, led_work.work); | ||
68 | int i, tmp, blink_delay = 1000; | ||
69 | u32 led_val = 0; | ||
70 | bool rerun = false; | ||
71 | |||
72 | if (unlikely(!IS_ACCEPTING_CMD(ar))) | ||
73 | return ; | ||
74 | |||
75 | mutex_lock(&ar->mutex); | ||
76 | for (i = 0; i < AR9170_NUM_LEDS; i++) | ||
77 | if (ar->leds[i].registered && ar->leds[i].toggled) { | ||
78 | led_val |= 1 << i; | ||
79 | |||
80 | tmp = 70 + 200 / (ar->leds[i].toggled); | ||
81 | if (tmp < blink_delay) | ||
82 | blink_delay = tmp; | ||
83 | |||
84 | if (ar->leds[i].toggled > 1) | ||
85 | ar->leds[i].toggled = 0; | ||
86 | |||
87 | rerun = true; | ||
88 | } | ||
89 | |||
90 | ar9170_set_leds_state(ar, led_val); | ||
91 | mutex_unlock(&ar->mutex); | ||
92 | |||
93 | if (!rerun) | ||
94 | return; | ||
95 | |||
96 | ieee80211_queue_delayed_work(ar->hw, | ||
97 | &ar->led_work, | ||
98 | msecs_to_jiffies(blink_delay)); | ||
99 | } | ||
100 | |||
101 | static void ar9170_led_brightness_set(struct led_classdev *led, | ||
102 | enum led_brightness brightness) | ||
103 | { | ||
104 | struct ar9170_led *arl = container_of(led, struct ar9170_led, l); | ||
105 | struct ar9170 *ar = arl->ar; | ||
106 | |||
107 | if (unlikely(!arl->registered)) | ||
108 | return ; | ||
109 | |||
110 | if (arl->last_state != !!brightness) { | ||
111 | arl->toggled++; | ||
112 | arl->last_state = !!brightness; | ||
113 | } | ||
114 | |||
115 | if (likely(IS_ACCEPTING_CMD(ar) && arl->toggled)) | ||
116 | ieee80211_queue_delayed_work(ar->hw, &ar->led_work, HZ/10); | ||
117 | } | ||
118 | |||
119 | static int ar9170_register_led(struct ar9170 *ar, int i, char *name, | ||
120 | char *trigger) | ||
121 | { | ||
122 | int err; | ||
123 | |||
124 | snprintf(ar->leds[i].name, sizeof(ar->leds[i].name), | ||
125 | "ar9170-%s::%s", wiphy_name(ar->hw->wiphy), name); | ||
126 | |||
127 | ar->leds[i].ar = ar; | ||
128 | ar->leds[i].l.name = ar->leds[i].name; | ||
129 | ar->leds[i].l.brightness_set = ar9170_led_brightness_set; | ||
130 | ar->leds[i].l.brightness = 0; | ||
131 | ar->leds[i].l.default_trigger = trigger; | ||
132 | |||
133 | err = led_classdev_register(wiphy_dev(ar->hw->wiphy), | ||
134 | &ar->leds[i].l); | ||
135 | if (err) | ||
136 | wiphy_err(ar->hw->wiphy, "failed to register %s LED (%d).\n", | ||
137 | ar->leds[i].name, err); | ||
138 | else | ||
139 | ar->leds[i].registered = true; | ||
140 | |||
141 | return err; | ||
142 | } | ||
143 | |||
144 | void ar9170_unregister_leds(struct ar9170 *ar) | ||
145 | { | ||
146 | int i; | ||
147 | |||
148 | for (i = 0; i < AR9170_NUM_LEDS; i++) | ||
149 | if (ar->leds[i].registered) { | ||
150 | led_classdev_unregister(&ar->leds[i].l); | ||
151 | ar->leds[i].registered = false; | ||
152 | ar->leds[i].toggled = 0; | ||
153 | } | ||
154 | |||
155 | cancel_delayed_work_sync(&ar->led_work); | ||
156 | } | ||
157 | |||
158 | int ar9170_register_leds(struct ar9170 *ar) | ||
159 | { | ||
160 | int err; | ||
161 | |||
162 | INIT_DELAYED_WORK(&ar->led_work, ar9170_update_leds); | ||
163 | |||
164 | err = ar9170_register_led(ar, 0, "tx", | ||
165 | ieee80211_get_tx_led_name(ar->hw)); | ||
166 | if (err) | ||
167 | goto fail; | ||
168 | |||
169 | err = ar9170_register_led(ar, 1, "assoc", | ||
170 | ieee80211_get_assoc_led_name(ar->hw)); | ||
171 | if (err) | ||
172 | goto fail; | ||
173 | |||
174 | return 0; | ||
175 | |||
176 | fail: | ||
177 | ar9170_unregister_leds(ar); | ||
178 | return err; | ||
179 | } | ||
180 | |||
181 | #endif /* CONFIG_AR9170_LEDS */ | ||
diff --git a/drivers/net/wireless/ath/ar9170/mac.c b/drivers/net/wireless/ath/ar9170/mac.c deleted file mode 100644 index 857e86104295..000000000000 --- a/drivers/net/wireless/ath/ar9170/mac.c +++ /dev/null | |||
@@ -1,519 +0,0 @@ | |||
1 | /* | ||
2 | * Atheros AR9170 driver | ||
3 | * | ||
4 | * MAC programming | ||
5 | * | ||
6 | * Copyright 2008, Johannes Berg <johannes@sipsolutions.net> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; see the file COPYING. If not, see | ||
20 | * http://www.gnu.org/licenses/. | ||
21 | * | ||
22 | * This file incorporates work covered by the following copyright and | ||
23 | * permission notice: | ||
24 | * Copyright (c) 2007-2008 Atheros Communications, Inc. | ||
25 | * | ||
26 | * Permission to use, copy, modify, and/or distribute this software for any | ||
27 | * purpose with or without fee is hereby granted, provided that the above | ||
28 | * copyright notice and this permission notice appear in all copies. | ||
29 | * | ||
30 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
31 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
32 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
33 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
34 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
35 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
36 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
37 | */ | ||
38 | |||
39 | #include <asm/unaligned.h> | ||
40 | |||
41 | #include "ar9170.h" | ||
42 | #include "cmd.h" | ||
43 | |||
44 | int ar9170_set_dyn_sifs_ack(struct ar9170 *ar) | ||
45 | { | ||
46 | u32 val; | ||
47 | |||
48 | if (conf_is_ht40(&ar->hw->conf)) | ||
49 | val = 0x010a; | ||
50 | else { | ||
51 | if (ar->hw->conf.channel->band == IEEE80211_BAND_2GHZ) | ||
52 | val = 0x105; | ||
53 | else | ||
54 | val = 0x104; | ||
55 | } | ||
56 | |||
57 | return ar9170_write_reg(ar, AR9170_MAC_REG_DYNAMIC_SIFS_ACK, val); | ||
58 | } | ||
59 | |||
60 | int ar9170_set_slot_time(struct ar9170 *ar) | ||
61 | { | ||
62 | u32 slottime = 20; | ||
63 | |||
64 | if (!ar->vif) | ||
65 | return 0; | ||
66 | |||
67 | if ((ar->hw->conf.channel->band == IEEE80211_BAND_5GHZ) || | ||
68 | ar->vif->bss_conf.use_short_slot) | ||
69 | slottime = 9; | ||
70 | |||
71 | return ar9170_write_reg(ar, AR9170_MAC_REG_SLOT_TIME, slottime << 10); | ||
72 | } | ||
73 | |||
74 | int ar9170_set_basic_rates(struct ar9170 *ar) | ||
75 | { | ||
76 | u8 cck, ofdm; | ||
77 | |||
78 | if (!ar->vif) | ||
79 | return 0; | ||
80 | |||
81 | ofdm = ar->vif->bss_conf.basic_rates >> 4; | ||
82 | |||
83 | /* FIXME: is still necessary? */ | ||
84 | if (ar->hw->conf.channel->band == IEEE80211_BAND_5GHZ) | ||
85 | cck = 0; | ||
86 | else | ||
87 | cck = ar->vif->bss_conf.basic_rates & 0xf; | ||
88 | |||
89 | return ar9170_write_reg(ar, AR9170_MAC_REG_BASIC_RATE, | ||
90 | ofdm << 8 | cck); | ||
91 | } | ||
92 | |||
93 | int ar9170_set_qos(struct ar9170 *ar) | ||
94 | { | ||
95 | ar9170_regwrite_begin(ar); | ||
96 | |||
97 | ar9170_regwrite(AR9170_MAC_REG_AC0_CW, ar->edcf[0].cw_min | | ||
98 | (ar->edcf[0].cw_max << 16)); | ||
99 | ar9170_regwrite(AR9170_MAC_REG_AC1_CW, ar->edcf[1].cw_min | | ||
100 | (ar->edcf[1].cw_max << 16)); | ||
101 | ar9170_regwrite(AR9170_MAC_REG_AC2_CW, ar->edcf[2].cw_min | | ||
102 | (ar->edcf[2].cw_max << 16)); | ||
103 | ar9170_regwrite(AR9170_MAC_REG_AC3_CW, ar->edcf[3].cw_min | | ||
104 | (ar->edcf[3].cw_max << 16)); | ||
105 | ar9170_regwrite(AR9170_MAC_REG_AC4_CW, ar->edcf[4].cw_min | | ||
106 | (ar->edcf[4].cw_max << 16)); | ||
107 | |||
108 | ar9170_regwrite(AR9170_MAC_REG_AC1_AC0_AIFS, | ||
109 | ((ar->edcf[0].aifs * 9 + 10)) | | ||
110 | ((ar->edcf[1].aifs * 9 + 10) << 12) | | ||
111 | ((ar->edcf[2].aifs * 9 + 10) << 24)); | ||
112 | ar9170_regwrite(AR9170_MAC_REG_AC3_AC2_AIFS, | ||
113 | ((ar->edcf[2].aifs * 9 + 10) >> 8) | | ||
114 | ((ar->edcf[3].aifs * 9 + 10) << 4) | | ||
115 | ((ar->edcf[4].aifs * 9 + 10) << 16)); | ||
116 | |||
117 | ar9170_regwrite(AR9170_MAC_REG_AC1_AC0_TXOP, | ||
118 | ar->edcf[0].txop | ar->edcf[1].txop << 16); | ||
119 | ar9170_regwrite(AR9170_MAC_REG_AC3_AC2_TXOP, | ||
120 | ar->edcf[2].txop | ar->edcf[3].txop << 16); | ||
121 | |||
122 | ar9170_regwrite_finish(); | ||
123 | |||
124 | return ar9170_regwrite_result(); | ||
125 | } | ||
126 | |||
127 | static int ar9170_set_ampdu_density(struct ar9170 *ar, u8 mpdudensity) | ||
128 | { | ||
129 | u32 val; | ||
130 | |||
131 | /* don't allow AMPDU density > 8us */ | ||
132 | if (mpdudensity > 6) | ||
133 | return -EINVAL; | ||
134 | |||
135 | /* Watch out! Otus uses slightly different density values. */ | ||
136 | val = 0x140a00 | (mpdudensity ? (mpdudensity + 1) : 0); | ||
137 | |||
138 | ar9170_regwrite_begin(ar); | ||
139 | ar9170_regwrite(AR9170_MAC_REG_AMPDU_DENSITY, val); | ||
140 | ar9170_regwrite_finish(); | ||
141 | |||
142 | return ar9170_regwrite_result(); | ||
143 | } | ||
144 | |||
145 | int ar9170_init_mac(struct ar9170 *ar) | ||
146 | { | ||
147 | ar9170_regwrite_begin(ar); | ||
148 | |||
149 | ar9170_regwrite(AR9170_MAC_REG_ACK_EXTENSION, 0x40); | ||
150 | |||
151 | ar9170_regwrite(AR9170_MAC_REG_RETRY_MAX, 0); | ||
152 | |||
153 | /* enable MMIC */ | ||
154 | ar9170_regwrite(AR9170_MAC_REG_SNIFFER, | ||
155 | AR9170_MAC_REG_SNIFFER_DEFAULTS); | ||
156 | |||
157 | ar9170_regwrite(AR9170_MAC_REG_RX_THRESHOLD, 0xc1f80); | ||
158 | |||
159 | ar9170_regwrite(AR9170_MAC_REG_RX_PE_DELAY, 0x70); | ||
160 | ar9170_regwrite(AR9170_MAC_REG_EIFS_AND_SIFS, 0xa144000); | ||
161 | ar9170_regwrite(AR9170_MAC_REG_SLOT_TIME, 9 << 10); | ||
162 | |||
163 | /* CF-END mode */ | ||
164 | ar9170_regwrite(0x1c3b2c, 0x19000000); | ||
165 | |||
166 | /* NAV protects ACK only (in TXOP) */ | ||
167 | ar9170_regwrite(0x1c3b38, 0x201); | ||
168 | |||
169 | /* Set Beacon PHY CTRL's TPC to 0x7, TA1=1 */ | ||
170 | /* OTUS set AM to 0x1 */ | ||
171 | ar9170_regwrite(AR9170_MAC_REG_BCN_HT1, 0x8000170); | ||
172 | |||
173 | ar9170_regwrite(AR9170_MAC_REG_BACKOFF_PROTECT, 0x105); | ||
174 | |||
175 | /* AGG test code*/ | ||
176 | /* Aggregation MAX number and timeout */ | ||
177 | ar9170_regwrite(0x1c3b9c, 0x10000a); | ||
178 | |||
179 | ar9170_regwrite(AR9170_MAC_REG_FRAMETYPE_FILTER, | ||
180 | AR9170_MAC_REG_FTF_DEFAULTS); | ||
181 | |||
182 | /* Enable deaggregator, response in sniffer mode */ | ||
183 | ar9170_regwrite(0x1c3c40, 0x1 | 1<<30); | ||
184 | |||
185 | /* rate sets */ | ||
186 | ar9170_regwrite(AR9170_MAC_REG_BASIC_RATE, 0x150f); | ||
187 | ar9170_regwrite(AR9170_MAC_REG_MANDATORY_RATE, 0x150f); | ||
188 | ar9170_regwrite(AR9170_MAC_REG_RTS_CTS_RATE, 0x10b01bb); | ||
189 | |||
190 | /* MIMO response control */ | ||
191 | ar9170_regwrite(0x1c3694, 0x4003C1E);/* bit 26~28 otus-AM */ | ||
192 | |||
193 | /* switch MAC to OTUS interface */ | ||
194 | ar9170_regwrite(0x1c3600, 0x3); | ||
195 | |||
196 | ar9170_regwrite(AR9170_MAC_REG_AMPDU_RX_THRESH, 0xffff); | ||
197 | |||
198 | /* set PHY register read timeout (??) */ | ||
199 | ar9170_regwrite(AR9170_MAC_REG_MISC_680, 0xf00008); | ||
200 | |||
201 | /* Disable Rx TimeOut, workaround for BB. */ | ||
202 | ar9170_regwrite(AR9170_MAC_REG_RX_TIMEOUT, 0x0); | ||
203 | |||
204 | /* Set CPU clock frequency to 88/80MHz */ | ||
205 | ar9170_regwrite(AR9170_PWR_REG_CLOCK_SEL, | ||
206 | AR9170_PWR_CLK_AHB_80_88MHZ | | ||
207 | AR9170_PWR_CLK_DAC_160_INV_DLY); | ||
208 | |||
209 | /* Set WLAN DMA interrupt mode: generate int per packet */ | ||
210 | ar9170_regwrite(AR9170_MAC_REG_TXRX_MPI, 0x110011); | ||
211 | |||
212 | ar9170_regwrite(AR9170_MAC_REG_FCS_SELECT, | ||
213 | AR9170_MAC_FCS_FIFO_PROT); | ||
214 | |||
215 | /* Disables the CF_END frame, undocumented register */ | ||
216 | ar9170_regwrite(AR9170_MAC_REG_TXOP_NOT_ENOUGH_IND, | ||
217 | 0x141E0F48); | ||
218 | |||
219 | ar9170_regwrite_finish(); | ||
220 | |||
221 | return ar9170_regwrite_result(); | ||
222 | } | ||
223 | |||
224 | static int ar9170_set_mac_reg(struct ar9170 *ar, const u32 reg, const u8 *mac) | ||
225 | { | ||
226 | static const u8 zero[ETH_ALEN] = { 0 }; | ||
227 | |||
228 | if (!mac) | ||
229 | mac = zero; | ||
230 | |||
231 | ar9170_regwrite_begin(ar); | ||
232 | |||
233 | ar9170_regwrite(reg, get_unaligned_le32(mac)); | ||
234 | ar9170_regwrite(reg + 4, get_unaligned_le16(mac + 4)); | ||
235 | |||
236 | ar9170_regwrite_finish(); | ||
237 | |||
238 | return ar9170_regwrite_result(); | ||
239 | } | ||
240 | |||
241 | int ar9170_update_multicast(struct ar9170 *ar, const u64 mc_hash) | ||
242 | { | ||
243 | int err; | ||
244 | |||
245 | ar9170_regwrite_begin(ar); | ||
246 | ar9170_regwrite(AR9170_MAC_REG_GROUP_HASH_TBL_H, mc_hash >> 32); | ||
247 | ar9170_regwrite(AR9170_MAC_REG_GROUP_HASH_TBL_L, mc_hash); | ||
248 | ar9170_regwrite_finish(); | ||
249 | err = ar9170_regwrite_result(); | ||
250 | if (err) | ||
251 | return err; | ||
252 | |||
253 | ar->cur_mc_hash = mc_hash; | ||
254 | return 0; | ||
255 | } | ||
256 | |||
257 | int ar9170_update_frame_filter(struct ar9170 *ar, const u32 filter) | ||
258 | { | ||
259 | int err; | ||
260 | |||
261 | err = ar9170_write_reg(ar, AR9170_MAC_REG_FRAMETYPE_FILTER, filter); | ||
262 | if (err) | ||
263 | return err; | ||
264 | |||
265 | ar->cur_filter = filter; | ||
266 | return 0; | ||
267 | } | ||
268 | |||
269 | static int ar9170_set_promiscouous(struct ar9170 *ar) | ||
270 | { | ||
271 | u32 encr_mode, sniffer; | ||
272 | int err; | ||
273 | |||
274 | err = ar9170_read_reg(ar, AR9170_MAC_REG_SNIFFER, &sniffer); | ||
275 | if (err) | ||
276 | return err; | ||
277 | |||
278 | err = ar9170_read_reg(ar, AR9170_MAC_REG_ENCRYPTION, &encr_mode); | ||
279 | if (err) | ||
280 | return err; | ||
281 | |||
282 | if (ar->sniffer_enabled) { | ||
283 | sniffer |= AR9170_MAC_REG_SNIFFER_ENABLE_PROMISC; | ||
284 | |||
285 | /* | ||
286 | * Rx decryption works in place. | ||
287 | * | ||
288 | * If we don't disable it, the hardware will render all | ||
289 | * encrypted frames which are encrypted with an unknown | ||
290 | * key useless. | ||
291 | */ | ||
292 | |||
293 | encr_mode |= AR9170_MAC_REG_ENCRYPTION_RX_SOFTWARE; | ||
294 | ar->sniffer_enabled = true; | ||
295 | } else { | ||
296 | sniffer &= ~AR9170_MAC_REG_SNIFFER_ENABLE_PROMISC; | ||
297 | |||
298 | if (ar->rx_software_decryption) | ||
299 | encr_mode |= AR9170_MAC_REG_ENCRYPTION_RX_SOFTWARE; | ||
300 | else | ||
301 | encr_mode &= ~AR9170_MAC_REG_ENCRYPTION_RX_SOFTWARE; | ||
302 | } | ||
303 | |||
304 | ar9170_regwrite_begin(ar); | ||
305 | ar9170_regwrite(AR9170_MAC_REG_ENCRYPTION, encr_mode); | ||
306 | ar9170_regwrite(AR9170_MAC_REG_SNIFFER, sniffer); | ||
307 | ar9170_regwrite_finish(); | ||
308 | |||
309 | return ar9170_regwrite_result(); | ||
310 | } | ||
311 | |||
312 | int ar9170_set_operating_mode(struct ar9170 *ar) | ||
313 | { | ||
314 | struct ath_common *common = &ar->common; | ||
315 | u32 pm_mode = AR9170_MAC_REG_POWERMGT_DEFAULTS; | ||
316 | u8 *mac_addr, *bssid; | ||
317 | int err; | ||
318 | |||
319 | if (ar->vif) { | ||
320 | mac_addr = common->macaddr; | ||
321 | bssid = common->curbssid; | ||
322 | |||
323 | switch (ar->vif->type) { | ||
324 | case NL80211_IFTYPE_MESH_POINT: | ||
325 | case NL80211_IFTYPE_ADHOC: | ||
326 | pm_mode |= AR9170_MAC_REG_POWERMGT_IBSS; | ||
327 | break; | ||
328 | case NL80211_IFTYPE_AP: | ||
329 | pm_mode |= AR9170_MAC_REG_POWERMGT_AP; | ||
330 | break; | ||
331 | case NL80211_IFTYPE_WDS: | ||
332 | pm_mode |= AR9170_MAC_REG_POWERMGT_AP_WDS; | ||
333 | break; | ||
334 | case NL80211_IFTYPE_MONITOR: | ||
335 | ar->sniffer_enabled = true; | ||
336 | ar->rx_software_decryption = true; | ||
337 | break; | ||
338 | default: | ||
339 | pm_mode |= AR9170_MAC_REG_POWERMGT_STA; | ||
340 | break; | ||
341 | } | ||
342 | } else { | ||
343 | mac_addr = NULL; | ||
344 | bssid = NULL; | ||
345 | } | ||
346 | |||
347 | err = ar9170_set_mac_reg(ar, AR9170_MAC_REG_MAC_ADDR_L, mac_addr); | ||
348 | if (err) | ||
349 | return err; | ||
350 | |||
351 | err = ar9170_set_mac_reg(ar, AR9170_MAC_REG_BSSID_L, bssid); | ||
352 | if (err) | ||
353 | return err; | ||
354 | |||
355 | err = ar9170_set_promiscouous(ar); | ||
356 | if (err) | ||
357 | return err; | ||
358 | |||
359 | /* set AMPDU density to 8us. */ | ||
360 | err = ar9170_set_ampdu_density(ar, 6); | ||
361 | if (err) | ||
362 | return err; | ||
363 | |||
364 | ar9170_regwrite_begin(ar); | ||
365 | |||
366 | ar9170_regwrite(AR9170_MAC_REG_POWERMANAGEMENT, pm_mode); | ||
367 | ar9170_regwrite_finish(); | ||
368 | |||
369 | return ar9170_regwrite_result(); | ||
370 | } | ||
371 | |||
372 | int ar9170_set_hwretry_limit(struct ar9170 *ar, unsigned int max_retry) | ||
373 | { | ||
374 | u32 tmp = min_t(u32, 0x33333, max_retry * 0x11111); | ||
375 | |||
376 | return ar9170_write_reg(ar, AR9170_MAC_REG_RETRY_MAX, tmp); | ||
377 | } | ||
378 | |||
379 | int ar9170_set_beacon_timers(struct ar9170 *ar) | ||
380 | { | ||
381 | u32 v = 0; | ||
382 | u32 pretbtt = 0; | ||
383 | |||
384 | if (ar->vif) { | ||
385 | v |= ar->vif->bss_conf.beacon_int; | ||
386 | |||
387 | if (ar->enable_beacon) { | ||
388 | switch (ar->vif->type) { | ||
389 | case NL80211_IFTYPE_MESH_POINT: | ||
390 | case NL80211_IFTYPE_ADHOC: | ||
391 | v |= BIT(25); | ||
392 | break; | ||
393 | case NL80211_IFTYPE_AP: | ||
394 | v |= BIT(24); | ||
395 | pretbtt = (ar->vif->bss_conf.beacon_int - 6) << | ||
396 | 16; | ||
397 | break; | ||
398 | default: | ||
399 | break; | ||
400 | } | ||
401 | } | ||
402 | |||
403 | v |= ar->vif->bss_conf.dtim_period << 16; | ||
404 | } | ||
405 | |||
406 | ar9170_regwrite_begin(ar); | ||
407 | ar9170_regwrite(AR9170_MAC_REG_PRETBTT, pretbtt); | ||
408 | ar9170_regwrite(AR9170_MAC_REG_BCN_PERIOD, v); | ||
409 | ar9170_regwrite_finish(); | ||
410 | return ar9170_regwrite_result(); | ||
411 | } | ||
412 | |||
413 | int ar9170_update_beacon(struct ar9170 *ar) | ||
414 | { | ||
415 | struct sk_buff *skb; | ||
416 | __le32 *data, *old = NULL; | ||
417 | u32 word; | ||
418 | int i; | ||
419 | |||
420 | skb = ieee80211_beacon_get(ar->hw, ar->vif); | ||
421 | if (!skb) | ||
422 | return -ENOMEM; | ||
423 | |||
424 | data = (__le32 *)skb->data; | ||
425 | if (ar->beacon) | ||
426 | old = (__le32 *)ar->beacon->data; | ||
427 | |||
428 | ar9170_regwrite_begin(ar); | ||
429 | for (i = 0; i < DIV_ROUND_UP(skb->len, 4); i++) { | ||
430 | /* | ||
431 | * XXX: This accesses beyond skb data for up | ||
432 | * to the last 3 bytes!! | ||
433 | */ | ||
434 | |||
435 | if (old && (data[i] == old[i])) | ||
436 | continue; | ||
437 | |||
438 | word = le32_to_cpu(data[i]); | ||
439 | ar9170_regwrite(AR9170_BEACON_BUFFER_ADDRESS + 4 * i, word); | ||
440 | } | ||
441 | |||
442 | /* XXX: use skb->cb info */ | ||
443 | if (ar->hw->conf.channel->band == IEEE80211_BAND_2GHZ) | ||
444 | ar9170_regwrite(AR9170_MAC_REG_BCN_PLCP, | ||
445 | ((skb->len + 4) << (3 + 16)) + 0x0400); | ||
446 | else | ||
447 | ar9170_regwrite(AR9170_MAC_REG_BCN_PLCP, | ||
448 | ((skb->len + 4) << 16) + 0x001b); | ||
449 | |||
450 | ar9170_regwrite(AR9170_MAC_REG_BCN_LENGTH, skb->len + 4); | ||
451 | ar9170_regwrite(AR9170_MAC_REG_BCN_ADDR, AR9170_BEACON_BUFFER_ADDRESS); | ||
452 | ar9170_regwrite(AR9170_MAC_REG_BCN_CTRL, 1); | ||
453 | |||
454 | ar9170_regwrite_finish(); | ||
455 | |||
456 | dev_kfree_skb(ar->beacon); | ||
457 | ar->beacon = skb; | ||
458 | |||
459 | return ar9170_regwrite_result(); | ||
460 | } | ||
461 | |||
462 | void ar9170_new_beacon(struct work_struct *work) | ||
463 | { | ||
464 | struct ar9170 *ar = container_of(work, struct ar9170, | ||
465 | beacon_work); | ||
466 | struct sk_buff *skb; | ||
467 | |||
468 | if (unlikely(!IS_STARTED(ar))) | ||
469 | return ; | ||
470 | |||
471 | mutex_lock(&ar->mutex); | ||
472 | |||
473 | if (!ar->vif) | ||
474 | goto out; | ||
475 | |||
476 | ar9170_update_beacon(ar); | ||
477 | |||
478 | rcu_read_lock(); | ||
479 | while ((skb = ieee80211_get_buffered_bc(ar->hw, ar->vif))) | ||
480 | ar9170_op_tx(ar->hw, skb); | ||
481 | |||
482 | rcu_read_unlock(); | ||
483 | |||
484 | out: | ||
485 | mutex_unlock(&ar->mutex); | ||
486 | } | ||
487 | |||
488 | int ar9170_upload_key(struct ar9170 *ar, u8 id, const u8 *mac, u8 ktype, | ||
489 | u8 keyidx, u8 *keydata, int keylen) | ||
490 | { | ||
491 | __le32 vals[7]; | ||
492 | static const u8 bcast[ETH_ALEN] = | ||
493 | { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; | ||
494 | u8 dummy; | ||
495 | |||
496 | mac = mac ? : bcast; | ||
497 | |||
498 | vals[0] = cpu_to_le32((keyidx << 16) + id); | ||
499 | vals[1] = cpu_to_le32(mac[1] << 24 | mac[0] << 16 | ktype); | ||
500 | vals[2] = cpu_to_le32(mac[5] << 24 | mac[4] << 16 | | ||
501 | mac[3] << 8 | mac[2]); | ||
502 | memset(&vals[3], 0, 16); | ||
503 | if (keydata) | ||
504 | memcpy(&vals[3], keydata, keylen); | ||
505 | |||
506 | return ar->exec_cmd(ar, AR9170_CMD_EKEY, | ||
507 | sizeof(vals), (u8 *)vals, | ||
508 | 1, &dummy); | ||
509 | } | ||
510 | |||
511 | int ar9170_disable_key(struct ar9170 *ar, u8 id) | ||
512 | { | ||
513 | __le32 val = cpu_to_le32(id); | ||
514 | u8 dummy; | ||
515 | |||
516 | return ar->exec_cmd(ar, AR9170_CMD_EKEY, | ||
517 | sizeof(val), (u8 *)&val, | ||
518 | 1, &dummy); | ||
519 | } | ||
diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c deleted file mode 100644 index ccc2edaaeda0..000000000000 --- a/drivers/net/wireless/ath/ar9170/main.c +++ /dev/null | |||
@@ -1,2190 +0,0 @@ | |||
1 | /* | ||
2 | * Atheros AR9170 driver | ||
3 | * | ||
4 | * mac80211 interaction code | ||
5 | * | ||
6 | * Copyright 2008, Johannes Berg <johannes@sipsolutions.net> | ||
7 | * Copyright 2009, Christian Lamparter <chunkeey@web.de> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; see the file COPYING. If not, see | ||
21 | * http://www.gnu.org/licenses/. | ||
22 | * | ||
23 | * This file incorporates work covered by the following copyright and | ||
24 | * permission notice: | ||
25 | * Copyright (c) 2007-2008 Atheros Communications, Inc. | ||
26 | * | ||
27 | * Permission to use, copy, modify, and/or distribute this software for any | ||
28 | * purpose with or without fee is hereby granted, provided that the above | ||
29 | * copyright notice and this permission notice appear in all copies. | ||
30 | * | ||
31 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
32 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
33 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
34 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
35 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
36 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
37 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
38 | */ | ||
39 | |||
40 | #include <linux/init.h> | ||
41 | #include <linux/slab.h> | ||
42 | #include <linux/module.h> | ||
43 | #include <linux/etherdevice.h> | ||
44 | #include <net/mac80211.h> | ||
45 | #include "ar9170.h" | ||
46 | #include "hw.h" | ||
47 | #include "cmd.h" | ||
48 | |||
49 | static int modparam_nohwcrypt; | ||
50 | module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); | ||
51 | MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); | ||
52 | |||
53 | #define RATE(_bitrate, _hw_rate, _txpidx, _flags) { \ | ||
54 | .bitrate = (_bitrate), \ | ||
55 | .flags = (_flags), \ | ||
56 | .hw_value = (_hw_rate) | (_txpidx) << 4, \ | ||
57 | } | ||
58 | |||
59 | static struct ieee80211_rate __ar9170_ratetable[] = { | ||
60 | RATE(10, 0, 0, 0), | ||
61 | RATE(20, 1, 1, IEEE80211_RATE_SHORT_PREAMBLE), | ||
62 | RATE(55, 2, 2, IEEE80211_RATE_SHORT_PREAMBLE), | ||
63 | RATE(110, 3, 3, IEEE80211_RATE_SHORT_PREAMBLE), | ||
64 | RATE(60, 0xb, 0, 0), | ||
65 | RATE(90, 0xf, 0, 0), | ||
66 | RATE(120, 0xa, 0, 0), | ||
67 | RATE(180, 0xe, 0, 0), | ||
68 | RATE(240, 0x9, 0, 0), | ||
69 | RATE(360, 0xd, 1, 0), | ||
70 | RATE(480, 0x8, 2, 0), | ||
71 | RATE(540, 0xc, 3, 0), | ||
72 | }; | ||
73 | #undef RATE | ||
74 | |||
75 | #define ar9170_g_ratetable (__ar9170_ratetable + 0) | ||
76 | #define ar9170_g_ratetable_size 12 | ||
77 | #define ar9170_a_ratetable (__ar9170_ratetable + 4) | ||
78 | #define ar9170_a_ratetable_size 8 | ||
79 | |||
80 | /* | ||
81 | * NB: The hw_value is used as an index into the ar9170_phy_freq_params | ||
82 | * array in phy.c so that we don't have to do frequency lookups! | ||
83 | */ | ||
84 | #define CHAN(_freq, _idx) { \ | ||
85 | .center_freq = (_freq), \ | ||
86 | .hw_value = (_idx), \ | ||
87 | .max_power = 18, /* XXX */ \ | ||
88 | } | ||
89 | |||
90 | static struct ieee80211_channel ar9170_2ghz_chantable[] = { | ||
91 | CHAN(2412, 0), | ||
92 | CHAN(2417, 1), | ||
93 | CHAN(2422, 2), | ||
94 | CHAN(2427, 3), | ||
95 | CHAN(2432, 4), | ||
96 | CHAN(2437, 5), | ||
97 | CHAN(2442, 6), | ||
98 | CHAN(2447, 7), | ||
99 | CHAN(2452, 8), | ||
100 | CHAN(2457, 9), | ||
101 | CHAN(2462, 10), | ||
102 | CHAN(2467, 11), | ||
103 | CHAN(2472, 12), | ||
104 | CHAN(2484, 13), | ||
105 | }; | ||
106 | |||
107 | static struct ieee80211_channel ar9170_5ghz_chantable[] = { | ||
108 | CHAN(4920, 14), | ||
109 | CHAN(4940, 15), | ||
110 | CHAN(4960, 16), | ||
111 | CHAN(4980, 17), | ||
112 | CHAN(5040, 18), | ||
113 | CHAN(5060, 19), | ||
114 | CHAN(5080, 20), | ||
115 | CHAN(5180, 21), | ||
116 | CHAN(5200, 22), | ||
117 | CHAN(5220, 23), | ||
118 | CHAN(5240, 24), | ||
119 | CHAN(5260, 25), | ||
120 | CHAN(5280, 26), | ||
121 | CHAN(5300, 27), | ||
122 | CHAN(5320, 28), | ||
123 | CHAN(5500, 29), | ||
124 | CHAN(5520, 30), | ||
125 | CHAN(5540, 31), | ||
126 | CHAN(5560, 32), | ||
127 | CHAN(5580, 33), | ||
128 | CHAN(5600, 34), | ||
129 | CHAN(5620, 35), | ||
130 | CHAN(5640, 36), | ||
131 | CHAN(5660, 37), | ||
132 | CHAN(5680, 38), | ||
133 | CHAN(5700, 39), | ||
134 | CHAN(5745, 40), | ||
135 | CHAN(5765, 41), | ||
136 | CHAN(5785, 42), | ||
137 | CHAN(5805, 43), | ||
138 | CHAN(5825, 44), | ||
139 | CHAN(5170, 45), | ||
140 | CHAN(5190, 46), | ||
141 | CHAN(5210, 47), | ||
142 | CHAN(5230, 48), | ||
143 | }; | ||
144 | #undef CHAN | ||
145 | |||
146 | #define AR9170_HT_CAP \ | ||
147 | { \ | ||
148 | .ht_supported = true, \ | ||
149 | .cap = IEEE80211_HT_CAP_MAX_AMSDU | \ | ||
150 | IEEE80211_HT_CAP_SUP_WIDTH_20_40 | \ | ||
151 | IEEE80211_HT_CAP_SGI_40 | \ | ||
152 | IEEE80211_HT_CAP_GRN_FLD | \ | ||
153 | IEEE80211_HT_CAP_DSSSCCK40 | \ | ||
154 | IEEE80211_HT_CAP_SM_PS, \ | ||
155 | .ampdu_factor = 3, \ | ||
156 | .ampdu_density = 6, \ | ||
157 | .mcs = { \ | ||
158 | .rx_mask = { 0xff, 0xff, 0, 0, 0x1, 0, 0, 0, 0, 0, }, \ | ||
159 | .rx_highest = cpu_to_le16(300), \ | ||
160 | .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \ | ||
161 | }, \ | ||
162 | } | ||
163 | |||
164 | static struct ieee80211_supported_band ar9170_band_2GHz = { | ||
165 | .channels = ar9170_2ghz_chantable, | ||
166 | .n_channels = ARRAY_SIZE(ar9170_2ghz_chantable), | ||
167 | .bitrates = ar9170_g_ratetable, | ||
168 | .n_bitrates = ar9170_g_ratetable_size, | ||
169 | .ht_cap = AR9170_HT_CAP, | ||
170 | }; | ||
171 | |||
172 | static struct ieee80211_supported_band ar9170_band_5GHz = { | ||
173 | .channels = ar9170_5ghz_chantable, | ||
174 | .n_channels = ARRAY_SIZE(ar9170_5ghz_chantable), | ||
175 | .bitrates = ar9170_a_ratetable, | ||
176 | .n_bitrates = ar9170_a_ratetable_size, | ||
177 | .ht_cap = AR9170_HT_CAP, | ||
178 | }; | ||
179 | |||
180 | static void ar9170_tx(struct ar9170 *ar); | ||
181 | |||
182 | static inline u16 ar9170_get_seq_h(struct ieee80211_hdr *hdr) | ||
183 | { | ||
184 | return le16_to_cpu(hdr->seq_ctrl) >> 4; | ||
185 | } | ||
186 | |||
187 | static inline u16 ar9170_get_seq(struct sk_buff *skb) | ||
188 | { | ||
189 | struct ar9170_tx_control *txc = (void *) skb->data; | ||
190 | return ar9170_get_seq_h((void *) txc->frame_data); | ||
191 | } | ||
192 | |||
193 | #ifdef AR9170_QUEUE_DEBUG | ||
194 | static void ar9170_print_txheader(struct ar9170 *ar, struct sk_buff *skb) | ||
195 | { | ||
196 | struct ar9170_tx_control *txc = (void *) skb->data; | ||
197 | struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb); | ||
198 | struct ar9170_tx_info *arinfo = (void *) txinfo->rate_driver_data; | ||
199 | struct ieee80211_hdr *hdr = (void *) txc->frame_data; | ||
200 | |||
201 | wiphy_debug(ar->hw->wiphy, | ||
202 | "=> FRAME [skb:%p, q:%d, DA:[%pM] s:%d " | ||
203 | "mac_ctrl:%04x, phy_ctrl:%08x, timeout:[%d ms]]\n", | ||
204 | skb, skb_get_queue_mapping(skb), | ||
205 | ieee80211_get_DA(hdr), ar9170_get_seq_h(hdr), | ||
206 | le16_to_cpu(txc->mac_control), le32_to_cpu(txc->phy_control), | ||
207 | jiffies_to_msecs(arinfo->timeout - jiffies)); | ||
208 | } | ||
209 | |||
210 | static void __ar9170_dump_txqueue(struct ar9170 *ar, | ||
211 | struct sk_buff_head *queue) | ||
212 | { | ||
213 | struct sk_buff *skb; | ||
214 | int i = 0; | ||
215 | |||
216 | printk(KERN_DEBUG "---[ cut here ]---\n"); | ||
217 | wiphy_debug(ar->hw->wiphy, "%d entries in queue.\n", | ||
218 | skb_queue_len(queue)); | ||
219 | |||
220 | skb_queue_walk(queue, skb) { | ||
221 | printk(KERN_DEBUG "index:%d =>\n", i++); | ||
222 | ar9170_print_txheader(ar, skb); | ||
223 | } | ||
224 | if (i != skb_queue_len(queue)) | ||
225 | printk(KERN_DEBUG "WARNING: queue frame counter " | ||
226 | "mismatch %d != %d\n", skb_queue_len(queue), i); | ||
227 | printk(KERN_DEBUG "---[ end ]---\n"); | ||
228 | } | ||
229 | #endif /* AR9170_QUEUE_DEBUG */ | ||
230 | |||
231 | #ifdef AR9170_QUEUE_DEBUG | ||
232 | static void ar9170_dump_txqueue(struct ar9170 *ar, | ||
233 | struct sk_buff_head *queue) | ||
234 | { | ||
235 | unsigned long flags; | ||
236 | |||
237 | spin_lock_irqsave(&queue->lock, flags); | ||
238 | __ar9170_dump_txqueue(ar, queue); | ||
239 | spin_unlock_irqrestore(&queue->lock, flags); | ||
240 | } | ||
241 | #endif /* AR9170_QUEUE_DEBUG */ | ||
242 | |||
243 | #ifdef AR9170_QUEUE_STOP_DEBUG | ||
244 | static void __ar9170_dump_txstats(struct ar9170 *ar) | ||
245 | { | ||
246 | int i; | ||
247 | |||
248 | wiphy_debug(ar->hw->wiphy, "QoS queue stats\n"); | ||
249 | |||
250 | for (i = 0; i < __AR9170_NUM_TXQ; i++) | ||
251 | wiphy_debug(ar->hw->wiphy, | ||
252 | "queue:%d limit:%d len:%d waitack:%d stopped:%d\n", | ||
253 | i, ar->tx_stats[i].limit, ar->tx_stats[i].len, | ||
254 | skb_queue_len(&ar->tx_status[i]), | ||
255 | ieee80211_queue_stopped(ar->hw, i)); | ||
256 | } | ||
257 | #endif /* AR9170_QUEUE_STOP_DEBUG */ | ||
258 | |||
259 | /* caller must guarantee exclusive access for _bin_ queue. */ | ||
260 | static void ar9170_recycle_expired(struct ar9170 *ar, | ||
261 | struct sk_buff_head *queue, | ||
262 | struct sk_buff_head *bin) | ||
263 | { | ||
264 | struct sk_buff *skb, *old = NULL; | ||
265 | unsigned long flags; | ||
266 | |||
267 | spin_lock_irqsave(&queue->lock, flags); | ||
268 | while ((skb = skb_peek(queue))) { | ||
269 | struct ieee80211_tx_info *txinfo; | ||
270 | struct ar9170_tx_info *arinfo; | ||
271 | |||
272 | txinfo = IEEE80211_SKB_CB(skb); | ||
273 | arinfo = (void *) txinfo->rate_driver_data; | ||
274 | |||
275 | if (time_is_before_jiffies(arinfo->timeout)) { | ||
276 | #ifdef AR9170_QUEUE_DEBUG | ||
277 | wiphy_debug(ar->hw->wiphy, | ||
278 | "[%ld > %ld] frame expired => recycle\n", | ||
279 | jiffies, arinfo->timeout); | ||
280 | ar9170_print_txheader(ar, skb); | ||
281 | #endif /* AR9170_QUEUE_DEBUG */ | ||
282 | __skb_unlink(skb, queue); | ||
283 | __skb_queue_tail(bin, skb); | ||
284 | } else { | ||
285 | break; | ||
286 | } | ||
287 | |||
288 | if (unlikely(old == skb)) { | ||
289 | /* bail out - queue is shot. */ | ||
290 | |||
291 | WARN_ON(1); | ||
292 | break; | ||
293 | } | ||
294 | old = skb; | ||
295 | } | ||
296 | spin_unlock_irqrestore(&queue->lock, flags); | ||
297 | } | ||
298 | |||
299 | static void ar9170_tx_status(struct ar9170 *ar, struct sk_buff *skb, | ||
300 | u16 tx_status) | ||
301 | { | ||
302 | struct ieee80211_tx_info *txinfo; | ||
303 | unsigned int retries = 0; | ||
304 | |||
305 | txinfo = IEEE80211_SKB_CB(skb); | ||
306 | ieee80211_tx_info_clear_status(txinfo); | ||
307 | |||
308 | switch (tx_status) { | ||
309 | case AR9170_TX_STATUS_RETRY: | ||
310 | retries = 2; | ||
311 | case AR9170_TX_STATUS_COMPLETE: | ||
312 | txinfo->flags |= IEEE80211_TX_STAT_ACK; | ||
313 | break; | ||
314 | |||
315 | case AR9170_TX_STATUS_FAILED: | ||
316 | retries = ar->hw->conf.long_frame_max_tx_count; | ||
317 | break; | ||
318 | |||
319 | default: | ||
320 | wiphy_err(ar->hw->wiphy, | ||
321 | "invalid tx_status response (%x)\n", tx_status); | ||
322 | break; | ||
323 | } | ||
324 | |||
325 | txinfo->status.rates[0].count = retries + 1; | ||
326 | skb_pull(skb, sizeof(struct ar9170_tx_control)); | ||
327 | ieee80211_tx_status_irqsafe(ar->hw, skb); | ||
328 | } | ||
329 | |||
330 | void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb) | ||
331 | { | ||
332 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
333 | struct ar9170_tx_info *arinfo = (void *) info->rate_driver_data; | ||
334 | unsigned int queue = skb_get_queue_mapping(skb); | ||
335 | unsigned long flags; | ||
336 | |||
337 | spin_lock_irqsave(&ar->tx_stats_lock, flags); | ||
338 | ar->tx_stats[queue].len--; | ||
339 | |||
340 | if (ar->tx_stats[queue].len < AR9170_NUM_TX_LIMIT_SOFT) { | ||
341 | #ifdef AR9170_QUEUE_STOP_DEBUG | ||
342 | wiphy_debug(ar->hw->wiphy, "wake queue %d\n", queue); | ||
343 | __ar9170_dump_txstats(ar); | ||
344 | #endif /* AR9170_QUEUE_STOP_DEBUG */ | ||
345 | ieee80211_wake_queue(ar->hw, queue); | ||
346 | } | ||
347 | spin_unlock_irqrestore(&ar->tx_stats_lock, flags); | ||
348 | |||
349 | if (info->flags & IEEE80211_TX_CTL_NO_ACK) { | ||
350 | ar9170_tx_status(ar, skb, AR9170_TX_STATUS_FAILED); | ||
351 | } else { | ||
352 | arinfo->timeout = jiffies + | ||
353 | msecs_to_jiffies(AR9170_TX_TIMEOUT); | ||
354 | |||
355 | skb_queue_tail(&ar->tx_status[queue], skb); | ||
356 | } | ||
357 | |||
358 | if (!ar->tx_stats[queue].len && | ||
359 | !skb_queue_empty(&ar->tx_pending[queue])) { | ||
360 | ar9170_tx(ar); | ||
361 | } | ||
362 | } | ||
363 | |||
364 | static struct sk_buff *ar9170_get_queued_skb(struct ar9170 *ar, | ||
365 | const u8 *mac, | ||
366 | struct sk_buff_head *queue, | ||
367 | const u32 rate) | ||
368 | { | ||
369 | unsigned long flags; | ||
370 | struct sk_buff *skb; | ||
371 | |||
372 | /* | ||
373 | * Unfortunately, the firmware does not tell to which (queued) frame | ||
374 | * this transmission status report belongs to. | ||
375 | * | ||
376 | * So we have to make risky guesses - with the scarce information | ||
377 | * the firmware provided (-> destination MAC, and phy_control) - | ||
378 | * and hope that we picked the right one... | ||
379 | */ | ||
380 | |||
381 | spin_lock_irqsave(&queue->lock, flags); | ||
382 | skb_queue_walk(queue, skb) { | ||
383 | struct ar9170_tx_control *txc = (void *) skb->data; | ||
384 | struct ieee80211_hdr *hdr = (void *) txc->frame_data; | ||
385 | u32 r; | ||
386 | |||
387 | if (mac && compare_ether_addr(ieee80211_get_DA(hdr), mac)) { | ||
388 | #ifdef AR9170_QUEUE_DEBUG | ||
389 | wiphy_debug(ar->hw->wiphy, | ||
390 | "skip frame => DA %pM != %pM\n", | ||
391 | mac, ieee80211_get_DA(hdr)); | ||
392 | ar9170_print_txheader(ar, skb); | ||
393 | #endif /* AR9170_QUEUE_DEBUG */ | ||
394 | continue; | ||
395 | } | ||
396 | |||
397 | r = (le32_to_cpu(txc->phy_control) & AR9170_TX_PHY_MCS_MASK) >> | ||
398 | AR9170_TX_PHY_MCS_SHIFT; | ||
399 | |||
400 | if ((rate != AR9170_TX_INVALID_RATE) && (r != rate)) { | ||
401 | #ifdef AR9170_QUEUE_DEBUG | ||
402 | wiphy_debug(ar->hw->wiphy, | ||
403 | "skip frame => rate %d != %d\n", rate, r); | ||
404 | ar9170_print_txheader(ar, skb); | ||
405 | #endif /* AR9170_QUEUE_DEBUG */ | ||
406 | continue; | ||
407 | } | ||
408 | |||
409 | __skb_unlink(skb, queue); | ||
410 | spin_unlock_irqrestore(&queue->lock, flags); | ||
411 | return skb; | ||
412 | } | ||
413 | |||
414 | #ifdef AR9170_QUEUE_DEBUG | ||
415 | wiphy_err(ar->hw->wiphy, | ||
416 | "ESS:[%pM] does not have any outstanding frames in queue.\n", | ||
417 | mac); | ||
418 | __ar9170_dump_txqueue(ar, queue); | ||
419 | #endif /* AR9170_QUEUE_DEBUG */ | ||
420 | spin_unlock_irqrestore(&queue->lock, flags); | ||
421 | |||
422 | return NULL; | ||
423 | } | ||
424 | |||
425 | /* | ||
426 | * This worker tries to keeps an maintain tx_status queues. | ||
427 | * So we can guarantee that incoming tx_status reports are | ||
428 | * actually for a pending frame. | ||
429 | */ | ||
430 | |||
431 | static void ar9170_tx_janitor(struct work_struct *work) | ||
432 | { | ||
433 | struct ar9170 *ar = container_of(work, struct ar9170, | ||
434 | tx_janitor.work); | ||
435 | struct sk_buff_head waste; | ||
436 | unsigned int i; | ||
437 | bool resched = false; | ||
438 | |||
439 | if (unlikely(!IS_STARTED(ar))) | ||
440 | return ; | ||
441 | |||
442 | skb_queue_head_init(&waste); | ||
443 | |||
444 | for (i = 0; i < __AR9170_NUM_TXQ; i++) { | ||
445 | #ifdef AR9170_QUEUE_DEBUG | ||
446 | wiphy_debug(ar->hw->wiphy, "garbage collector scans queue:%d\n", | ||
447 | i); | ||
448 | ar9170_dump_txqueue(ar, &ar->tx_pending[i]); | ||
449 | ar9170_dump_txqueue(ar, &ar->tx_status[i]); | ||
450 | #endif /* AR9170_QUEUE_DEBUG */ | ||
451 | |||
452 | ar9170_recycle_expired(ar, &ar->tx_status[i], &waste); | ||
453 | ar9170_recycle_expired(ar, &ar->tx_pending[i], &waste); | ||
454 | skb_queue_purge(&waste); | ||
455 | |||
456 | if (!skb_queue_empty(&ar->tx_status[i]) || | ||
457 | !skb_queue_empty(&ar->tx_pending[i])) | ||
458 | resched = true; | ||
459 | } | ||
460 | |||
461 | if (!resched) | ||
462 | return; | ||
463 | |||
464 | ieee80211_queue_delayed_work(ar->hw, | ||
465 | &ar->tx_janitor, | ||
466 | msecs_to_jiffies(AR9170_JANITOR_DELAY)); | ||
467 | } | ||
468 | |||
469 | void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len) | ||
470 | { | ||
471 | struct ar9170_cmd_response *cmd = (void *) buf; | ||
472 | |||
473 | if ((cmd->type & 0xc0) != 0xc0) { | ||
474 | ar->callback_cmd(ar, len, buf); | ||
475 | return; | ||
476 | } | ||
477 | |||
478 | /* hardware event handlers */ | ||
479 | switch (cmd->type) { | ||
480 | case 0xc1: { | ||
481 | /* | ||
482 | * TX status notification: | ||
483 | * bytes: 0c c1 XX YY M1 M2 M3 M4 M5 M6 R4 R3 R2 R1 S2 S1 | ||
484 | * | ||
485 | * XX always 81 | ||
486 | * YY always 00 | ||
487 | * M1-M6 is the MAC address | ||
488 | * R1-R4 is the transmit rate | ||
489 | * S1-S2 is the transmit status | ||
490 | */ | ||
491 | |||
492 | struct sk_buff *skb; | ||
493 | u32 phy = le32_to_cpu(cmd->tx_status.rate); | ||
494 | u32 q = (phy & AR9170_TX_PHY_QOS_MASK) >> | ||
495 | AR9170_TX_PHY_QOS_SHIFT; | ||
496 | #ifdef AR9170_QUEUE_DEBUG | ||
497 | wiphy_debug(ar->hw->wiphy, | ||
498 | "recv tx_status for %pm, p:%08x, q:%d\n", | ||
499 | cmd->tx_status.dst, phy, q); | ||
500 | #endif /* AR9170_QUEUE_DEBUG */ | ||
501 | |||
502 | skb = ar9170_get_queued_skb(ar, cmd->tx_status.dst, | ||
503 | &ar->tx_status[q], | ||
504 | AR9170_TX_INVALID_RATE); | ||
505 | if (unlikely(!skb)) | ||
506 | return ; | ||
507 | |||
508 | ar9170_tx_status(ar, skb, le16_to_cpu(cmd->tx_status.status)); | ||
509 | break; | ||
510 | } | ||
511 | |||
512 | case 0xc0: | ||
513 | /* | ||
514 | * pre-TBTT event | ||
515 | */ | ||
516 | if (ar->vif && ar->vif->type == NL80211_IFTYPE_AP) | ||
517 | ieee80211_queue_work(ar->hw, &ar->beacon_work); | ||
518 | break; | ||
519 | |||
520 | case 0xc2: | ||
521 | /* | ||
522 | * (IBSS) beacon send notification | ||
523 | * bytes: 04 c2 XX YY B4 B3 B2 B1 | ||
524 | * | ||
525 | * XX always 80 | ||
526 | * YY always 00 | ||
527 | * B1-B4 "should" be the number of send out beacons. | ||
528 | */ | ||
529 | break; | ||
530 | |||
531 | case 0xc3: | ||
532 | /* End of Atim Window */ | ||
533 | break; | ||
534 | |||
535 | case 0xc4: | ||
536 | /* BlockACK bitmap */ | ||
537 | break; | ||
538 | |||
539 | case 0xc5: | ||
540 | /* BlockACK events */ | ||
541 | break; | ||
542 | |||
543 | case 0xc6: | ||
544 | /* Watchdog Interrupt */ | ||
545 | break; | ||
546 | |||
547 | case 0xc9: | ||
548 | /* retransmission issue / SIFS/EIFS collision ?! */ | ||
549 | break; | ||
550 | |||
551 | /* firmware debug */ | ||
552 | case 0xca: | ||
553 | printk(KERN_DEBUG "ar9170 FW: %.*s\n", len - 4, | ||
554 | (char *)buf + 4); | ||
555 | break; | ||
556 | case 0xcb: | ||
557 | len -= 4; | ||
558 | |||
559 | switch (len) { | ||
560 | case 1: | ||
561 | printk(KERN_DEBUG "ar9170 FW: u8: %#.2x\n", | ||
562 | *((char *)buf + 4)); | ||
563 | break; | ||
564 | case 2: | ||
565 | printk(KERN_DEBUG "ar9170 FW: u8: %#.4x\n", | ||
566 | le16_to_cpup((__le16 *)((char *)buf + 4))); | ||
567 | break; | ||
568 | case 4: | ||
569 | printk(KERN_DEBUG "ar9170 FW: u8: %#.8x\n", | ||
570 | le32_to_cpup((__le32 *)((char *)buf + 4))); | ||
571 | break; | ||
572 | case 8: | ||
573 | printk(KERN_DEBUG "ar9170 FW: u8: %#.16lx\n", | ||
574 | (unsigned long)le64_to_cpup( | ||
575 | (__le64 *)((char *)buf + 4))); | ||
576 | break; | ||
577 | } | ||
578 | break; | ||
579 | case 0xcc: | ||
580 | print_hex_dump_bytes("ar9170 FW:", DUMP_PREFIX_NONE, | ||
581 | (char *)buf + 4, len - 4); | ||
582 | break; | ||
583 | |||
584 | default: | ||
585 | pr_info("received unhandled event %x\n", cmd->type); | ||
586 | print_hex_dump_bytes("dump:", DUMP_PREFIX_NONE, buf, len); | ||
587 | break; | ||
588 | } | ||
589 | } | ||
590 | |||
591 | static void ar9170_rx_reset_rx_mpdu(struct ar9170 *ar) | ||
592 | { | ||
593 | memset(&ar->rx_mpdu.plcp, 0, sizeof(struct ar9170_rx_head)); | ||
594 | ar->rx_mpdu.has_plcp = false; | ||
595 | } | ||
596 | |||
597 | int ar9170_nag_limiter(struct ar9170 *ar) | ||
598 | { | ||
599 | bool print_message; | ||
600 | |||
601 | /* | ||
602 | * we expect all sorts of errors in promiscuous mode. | ||
603 | * don't bother with it, it's OK! | ||
604 | */ | ||
605 | if (ar->sniffer_enabled) | ||
606 | return false; | ||
607 | |||
608 | /* | ||
609 | * only go for frequent errors! The hardware tends to | ||
610 | * do some stupid thing once in a while under load, in | ||
611 | * noisy environments or just for fun! | ||
612 | */ | ||
613 | if (time_before(jiffies, ar->bad_hw_nagger) && net_ratelimit()) | ||
614 | print_message = true; | ||
615 | else | ||
616 | print_message = false; | ||
617 | |||
618 | /* reset threshold for "once in a while" */ | ||
619 | ar->bad_hw_nagger = jiffies + HZ / 4; | ||
620 | return print_message; | ||
621 | } | ||
622 | |||
623 | static int ar9170_rx_mac_status(struct ar9170 *ar, | ||
624 | struct ar9170_rx_head *head, | ||
625 | struct ar9170_rx_macstatus *mac, | ||
626 | struct ieee80211_rx_status *status) | ||
627 | { | ||
628 | u8 error, decrypt; | ||
629 | |||
630 | BUILD_BUG_ON(sizeof(struct ar9170_rx_head) != 12); | ||
631 | BUILD_BUG_ON(sizeof(struct ar9170_rx_macstatus) != 4); | ||
632 | |||
633 | error = mac->error; | ||
634 | if (error & AR9170_RX_ERROR_MMIC) { | ||
635 | status->flag |= RX_FLAG_MMIC_ERROR; | ||
636 | error &= ~AR9170_RX_ERROR_MMIC; | ||
637 | } | ||
638 | |||
639 | if (error & AR9170_RX_ERROR_PLCP) { | ||
640 | status->flag |= RX_FLAG_FAILED_PLCP_CRC; | ||
641 | error &= ~AR9170_RX_ERROR_PLCP; | ||
642 | |||
643 | if (!(ar->filter_state & FIF_PLCPFAIL)) | ||
644 | return -EINVAL; | ||
645 | } | ||
646 | |||
647 | if (error & AR9170_RX_ERROR_FCS) { | ||
648 | status->flag |= RX_FLAG_FAILED_FCS_CRC; | ||
649 | error &= ~AR9170_RX_ERROR_FCS; | ||
650 | |||
651 | if (!(ar->filter_state & FIF_FCSFAIL)) | ||
652 | return -EINVAL; | ||
653 | } | ||
654 | |||
655 | decrypt = ar9170_get_decrypt_type(mac); | ||
656 | if (!(decrypt & AR9170_RX_ENC_SOFTWARE) && | ||
657 | decrypt != AR9170_ENC_ALG_NONE) | ||
658 | status->flag |= RX_FLAG_DECRYPTED; | ||
659 | |||
660 | /* ignore wrong RA errors */ | ||
661 | error &= ~AR9170_RX_ERROR_WRONG_RA; | ||
662 | |||
663 | if (error & AR9170_RX_ERROR_DECRYPT) { | ||
664 | error &= ~AR9170_RX_ERROR_DECRYPT; | ||
665 | /* | ||
666 | * Rx decryption is done in place, | ||
667 | * the original data is lost anyway. | ||
668 | */ | ||
669 | |||
670 | return -EINVAL; | ||
671 | } | ||
672 | |||
673 | /* drop any other error frames */ | ||
674 | if (unlikely(error)) { | ||
675 | /* TODO: update netdevice's RX dropped/errors statistics */ | ||
676 | |||
677 | if (ar9170_nag_limiter(ar)) | ||
678 | wiphy_debug(ar->hw->wiphy, | ||
679 | "received frame with suspicious error code (%#x).\n", | ||
680 | error); | ||
681 | |||
682 | return -EINVAL; | ||
683 | } | ||
684 | |||
685 | status->band = ar->channel->band; | ||
686 | status->freq = ar->channel->center_freq; | ||
687 | |||
688 | switch (mac->status & AR9170_RX_STATUS_MODULATION_MASK) { | ||
689 | case AR9170_RX_STATUS_MODULATION_CCK: | ||
690 | if (mac->status & AR9170_RX_STATUS_SHORT_PREAMBLE) | ||
691 | status->flag |= RX_FLAG_SHORTPRE; | ||
692 | switch (head->plcp[0]) { | ||
693 | case 0x0a: | ||
694 | status->rate_idx = 0; | ||
695 | break; | ||
696 | case 0x14: | ||
697 | status->rate_idx = 1; | ||
698 | break; | ||
699 | case 0x37: | ||
700 | status->rate_idx = 2; | ||
701 | break; | ||
702 | case 0x6e: | ||
703 | status->rate_idx = 3; | ||
704 | break; | ||
705 | default: | ||
706 | if (ar9170_nag_limiter(ar)) | ||
707 | wiphy_err(ar->hw->wiphy, | ||
708 | "invalid plcp cck rate (%x).\n", | ||
709 | head->plcp[0]); | ||
710 | return -EINVAL; | ||
711 | } | ||
712 | break; | ||
713 | |||
714 | case AR9170_RX_STATUS_MODULATION_DUPOFDM: | ||
715 | case AR9170_RX_STATUS_MODULATION_OFDM: | ||
716 | switch (head->plcp[0] & 0xf) { | ||
717 | case 0xb: | ||
718 | status->rate_idx = 0; | ||
719 | break; | ||
720 | case 0xf: | ||
721 | status->rate_idx = 1; | ||
722 | break; | ||
723 | case 0xa: | ||
724 | status->rate_idx = 2; | ||
725 | break; | ||
726 | case 0xe: | ||
727 | status->rate_idx = 3; | ||
728 | break; | ||
729 | case 0x9: | ||
730 | status->rate_idx = 4; | ||
731 | break; | ||
732 | case 0xd: | ||
733 | status->rate_idx = 5; | ||
734 | break; | ||
735 | case 0x8: | ||
736 | status->rate_idx = 6; | ||
737 | break; | ||
738 | case 0xc: | ||
739 | status->rate_idx = 7; | ||
740 | break; | ||
741 | default: | ||
742 | if (ar9170_nag_limiter(ar)) | ||
743 | wiphy_err(ar->hw->wiphy, | ||
744 | "invalid plcp ofdm rate (%x).\n", | ||
745 | head->plcp[0]); | ||
746 | return -EINVAL; | ||
747 | } | ||
748 | if (status->band == IEEE80211_BAND_2GHZ) | ||
749 | status->rate_idx += 4; | ||
750 | break; | ||
751 | |||
752 | case AR9170_RX_STATUS_MODULATION_HT: | ||
753 | if (head->plcp[3] & 0x80) | ||
754 | status->flag |= RX_FLAG_40MHZ; | ||
755 | if (head->plcp[6] & 0x80) | ||
756 | status->flag |= RX_FLAG_SHORT_GI; | ||
757 | |||
758 | status->rate_idx = clamp(0, 75, head->plcp[6] & 0x7f); | ||
759 | status->flag |= RX_FLAG_HT; | ||
760 | break; | ||
761 | |||
762 | default: | ||
763 | if (ar9170_nag_limiter(ar)) | ||
764 | wiphy_err(ar->hw->wiphy, "invalid modulation\n"); | ||
765 | return -EINVAL; | ||
766 | } | ||
767 | |||
768 | return 0; | ||
769 | } | ||
770 | |||
771 | static void ar9170_rx_phy_status(struct ar9170 *ar, | ||
772 | struct ar9170_rx_phystatus *phy, | ||
773 | struct ieee80211_rx_status *status) | ||
774 | { | ||
775 | int i; | ||
776 | |||
777 | BUILD_BUG_ON(sizeof(struct ar9170_rx_phystatus) != 20); | ||
778 | |||
779 | for (i = 0; i < 3; i++) | ||
780 | if (phy->rssi[i] != 0x80) | ||
781 | status->antenna |= BIT(i); | ||
782 | |||
783 | /* post-process RSSI */ | ||
784 | for (i = 0; i < 7; i++) | ||
785 | if (phy->rssi[i] & 0x80) | ||
786 | phy->rssi[i] = ((phy->rssi[i] & 0x7f) + 1) & 0x7f; | ||
787 | |||
788 | /* TODO: we could do something with phy_errors */ | ||
789 | status->signal = ar->noise[0] + phy->rssi_combined; | ||
790 | } | ||
791 | |||
792 | static struct sk_buff *ar9170_rx_copy_data(u8 *buf, int len) | ||
793 | { | ||
794 | struct sk_buff *skb; | ||
795 | int reserved = 0; | ||
796 | struct ieee80211_hdr *hdr = (void *) buf; | ||
797 | |||
798 | if (ieee80211_is_data_qos(hdr->frame_control)) { | ||
799 | u8 *qc = ieee80211_get_qos_ctl(hdr); | ||
800 | reserved += NET_IP_ALIGN; | ||
801 | |||
802 | if (*qc & IEEE80211_QOS_CONTROL_A_MSDU_PRESENT) | ||
803 | reserved += NET_IP_ALIGN; | ||
804 | } | ||
805 | |||
806 | if (ieee80211_has_a4(hdr->frame_control)) | ||
807 | reserved += NET_IP_ALIGN; | ||
808 | |||
809 | reserved = 32 + (reserved & NET_IP_ALIGN); | ||
810 | |||
811 | skb = dev_alloc_skb(len + reserved); | ||
812 | if (likely(skb)) { | ||
813 | skb_reserve(skb, reserved); | ||
814 | memcpy(skb_put(skb, len), buf, len); | ||
815 | } | ||
816 | |||
817 | return skb; | ||
818 | } | ||
819 | |||
820 | /* | ||
821 | * If the frame alignment is right (or the kernel has | ||
822 | * CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS), and there | ||
823 | * is only a single MPDU in the USB frame, then we could | ||
824 | * submit to mac80211 the SKB directly. However, since | ||
825 | * there may be multiple packets in one SKB in stream | ||
826 | * mode, and we need to observe the proper ordering, | ||
827 | * this is non-trivial. | ||
828 | */ | ||
829 | |||
830 | static void ar9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len) | ||
831 | { | ||
832 | struct ar9170_rx_head *head; | ||
833 | struct ar9170_rx_macstatus *mac; | ||
834 | struct ar9170_rx_phystatus *phy = NULL; | ||
835 | struct ieee80211_rx_status status; | ||
836 | struct sk_buff *skb; | ||
837 | int mpdu_len; | ||
838 | |||
839 | if (unlikely(!IS_STARTED(ar) || len < (sizeof(*mac)))) | ||
840 | return ; | ||
841 | |||
842 | /* Received MPDU */ | ||
843 | mpdu_len = len - sizeof(*mac); | ||
844 | |||
845 | mac = (void *)(buf + mpdu_len); | ||
846 | if (unlikely(mac->error & AR9170_RX_ERROR_FATAL)) { | ||
847 | /* this frame is too damaged and can't be used - drop it */ | ||
848 | |||
849 | return ; | ||
850 | } | ||
851 | |||
852 | switch (mac->status & AR9170_RX_STATUS_MPDU_MASK) { | ||
853 | case AR9170_RX_STATUS_MPDU_FIRST: | ||
854 | /* first mpdu packet has the plcp header */ | ||
855 | if (likely(mpdu_len >= sizeof(struct ar9170_rx_head))) { | ||
856 | head = (void *) buf; | ||
857 | memcpy(&ar->rx_mpdu.plcp, (void *) buf, | ||
858 | sizeof(struct ar9170_rx_head)); | ||
859 | |||
860 | mpdu_len -= sizeof(struct ar9170_rx_head); | ||
861 | buf += sizeof(struct ar9170_rx_head); | ||
862 | ar->rx_mpdu.has_plcp = true; | ||
863 | } else { | ||
864 | if (ar9170_nag_limiter(ar)) | ||
865 | wiphy_err(ar->hw->wiphy, | ||
866 | "plcp info is clipped.\n"); | ||
867 | return ; | ||
868 | } | ||
869 | break; | ||
870 | |||
871 | case AR9170_RX_STATUS_MPDU_LAST: | ||
872 | /* last mpdu has a extra tail with phy status information */ | ||
873 | |||
874 | if (likely(mpdu_len >= sizeof(struct ar9170_rx_phystatus))) { | ||
875 | mpdu_len -= sizeof(struct ar9170_rx_phystatus); | ||
876 | phy = (void *)(buf + mpdu_len); | ||
877 | } else { | ||
878 | if (ar9170_nag_limiter(ar)) | ||
879 | wiphy_err(ar->hw->wiphy, | ||
880 | "frame tail is clipped.\n"); | ||
881 | return ; | ||
882 | } | ||
883 | |||
884 | case AR9170_RX_STATUS_MPDU_MIDDLE: | ||
885 | /* middle mpdus are just data */ | ||
886 | if (unlikely(!ar->rx_mpdu.has_plcp)) { | ||
887 | if (!ar9170_nag_limiter(ar)) | ||
888 | return ; | ||
889 | |||
890 | wiphy_err(ar->hw->wiphy, | ||
891 | "rx stream did not start with a first_mpdu frame tag.\n"); | ||
892 | |||
893 | return ; | ||
894 | } | ||
895 | |||
896 | head = &ar->rx_mpdu.plcp; | ||
897 | break; | ||
898 | |||
899 | case AR9170_RX_STATUS_MPDU_SINGLE: | ||
900 | /* single mpdu - has plcp (head) and phy status (tail) */ | ||
901 | head = (void *) buf; | ||
902 | |||
903 | mpdu_len -= sizeof(struct ar9170_rx_head); | ||
904 | mpdu_len -= sizeof(struct ar9170_rx_phystatus); | ||
905 | |||
906 | buf += sizeof(struct ar9170_rx_head); | ||
907 | phy = (void *)(buf + mpdu_len); | ||
908 | break; | ||
909 | |||
910 | default: | ||
911 | BUG_ON(1); | ||
912 | break; | ||
913 | } | ||
914 | |||
915 | if (unlikely(mpdu_len < FCS_LEN)) | ||
916 | return ; | ||
917 | |||
918 | memset(&status, 0, sizeof(status)); | ||
919 | if (unlikely(ar9170_rx_mac_status(ar, head, mac, &status))) | ||
920 | return ; | ||
921 | |||
922 | if (phy) | ||
923 | ar9170_rx_phy_status(ar, phy, &status); | ||
924 | |||
925 | skb = ar9170_rx_copy_data(buf, mpdu_len); | ||
926 | if (likely(skb)) { | ||
927 | memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); | ||
928 | ieee80211_rx_irqsafe(ar->hw, skb); | ||
929 | } | ||
930 | } | ||
931 | |||
932 | void ar9170_rx(struct ar9170 *ar, struct sk_buff *skb) | ||
933 | { | ||
934 | unsigned int i, tlen, resplen, wlen = 0, clen = 0; | ||
935 | u8 *tbuf, *respbuf; | ||
936 | |||
937 | tbuf = skb->data; | ||
938 | tlen = skb->len; | ||
939 | |||
940 | while (tlen >= 4) { | ||
941 | clen = tbuf[1] << 8 | tbuf[0]; | ||
942 | wlen = ALIGN(clen, 4); | ||
943 | |||
944 | /* check if this is stream has a valid tag.*/ | ||
945 | if (tbuf[2] != 0 || tbuf[3] != 0x4e) { | ||
946 | /* | ||
947 | * TODO: handle the highly unlikely event that the | ||
948 | * corrupted stream has the TAG at the right position. | ||
949 | */ | ||
950 | |||
951 | /* check if the frame can be repaired. */ | ||
952 | if (!ar->rx_failover_missing) { | ||
953 | /* this is no "short read". */ | ||
954 | if (ar9170_nag_limiter(ar)) { | ||
955 | wiphy_err(ar->hw->wiphy, | ||
956 | "missing tag!\n"); | ||
957 | goto err_telluser; | ||
958 | } else | ||
959 | goto err_silent; | ||
960 | } | ||
961 | |||
962 | if (ar->rx_failover_missing > tlen) { | ||
963 | if (ar9170_nag_limiter(ar)) { | ||
964 | wiphy_err(ar->hw->wiphy, | ||
965 | "possible multi stream corruption!\n"); | ||
966 | goto err_telluser; | ||
967 | } else | ||
968 | goto err_silent; | ||
969 | } | ||
970 | |||
971 | memcpy(skb_put(ar->rx_failover, tlen), tbuf, tlen); | ||
972 | ar->rx_failover_missing -= tlen; | ||
973 | |||
974 | if (ar->rx_failover_missing <= 0) { | ||
975 | /* | ||
976 | * nested ar9170_rx call! | ||
977 | * termination is guaranteed, even when the | ||
978 | * combined frame also have a element with | ||
979 | * a bad tag. | ||
980 | */ | ||
981 | |||
982 | ar->rx_failover_missing = 0; | ||
983 | ar9170_rx(ar, ar->rx_failover); | ||
984 | |||
985 | skb_reset_tail_pointer(ar->rx_failover); | ||
986 | skb_trim(ar->rx_failover, 0); | ||
987 | } | ||
988 | |||
989 | return ; | ||
990 | } | ||
991 | |||
992 | /* check if stream is clipped */ | ||
993 | if (wlen > tlen - 4) { | ||
994 | if (ar->rx_failover_missing) { | ||
995 | /* TODO: handle double stream corruption. */ | ||
996 | if (ar9170_nag_limiter(ar)) { | ||
997 | wiphy_err(ar->hw->wiphy, | ||
998 | "double rx stream corruption!\n"); | ||
999 | goto err_telluser; | ||
1000 | } else | ||
1001 | goto err_silent; | ||
1002 | } | ||
1003 | |||
1004 | /* | ||
1005 | * save incomplete data set. | ||
1006 | * the firmware will resend the missing bits when | ||
1007 | * the rx - descriptor comes round again. | ||
1008 | */ | ||
1009 | |||
1010 | memcpy(skb_put(ar->rx_failover, tlen), tbuf, tlen); | ||
1011 | ar->rx_failover_missing = clen - tlen; | ||
1012 | return ; | ||
1013 | } | ||
1014 | resplen = clen; | ||
1015 | respbuf = tbuf + 4; | ||
1016 | tbuf += wlen + 4; | ||
1017 | tlen -= wlen + 4; | ||
1018 | |||
1019 | i = 0; | ||
1020 | |||
1021 | /* weird thing, but this is the same in the original driver */ | ||
1022 | while (resplen > 2 && i < 12 && | ||
1023 | respbuf[0] == 0xff && respbuf[1] == 0xff) { | ||
1024 | i += 2; | ||
1025 | resplen -= 2; | ||
1026 | respbuf += 2; | ||
1027 | } | ||
1028 | |||
1029 | if (resplen < 4) | ||
1030 | continue; | ||
1031 | |||
1032 | /* found the 6 * 0xffff marker? */ | ||
1033 | if (i == 12) | ||
1034 | ar9170_handle_command_response(ar, respbuf, resplen); | ||
1035 | else | ||
1036 | ar9170_handle_mpdu(ar, respbuf, clen); | ||
1037 | } | ||
1038 | |||
1039 | if (tlen) { | ||
1040 | if (net_ratelimit()) | ||
1041 | wiphy_err(ar->hw->wiphy, | ||
1042 | "%d bytes of unprocessed data left in rx stream!\n", | ||
1043 | tlen); | ||
1044 | |||
1045 | goto err_telluser; | ||
1046 | } | ||
1047 | |||
1048 | return ; | ||
1049 | |||
1050 | err_telluser: | ||
1051 | wiphy_err(ar->hw->wiphy, | ||
1052 | "damaged RX stream data [want:%d, data:%d, rx:%d, pending:%d ]\n", | ||
1053 | clen, wlen, tlen, ar->rx_failover_missing); | ||
1054 | |||
1055 | if (ar->rx_failover_missing) | ||
1056 | print_hex_dump_bytes("rxbuf:", DUMP_PREFIX_OFFSET, | ||
1057 | ar->rx_failover->data, | ||
1058 | ar->rx_failover->len); | ||
1059 | |||
1060 | print_hex_dump_bytes("stream:", DUMP_PREFIX_OFFSET, | ||
1061 | skb->data, skb->len); | ||
1062 | |||
1063 | wiphy_err(ar->hw->wiphy, | ||
1064 | "If you see this message frequently, please check your hardware and cables.\n"); | ||
1065 | |||
1066 | err_silent: | ||
1067 | if (ar->rx_failover_missing) { | ||
1068 | skb_reset_tail_pointer(ar->rx_failover); | ||
1069 | skb_trim(ar->rx_failover, 0); | ||
1070 | ar->rx_failover_missing = 0; | ||
1071 | } | ||
1072 | } | ||
1073 | |||
1074 | #define AR9170_FILL_QUEUE(queue, ai_fs, cwmin, cwmax, _txop) \ | ||
1075 | do { \ | ||
1076 | queue.aifs = ai_fs; \ | ||
1077 | queue.cw_min = cwmin; \ | ||
1078 | queue.cw_max = cwmax; \ | ||
1079 | queue.txop = _txop; \ | ||
1080 | } while (0) | ||
1081 | |||
1082 | static int ar9170_op_start(struct ieee80211_hw *hw) | ||
1083 | { | ||
1084 | struct ar9170 *ar = hw->priv; | ||
1085 | int err, i; | ||
1086 | |||
1087 | mutex_lock(&ar->mutex); | ||
1088 | |||
1089 | /* reinitialize queues statistics */ | ||
1090 | memset(&ar->tx_stats, 0, sizeof(ar->tx_stats)); | ||
1091 | for (i = 0; i < __AR9170_NUM_TXQ; i++) | ||
1092 | ar->tx_stats[i].limit = AR9170_TXQ_DEPTH; | ||
1093 | |||
1094 | /* reset QoS defaults */ | ||
1095 | AR9170_FILL_QUEUE(ar->edcf[0], 3, 15, 1023, 0); /* BEST EFFORT*/ | ||
1096 | AR9170_FILL_QUEUE(ar->edcf[1], 7, 15, 1023, 0); /* BACKGROUND */ | ||
1097 | AR9170_FILL_QUEUE(ar->edcf[2], 2, 7, 15, 94); /* VIDEO */ | ||
1098 | AR9170_FILL_QUEUE(ar->edcf[3], 2, 3, 7, 47); /* VOICE */ | ||
1099 | AR9170_FILL_QUEUE(ar->edcf[4], 2, 3, 7, 0); /* SPECIAL */ | ||
1100 | |||
1101 | /* set sane AMPDU defaults */ | ||
1102 | ar->global_ampdu_density = 6; | ||
1103 | ar->global_ampdu_factor = 3; | ||
1104 | |||
1105 | ar->bad_hw_nagger = jiffies; | ||
1106 | |||
1107 | err = ar->open(ar); | ||
1108 | if (err) | ||
1109 | goto out; | ||
1110 | |||
1111 | err = ar9170_init_mac(ar); | ||
1112 | if (err) | ||
1113 | goto out; | ||
1114 | |||
1115 | err = ar9170_set_qos(ar); | ||
1116 | if (err) | ||
1117 | goto out; | ||
1118 | |||
1119 | err = ar9170_init_phy(ar, IEEE80211_BAND_2GHZ); | ||
1120 | if (err) | ||
1121 | goto out; | ||
1122 | |||
1123 | err = ar9170_init_rf(ar); | ||
1124 | if (err) | ||
1125 | goto out; | ||
1126 | |||
1127 | /* start DMA */ | ||
1128 | err = ar9170_write_reg(ar, 0x1c3d30, 0x100); | ||
1129 | if (err) | ||
1130 | goto out; | ||
1131 | |||
1132 | ar->state = AR9170_STARTED; | ||
1133 | |||
1134 | out: | ||
1135 | mutex_unlock(&ar->mutex); | ||
1136 | return err; | ||
1137 | } | ||
1138 | |||
1139 | static void ar9170_op_stop(struct ieee80211_hw *hw) | ||
1140 | { | ||
1141 | struct ar9170 *ar = hw->priv; | ||
1142 | unsigned int i; | ||
1143 | |||
1144 | if (IS_STARTED(ar)) | ||
1145 | ar->state = AR9170_IDLE; | ||
1146 | |||
1147 | cancel_delayed_work_sync(&ar->tx_janitor); | ||
1148 | #ifdef CONFIG_AR9170_LEDS | ||
1149 | cancel_delayed_work_sync(&ar->led_work); | ||
1150 | #endif | ||
1151 | cancel_work_sync(&ar->beacon_work); | ||
1152 | |||
1153 | mutex_lock(&ar->mutex); | ||
1154 | |||
1155 | if (IS_ACCEPTING_CMD(ar)) { | ||
1156 | ar9170_set_leds_state(ar, 0); | ||
1157 | |||
1158 | /* stop DMA */ | ||
1159 | ar9170_write_reg(ar, 0x1c3d30, 0); | ||
1160 | ar->stop(ar); | ||
1161 | } | ||
1162 | |||
1163 | for (i = 0; i < __AR9170_NUM_TXQ; i++) { | ||
1164 | skb_queue_purge(&ar->tx_pending[i]); | ||
1165 | skb_queue_purge(&ar->tx_status[i]); | ||
1166 | } | ||
1167 | |||
1168 | mutex_unlock(&ar->mutex); | ||
1169 | } | ||
1170 | |||
1171 | static int ar9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb) | ||
1172 | { | ||
1173 | struct ieee80211_hdr *hdr; | ||
1174 | struct ar9170_tx_control *txc; | ||
1175 | struct ieee80211_tx_info *info; | ||
1176 | struct ieee80211_tx_rate *txrate; | ||
1177 | struct ar9170_tx_info *arinfo; | ||
1178 | unsigned int queue = skb_get_queue_mapping(skb); | ||
1179 | u16 keytype = 0; | ||
1180 | u16 len, icv = 0; | ||
1181 | |||
1182 | BUILD_BUG_ON(sizeof(*arinfo) > sizeof(info->rate_driver_data)); | ||
1183 | |||
1184 | hdr = (void *)skb->data; | ||
1185 | info = IEEE80211_SKB_CB(skb); | ||
1186 | len = skb->len; | ||
1187 | |||
1188 | txc = (void *)skb_push(skb, sizeof(*txc)); | ||
1189 | |||
1190 | if (info->control.hw_key) { | ||
1191 | icv = info->control.hw_key->icv_len; | ||
1192 | |||
1193 | switch (info->control.hw_key->cipher) { | ||
1194 | case WLAN_CIPHER_SUITE_WEP40: | ||
1195 | case WLAN_CIPHER_SUITE_WEP104: | ||
1196 | case WLAN_CIPHER_SUITE_TKIP: | ||
1197 | keytype = AR9170_TX_MAC_ENCR_RC4; | ||
1198 | break; | ||
1199 | case WLAN_CIPHER_SUITE_CCMP: | ||
1200 | keytype = AR9170_TX_MAC_ENCR_AES; | ||
1201 | break; | ||
1202 | default: | ||
1203 | WARN_ON(1); | ||
1204 | goto err_out; | ||
1205 | } | ||
1206 | } | ||
1207 | |||
1208 | /* Length */ | ||
1209 | txc->length = cpu_to_le16(len + icv + 4); | ||
1210 | |||
1211 | txc->mac_control = cpu_to_le16(AR9170_TX_MAC_HW_DURATION | | ||
1212 | AR9170_TX_MAC_BACKOFF); | ||
1213 | txc->mac_control |= cpu_to_le16(ar9170_qos_hwmap[queue] << | ||
1214 | AR9170_TX_MAC_QOS_SHIFT); | ||
1215 | txc->mac_control |= cpu_to_le16(keytype); | ||
1216 | txc->phy_control = cpu_to_le32(0); | ||
1217 | |||
1218 | if (info->flags & IEEE80211_TX_CTL_NO_ACK) | ||
1219 | txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_NO_ACK); | ||
1220 | |||
1221 | txrate = &info->control.rates[0]; | ||
1222 | if (txrate->flags & IEEE80211_TX_RC_USE_CTS_PROTECT) | ||
1223 | txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_PROT_CTS); | ||
1224 | else if (txrate->flags & IEEE80211_TX_RC_USE_RTS_CTS) | ||
1225 | txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_PROT_RTS); | ||
1226 | |||
1227 | arinfo = (void *)info->rate_driver_data; | ||
1228 | arinfo->timeout = jiffies + msecs_to_jiffies(AR9170_QUEUE_TIMEOUT); | ||
1229 | |||
1230 | if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && | ||
1231 | (is_valid_ether_addr(ieee80211_get_DA(hdr)))) { | ||
1232 | /* | ||
1233 | * WARNING: | ||
1234 | * Putting the QoS queue bits into an unexplored territory is | ||
1235 | * certainly not elegant. | ||
1236 | * | ||
1237 | * In my defense: This idea provides a reasonable way to | ||
1238 | * smuggle valuable information to the tx_status callback. | ||
1239 | * Also, the idea behind this bit-abuse came straight from | ||
1240 | * the original driver code. | ||
1241 | */ | ||
1242 | |||
1243 | txc->phy_control |= | ||
1244 | cpu_to_le32(queue << AR9170_TX_PHY_QOS_SHIFT); | ||
1245 | |||
1246 | txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_RATE_PROBE); | ||
1247 | } | ||
1248 | |||
1249 | return 0; | ||
1250 | |||
1251 | err_out: | ||
1252 | skb_pull(skb, sizeof(*txc)); | ||
1253 | return -EINVAL; | ||
1254 | } | ||
1255 | |||
1256 | static void ar9170_tx_prepare_phy(struct ar9170 *ar, struct sk_buff *skb) | ||
1257 | { | ||
1258 | struct ar9170_tx_control *txc; | ||
1259 | struct ieee80211_tx_info *info; | ||
1260 | struct ieee80211_rate *rate = NULL; | ||
1261 | struct ieee80211_tx_rate *txrate; | ||
1262 | u32 power, chains; | ||
1263 | |||
1264 | txc = (void *) skb->data; | ||
1265 | info = IEEE80211_SKB_CB(skb); | ||
1266 | txrate = &info->control.rates[0]; | ||
1267 | |||
1268 | if (txrate->flags & IEEE80211_TX_RC_GREEN_FIELD) | ||
1269 | txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_GREENFIELD); | ||
1270 | |||
1271 | if (txrate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) | ||
1272 | txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_SHORT_PREAMBLE); | ||
1273 | |||
1274 | if (txrate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) | ||
1275 | txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_BW_40MHZ); | ||
1276 | /* this works because 40 MHz is 2 and dup is 3 */ | ||
1277 | if (txrate->flags & IEEE80211_TX_RC_DUP_DATA) | ||
1278 | txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_BW_40MHZ_DUP); | ||
1279 | |||
1280 | if (txrate->flags & IEEE80211_TX_RC_SHORT_GI) | ||
1281 | txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_SHORT_GI); | ||
1282 | |||
1283 | if (txrate->flags & IEEE80211_TX_RC_MCS) { | ||
1284 | u32 r = txrate->idx; | ||
1285 | u8 *txpower; | ||
1286 | |||
1287 | /* heavy clip control */ | ||
1288 | txc->phy_control |= cpu_to_le32((r & 0x7) << 7); | ||
1289 | |||
1290 | r <<= AR9170_TX_PHY_MCS_SHIFT; | ||
1291 | BUG_ON(r & ~AR9170_TX_PHY_MCS_MASK); | ||
1292 | |||
1293 | txc->phy_control |= cpu_to_le32(r & AR9170_TX_PHY_MCS_MASK); | ||
1294 | txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_MOD_HT); | ||
1295 | |||
1296 | if (txrate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) { | ||
1297 | if (info->band == IEEE80211_BAND_5GHZ) | ||
1298 | txpower = ar->power_5G_ht40; | ||
1299 | else | ||
1300 | txpower = ar->power_2G_ht40; | ||
1301 | } else { | ||
1302 | if (info->band == IEEE80211_BAND_5GHZ) | ||
1303 | txpower = ar->power_5G_ht20; | ||
1304 | else | ||
1305 | txpower = ar->power_2G_ht20; | ||
1306 | } | ||
1307 | |||
1308 | power = txpower[(txrate->idx) & 7]; | ||
1309 | } else { | ||
1310 | u8 *txpower; | ||
1311 | u32 mod; | ||
1312 | u32 phyrate; | ||
1313 | u8 idx = txrate->idx; | ||
1314 | |||
1315 | if (info->band != IEEE80211_BAND_2GHZ) { | ||
1316 | idx += 4; | ||
1317 | txpower = ar->power_5G_leg; | ||
1318 | mod = AR9170_TX_PHY_MOD_OFDM; | ||
1319 | } else { | ||
1320 | if (idx < 4) { | ||
1321 | txpower = ar->power_2G_cck; | ||
1322 | mod = AR9170_TX_PHY_MOD_CCK; | ||
1323 | } else { | ||
1324 | mod = AR9170_TX_PHY_MOD_OFDM; | ||
1325 | txpower = ar->power_2G_ofdm; | ||
1326 | } | ||
1327 | } | ||
1328 | |||
1329 | rate = &__ar9170_ratetable[idx]; | ||
1330 | |||
1331 | phyrate = rate->hw_value & 0xF; | ||
1332 | power = txpower[(rate->hw_value & 0x30) >> 4]; | ||
1333 | phyrate <<= AR9170_TX_PHY_MCS_SHIFT; | ||
1334 | |||
1335 | txc->phy_control |= cpu_to_le32(mod); | ||
1336 | txc->phy_control |= cpu_to_le32(phyrate); | ||
1337 | } | ||
1338 | |||
1339 | power <<= AR9170_TX_PHY_TX_PWR_SHIFT; | ||
1340 | power &= AR9170_TX_PHY_TX_PWR_MASK; | ||
1341 | txc->phy_control |= cpu_to_le32(power); | ||
1342 | |||
1343 | /* set TX chains */ | ||
1344 | if (ar->eeprom.tx_mask == 1) { | ||
1345 | chains = AR9170_TX_PHY_TXCHAIN_1; | ||
1346 | } else { | ||
1347 | chains = AR9170_TX_PHY_TXCHAIN_2; | ||
1348 | |||
1349 | /* >= 36M legacy OFDM - use only one chain */ | ||
1350 | if (rate && rate->bitrate >= 360) | ||
1351 | chains = AR9170_TX_PHY_TXCHAIN_1; | ||
1352 | } | ||
1353 | txc->phy_control |= cpu_to_le32(chains << AR9170_TX_PHY_TXCHAIN_SHIFT); | ||
1354 | } | ||
1355 | |||
1356 | static void ar9170_tx(struct ar9170 *ar) | ||
1357 | { | ||
1358 | struct sk_buff *skb; | ||
1359 | unsigned long flags; | ||
1360 | struct ieee80211_tx_info *info; | ||
1361 | struct ar9170_tx_info *arinfo; | ||
1362 | unsigned int i, frames, frames_failed, remaining_space; | ||
1363 | int err; | ||
1364 | bool schedule_garbagecollector = false; | ||
1365 | |||
1366 | BUILD_BUG_ON(sizeof(*arinfo) > sizeof(info->rate_driver_data)); | ||
1367 | |||
1368 | if (unlikely(!IS_STARTED(ar))) | ||
1369 | return ; | ||
1370 | |||
1371 | remaining_space = AR9170_TX_MAX_PENDING; | ||
1372 | |||
1373 | for (i = 0; i < __AR9170_NUM_TXQ; i++) { | ||
1374 | spin_lock_irqsave(&ar->tx_stats_lock, flags); | ||
1375 | frames = min(ar->tx_stats[i].limit - ar->tx_stats[i].len, | ||
1376 | skb_queue_len(&ar->tx_pending[i])); | ||
1377 | |||
1378 | if (remaining_space < frames) { | ||
1379 | #ifdef AR9170_QUEUE_DEBUG | ||
1380 | wiphy_debug(ar->hw->wiphy, | ||
1381 | "tx quota reached queue:%d, " | ||
1382 | "remaining slots:%d, needed:%d\n", | ||
1383 | i, remaining_space, frames); | ||
1384 | #endif /* AR9170_QUEUE_DEBUG */ | ||
1385 | frames = remaining_space; | ||
1386 | } | ||
1387 | |||
1388 | ar->tx_stats[i].len += frames; | ||
1389 | ar->tx_stats[i].count += frames; | ||
1390 | if (ar->tx_stats[i].len >= ar->tx_stats[i].limit) { | ||
1391 | #ifdef AR9170_QUEUE_DEBUG | ||
1392 | wiphy_debug(ar->hw->wiphy, "queue %d full\n", i); | ||
1393 | wiphy_debug(ar->hw->wiphy, "stuck frames: ===>\n"); | ||
1394 | ar9170_dump_txqueue(ar, &ar->tx_pending[i]); | ||
1395 | ar9170_dump_txqueue(ar, &ar->tx_status[i]); | ||
1396 | #endif /* AR9170_QUEUE_DEBUG */ | ||
1397 | |||
1398 | #ifdef AR9170_QUEUE_STOP_DEBUG | ||
1399 | wiphy_debug(ar->hw->wiphy, "stop queue %d\n", i); | ||
1400 | __ar9170_dump_txstats(ar); | ||
1401 | #endif /* AR9170_QUEUE_STOP_DEBUG */ | ||
1402 | ieee80211_stop_queue(ar->hw, i); | ||
1403 | } | ||
1404 | |||
1405 | spin_unlock_irqrestore(&ar->tx_stats_lock, flags); | ||
1406 | |||
1407 | if (!frames) | ||
1408 | continue; | ||
1409 | |||
1410 | frames_failed = 0; | ||
1411 | while (frames) { | ||
1412 | skb = skb_dequeue(&ar->tx_pending[i]); | ||
1413 | if (unlikely(!skb)) { | ||
1414 | frames_failed += frames; | ||
1415 | frames = 0; | ||
1416 | break; | ||
1417 | } | ||
1418 | |||
1419 | info = IEEE80211_SKB_CB(skb); | ||
1420 | arinfo = (void *) info->rate_driver_data; | ||
1421 | |||
1422 | /* TODO: cancel stuck frames */ | ||
1423 | arinfo->timeout = jiffies + | ||
1424 | msecs_to_jiffies(AR9170_TX_TIMEOUT); | ||
1425 | |||
1426 | #ifdef AR9170_QUEUE_DEBUG | ||
1427 | wiphy_debug(ar->hw->wiphy, "send frame q:%d =>\n", i); | ||
1428 | ar9170_print_txheader(ar, skb); | ||
1429 | #endif /* AR9170_QUEUE_DEBUG */ | ||
1430 | |||
1431 | err = ar->tx(ar, skb); | ||
1432 | if (unlikely(err)) { | ||
1433 | frames_failed++; | ||
1434 | dev_kfree_skb_any(skb); | ||
1435 | } else { | ||
1436 | remaining_space--; | ||
1437 | schedule_garbagecollector = true; | ||
1438 | } | ||
1439 | |||
1440 | frames--; | ||
1441 | } | ||
1442 | |||
1443 | #ifdef AR9170_QUEUE_DEBUG | ||
1444 | wiphy_debug(ar->hw->wiphy, | ||
1445 | "ar9170_tx report for queue %d\n", i); | ||
1446 | |||
1447 | wiphy_debug(ar->hw->wiphy, | ||
1448 | "unprocessed pending frames left:\n"); | ||
1449 | ar9170_dump_txqueue(ar, &ar->tx_pending[i]); | ||
1450 | #endif /* AR9170_QUEUE_DEBUG */ | ||
1451 | |||
1452 | if (unlikely(frames_failed)) { | ||
1453 | #ifdef AR9170_QUEUE_DEBUG | ||
1454 | wiphy_debug(ar->hw->wiphy, | ||
1455 | "frames failed %d =>\n", frames_failed); | ||
1456 | #endif /* AR9170_QUEUE_DEBUG */ | ||
1457 | |||
1458 | spin_lock_irqsave(&ar->tx_stats_lock, flags); | ||
1459 | ar->tx_stats[i].len -= frames_failed; | ||
1460 | ar->tx_stats[i].count -= frames_failed; | ||
1461 | #ifdef AR9170_QUEUE_STOP_DEBUG | ||
1462 | wiphy_debug(ar->hw->wiphy, "wake queue %d\n", i); | ||
1463 | __ar9170_dump_txstats(ar); | ||
1464 | #endif /* AR9170_QUEUE_STOP_DEBUG */ | ||
1465 | ieee80211_wake_queue(ar->hw, i); | ||
1466 | spin_unlock_irqrestore(&ar->tx_stats_lock, flags); | ||
1467 | } | ||
1468 | } | ||
1469 | |||
1470 | if (!schedule_garbagecollector) | ||
1471 | return; | ||
1472 | |||
1473 | ieee80211_queue_delayed_work(ar->hw, | ||
1474 | &ar->tx_janitor, | ||
1475 | msecs_to_jiffies(AR9170_JANITOR_DELAY)); | ||
1476 | } | ||
1477 | |||
1478 | void ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | ||
1479 | { | ||
1480 | struct ar9170 *ar = hw->priv; | ||
1481 | struct ieee80211_tx_info *info; | ||
1482 | unsigned int queue; | ||
1483 | |||
1484 | if (unlikely(!IS_STARTED(ar))) | ||
1485 | goto err_free; | ||
1486 | |||
1487 | if (unlikely(ar9170_tx_prepare(ar, skb))) | ||
1488 | goto err_free; | ||
1489 | |||
1490 | queue = skb_get_queue_mapping(skb); | ||
1491 | info = IEEE80211_SKB_CB(skb); | ||
1492 | ar9170_tx_prepare_phy(ar, skb); | ||
1493 | skb_queue_tail(&ar->tx_pending[queue], skb); | ||
1494 | |||
1495 | ar9170_tx(ar); | ||
1496 | return; | ||
1497 | |||
1498 | err_free: | ||
1499 | dev_kfree_skb_any(skb); | ||
1500 | } | ||
1501 | |||
1502 | static int ar9170_op_add_interface(struct ieee80211_hw *hw, | ||
1503 | struct ieee80211_vif *vif) | ||
1504 | { | ||
1505 | struct ar9170 *ar = hw->priv; | ||
1506 | struct ath_common *common = &ar->common; | ||
1507 | int err = 0; | ||
1508 | |||
1509 | mutex_lock(&ar->mutex); | ||
1510 | |||
1511 | if (ar->vif) { | ||
1512 | err = -EBUSY; | ||
1513 | goto unlock; | ||
1514 | } | ||
1515 | |||
1516 | ar->vif = vif; | ||
1517 | memcpy(common->macaddr, vif->addr, ETH_ALEN); | ||
1518 | |||
1519 | if (modparam_nohwcrypt || (ar->vif->type != NL80211_IFTYPE_STATION)) { | ||
1520 | ar->rx_software_decryption = true; | ||
1521 | ar->disable_offload = true; | ||
1522 | } | ||
1523 | |||
1524 | ar->cur_filter = 0; | ||
1525 | err = ar9170_update_frame_filter(ar, AR9170_MAC_REG_FTF_DEFAULTS); | ||
1526 | if (err) | ||
1527 | goto unlock; | ||
1528 | |||
1529 | err = ar9170_set_operating_mode(ar); | ||
1530 | |||
1531 | unlock: | ||
1532 | mutex_unlock(&ar->mutex); | ||
1533 | return err; | ||
1534 | } | ||
1535 | |||
1536 | static void ar9170_op_remove_interface(struct ieee80211_hw *hw, | ||
1537 | struct ieee80211_vif *vif) | ||
1538 | { | ||
1539 | struct ar9170 *ar = hw->priv; | ||
1540 | |||
1541 | mutex_lock(&ar->mutex); | ||
1542 | ar->vif = NULL; | ||
1543 | ar9170_update_frame_filter(ar, 0); | ||
1544 | ar9170_set_beacon_timers(ar); | ||
1545 | dev_kfree_skb(ar->beacon); | ||
1546 | ar->beacon = NULL; | ||
1547 | ar->sniffer_enabled = false; | ||
1548 | ar->rx_software_decryption = false; | ||
1549 | ar9170_set_operating_mode(ar); | ||
1550 | mutex_unlock(&ar->mutex); | ||
1551 | } | ||
1552 | |||
1553 | static int ar9170_op_config(struct ieee80211_hw *hw, u32 changed) | ||
1554 | { | ||
1555 | struct ar9170 *ar = hw->priv; | ||
1556 | int err = 0; | ||
1557 | |||
1558 | mutex_lock(&ar->mutex); | ||
1559 | |||
1560 | if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL) { | ||
1561 | /* TODO */ | ||
1562 | err = 0; | ||
1563 | } | ||
1564 | |||
1565 | if (changed & IEEE80211_CONF_CHANGE_PS) { | ||
1566 | /* TODO */ | ||
1567 | err = 0; | ||
1568 | } | ||
1569 | |||
1570 | if (changed & IEEE80211_CONF_CHANGE_POWER) { | ||
1571 | /* TODO */ | ||
1572 | err = 0; | ||
1573 | } | ||
1574 | |||
1575 | if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) { | ||
1576 | /* | ||
1577 | * is it long_frame_max_tx_count or short_frame_max_tx_count? | ||
1578 | */ | ||
1579 | |||
1580 | err = ar9170_set_hwretry_limit(ar, | ||
1581 | ar->hw->conf.long_frame_max_tx_count); | ||
1582 | if (err) | ||
1583 | goto out; | ||
1584 | } | ||
1585 | |||
1586 | if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { | ||
1587 | |||
1588 | /* adjust slot time for 5 GHz */ | ||
1589 | err = ar9170_set_slot_time(ar); | ||
1590 | if (err) | ||
1591 | goto out; | ||
1592 | |||
1593 | err = ar9170_set_dyn_sifs_ack(ar); | ||
1594 | if (err) | ||
1595 | goto out; | ||
1596 | |||
1597 | err = ar9170_set_channel(ar, hw->conf.channel, | ||
1598 | AR9170_RFI_NONE, | ||
1599 | nl80211_to_ar9170(hw->conf.channel_type)); | ||
1600 | if (err) | ||
1601 | goto out; | ||
1602 | } | ||
1603 | |||
1604 | out: | ||
1605 | mutex_unlock(&ar->mutex); | ||
1606 | return err; | ||
1607 | } | ||
1608 | |||
1609 | static u64 ar9170_op_prepare_multicast(struct ieee80211_hw *hw, | ||
1610 | struct netdev_hw_addr_list *mc_list) | ||
1611 | { | ||
1612 | u64 mchash; | ||
1613 | struct netdev_hw_addr *ha; | ||
1614 | |||
1615 | /* always get broadcast frames */ | ||
1616 | mchash = 1ULL << (0xff >> 2); | ||
1617 | |||
1618 | netdev_hw_addr_list_for_each(ha, mc_list) | ||
1619 | mchash |= 1ULL << (ha->addr[5] >> 2); | ||
1620 | |||
1621 | return mchash; | ||
1622 | } | ||
1623 | |||
1624 | static void ar9170_op_configure_filter(struct ieee80211_hw *hw, | ||
1625 | unsigned int changed_flags, | ||
1626 | unsigned int *new_flags, | ||
1627 | u64 multicast) | ||
1628 | { | ||
1629 | struct ar9170 *ar = hw->priv; | ||
1630 | |||
1631 | if (unlikely(!IS_ACCEPTING_CMD(ar))) | ||
1632 | return ; | ||
1633 | |||
1634 | mutex_lock(&ar->mutex); | ||
1635 | |||
1636 | /* mask supported flags */ | ||
1637 | *new_flags &= FIF_ALLMULTI | FIF_CONTROL | FIF_BCN_PRBRESP_PROMISC | | ||
1638 | FIF_PROMISC_IN_BSS | FIF_FCSFAIL | FIF_PLCPFAIL; | ||
1639 | ar->filter_state = *new_flags; | ||
1640 | /* | ||
1641 | * We can support more by setting the sniffer bit and | ||
1642 | * then checking the error flags, later. | ||
1643 | */ | ||
1644 | |||
1645 | if (changed_flags & FIF_ALLMULTI && *new_flags & FIF_ALLMULTI) | ||
1646 | multicast = ~0ULL; | ||
1647 | |||
1648 | if (multicast != ar->cur_mc_hash) | ||
1649 | ar9170_update_multicast(ar, multicast); | ||
1650 | |||
1651 | if (changed_flags & FIF_CONTROL) { | ||
1652 | u32 filter = AR9170_MAC_REG_FTF_PSPOLL | | ||
1653 | AR9170_MAC_REG_FTF_RTS | | ||
1654 | AR9170_MAC_REG_FTF_CTS | | ||
1655 | AR9170_MAC_REG_FTF_ACK | | ||
1656 | AR9170_MAC_REG_FTF_CFE | | ||
1657 | AR9170_MAC_REG_FTF_CFE_ACK; | ||
1658 | |||
1659 | if (*new_flags & FIF_CONTROL) | ||
1660 | filter |= ar->cur_filter; | ||
1661 | else | ||
1662 | filter &= (~ar->cur_filter); | ||
1663 | |||
1664 | ar9170_update_frame_filter(ar, filter); | ||
1665 | } | ||
1666 | |||
1667 | if (changed_flags & FIF_PROMISC_IN_BSS) { | ||
1668 | ar->sniffer_enabled = ((*new_flags) & FIF_PROMISC_IN_BSS) != 0; | ||
1669 | ar9170_set_operating_mode(ar); | ||
1670 | } | ||
1671 | |||
1672 | mutex_unlock(&ar->mutex); | ||
1673 | } | ||
1674 | |||
1675 | |||
1676 | static void ar9170_op_bss_info_changed(struct ieee80211_hw *hw, | ||
1677 | struct ieee80211_vif *vif, | ||
1678 | struct ieee80211_bss_conf *bss_conf, | ||
1679 | u32 changed) | ||
1680 | { | ||
1681 | struct ar9170 *ar = hw->priv; | ||
1682 | struct ath_common *common = &ar->common; | ||
1683 | int err = 0; | ||
1684 | |||
1685 | mutex_lock(&ar->mutex); | ||
1686 | |||
1687 | if (changed & BSS_CHANGED_BSSID) { | ||
1688 | memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); | ||
1689 | err = ar9170_set_operating_mode(ar); | ||
1690 | if (err) | ||
1691 | goto out; | ||
1692 | } | ||
1693 | |||
1694 | if (changed & BSS_CHANGED_BEACON_ENABLED) | ||
1695 | ar->enable_beacon = bss_conf->enable_beacon; | ||
1696 | |||
1697 | if (changed & BSS_CHANGED_BEACON) { | ||
1698 | err = ar9170_update_beacon(ar); | ||
1699 | if (err) | ||
1700 | goto out; | ||
1701 | } | ||
1702 | |||
1703 | if (changed & (BSS_CHANGED_BEACON_ENABLED | BSS_CHANGED_BEACON | | ||
1704 | BSS_CHANGED_BEACON_INT)) { | ||
1705 | err = ar9170_set_beacon_timers(ar); | ||
1706 | if (err) | ||
1707 | goto out; | ||
1708 | } | ||
1709 | |||
1710 | if (changed & BSS_CHANGED_ASSOC) { | ||
1711 | #ifndef CONFIG_AR9170_LEDS | ||
1712 | /* enable assoc LED. */ | ||
1713 | err = ar9170_set_leds_state(ar, bss_conf->assoc ? 2 : 0); | ||
1714 | #endif /* CONFIG_AR9170_LEDS */ | ||
1715 | } | ||
1716 | |||
1717 | if (changed & BSS_CHANGED_HT) { | ||
1718 | /* TODO */ | ||
1719 | err = 0; | ||
1720 | } | ||
1721 | |||
1722 | if (changed & BSS_CHANGED_ERP_SLOT) { | ||
1723 | err = ar9170_set_slot_time(ar); | ||
1724 | if (err) | ||
1725 | goto out; | ||
1726 | } | ||
1727 | |||
1728 | if (changed & BSS_CHANGED_BASIC_RATES) { | ||
1729 | err = ar9170_set_basic_rates(ar); | ||
1730 | if (err) | ||
1731 | goto out; | ||
1732 | } | ||
1733 | |||
1734 | out: | ||
1735 | mutex_unlock(&ar->mutex); | ||
1736 | } | ||
1737 | |||
1738 | static u64 ar9170_op_get_tsf(struct ieee80211_hw *hw) | ||
1739 | { | ||
1740 | struct ar9170 *ar = hw->priv; | ||
1741 | int err; | ||
1742 | u64 tsf; | ||
1743 | #define NR 3 | ||
1744 | static const u32 addr[NR] = { AR9170_MAC_REG_TSF_H, | ||
1745 | AR9170_MAC_REG_TSF_L, | ||
1746 | AR9170_MAC_REG_TSF_H }; | ||
1747 | u32 val[NR]; | ||
1748 | int loops = 0; | ||
1749 | |||
1750 | mutex_lock(&ar->mutex); | ||
1751 | |||
1752 | while (loops++ < 10) { | ||
1753 | err = ar9170_read_mreg(ar, NR, addr, val); | ||
1754 | if (err || val[0] == val[2]) | ||
1755 | break; | ||
1756 | } | ||
1757 | |||
1758 | mutex_unlock(&ar->mutex); | ||
1759 | |||
1760 | if (WARN_ON(err)) | ||
1761 | return 0; | ||
1762 | tsf = val[0]; | ||
1763 | tsf = (tsf << 32) | val[1]; | ||
1764 | return tsf; | ||
1765 | #undef NR | ||
1766 | } | ||
1767 | |||
1768 | static int ar9170_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, | ||
1769 | struct ieee80211_vif *vif, struct ieee80211_sta *sta, | ||
1770 | struct ieee80211_key_conf *key) | ||
1771 | { | ||
1772 | struct ar9170 *ar = hw->priv; | ||
1773 | int err = 0, i; | ||
1774 | u8 ktype; | ||
1775 | |||
1776 | if ((!ar->vif) || (ar->disable_offload)) | ||
1777 | return -EOPNOTSUPP; | ||
1778 | |||
1779 | switch (key->cipher) { | ||
1780 | case WLAN_CIPHER_SUITE_WEP40: | ||
1781 | ktype = AR9170_ENC_ALG_WEP64; | ||
1782 | break; | ||
1783 | case WLAN_CIPHER_SUITE_WEP104: | ||
1784 | ktype = AR9170_ENC_ALG_WEP128; | ||
1785 | break; | ||
1786 | case WLAN_CIPHER_SUITE_TKIP: | ||
1787 | ktype = AR9170_ENC_ALG_TKIP; | ||
1788 | break; | ||
1789 | case WLAN_CIPHER_SUITE_CCMP: | ||
1790 | ktype = AR9170_ENC_ALG_AESCCMP; | ||
1791 | break; | ||
1792 | default: | ||
1793 | return -EOPNOTSUPP; | ||
1794 | } | ||
1795 | |||
1796 | mutex_lock(&ar->mutex); | ||
1797 | if (cmd == SET_KEY) { | ||
1798 | if (unlikely(!IS_STARTED(ar))) { | ||
1799 | err = -EOPNOTSUPP; | ||
1800 | goto out; | ||
1801 | } | ||
1802 | |||
1803 | /* group keys need all-zeroes address */ | ||
1804 | if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) | ||
1805 | sta = NULL; | ||
1806 | |||
1807 | if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) { | ||
1808 | for (i = 0; i < 64; i++) | ||
1809 | if (!(ar->usedkeys & BIT(i))) | ||
1810 | break; | ||
1811 | if (i == 64) { | ||
1812 | ar->rx_software_decryption = true; | ||
1813 | ar9170_set_operating_mode(ar); | ||
1814 | err = -ENOSPC; | ||
1815 | goto out; | ||
1816 | } | ||
1817 | } else { | ||
1818 | i = 64 + key->keyidx; | ||
1819 | } | ||
1820 | |||
1821 | key->hw_key_idx = i; | ||
1822 | |||
1823 | err = ar9170_upload_key(ar, i, sta ? sta->addr : NULL, ktype, 0, | ||
1824 | key->key, min_t(u8, 16, key->keylen)); | ||
1825 | if (err) | ||
1826 | goto out; | ||
1827 | |||
1828 | if (key->cipher == WLAN_CIPHER_SUITE_TKIP) { | ||
1829 | err = ar9170_upload_key(ar, i, sta ? sta->addr : NULL, | ||
1830 | ktype, 1, key->key + 16, 16); | ||
1831 | if (err) | ||
1832 | goto out; | ||
1833 | |||
1834 | /* | ||
1835 | * hardware is not capable generating the MMIC | ||
1836 | * for fragmented frames! | ||
1837 | */ | ||
1838 | key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; | ||
1839 | } | ||
1840 | |||
1841 | if (i < 64) | ||
1842 | ar->usedkeys |= BIT(i); | ||
1843 | |||
1844 | key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; | ||
1845 | } else { | ||
1846 | if (unlikely(!IS_STARTED(ar))) { | ||
1847 | /* The device is gone... together with the key ;-) */ | ||
1848 | err = 0; | ||
1849 | goto out; | ||
1850 | } | ||
1851 | |||
1852 | err = ar9170_disable_key(ar, key->hw_key_idx); | ||
1853 | if (err) | ||
1854 | goto out; | ||
1855 | |||
1856 | if (key->hw_key_idx < 64) { | ||
1857 | ar->usedkeys &= ~BIT(key->hw_key_idx); | ||
1858 | } else { | ||
1859 | err = ar9170_upload_key(ar, key->hw_key_idx, NULL, | ||
1860 | AR9170_ENC_ALG_NONE, 0, | ||
1861 | NULL, 0); | ||
1862 | if (err) | ||
1863 | goto out; | ||
1864 | |||
1865 | if (key->cipher == WLAN_CIPHER_SUITE_TKIP) { | ||
1866 | err = ar9170_upload_key(ar, key->hw_key_idx, | ||
1867 | NULL, | ||
1868 | AR9170_ENC_ALG_NONE, 1, | ||
1869 | NULL, 0); | ||
1870 | if (err) | ||
1871 | goto out; | ||
1872 | } | ||
1873 | |||
1874 | } | ||
1875 | } | ||
1876 | |||
1877 | ar9170_regwrite_begin(ar); | ||
1878 | ar9170_regwrite(AR9170_MAC_REG_ROLL_CALL_TBL_L, ar->usedkeys); | ||
1879 | ar9170_regwrite(AR9170_MAC_REG_ROLL_CALL_TBL_H, ar->usedkeys >> 32); | ||
1880 | ar9170_regwrite_finish(); | ||
1881 | err = ar9170_regwrite_result(); | ||
1882 | |||
1883 | out: | ||
1884 | mutex_unlock(&ar->mutex); | ||
1885 | |||
1886 | return err; | ||
1887 | } | ||
1888 | |||
1889 | static int ar9170_get_stats(struct ieee80211_hw *hw, | ||
1890 | struct ieee80211_low_level_stats *stats) | ||
1891 | { | ||
1892 | struct ar9170 *ar = hw->priv; | ||
1893 | u32 val; | ||
1894 | int err; | ||
1895 | |||
1896 | mutex_lock(&ar->mutex); | ||
1897 | err = ar9170_read_reg(ar, AR9170_MAC_REG_TX_RETRY, &val); | ||
1898 | ar->stats.dot11ACKFailureCount += val; | ||
1899 | |||
1900 | memcpy(stats, &ar->stats, sizeof(*stats)); | ||
1901 | mutex_unlock(&ar->mutex); | ||
1902 | |||
1903 | return 0; | ||
1904 | } | ||
1905 | |||
1906 | static int ar9170_get_survey(struct ieee80211_hw *hw, int idx, | ||
1907 | struct survey_info *survey) | ||
1908 | { | ||
1909 | struct ar9170 *ar = hw->priv; | ||
1910 | struct ieee80211_conf *conf = &hw->conf; | ||
1911 | |||
1912 | if (idx != 0) | ||
1913 | return -ENOENT; | ||
1914 | |||
1915 | /* TODO: update noise value, e.g. call ar9170_set_channel */ | ||
1916 | |||
1917 | survey->channel = conf->channel; | ||
1918 | survey->filled = SURVEY_INFO_NOISE_DBM; | ||
1919 | survey->noise = ar->noise[0]; | ||
1920 | |||
1921 | return 0; | ||
1922 | } | ||
1923 | |||
1924 | static int ar9170_conf_tx(struct ieee80211_hw *hw, u16 queue, | ||
1925 | const struct ieee80211_tx_queue_params *param) | ||
1926 | { | ||
1927 | struct ar9170 *ar = hw->priv; | ||
1928 | int ret; | ||
1929 | |||
1930 | mutex_lock(&ar->mutex); | ||
1931 | if (queue < __AR9170_NUM_TXQ) { | ||
1932 | memcpy(&ar->edcf[ar9170_qos_hwmap[queue]], | ||
1933 | param, sizeof(*param)); | ||
1934 | |||
1935 | ret = ar9170_set_qos(ar); | ||
1936 | } else { | ||
1937 | ret = -EINVAL; | ||
1938 | } | ||
1939 | |||
1940 | mutex_unlock(&ar->mutex); | ||
1941 | return ret; | ||
1942 | } | ||
1943 | |||
1944 | static int ar9170_ampdu_action(struct ieee80211_hw *hw, | ||
1945 | struct ieee80211_vif *vif, | ||
1946 | enum ieee80211_ampdu_mlme_action action, | ||
1947 | struct ieee80211_sta *sta, u16 tid, u16 *ssn, | ||
1948 | u8 buf_size) | ||
1949 | { | ||
1950 | switch (action) { | ||
1951 | case IEEE80211_AMPDU_RX_START: | ||
1952 | case IEEE80211_AMPDU_RX_STOP: | ||
1953 | /* Handled by firmware */ | ||
1954 | break; | ||
1955 | |||
1956 | default: | ||
1957 | return -EOPNOTSUPP; | ||
1958 | } | ||
1959 | |||
1960 | return 0; | ||
1961 | } | ||
1962 | |||
1963 | static const struct ieee80211_ops ar9170_ops = { | ||
1964 | .start = ar9170_op_start, | ||
1965 | .stop = ar9170_op_stop, | ||
1966 | .tx = ar9170_op_tx, | ||
1967 | .add_interface = ar9170_op_add_interface, | ||
1968 | .remove_interface = ar9170_op_remove_interface, | ||
1969 | .config = ar9170_op_config, | ||
1970 | .prepare_multicast = ar9170_op_prepare_multicast, | ||
1971 | .configure_filter = ar9170_op_configure_filter, | ||
1972 | .conf_tx = ar9170_conf_tx, | ||
1973 | .bss_info_changed = ar9170_op_bss_info_changed, | ||
1974 | .get_tsf = ar9170_op_get_tsf, | ||
1975 | .set_key = ar9170_set_key, | ||
1976 | .get_stats = ar9170_get_stats, | ||
1977 | .get_survey = ar9170_get_survey, | ||
1978 | .ampdu_action = ar9170_ampdu_action, | ||
1979 | }; | ||
1980 | |||
1981 | void *ar9170_alloc(size_t priv_size) | ||
1982 | { | ||
1983 | struct ieee80211_hw *hw; | ||
1984 | struct ar9170 *ar; | ||
1985 | struct sk_buff *skb; | ||
1986 | int i; | ||
1987 | |||
1988 | /* | ||
1989 | * this buffer is used for rx stream reconstruction. | ||
1990 | * Under heavy load this device (or the transport layer?) | ||
1991 | * tends to split the streams into separate rx descriptors. | ||
1992 | */ | ||
1993 | |||
1994 | skb = __dev_alloc_skb(AR9170_RX_STREAM_MAX_SIZE, GFP_KERNEL); | ||
1995 | if (!skb) | ||
1996 | goto err_nomem; | ||
1997 | |||
1998 | hw = ieee80211_alloc_hw(priv_size, &ar9170_ops); | ||
1999 | if (!hw) | ||
2000 | goto err_nomem; | ||
2001 | |||
2002 | ar = hw->priv; | ||
2003 | ar->hw = hw; | ||
2004 | ar->rx_failover = skb; | ||
2005 | |||
2006 | mutex_init(&ar->mutex); | ||
2007 | spin_lock_init(&ar->cmdlock); | ||
2008 | spin_lock_init(&ar->tx_stats_lock); | ||
2009 | for (i = 0; i < __AR9170_NUM_TXQ; i++) { | ||
2010 | skb_queue_head_init(&ar->tx_status[i]); | ||
2011 | skb_queue_head_init(&ar->tx_pending[i]); | ||
2012 | } | ||
2013 | ar9170_rx_reset_rx_mpdu(ar); | ||
2014 | INIT_WORK(&ar->beacon_work, ar9170_new_beacon); | ||
2015 | INIT_DELAYED_WORK(&ar->tx_janitor, ar9170_tx_janitor); | ||
2016 | |||
2017 | /* all hw supports 2.4 GHz, so set channel to 1 by default */ | ||
2018 | ar->channel = &ar9170_2ghz_chantable[0]; | ||
2019 | |||
2020 | /* first part of wiphy init */ | ||
2021 | ar->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | | ||
2022 | BIT(NL80211_IFTYPE_WDS) | | ||
2023 | BIT(NL80211_IFTYPE_ADHOC); | ||
2024 | ar->hw->flags |= IEEE80211_HW_RX_INCLUDES_FCS | | ||
2025 | IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | | ||
2026 | IEEE80211_HW_SIGNAL_DBM; | ||
2027 | |||
2028 | ar->hw->queues = __AR9170_NUM_TXQ; | ||
2029 | ar->hw->extra_tx_headroom = 8; | ||
2030 | |||
2031 | ar->hw->max_rates = 1; | ||
2032 | ar->hw->max_rate_tries = 3; | ||
2033 | |||
2034 | for (i = 0; i < ARRAY_SIZE(ar->noise); i++) | ||
2035 | ar->noise[i] = -95; /* ATH_DEFAULT_NOISE_FLOOR */ | ||
2036 | |||
2037 | return ar; | ||
2038 | |||
2039 | err_nomem: | ||
2040 | kfree_skb(skb); | ||
2041 | return ERR_PTR(-ENOMEM); | ||
2042 | } | ||
2043 | |||
2044 | static int ar9170_read_eeprom(struct ar9170 *ar) | ||
2045 | { | ||
2046 | #define RW 8 /* number of words to read at once */ | ||
2047 | #define RB (sizeof(u32) * RW) | ||
2048 | struct ath_regulatory *regulatory = &ar->common.regulatory; | ||
2049 | u8 *eeprom = (void *)&ar->eeprom; | ||
2050 | u8 *addr = ar->eeprom.mac_address; | ||
2051 | __le32 offsets[RW]; | ||
2052 | unsigned int rx_streams, tx_streams, tx_params = 0; | ||
2053 | int i, j, err, bands = 0; | ||
2054 | |||
2055 | BUILD_BUG_ON(sizeof(ar->eeprom) & 3); | ||
2056 | |||
2057 | BUILD_BUG_ON(RB > AR9170_MAX_CMD_LEN - 4); | ||
2058 | #ifndef __CHECKER__ | ||
2059 | /* don't want to handle trailing remains */ | ||
2060 | BUILD_BUG_ON(sizeof(ar->eeprom) % RB); | ||
2061 | #endif | ||
2062 | |||
2063 | for (i = 0; i < sizeof(ar->eeprom)/RB; i++) { | ||
2064 | for (j = 0; j < RW; j++) | ||
2065 | offsets[j] = cpu_to_le32(AR9170_EEPROM_START + | ||
2066 | RB * i + 4 * j); | ||
2067 | |||
2068 | err = ar->exec_cmd(ar, AR9170_CMD_RREG, | ||
2069 | RB, (u8 *) &offsets, | ||
2070 | RB, eeprom + RB * i); | ||
2071 | if (err) | ||
2072 | return err; | ||
2073 | } | ||
2074 | |||
2075 | #undef RW | ||
2076 | #undef RB | ||
2077 | |||
2078 | if (ar->eeprom.length == cpu_to_le16(0xFFFF)) | ||
2079 | return -ENODATA; | ||
2080 | |||
2081 | if (ar->eeprom.operating_flags & AR9170_OPFLAG_2GHZ) { | ||
2082 | ar->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &ar9170_band_2GHz; | ||
2083 | bands++; | ||
2084 | } | ||
2085 | if (ar->eeprom.operating_flags & AR9170_OPFLAG_5GHZ) { | ||
2086 | ar->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &ar9170_band_5GHz; | ||
2087 | bands++; | ||
2088 | } | ||
2089 | |||
2090 | rx_streams = hweight8(ar->eeprom.rx_mask); | ||
2091 | tx_streams = hweight8(ar->eeprom.tx_mask); | ||
2092 | |||
2093 | if (rx_streams != tx_streams) | ||
2094 | tx_params = IEEE80211_HT_MCS_TX_RX_DIFF; | ||
2095 | |||
2096 | if (tx_streams >= 1 && tx_streams <= IEEE80211_HT_MCS_TX_MAX_STREAMS) | ||
2097 | tx_params = (tx_streams - 1) << | ||
2098 | IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT; | ||
2099 | |||
2100 | ar9170_band_2GHz.ht_cap.mcs.tx_params |= tx_params; | ||
2101 | ar9170_band_5GHz.ht_cap.mcs.tx_params |= tx_params; | ||
2102 | |||
2103 | /* | ||
2104 | * I measured this, a bandswitch takes roughly | ||
2105 | * 135 ms and a frequency switch about 80. | ||
2106 | * | ||
2107 | * FIXME: measure these values again once EEPROM settings | ||
2108 | * are used, that will influence them! | ||
2109 | */ | ||
2110 | if (bands == 2) | ||
2111 | ar->hw->channel_change_time = 135 * 1000; | ||
2112 | else | ||
2113 | ar->hw->channel_change_time = 80 * 1000; | ||
2114 | |||
2115 | regulatory->current_rd = le16_to_cpu(ar->eeprom.reg_domain[0]); | ||
2116 | regulatory->current_rd_ext = le16_to_cpu(ar->eeprom.reg_domain[1]); | ||
2117 | |||
2118 | /* second part of wiphy init */ | ||
2119 | SET_IEEE80211_PERM_ADDR(ar->hw, addr); | ||
2120 | |||
2121 | return bands ? 0 : -EINVAL; | ||
2122 | } | ||
2123 | |||
2124 | static int ar9170_reg_notifier(struct wiphy *wiphy, | ||
2125 | struct regulatory_request *request) | ||
2126 | { | ||
2127 | struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); | ||
2128 | struct ar9170 *ar = hw->priv; | ||
2129 | |||
2130 | return ath_reg_notifier_apply(wiphy, request, &ar->common.regulatory); | ||
2131 | } | ||
2132 | |||
2133 | int ar9170_register(struct ar9170 *ar, struct device *pdev) | ||
2134 | { | ||
2135 | struct ath_regulatory *regulatory = &ar->common.regulatory; | ||
2136 | int err; | ||
2137 | |||
2138 | /* try to read EEPROM, init MAC addr */ | ||
2139 | err = ar9170_read_eeprom(ar); | ||
2140 | if (err) | ||
2141 | goto err_out; | ||
2142 | |||
2143 | err = ath_regd_init(regulatory, ar->hw->wiphy, | ||
2144 | ar9170_reg_notifier); | ||
2145 | if (err) | ||
2146 | goto err_out; | ||
2147 | |||
2148 | err = ieee80211_register_hw(ar->hw); | ||
2149 | if (err) | ||
2150 | goto err_out; | ||
2151 | |||
2152 | if (!ath_is_world_regd(regulatory)) | ||
2153 | regulatory_hint(ar->hw->wiphy, regulatory->alpha2); | ||
2154 | |||
2155 | err = ar9170_init_leds(ar); | ||
2156 | if (err) | ||
2157 | goto err_unreg; | ||
2158 | |||
2159 | #ifdef CONFIG_AR9170_LEDS | ||
2160 | err = ar9170_register_leds(ar); | ||
2161 | if (err) | ||
2162 | goto err_unreg; | ||
2163 | #endif /* CONFIG_AR9170_LEDS */ | ||
2164 | |||
2165 | dev_info(pdev, "Atheros AR9170 is registered as '%s'\n", | ||
2166 | wiphy_name(ar->hw->wiphy)); | ||
2167 | |||
2168 | ar->registered = true; | ||
2169 | return 0; | ||
2170 | |||
2171 | err_unreg: | ||
2172 | ieee80211_unregister_hw(ar->hw); | ||
2173 | |||
2174 | err_out: | ||
2175 | return err; | ||
2176 | } | ||
2177 | |||
2178 | void ar9170_unregister(struct ar9170 *ar) | ||
2179 | { | ||
2180 | if (ar->registered) { | ||
2181 | #ifdef CONFIG_AR9170_LEDS | ||
2182 | ar9170_unregister_leds(ar); | ||
2183 | #endif /* CONFIG_AR9170_LEDS */ | ||
2184 | |||
2185 | ieee80211_unregister_hw(ar->hw); | ||
2186 | } | ||
2187 | |||
2188 | kfree_skb(ar->rx_failover); | ||
2189 | mutex_destroy(&ar->mutex); | ||
2190 | } | ||
diff --git a/drivers/net/wireless/ath/ar9170/phy.c b/drivers/net/wireless/ath/ar9170/phy.c deleted file mode 100644 index aa8d06ba1ee4..000000000000 --- a/drivers/net/wireless/ath/ar9170/phy.c +++ /dev/null | |||
@@ -1,1719 +0,0 @@ | |||
1 | /* | ||
2 | * Atheros AR9170 driver | ||
3 | * | ||
4 | * PHY and RF code | ||
5 | * | ||
6 | * Copyright 2008, Johannes Berg <johannes@sipsolutions.net> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; see the file COPYING. If not, see | ||
20 | * http://www.gnu.org/licenses/. | ||
21 | * | ||
22 | * This file incorporates work covered by the following copyright and | ||
23 | * permission notice: | ||
24 | * Copyright (c) 2007-2008 Atheros Communications, Inc. | ||
25 | * | ||
26 | * Permission to use, copy, modify, and/or distribute this software for any | ||
27 | * purpose with or without fee is hereby granted, provided that the above | ||
28 | * copyright notice and this permission notice appear in all copies. | ||
29 | * | ||
30 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
31 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
32 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
33 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
34 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
35 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
36 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
37 | */ | ||
38 | |||
39 | #include <linux/bitrev.h> | ||
40 | #include "ar9170.h" | ||
41 | #include "cmd.h" | ||
42 | |||
43 | static int ar9170_init_power_cal(struct ar9170 *ar) | ||
44 | { | ||
45 | ar9170_regwrite_begin(ar); | ||
46 | |||
47 | ar9170_regwrite(0x1bc000 + 0x993c, 0x7f); | ||
48 | ar9170_regwrite(0x1bc000 + 0x9934, 0x3f3f3f3f); | ||
49 | ar9170_regwrite(0x1bc000 + 0x9938, 0x3f3f3f3f); | ||
50 | ar9170_regwrite(0x1bc000 + 0xa234, 0x3f3f3f3f); | ||
51 | ar9170_regwrite(0x1bc000 + 0xa238, 0x3f3f3f3f); | ||
52 | ar9170_regwrite(0x1bc000 + 0xa38c, 0x3f3f3f3f); | ||
53 | ar9170_regwrite(0x1bc000 + 0xa390, 0x3f3f3f3f); | ||
54 | ar9170_regwrite(0x1bc000 + 0xa3cc, 0x3f3f3f3f); | ||
55 | ar9170_regwrite(0x1bc000 + 0xa3d0, 0x3f3f3f3f); | ||
56 | ar9170_regwrite(0x1bc000 + 0xa3d4, 0x3f3f3f3f); | ||
57 | |||
58 | ar9170_regwrite_finish(); | ||
59 | return ar9170_regwrite_result(); | ||
60 | } | ||
61 | |||
62 | struct ar9170_phy_init { | ||
63 | u32 reg, _5ghz_20, _5ghz_40, _2ghz_40, _2ghz_20; | ||
64 | }; | ||
65 | |||
66 | static struct ar9170_phy_init ar5416_phy_init[] = { | ||
67 | { 0x1c5800, 0x00000007, 0x00000007, 0x00000007, 0x00000007, }, | ||
68 | { 0x1c5804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, }, | ||
69 | { 0x1c5808, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
70 | { 0x1c580c, 0xad848e19, 0xad848e19, 0xad848e19, 0xad848e19, }, | ||
71 | { 0x1c5810, 0x7d14e000, 0x7d14e000, 0x7d14e000, 0x7d14e000, }, | ||
72 | { 0x1c5814, 0x9c0a9f6b, 0x9c0a9f6b, 0x9c0a9f6b, 0x9c0a9f6b, }, | ||
73 | { 0x1c5818, 0x00000090, 0x00000090, 0x00000090, 0x00000090, }, | ||
74 | { 0x1c581c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
75 | { 0x1c5820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, }, | ||
76 | { 0x1c5824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, }, | ||
77 | { 0x1c5828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, }, | ||
78 | { 0x1c582c, 0x0000a000, 0x0000a000, 0x0000a000, 0x0000a000, }, | ||
79 | { 0x1c5830, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
80 | { 0x1c5834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, }, | ||
81 | { 0x1c5838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, }, | ||
82 | { 0x1c583c, 0x00200400, 0x00200400, 0x00200400, 0x00200400, }, | ||
83 | { 0x1c5840, 0x206a002e, 0x206a002e, 0x206a002e, 0x206a002e, }, | ||
84 | { 0x1c5844, 0x1372161e, 0x13721c1e, 0x13721c24, 0x137216a4, }, | ||
85 | { 0x1c5848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, }, | ||
86 | { 0x1c584c, 0x1284233c, 0x1284233c, 0x1284233c, 0x1284233c, }, | ||
87 | { 0x1c5850, 0x6c48b4e4, 0x6c48b4e4, 0x6c48b0e4, 0x6c48b0e4, }, | ||
88 | { 0x1c5854, 0x00000859, 0x00000859, 0x00000859, 0x00000859, }, | ||
89 | { 0x1c5858, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, }, | ||
90 | { 0x1c585c, 0x31395c5e, 0x31395c5e, 0x31395c5e, 0x31395c5e, }, | ||
91 | { 0x1c5860, 0x0004dd10, 0x0004dd10, 0x0004dd20, 0x0004dd20, }, | ||
92 | { 0x1c5868, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190, }, | ||
93 | { 0x1c586c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, }, | ||
94 | { 0x1c5900, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
95 | { 0x1c5904, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
96 | { 0x1c5908, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
97 | { 0x1c590c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
98 | { 0x1c5914, 0x000007d0, 0x000007d0, 0x00000898, 0x00000898, }, | ||
99 | { 0x1c5918, 0x00000118, 0x00000230, 0x00000268, 0x00000134, }, | ||
100 | { 0x1c591c, 0x10000fff, 0x10000fff, 0x10000fff, 0x10000fff, }, | ||
101 | { 0x1c5920, 0x0510081c, 0x0510081c, 0x0510001c, 0x0510001c, }, | ||
102 | { 0x1c5924, 0xd0058a15, 0xd0058a15, 0xd0058a15, 0xd0058a15, }, | ||
103 | { 0x1c5928, 0x00000001, 0x00000001, 0x00000001, 0x00000001, }, | ||
104 | { 0x1c592c, 0x00000004, 0x00000004, 0x00000004, 0x00000004, }, | ||
105 | { 0x1c5934, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, | ||
106 | { 0x1c5938, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, | ||
107 | { 0x1c593c, 0x0000007f, 0x0000007f, 0x0000007f, 0x0000007f, }, | ||
108 | { 0x1c5944, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020, }, | ||
109 | { 0x1c5948, 0x9280b212, 0x9280b212, 0x9280b212, 0x9280b212, }, | ||
110 | { 0x1c594c, 0x00020028, 0x00020028, 0x00020028, 0x00020028, }, | ||
111 | { 0x1c5954, 0x5d50e188, 0x5d50e188, 0x5d50e188, 0x5d50e188, }, | ||
112 | { 0x1c5958, 0x00081fff, 0x00081fff, 0x00081fff, 0x00081fff, }, | ||
113 | { 0x1c5960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, }, | ||
114 | { 0x1c5964, 0x00001120, 0x00001120, 0x00001120, 0x00001120, }, | ||
115 | { 0x1c5970, 0x190fb515, 0x190fb515, 0x190fb515, 0x190fb515, }, | ||
116 | { 0x1c5974, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
117 | { 0x1c5978, 0x00000001, 0x00000001, 0x00000001, 0x00000001, }, | ||
118 | { 0x1c597c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
119 | { 0x1c5980, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
120 | { 0x1c5984, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
121 | { 0x1c5988, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
122 | { 0x1c598c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
123 | { 0x1c5990, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
124 | { 0x1c5994, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
125 | { 0x1c5998, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
126 | { 0x1c599c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
127 | { 0x1c59a0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
128 | { 0x1c59a4, 0x00000007, 0x00000007, 0x00000007, 0x00000007, }, | ||
129 | { 0x1c59a8, 0x001fff00, 0x001fff00, 0x001fff00, 0x001fff00, }, | ||
130 | { 0x1c59ac, 0x006f00c4, 0x006f00c4, 0x006f00c4, 0x006f00c4, }, | ||
131 | { 0x1c59b0, 0x03051000, 0x03051000, 0x03051000, 0x03051000, }, | ||
132 | { 0x1c59b4, 0x00000820, 0x00000820, 0x00000820, 0x00000820, }, | ||
133 | { 0x1c59c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, }, | ||
134 | { 0x1c59c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, }, | ||
135 | { 0x1c59c8, 0x60f6532c, 0x60f6532c, 0x60f6532c, 0x60f6532c, }, | ||
136 | { 0x1c59cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, }, | ||
137 | { 0x1c59d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, }, | ||
138 | { 0x1c59d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
139 | { 0x1c59d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
140 | { 0x1c59dc, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
141 | { 0x1c59e0, 0x00000200, 0x00000200, 0x00000200, 0x00000200, }, | ||
142 | { 0x1c59e4, 0x64646464, 0x64646464, 0x64646464, 0x64646464, }, | ||
143 | { 0x1c59e8, 0x3c787878, 0x3c787878, 0x3c787878, 0x3c787878, }, | ||
144 | { 0x1c59ec, 0x000000aa, 0x000000aa, 0x000000aa, 0x000000aa, }, | ||
145 | { 0x1c59f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
146 | { 0x1c59fc, 0x00001042, 0x00001042, 0x00001042, 0x00001042, }, | ||
147 | { 0x1c5a00, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
148 | { 0x1c5a04, 0x00000040, 0x00000040, 0x00000040, 0x00000040, }, | ||
149 | { 0x1c5a08, 0x00000080, 0x00000080, 0x00000080, 0x00000080, }, | ||
150 | { 0x1c5a0c, 0x000001a1, 0x000001a1, 0x00000141, 0x00000141, }, | ||
151 | { 0x1c5a10, 0x000001e1, 0x000001e1, 0x00000181, 0x00000181, }, | ||
152 | { 0x1c5a14, 0x00000021, 0x00000021, 0x000001c1, 0x000001c1, }, | ||
153 | { 0x1c5a18, 0x00000061, 0x00000061, 0x00000001, 0x00000001, }, | ||
154 | { 0x1c5a1c, 0x00000168, 0x00000168, 0x00000041, 0x00000041, }, | ||
155 | { 0x1c5a20, 0x000001a8, 0x000001a8, 0x000001a8, 0x000001a8, }, | ||
156 | { 0x1c5a24, 0x000001e8, 0x000001e8, 0x000001e8, 0x000001e8, }, | ||
157 | { 0x1c5a28, 0x00000028, 0x00000028, 0x00000028, 0x00000028, }, | ||
158 | { 0x1c5a2c, 0x00000068, 0x00000068, 0x00000068, 0x00000068, }, | ||
159 | { 0x1c5a30, 0x00000189, 0x00000189, 0x000000a8, 0x000000a8, }, | ||
160 | { 0x1c5a34, 0x000001c9, 0x000001c9, 0x00000169, 0x00000169, }, | ||
161 | { 0x1c5a38, 0x00000009, 0x00000009, 0x000001a9, 0x000001a9, }, | ||
162 | { 0x1c5a3c, 0x00000049, 0x00000049, 0x000001e9, 0x000001e9, }, | ||
163 | { 0x1c5a40, 0x00000089, 0x00000089, 0x00000029, 0x00000029, }, | ||
164 | { 0x1c5a44, 0x00000170, 0x00000170, 0x00000069, 0x00000069, }, | ||
165 | { 0x1c5a48, 0x000001b0, 0x000001b0, 0x00000190, 0x00000190, }, | ||
166 | { 0x1c5a4c, 0x000001f0, 0x000001f0, 0x000001d0, 0x000001d0, }, | ||
167 | { 0x1c5a50, 0x00000030, 0x00000030, 0x00000010, 0x00000010, }, | ||
168 | { 0x1c5a54, 0x00000070, 0x00000070, 0x00000050, 0x00000050, }, | ||
169 | { 0x1c5a58, 0x00000191, 0x00000191, 0x00000090, 0x00000090, }, | ||
170 | { 0x1c5a5c, 0x000001d1, 0x000001d1, 0x00000151, 0x00000151, }, | ||
171 | { 0x1c5a60, 0x00000011, 0x00000011, 0x00000191, 0x00000191, }, | ||
172 | { 0x1c5a64, 0x00000051, 0x00000051, 0x000001d1, 0x000001d1, }, | ||
173 | { 0x1c5a68, 0x00000091, 0x00000091, 0x00000011, 0x00000011, }, | ||
174 | { 0x1c5a6c, 0x000001b8, 0x000001b8, 0x00000051, 0x00000051, }, | ||
175 | { 0x1c5a70, 0x000001f8, 0x000001f8, 0x00000198, 0x00000198, }, | ||
176 | { 0x1c5a74, 0x00000038, 0x00000038, 0x000001d8, 0x000001d8, }, | ||
177 | { 0x1c5a78, 0x00000078, 0x00000078, 0x00000018, 0x00000018, }, | ||
178 | { 0x1c5a7c, 0x00000199, 0x00000199, 0x00000058, 0x00000058, }, | ||
179 | { 0x1c5a80, 0x000001d9, 0x000001d9, 0x00000098, 0x00000098, }, | ||
180 | { 0x1c5a84, 0x00000019, 0x00000019, 0x00000159, 0x00000159, }, | ||
181 | { 0x1c5a88, 0x00000059, 0x00000059, 0x00000199, 0x00000199, }, | ||
182 | { 0x1c5a8c, 0x00000099, 0x00000099, 0x000001d9, 0x000001d9, }, | ||
183 | { 0x1c5a90, 0x000000d9, 0x000000d9, 0x00000019, 0x00000019, }, | ||
184 | { 0x1c5a94, 0x000000f9, 0x000000f9, 0x00000059, 0x00000059, }, | ||
185 | { 0x1c5a98, 0x000000f9, 0x000000f9, 0x00000099, 0x00000099, }, | ||
186 | { 0x1c5a9c, 0x000000f9, 0x000000f9, 0x000000d9, 0x000000d9, }, | ||
187 | { 0x1c5aa0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, | ||
188 | { 0x1c5aa4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, | ||
189 | { 0x1c5aa8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, | ||
190 | { 0x1c5aac, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, | ||
191 | { 0x1c5ab0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, | ||
192 | { 0x1c5ab4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, | ||
193 | { 0x1c5ab8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, | ||
194 | { 0x1c5abc, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, | ||
195 | { 0x1c5ac0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, | ||
196 | { 0x1c5ac4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, | ||
197 | { 0x1c5ac8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, | ||
198 | { 0x1c5acc, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, | ||
199 | { 0x1c5ad0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, | ||
200 | { 0x1c5ad4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, | ||
201 | { 0x1c5ad8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, | ||
202 | { 0x1c5adc, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, | ||
203 | { 0x1c5ae0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, | ||
204 | { 0x1c5ae4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, | ||
205 | { 0x1c5ae8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, | ||
206 | { 0x1c5aec, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, | ||
207 | { 0x1c5af0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, | ||
208 | { 0x1c5af4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, | ||
209 | { 0x1c5af8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, | ||
210 | { 0x1c5afc, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, | ||
211 | { 0x1c5b00, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
212 | { 0x1c5b04, 0x00000001, 0x00000001, 0x00000001, 0x00000001, }, | ||
213 | { 0x1c5b08, 0x00000002, 0x00000002, 0x00000002, 0x00000002, }, | ||
214 | { 0x1c5b0c, 0x00000003, 0x00000003, 0x00000003, 0x00000003, }, | ||
215 | { 0x1c5b10, 0x00000004, 0x00000004, 0x00000004, 0x00000004, }, | ||
216 | { 0x1c5b14, 0x00000005, 0x00000005, 0x00000005, 0x00000005, }, | ||
217 | { 0x1c5b18, 0x00000008, 0x00000008, 0x00000008, 0x00000008, }, | ||
218 | { 0x1c5b1c, 0x00000009, 0x00000009, 0x00000009, 0x00000009, }, | ||
219 | { 0x1c5b20, 0x0000000a, 0x0000000a, 0x0000000a, 0x0000000a, }, | ||
220 | { 0x1c5b24, 0x0000000b, 0x0000000b, 0x0000000b, 0x0000000b, }, | ||
221 | { 0x1c5b28, 0x0000000c, 0x0000000c, 0x0000000c, 0x0000000c, }, | ||
222 | { 0x1c5b2c, 0x0000000d, 0x0000000d, 0x0000000d, 0x0000000d, }, | ||
223 | { 0x1c5b30, 0x00000010, 0x00000010, 0x00000010, 0x00000010, }, | ||
224 | { 0x1c5b34, 0x00000011, 0x00000011, 0x00000011, 0x00000011, }, | ||
225 | { 0x1c5b38, 0x00000012, 0x00000012, 0x00000012, 0x00000012, }, | ||
226 | { 0x1c5b3c, 0x00000013, 0x00000013, 0x00000013, 0x00000013, }, | ||
227 | { 0x1c5b40, 0x00000014, 0x00000014, 0x00000014, 0x00000014, }, | ||
228 | { 0x1c5b44, 0x00000015, 0x00000015, 0x00000015, 0x00000015, }, | ||
229 | { 0x1c5b48, 0x00000018, 0x00000018, 0x00000018, 0x00000018, }, | ||
230 | { 0x1c5b4c, 0x00000019, 0x00000019, 0x00000019, 0x00000019, }, | ||
231 | { 0x1c5b50, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a, }, | ||
232 | { 0x1c5b54, 0x0000001b, 0x0000001b, 0x0000001b, 0x0000001b, }, | ||
233 | { 0x1c5b58, 0x0000001c, 0x0000001c, 0x0000001c, 0x0000001c, }, | ||
234 | { 0x1c5b5c, 0x0000001d, 0x0000001d, 0x0000001d, 0x0000001d, }, | ||
235 | { 0x1c5b60, 0x00000020, 0x00000020, 0x00000020, 0x00000020, }, | ||
236 | { 0x1c5b64, 0x00000021, 0x00000021, 0x00000021, 0x00000021, }, | ||
237 | { 0x1c5b68, 0x00000022, 0x00000022, 0x00000022, 0x00000022, }, | ||
238 | { 0x1c5b6c, 0x00000023, 0x00000023, 0x00000023, 0x00000023, }, | ||
239 | { 0x1c5b70, 0x00000024, 0x00000024, 0x00000024, 0x00000024, }, | ||
240 | { 0x1c5b74, 0x00000025, 0x00000025, 0x00000025, 0x00000025, }, | ||
241 | { 0x1c5b78, 0x00000028, 0x00000028, 0x00000028, 0x00000028, }, | ||
242 | { 0x1c5b7c, 0x00000029, 0x00000029, 0x00000029, 0x00000029, }, | ||
243 | { 0x1c5b80, 0x0000002a, 0x0000002a, 0x0000002a, 0x0000002a, }, | ||
244 | { 0x1c5b84, 0x0000002b, 0x0000002b, 0x0000002b, 0x0000002b, }, | ||
245 | { 0x1c5b88, 0x0000002c, 0x0000002c, 0x0000002c, 0x0000002c, }, | ||
246 | { 0x1c5b8c, 0x0000002d, 0x0000002d, 0x0000002d, 0x0000002d, }, | ||
247 | { 0x1c5b90, 0x00000030, 0x00000030, 0x00000030, 0x00000030, }, | ||
248 | { 0x1c5b94, 0x00000031, 0x00000031, 0x00000031, 0x00000031, }, | ||
249 | { 0x1c5b98, 0x00000032, 0x00000032, 0x00000032, 0x00000032, }, | ||
250 | { 0x1c5b9c, 0x00000033, 0x00000033, 0x00000033, 0x00000033, }, | ||
251 | { 0x1c5ba0, 0x00000034, 0x00000034, 0x00000034, 0x00000034, }, | ||
252 | { 0x1c5ba4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, | ||
253 | { 0x1c5ba8, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, | ||
254 | { 0x1c5bac, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, | ||
255 | { 0x1c5bb0, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, | ||
256 | { 0x1c5bb4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, | ||
257 | { 0x1c5bb8, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, | ||
258 | { 0x1c5bbc, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, | ||
259 | { 0x1c5bc0, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, | ||
260 | { 0x1c5bc4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, | ||
261 | { 0x1c5bc8, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, | ||
262 | { 0x1c5bcc, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, | ||
263 | { 0x1c5bd0, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, | ||
264 | { 0x1c5bd4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, | ||
265 | { 0x1c5bd8, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, | ||
266 | { 0x1c5bdc, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, | ||
267 | { 0x1c5be0, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, | ||
268 | { 0x1c5be4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, | ||
269 | { 0x1c5be8, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, | ||
270 | { 0x1c5bec, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, | ||
271 | { 0x1c5bf0, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, | ||
272 | { 0x1c5bf4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, | ||
273 | { 0x1c5bf8, 0x00000010, 0x00000010, 0x00000010, 0x00000010, }, | ||
274 | { 0x1c5bfc, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a, }, | ||
275 | { 0x1c5c00, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
276 | { 0x1c5c0c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
277 | { 0x1c5c10, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
278 | { 0x1c5c14, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
279 | { 0x1c5c18, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
280 | { 0x1c5c1c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
281 | { 0x1c5c20, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
282 | { 0x1c5c24, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
283 | { 0x1c5c28, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
284 | { 0x1c5c2c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
285 | { 0x1c5c30, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
286 | { 0x1c5c34, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
287 | { 0x1c5c38, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
288 | { 0x1c5c3c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
289 | { 0x1c5cf0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
290 | { 0x1c5cf4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
291 | { 0x1c5cf8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
292 | { 0x1c5cfc, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
293 | { 0x1c6200, 0x00000008, 0x00000008, 0x0000000e, 0x0000000e, }, | ||
294 | { 0x1c6204, 0x00000440, 0x00000440, 0x00000440, 0x00000440, }, | ||
295 | { 0x1c6208, 0xd6be4788, 0xd6be4788, 0xd03e4788, 0xd03e4788, }, | ||
296 | { 0x1c620c, 0x012e8160, 0x012e8160, 0x012a8160, 0x012a8160, }, | ||
297 | { 0x1c6210, 0x40806333, 0x40806333, 0x40806333, 0x40806333, }, | ||
298 | { 0x1c6214, 0x00106c10, 0x00106c10, 0x00106c10, 0x00106c10, }, | ||
299 | { 0x1c6218, 0x009c4060, 0x009c4060, 0x009c4060, 0x009c4060, }, | ||
300 | { 0x1c621c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, }, | ||
301 | { 0x1c6220, 0x018830c6, 0x018830c6, 0x018830c6, 0x018830c6, }, | ||
302 | { 0x1c6224, 0x00000400, 0x00000400, 0x00000400, 0x00000400, }, | ||
303 | { 0x1c6228, 0x000009b5, 0x000009b5, 0x000009b5, 0x000009b5, }, | ||
304 | { 0x1c622c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
305 | { 0x1c6230, 0x00000108, 0x00000210, 0x00000210, 0x00000108, }, | ||
306 | { 0x1c6234, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, | ||
307 | { 0x1c6238, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, | ||
308 | { 0x1c623c, 0x13c889af, 0x13c889af, 0x13c889af, 0x13c889af, }, | ||
309 | { 0x1c6240, 0x38490a20, 0x38490a20, 0x38490a20, 0x38490a20, }, | ||
310 | { 0x1c6244, 0x00007bb6, 0x00007bb6, 0x00007bb6, 0x00007bb6, }, | ||
311 | { 0x1c6248, 0x0fff3ffc, 0x0fff3ffc, 0x0fff3ffc, 0x0fff3ffc, }, | ||
312 | { 0x1c624c, 0x00000001, 0x00000001, 0x00000001, 0x00000001, }, | ||
313 | { 0x1c6250, 0x0000a000, 0x0000a000, 0x0000a000, 0x0000a000, }, | ||
314 | { 0x1c6254, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
315 | { 0x1c6258, 0x0cc75380, 0x0cc75380, 0x0cc75380, 0x0cc75380, }, | ||
316 | { 0x1c625c, 0x0f0f0f01, 0x0f0f0f01, 0x0f0f0f01, 0x0f0f0f01, }, | ||
317 | { 0x1c6260, 0xdfa91f01, 0xdfa91f01, 0xdfa91f01, 0xdfa91f01, }, | ||
318 | { 0x1c6264, 0x00418a11, 0x00418a11, 0x00418a11, 0x00418a11, }, | ||
319 | { 0x1c6268, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
320 | { 0x1c626c, 0x09249126, 0x09249126, 0x09249126, 0x09249126, }, | ||
321 | { 0x1c6274, 0x0a1a9caa, 0x0a1a9caa, 0x0a1a7caa, 0x0a1a7caa, }, | ||
322 | { 0x1c6278, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, }, | ||
323 | { 0x1c627c, 0x051701ce, 0x051701ce, 0x051701ce, 0x051701ce, }, | ||
324 | { 0x1c6300, 0x18010000, 0x18010000, 0x18010000, 0x18010000, }, | ||
325 | { 0x1c6304, 0x30032602, 0x30032602, 0x2e032402, 0x2e032402, }, | ||
326 | { 0x1c6308, 0x48073e06, 0x48073e06, 0x4a0a3c06, 0x4a0a3c06, }, | ||
327 | { 0x1c630c, 0x560b4c0a, 0x560b4c0a, 0x621a540b, 0x621a540b, }, | ||
328 | { 0x1c6310, 0x641a600f, 0x641a600f, 0x764f6c1b, 0x764f6c1b, }, | ||
329 | { 0x1c6314, 0x7a4f6e1b, 0x7a4f6e1b, 0x845b7a5a, 0x845b7a5a, }, | ||
330 | { 0x1c6318, 0x8c5b7e5a, 0x8c5b7e5a, 0x950f8ccf, 0x950f8ccf, }, | ||
331 | { 0x1c631c, 0x9d0f96cf, 0x9d0f96cf, 0xa5cf9b4f, 0xa5cf9b4f, }, | ||
332 | { 0x1c6320, 0xb51fa69f, 0xb51fa69f, 0xbddfaf1f, 0xbddfaf1f, }, | ||
333 | { 0x1c6324, 0xcb3fbd07, 0xcb3fbcbf, 0xd1ffc93f, 0xd1ffc93f, }, | ||
334 | { 0x1c6328, 0x0000d7bf, 0x0000d7bf, 0x00000000, 0x00000000, }, | ||
335 | { 0x1c632c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
336 | { 0x1c6330, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
337 | { 0x1c6334, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
338 | { 0x1c6338, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
339 | { 0x1c633c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
340 | { 0x1c6340, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
341 | { 0x1c6344, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
342 | { 0x1c6348, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, }, | ||
343 | { 0x1c634c, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, }, | ||
344 | { 0x1c6350, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, }, | ||
345 | { 0x1c6354, 0x0003ffff, 0x0003ffff, 0x0003ffff, 0x0003ffff, }, | ||
346 | { 0x1c6358, 0x79a8aa1f, 0x79a8aa1f, 0x79a8aa1f, 0x79a8aa1f, }, | ||
347 | { 0x1c6388, 0x08000000, 0x08000000, 0x08000000, 0x08000000, }, | ||
348 | { 0x1c638c, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, | ||
349 | { 0x1c6390, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, | ||
350 | { 0x1c6394, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, }, | ||
351 | { 0x1c6398, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce, }, | ||
352 | { 0x1c639c, 0x00000007, 0x00000007, 0x00000007, 0x00000007, }, | ||
353 | { 0x1c63a0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
354 | { 0x1c63a4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
355 | { 0x1c63a8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
356 | { 0x1c63ac, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
357 | { 0x1c63b0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
358 | { 0x1c63b4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
359 | { 0x1c63b8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
360 | { 0x1c63bc, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
361 | { 0x1c63c0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
362 | { 0x1c63c4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
363 | { 0x1c63c8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
364 | { 0x1c63cc, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, | ||
365 | { 0x1c63d0, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, | ||
366 | { 0x1c63d4, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, | ||
367 | { 0x1c63d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
368 | { 0x1c63dc, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, }, | ||
369 | { 0x1c63e0, 0x000000c0, 0x000000c0, 0x000000c0, 0x000000c0, }, | ||
370 | { 0x1c6848, 0x00180a65, 0x00180a65, 0x00180a68, 0x00180a68, }, | ||
371 | { 0x1c6920, 0x0510001c, 0x0510001c, 0x0510001c, 0x0510001c, }, | ||
372 | { 0x1c6960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, }, | ||
373 | { 0x1c720c, 0x012e8160, 0x012e8160, 0x012a8160, 0x012a8160, }, | ||
374 | { 0x1c726c, 0x09249126, 0x09249126, 0x09249126, 0x09249126, }, | ||
375 | { 0x1c7848, 0x00180a65, 0x00180a65, 0x00180a68, 0x00180a68, }, | ||
376 | { 0x1c7920, 0x0510001c, 0x0510001c, 0x0510001c, 0x0510001c, }, | ||
377 | { 0x1c7960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, }, | ||
378 | { 0x1c820c, 0x012e8160, 0x012e8160, 0x012a8160, 0x012a8160, }, | ||
379 | { 0x1c826c, 0x09249126, 0x09249126, 0x09249126, 0x09249126, }, | ||
380 | /* { 0x1c8864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, }, */ | ||
381 | { 0x1c8864, 0x0001c600, 0x0001c600, 0x0001c600, 0x0001c600, }, | ||
382 | { 0x1c895c, 0x004b6a8e, 0x004b6a8e, 0x004b6a8e, 0x004b6a8e, }, | ||
383 | { 0x1c8968, 0x000003ce, 0x000003ce, 0x000003ce, 0x000003ce, }, | ||
384 | { 0x1c89bc, 0x00181400, 0x00181400, 0x00181400, 0x00181400, }, | ||
385 | { 0x1c9270, 0x00820820, 0x00820820, 0x00820820, 0x00820820, }, | ||
386 | { 0x1c935c, 0x066c420f, 0x066c420f, 0x066c420f, 0x066c420f, }, | ||
387 | { 0x1c9360, 0x0f282207, 0x0f282207, 0x0f282207, 0x0f282207, }, | ||
388 | { 0x1c9364, 0x17601685, 0x17601685, 0x17601685, 0x17601685, }, | ||
389 | { 0x1c9368, 0x1f801104, 0x1f801104, 0x1f801104, 0x1f801104, }, | ||
390 | { 0x1c936c, 0x37a00c03, 0x37a00c03, 0x37a00c03, 0x37a00c03, }, | ||
391 | { 0x1c9370, 0x3fc40883, 0x3fc40883, 0x3fc40883, 0x3fc40883, }, | ||
392 | { 0x1c9374, 0x57c00803, 0x57c00803, 0x57c00803, 0x57c00803, }, | ||
393 | { 0x1c9378, 0x5fd80682, 0x5fd80682, 0x5fd80682, 0x5fd80682, }, | ||
394 | { 0x1c937c, 0x7fe00482, 0x7fe00482, 0x7fe00482, 0x7fe00482, }, | ||
395 | { 0x1c9380, 0x7f3c7bba, 0x7f3c7bba, 0x7f3c7bba, 0x7f3c7bba, }, | ||
396 | { 0x1c9384, 0xf3307ff0, 0xf3307ff0, 0xf3307ff0, 0xf3307ff0, } | ||
397 | }; | ||
398 | |||
399 | /* | ||
400 | * look up a certain register in ar5416_phy_init[] and return the init. value | ||
401 | * for the band and bandwidth given. Return 0 if register address not found. | ||
402 | */ | ||
403 | static u32 ar9170_get_default_phy_reg_val(u32 reg, bool is_2ghz, bool is_40mhz) | ||
404 | { | ||
405 | unsigned int i; | ||
406 | for (i = 0; i < ARRAY_SIZE(ar5416_phy_init); i++) { | ||
407 | if (ar5416_phy_init[i].reg != reg) | ||
408 | continue; | ||
409 | |||
410 | if (is_2ghz) { | ||
411 | if (is_40mhz) | ||
412 | return ar5416_phy_init[i]._2ghz_40; | ||
413 | else | ||
414 | return ar5416_phy_init[i]._2ghz_20; | ||
415 | } else { | ||
416 | if (is_40mhz) | ||
417 | return ar5416_phy_init[i]._5ghz_40; | ||
418 | else | ||
419 | return ar5416_phy_init[i]._5ghz_20; | ||
420 | } | ||
421 | } | ||
422 | return 0; | ||
423 | } | ||
424 | |||
425 | /* | ||
426 | * initialize some phy regs from eeprom values in modal_header[] | ||
427 | * acc. to band and bandwidth | ||
428 | */ | ||
429 | static int ar9170_init_phy_from_eeprom(struct ar9170 *ar, | ||
430 | bool is_2ghz, bool is_40mhz) | ||
431 | { | ||
432 | static const u8 xpd2pd[16] = { | ||
433 | 0x2, 0x2, 0x2, 0x1, 0x2, 0x2, 0x6, 0x2, | ||
434 | 0x2, 0x3, 0x7, 0x2, 0xB, 0x2, 0x2, 0x2 | ||
435 | }; | ||
436 | u32 defval, newval; | ||
437 | /* pointer to the modal_header acc. to band */ | ||
438 | struct ar9170_eeprom_modal *m = &ar->eeprom.modal_header[is_2ghz]; | ||
439 | |||
440 | ar9170_regwrite_begin(ar); | ||
441 | |||
442 | /* ant common control (index 0) */ | ||
443 | newval = le32_to_cpu(m->antCtrlCommon); | ||
444 | ar9170_regwrite(0x1c5964, newval); | ||
445 | |||
446 | /* ant control chain 0 (index 1) */ | ||
447 | newval = le32_to_cpu(m->antCtrlChain[0]); | ||
448 | ar9170_regwrite(0x1c5960, newval); | ||
449 | |||
450 | /* ant control chain 2 (index 2) */ | ||
451 | newval = le32_to_cpu(m->antCtrlChain[1]); | ||
452 | ar9170_regwrite(0x1c7960, newval); | ||
453 | |||
454 | /* SwSettle (index 3) */ | ||
455 | if (!is_40mhz) { | ||
456 | defval = ar9170_get_default_phy_reg_val(0x1c5844, | ||
457 | is_2ghz, is_40mhz); | ||
458 | newval = (defval & ~0x3f80) | | ||
459 | ((m->switchSettling & 0x7f) << 7); | ||
460 | ar9170_regwrite(0x1c5844, newval); | ||
461 | } | ||
462 | |||
463 | /* adcDesired, pdaDesired (index 4) */ | ||
464 | defval = ar9170_get_default_phy_reg_val(0x1c5850, is_2ghz, is_40mhz); | ||
465 | newval = (defval & ~0xffff) | ((u8)m->pgaDesiredSize << 8) | | ||
466 | ((u8)m->adcDesiredSize); | ||
467 | ar9170_regwrite(0x1c5850, newval); | ||
468 | |||
469 | /* TxEndToXpaOff, TxFrameToXpaOn (index 5) */ | ||
470 | defval = ar9170_get_default_phy_reg_val(0x1c5834, is_2ghz, is_40mhz); | ||
471 | newval = (m->txEndToXpaOff << 24) | (m->txEndToXpaOff << 16) | | ||
472 | (m->txFrameToXpaOn << 8) | m->txFrameToXpaOn; | ||
473 | ar9170_regwrite(0x1c5834, newval); | ||
474 | |||
475 | /* TxEndToRxOn (index 6) */ | ||
476 | defval = ar9170_get_default_phy_reg_val(0x1c5828, is_2ghz, is_40mhz); | ||
477 | newval = (defval & ~0xff0000) | (m->txEndToRxOn << 16); | ||
478 | ar9170_regwrite(0x1c5828, newval); | ||
479 | |||
480 | /* thresh62 (index 7) */ | ||
481 | defval = ar9170_get_default_phy_reg_val(0x1c8864, is_2ghz, is_40mhz); | ||
482 | newval = (defval & ~0x7f000) | (m->thresh62 << 12); | ||
483 | ar9170_regwrite(0x1c8864, newval); | ||
484 | |||
485 | /* tx/rx attenuation chain 0 (index 8) */ | ||
486 | defval = ar9170_get_default_phy_reg_val(0x1c5848, is_2ghz, is_40mhz); | ||
487 | newval = (defval & ~0x3f000) | ((m->txRxAttenCh[0] & 0x3f) << 12); | ||
488 | ar9170_regwrite(0x1c5848, newval); | ||
489 | |||
490 | /* tx/rx attenuation chain 2 (index 9) */ | ||
491 | defval = ar9170_get_default_phy_reg_val(0x1c7848, is_2ghz, is_40mhz); | ||
492 | newval = (defval & ~0x3f000) | ((m->txRxAttenCh[1] & 0x3f) << 12); | ||
493 | ar9170_regwrite(0x1c7848, newval); | ||
494 | |||
495 | /* tx/rx margin chain 0 (index 10) */ | ||
496 | defval = ar9170_get_default_phy_reg_val(0x1c620c, is_2ghz, is_40mhz); | ||
497 | newval = (defval & ~0xfc0000) | ((m->rxTxMarginCh[0] & 0x3f) << 18); | ||
498 | /* bsw margin chain 0 for 5GHz only */ | ||
499 | if (!is_2ghz) | ||
500 | newval = (newval & ~0x3c00) | ((m->bswMargin[0] & 0xf) << 10); | ||
501 | ar9170_regwrite(0x1c620c, newval); | ||
502 | |||
503 | /* tx/rx margin chain 2 (index 11) */ | ||
504 | defval = ar9170_get_default_phy_reg_val(0x1c820c, is_2ghz, is_40mhz); | ||
505 | newval = (defval & ~0xfc0000) | ((m->rxTxMarginCh[1] & 0x3f) << 18); | ||
506 | ar9170_regwrite(0x1c820c, newval); | ||
507 | |||
508 | /* iqCall, iqCallq chain 0 (index 12) */ | ||
509 | defval = ar9170_get_default_phy_reg_val(0x1c5920, is_2ghz, is_40mhz); | ||
510 | newval = (defval & ~0x7ff) | (((u8)m->iqCalICh[0] & 0x3f) << 5) | | ||
511 | ((u8)m->iqCalQCh[0] & 0x1f); | ||
512 | ar9170_regwrite(0x1c5920, newval); | ||
513 | |||
514 | /* iqCall, iqCallq chain 2 (index 13) */ | ||
515 | defval = ar9170_get_default_phy_reg_val(0x1c7920, is_2ghz, is_40mhz); | ||
516 | newval = (defval & ~0x7ff) | (((u8)m->iqCalICh[1] & 0x3f) << 5) | | ||
517 | ((u8)m->iqCalQCh[1] & 0x1f); | ||
518 | ar9170_regwrite(0x1c7920, newval); | ||
519 | |||
520 | /* xpd gain mask (index 14) */ | ||
521 | defval = ar9170_get_default_phy_reg_val(0x1c6258, is_2ghz, is_40mhz); | ||
522 | newval = (defval & ~0xf0000) | (xpd2pd[m->xpdGain & 0xf] << 16); | ||
523 | ar9170_regwrite(0x1c6258, newval); | ||
524 | ar9170_regwrite_finish(); | ||
525 | |||
526 | return ar9170_regwrite_result(); | ||
527 | } | ||
528 | |||
529 | int ar9170_init_phy(struct ar9170 *ar, enum ieee80211_band band) | ||
530 | { | ||
531 | int i, err; | ||
532 | u32 val; | ||
533 | bool is_2ghz = band == IEEE80211_BAND_2GHZ; | ||
534 | bool is_40mhz = conf_is_ht40(&ar->hw->conf); | ||
535 | |||
536 | ar9170_regwrite_begin(ar); | ||
537 | |||
538 | for (i = 0; i < ARRAY_SIZE(ar5416_phy_init); i++) { | ||
539 | if (is_40mhz) { | ||
540 | if (is_2ghz) | ||
541 | val = ar5416_phy_init[i]._2ghz_40; | ||
542 | else | ||
543 | val = ar5416_phy_init[i]._5ghz_40; | ||
544 | } else { | ||
545 | if (is_2ghz) | ||
546 | val = ar5416_phy_init[i]._2ghz_20; | ||
547 | else | ||
548 | val = ar5416_phy_init[i]._5ghz_20; | ||
549 | } | ||
550 | |||
551 | ar9170_regwrite(ar5416_phy_init[i].reg, val); | ||
552 | } | ||
553 | |||
554 | ar9170_regwrite_finish(); | ||
555 | err = ar9170_regwrite_result(); | ||
556 | if (err) | ||
557 | return err; | ||
558 | |||
559 | err = ar9170_init_phy_from_eeprom(ar, is_2ghz, is_40mhz); | ||
560 | if (err) | ||
561 | return err; | ||
562 | |||
563 | err = ar9170_init_power_cal(ar); | ||
564 | if (err) | ||
565 | return err; | ||
566 | |||
567 | /* XXX: remove magic! */ | ||
568 | if (is_2ghz) | ||
569 | err = ar9170_write_reg(ar, 0x1d4014, 0x5163); | ||
570 | else | ||
571 | err = ar9170_write_reg(ar, 0x1d4014, 0x5143); | ||
572 | |||
573 | return err; | ||
574 | } | ||
575 | |||
576 | struct ar9170_rf_init { | ||
577 | u32 reg, _5ghz, _2ghz; | ||
578 | }; | ||
579 | |||
580 | static struct ar9170_rf_init ar9170_rf_init[] = { | ||
581 | /* bank 0 */ | ||
582 | { 0x1c58b0, 0x1e5795e5, 0x1e5795e5}, | ||
583 | { 0x1c58e0, 0x02008020, 0x02008020}, | ||
584 | /* bank 1 */ | ||
585 | { 0x1c58b0, 0x02108421, 0x02108421}, | ||
586 | { 0x1c58ec, 0x00000008, 0x00000008}, | ||
587 | /* bank 2 */ | ||
588 | { 0x1c58b0, 0x0e73ff17, 0x0e73ff17}, | ||
589 | { 0x1c58e0, 0x00000420, 0x00000420}, | ||
590 | /* bank 3 */ | ||
591 | { 0x1c58f0, 0x01400018, 0x01c00018}, | ||
592 | /* bank 4 */ | ||
593 | { 0x1c58b0, 0x000001a1, 0x000001a1}, | ||
594 | { 0x1c58e8, 0x00000001, 0x00000001}, | ||
595 | /* bank 5 */ | ||
596 | { 0x1c58b0, 0x00000013, 0x00000013}, | ||
597 | { 0x1c58e4, 0x00000002, 0x00000002}, | ||
598 | /* bank 6 */ | ||
599 | { 0x1c58b0, 0x00000000, 0x00000000}, | ||
600 | { 0x1c58b0, 0x00000000, 0x00000000}, | ||
601 | { 0x1c58b0, 0x00000000, 0x00000000}, | ||
602 | { 0x1c58b0, 0x00000000, 0x00000000}, | ||
603 | { 0x1c58b0, 0x00000000, 0x00000000}, | ||
604 | { 0x1c58b0, 0x00004000, 0x00004000}, | ||
605 | { 0x1c58b0, 0x00006c00, 0x00006c00}, | ||
606 | { 0x1c58b0, 0x00002c00, 0x00002c00}, | ||
607 | { 0x1c58b0, 0x00004800, 0x00004800}, | ||
608 | { 0x1c58b0, 0x00004000, 0x00004000}, | ||
609 | { 0x1c58b0, 0x00006000, 0x00006000}, | ||
610 | { 0x1c58b0, 0x00001000, 0x00001000}, | ||
611 | { 0x1c58b0, 0x00004000, 0x00004000}, | ||
612 | { 0x1c58b0, 0x00007c00, 0x00007c00}, | ||
613 | { 0x1c58b0, 0x00007c00, 0x00007c00}, | ||
614 | { 0x1c58b0, 0x00007c00, 0x00007c00}, | ||
615 | { 0x1c58b0, 0x00007c00, 0x00007c00}, | ||
616 | { 0x1c58b0, 0x00007c00, 0x00007c00}, | ||
617 | { 0x1c58b0, 0x00087c00, 0x00087c00}, | ||
618 | { 0x1c58b0, 0x00007c00, 0x00007c00}, | ||
619 | { 0x1c58b0, 0x00005400, 0x00005400}, | ||
620 | { 0x1c58b0, 0x00000c00, 0x00000c00}, | ||
621 | { 0x1c58b0, 0x00001800, 0x00001800}, | ||
622 | { 0x1c58b0, 0x00007c00, 0x00007c00}, | ||
623 | { 0x1c58b0, 0x00006c00, 0x00006c00}, | ||
624 | { 0x1c58b0, 0x00006c00, 0x00006c00}, | ||
625 | { 0x1c58b0, 0x00007c00, 0x00007c00}, | ||
626 | { 0x1c58b0, 0x00002c00, 0x00002c00}, | ||
627 | { 0x1c58b0, 0x00003c00, 0x00003c00}, | ||
628 | { 0x1c58b0, 0x00003800, 0x00003800}, | ||
629 | { 0x1c58b0, 0x00001c00, 0x00001c00}, | ||
630 | { 0x1c58b0, 0x00000800, 0x00000800}, | ||
631 | { 0x1c58b0, 0x00000408, 0x00000408}, | ||
632 | { 0x1c58b0, 0x00004c15, 0x00004c15}, | ||
633 | { 0x1c58b0, 0x00004188, 0x00004188}, | ||
634 | { 0x1c58b0, 0x0000201e, 0x0000201e}, | ||
635 | { 0x1c58b0, 0x00010408, 0x00010408}, | ||
636 | { 0x1c58b0, 0x00000801, 0x00000801}, | ||
637 | { 0x1c58b0, 0x00000c08, 0x00000c08}, | ||
638 | { 0x1c58b0, 0x0000181e, 0x0000181e}, | ||
639 | { 0x1c58b0, 0x00001016, 0x00001016}, | ||
640 | { 0x1c58b0, 0x00002800, 0x00002800}, | ||
641 | { 0x1c58b0, 0x00004010, 0x00004010}, | ||
642 | { 0x1c58b0, 0x0000081c, 0x0000081c}, | ||
643 | { 0x1c58b0, 0x00000115, 0x00000115}, | ||
644 | { 0x1c58b0, 0x00000015, 0x00000015}, | ||
645 | { 0x1c58b0, 0x00000066, 0x00000066}, | ||
646 | { 0x1c58b0, 0x0000001c, 0x0000001c}, | ||
647 | { 0x1c58b0, 0x00000000, 0x00000000}, | ||
648 | { 0x1c58b0, 0x00000004, 0x00000004}, | ||
649 | { 0x1c58b0, 0x00000015, 0x00000015}, | ||
650 | { 0x1c58b0, 0x0000001f, 0x0000001f}, | ||
651 | { 0x1c58e0, 0x00000000, 0x00000400}, | ||
652 | /* bank 7 */ | ||
653 | { 0x1c58b0, 0x000000a0, 0x000000a0}, | ||
654 | { 0x1c58b0, 0x00000000, 0x00000000}, | ||
655 | { 0x1c58b0, 0x00000040, 0x00000040}, | ||
656 | { 0x1c58f0, 0x0000001c, 0x0000001c}, | ||
657 | }; | ||
658 | |||
659 | static int ar9170_init_rf_banks_0_7(struct ar9170 *ar, bool band5ghz) | ||
660 | { | ||
661 | int err, i; | ||
662 | |||
663 | ar9170_regwrite_begin(ar); | ||
664 | |||
665 | for (i = 0; i < ARRAY_SIZE(ar9170_rf_init); i++) | ||
666 | ar9170_regwrite(ar9170_rf_init[i].reg, | ||
667 | band5ghz ? ar9170_rf_init[i]._5ghz | ||
668 | : ar9170_rf_init[i]._2ghz); | ||
669 | |||
670 | ar9170_regwrite_finish(); | ||
671 | err = ar9170_regwrite_result(); | ||
672 | if (err) | ||
673 | wiphy_err(ar->hw->wiphy, "rf init failed\n"); | ||
674 | return err; | ||
675 | } | ||
676 | |||
677 | static int ar9170_init_rf_bank4_pwr(struct ar9170 *ar, bool band5ghz, | ||
678 | u32 freq, enum ar9170_bw bw) | ||
679 | { | ||
680 | int err; | ||
681 | u32 d0, d1, td0, td1, fd0, fd1; | ||
682 | u8 chansel; | ||
683 | u8 refsel0 = 1, refsel1 = 0; | ||
684 | u8 lf_synth = 0; | ||
685 | |||
686 | switch (bw) { | ||
687 | case AR9170_BW_40_ABOVE: | ||
688 | freq += 10; | ||
689 | break; | ||
690 | case AR9170_BW_40_BELOW: | ||
691 | freq -= 10; | ||
692 | break; | ||
693 | case AR9170_BW_20: | ||
694 | break; | ||
695 | case __AR9170_NUM_BW: | ||
696 | BUG(); | ||
697 | } | ||
698 | |||
699 | if (band5ghz) { | ||
700 | if (freq % 10) { | ||
701 | chansel = (freq - 4800) / 5; | ||
702 | } else { | ||
703 | chansel = ((freq - 4800) / 10) * 2; | ||
704 | refsel0 = 0; | ||
705 | refsel1 = 1; | ||
706 | } | ||
707 | chansel = byte_rev_table[chansel]; | ||
708 | } else { | ||
709 | if (freq == 2484) { | ||
710 | chansel = 10 + (freq - 2274) / 5; | ||
711 | lf_synth = 1; | ||
712 | } else | ||
713 | chansel = 16 + (freq - 2272) / 5; | ||
714 | chansel *= 4; | ||
715 | chansel = byte_rev_table[chansel]; | ||
716 | } | ||
717 | |||
718 | d1 = chansel; | ||
719 | d0 = 0x21 | | ||
720 | refsel0 << 3 | | ||
721 | refsel1 << 2 | | ||
722 | lf_synth << 1; | ||
723 | td0 = d0 & 0x1f; | ||
724 | td1 = d1 & 0x1f; | ||
725 | fd0 = td1 << 5 | td0; | ||
726 | |||
727 | td0 = (d0 >> 5) & 0x7; | ||
728 | td1 = (d1 >> 5) & 0x7; | ||
729 | fd1 = td1 << 5 | td0; | ||
730 | |||
731 | ar9170_regwrite_begin(ar); | ||
732 | |||
733 | ar9170_regwrite(0x1c58b0, fd0); | ||
734 | ar9170_regwrite(0x1c58e8, fd1); | ||
735 | |||
736 | ar9170_regwrite_finish(); | ||
737 | err = ar9170_regwrite_result(); | ||
738 | if (err) | ||
739 | return err; | ||
740 | |||
741 | msleep(10); | ||
742 | |||
743 | return 0; | ||
744 | } | ||
745 | |||
746 | struct ar9170_phy_freq_params { | ||
747 | u8 coeff_exp; | ||
748 | u16 coeff_man; | ||
749 | u8 coeff_exp_shgi; | ||
750 | u16 coeff_man_shgi; | ||
751 | }; | ||
752 | |||
753 | struct ar9170_phy_freq_entry { | ||
754 | u16 freq; | ||
755 | struct ar9170_phy_freq_params params[__AR9170_NUM_BW]; | ||
756 | }; | ||
757 | |||
758 | /* NB: must be in sync with channel tables in main! */ | ||
759 | static const struct ar9170_phy_freq_entry ar9170_phy_freq_params[] = { | ||
760 | /* | ||
761 | * freq, | ||
762 | * 20MHz, | ||
763 | * 40MHz (below), | ||
764 | * 40Mhz (above), | ||
765 | */ | ||
766 | { 2412, { | ||
767 | { 3, 21737, 3, 19563, }, | ||
768 | { 3, 21827, 3, 19644, }, | ||
769 | { 3, 21647, 3, 19482, }, | ||
770 | } }, | ||
771 | { 2417, { | ||
772 | { 3, 21692, 3, 19523, }, | ||
773 | { 3, 21782, 3, 19604, }, | ||
774 | { 3, 21602, 3, 19442, }, | ||
775 | } }, | ||
776 | { 2422, { | ||
777 | { 3, 21647, 3, 19482, }, | ||
778 | { 3, 21737, 3, 19563, }, | ||
779 | { 3, 21558, 3, 19402, }, | ||
780 | } }, | ||
781 | { 2427, { | ||
782 | { 3, 21602, 3, 19442, }, | ||
783 | { 3, 21692, 3, 19523, }, | ||
784 | { 3, 21514, 3, 19362, }, | ||
785 | } }, | ||
786 | { 2432, { | ||
787 | { 3, 21558, 3, 19402, }, | ||
788 | { 3, 21647, 3, 19482, }, | ||
789 | { 3, 21470, 3, 19323, }, | ||
790 | } }, | ||
791 | { 2437, { | ||
792 | { 3, 21514, 3, 19362, }, | ||
793 | { 3, 21602, 3, 19442, }, | ||
794 | { 3, 21426, 3, 19283, }, | ||
795 | } }, | ||
796 | { 2442, { | ||
797 | { 3, 21470, 3, 19323, }, | ||
798 | { 3, 21558, 3, 19402, }, | ||
799 | { 3, 21382, 3, 19244, }, | ||
800 | } }, | ||
801 | { 2447, { | ||
802 | { 3, 21426, 3, 19283, }, | ||
803 | { 3, 21514, 3, 19362, }, | ||
804 | { 3, 21339, 3, 19205, }, | ||
805 | } }, | ||
806 | { 2452, { | ||
807 | { 3, 21382, 3, 19244, }, | ||
808 | { 3, 21470, 3, 19323, }, | ||
809 | { 3, 21295, 3, 19166, }, | ||
810 | } }, | ||
811 | { 2457, { | ||
812 | { 3, 21339, 3, 19205, }, | ||
813 | { 3, 21426, 3, 19283, }, | ||
814 | { 3, 21252, 3, 19127, }, | ||
815 | } }, | ||
816 | { 2462, { | ||
817 | { 3, 21295, 3, 19166, }, | ||
818 | { 3, 21382, 3, 19244, }, | ||
819 | { 3, 21209, 3, 19088, }, | ||
820 | } }, | ||
821 | { 2467, { | ||
822 | { 3, 21252, 3, 19127, }, | ||
823 | { 3, 21339, 3, 19205, }, | ||
824 | { 3, 21166, 3, 19050, }, | ||
825 | } }, | ||
826 | { 2472, { | ||
827 | { 3, 21209, 3, 19088, }, | ||
828 | { 3, 21295, 3, 19166, }, | ||
829 | { 3, 21124, 3, 19011, }, | ||
830 | } }, | ||
831 | { 2484, { | ||
832 | { 3, 21107, 3, 18996, }, | ||
833 | { 3, 21192, 3, 19073, }, | ||
834 | { 3, 21022, 3, 18920, }, | ||
835 | } }, | ||
836 | { 4920, { | ||
837 | { 4, 21313, 4, 19181, }, | ||
838 | { 4, 21356, 4, 19220, }, | ||
839 | { 4, 21269, 4, 19142, }, | ||
840 | } }, | ||
841 | { 4940, { | ||
842 | { 4, 21226, 4, 19104, }, | ||
843 | { 4, 21269, 4, 19142, }, | ||
844 | { 4, 21183, 4, 19065, }, | ||
845 | } }, | ||
846 | { 4960, { | ||
847 | { 4, 21141, 4, 19027, }, | ||
848 | { 4, 21183, 4, 19065, }, | ||
849 | { 4, 21098, 4, 18988, }, | ||
850 | } }, | ||
851 | { 4980, { | ||
852 | { 4, 21056, 4, 18950, }, | ||
853 | { 4, 21098, 4, 18988, }, | ||
854 | { 4, 21014, 4, 18912, }, | ||
855 | } }, | ||
856 | { 5040, { | ||
857 | { 4, 20805, 4, 18725, }, | ||
858 | { 4, 20846, 4, 18762, }, | ||
859 | { 4, 20764, 4, 18687, }, | ||
860 | } }, | ||
861 | { 5060, { | ||
862 | { 4, 20723, 4, 18651, }, | ||
863 | { 4, 20764, 4, 18687, }, | ||
864 | { 4, 20682, 4, 18614, }, | ||
865 | } }, | ||
866 | { 5080, { | ||
867 | { 4, 20641, 4, 18577, }, | ||
868 | { 4, 20682, 4, 18614, }, | ||
869 | { 4, 20601, 4, 18541, }, | ||
870 | } }, | ||
871 | { 5180, { | ||
872 | { 4, 20243, 4, 18219, }, | ||
873 | { 4, 20282, 4, 18254, }, | ||
874 | { 4, 20204, 4, 18183, }, | ||
875 | } }, | ||
876 | { 5200, { | ||
877 | { 4, 20165, 4, 18148, }, | ||
878 | { 4, 20204, 4, 18183, }, | ||
879 | { 4, 20126, 4, 18114, }, | ||
880 | } }, | ||
881 | { 5220, { | ||
882 | { 4, 20088, 4, 18079, }, | ||
883 | { 4, 20126, 4, 18114, }, | ||
884 | { 4, 20049, 4, 18044, }, | ||
885 | } }, | ||
886 | { 5240, { | ||
887 | { 4, 20011, 4, 18010, }, | ||
888 | { 4, 20049, 4, 18044, }, | ||
889 | { 4, 19973, 4, 17976, }, | ||
890 | } }, | ||
891 | { 5260, { | ||
892 | { 4, 19935, 4, 17941, }, | ||
893 | { 4, 19973, 4, 17976, }, | ||
894 | { 4, 19897, 4, 17907, }, | ||
895 | } }, | ||
896 | { 5280, { | ||
897 | { 4, 19859, 4, 17873, }, | ||
898 | { 4, 19897, 4, 17907, }, | ||
899 | { 4, 19822, 4, 17840, }, | ||
900 | } }, | ||
901 | { 5300, { | ||
902 | { 4, 19784, 4, 17806, }, | ||
903 | { 4, 19822, 4, 17840, }, | ||
904 | { 4, 19747, 4, 17772, }, | ||
905 | } }, | ||
906 | { 5320, { | ||
907 | { 4, 19710, 4, 17739, }, | ||
908 | { 4, 19747, 4, 17772, }, | ||
909 | { 4, 19673, 4, 17706, }, | ||
910 | } }, | ||
911 | { 5500, { | ||
912 | { 4, 19065, 4, 17159, }, | ||
913 | { 4, 19100, 4, 17190, }, | ||
914 | { 4, 19030, 4, 17127, }, | ||
915 | } }, | ||
916 | { 5520, { | ||
917 | { 4, 18996, 4, 17096, }, | ||
918 | { 4, 19030, 4, 17127, }, | ||
919 | { 4, 18962, 4, 17065, }, | ||
920 | } }, | ||
921 | { 5540, { | ||
922 | { 4, 18927, 4, 17035, }, | ||
923 | { 4, 18962, 4, 17065, }, | ||
924 | { 4, 18893, 4, 17004, }, | ||
925 | } }, | ||
926 | { 5560, { | ||
927 | { 4, 18859, 4, 16973, }, | ||
928 | { 4, 18893, 4, 17004, }, | ||
929 | { 4, 18825, 4, 16943, }, | ||
930 | } }, | ||
931 | { 5580, { | ||
932 | { 4, 18792, 4, 16913, }, | ||
933 | { 4, 18825, 4, 16943, }, | ||
934 | { 4, 18758, 4, 16882, }, | ||
935 | } }, | ||
936 | { 5600, { | ||
937 | { 4, 18725, 4, 16852, }, | ||
938 | { 4, 18758, 4, 16882, }, | ||
939 | { 4, 18691, 4, 16822, }, | ||
940 | } }, | ||
941 | { 5620, { | ||
942 | { 4, 18658, 4, 16792, }, | ||
943 | { 4, 18691, 4, 16822, }, | ||
944 | { 4, 18625, 4, 16762, }, | ||
945 | } }, | ||
946 | { 5640, { | ||
947 | { 4, 18592, 4, 16733, }, | ||
948 | { 4, 18625, 4, 16762, }, | ||
949 | { 4, 18559, 4, 16703, }, | ||
950 | } }, | ||
951 | { 5660, { | ||
952 | { 4, 18526, 4, 16673, }, | ||
953 | { 4, 18559, 4, 16703, }, | ||
954 | { 4, 18493, 4, 16644, }, | ||
955 | } }, | ||
956 | { 5680, { | ||
957 | { 4, 18461, 4, 16615, }, | ||
958 | { 4, 18493, 4, 16644, }, | ||
959 | { 4, 18428, 4, 16586, }, | ||
960 | } }, | ||
961 | { 5700, { | ||
962 | { 4, 18396, 4, 16556, }, | ||
963 | { 4, 18428, 4, 16586, }, | ||
964 | { 4, 18364, 4, 16527, }, | ||
965 | } }, | ||
966 | { 5745, { | ||
967 | { 4, 18252, 4, 16427, }, | ||
968 | { 4, 18284, 4, 16455, }, | ||
969 | { 4, 18220, 4, 16398, }, | ||
970 | } }, | ||
971 | { 5765, { | ||
972 | { 4, 18189, 5, 32740, }, | ||
973 | { 4, 18220, 4, 16398, }, | ||
974 | { 4, 18157, 5, 32683, }, | ||
975 | } }, | ||
976 | { 5785, { | ||
977 | { 4, 18126, 5, 32626, }, | ||
978 | { 4, 18157, 5, 32683, }, | ||
979 | { 4, 18094, 5, 32570, }, | ||
980 | } }, | ||
981 | { 5805, { | ||
982 | { 4, 18063, 5, 32514, }, | ||
983 | { 4, 18094, 5, 32570, }, | ||
984 | { 4, 18032, 5, 32458, }, | ||
985 | } }, | ||
986 | { 5825, { | ||
987 | { 4, 18001, 5, 32402, }, | ||
988 | { 4, 18032, 5, 32458, }, | ||
989 | { 4, 17970, 5, 32347, }, | ||
990 | } }, | ||
991 | { 5170, { | ||
992 | { 4, 20282, 4, 18254, }, | ||
993 | { 4, 20321, 4, 18289, }, | ||
994 | { 4, 20243, 4, 18219, }, | ||
995 | } }, | ||
996 | { 5190, { | ||
997 | { 4, 20204, 4, 18183, }, | ||
998 | { 4, 20243, 4, 18219, }, | ||
999 | { 4, 20165, 4, 18148, }, | ||
1000 | } }, | ||
1001 | { 5210, { | ||
1002 | { 4, 20126, 4, 18114, }, | ||
1003 | { 4, 20165, 4, 18148, }, | ||
1004 | { 4, 20088, 4, 18079, }, | ||
1005 | } }, | ||
1006 | { 5230, { | ||
1007 | { 4, 20049, 4, 18044, }, | ||
1008 | { 4, 20088, 4, 18079, }, | ||
1009 | { 4, 20011, 4, 18010, }, | ||
1010 | } }, | ||
1011 | }; | ||
1012 | |||
1013 | static const struct ar9170_phy_freq_params * | ||
1014 | ar9170_get_hw_dyn_params(struct ieee80211_channel *channel, | ||
1015 | enum ar9170_bw bw) | ||
1016 | { | ||
1017 | unsigned int chanidx = 0; | ||
1018 | u16 freq = 2412; | ||
1019 | |||
1020 | if (channel) { | ||
1021 | chanidx = channel->hw_value; | ||
1022 | freq = channel->center_freq; | ||
1023 | } | ||
1024 | |||
1025 | BUG_ON(chanidx >= ARRAY_SIZE(ar9170_phy_freq_params)); | ||
1026 | |||
1027 | BUILD_BUG_ON(__AR9170_NUM_BW != 3); | ||
1028 | |||
1029 | WARN_ON(ar9170_phy_freq_params[chanidx].freq != freq); | ||
1030 | |||
1031 | return &ar9170_phy_freq_params[chanidx].params[bw]; | ||
1032 | } | ||
1033 | |||
1034 | |||
1035 | int ar9170_init_rf(struct ar9170 *ar) | ||
1036 | { | ||
1037 | const struct ar9170_phy_freq_params *freqpar; | ||
1038 | __le32 cmd[7]; | ||
1039 | int err; | ||
1040 | |||
1041 | err = ar9170_init_rf_banks_0_7(ar, false); | ||
1042 | if (err) | ||
1043 | return err; | ||
1044 | |||
1045 | err = ar9170_init_rf_bank4_pwr(ar, false, 2412, AR9170_BW_20); | ||
1046 | if (err) | ||
1047 | return err; | ||
1048 | |||
1049 | freqpar = ar9170_get_hw_dyn_params(NULL, AR9170_BW_20); | ||
1050 | |||
1051 | cmd[0] = cpu_to_le32(2412 * 1000); | ||
1052 | cmd[1] = cpu_to_le32(0); | ||
1053 | cmd[2] = cpu_to_le32(1); | ||
1054 | cmd[3] = cpu_to_le32(freqpar->coeff_exp); | ||
1055 | cmd[4] = cpu_to_le32(freqpar->coeff_man); | ||
1056 | cmd[5] = cpu_to_le32(freqpar->coeff_exp_shgi); | ||
1057 | cmd[6] = cpu_to_le32(freqpar->coeff_man_shgi); | ||
1058 | |||
1059 | /* RF_INIT echoes the command back to us */ | ||
1060 | err = ar->exec_cmd(ar, AR9170_CMD_RF_INIT, | ||
1061 | sizeof(cmd), (u8 *)cmd, | ||
1062 | sizeof(cmd), (u8 *)cmd); | ||
1063 | if (err) | ||
1064 | return err; | ||
1065 | |||
1066 | msleep(1000); | ||
1067 | |||
1068 | return ar9170_echo_test(ar, 0xaabbccdd); | ||
1069 | } | ||
1070 | |||
1071 | static int ar9170_find_freq_idx(int nfreqs, u8 *freqs, u8 f) | ||
1072 | { | ||
1073 | int idx = nfreqs - 2; | ||
1074 | |||
1075 | while (idx >= 0) { | ||
1076 | if (f >= freqs[idx]) | ||
1077 | return idx; | ||
1078 | idx--; | ||
1079 | } | ||
1080 | |||
1081 | return 0; | ||
1082 | } | ||
1083 | |||
1084 | static s32 ar9170_interpolate_s32(s32 x, s32 x1, s32 y1, s32 x2, s32 y2) | ||
1085 | { | ||
1086 | /* nothing to interpolate, it's horizontal */ | ||
1087 | if (y2 == y1) | ||
1088 | return y1; | ||
1089 | |||
1090 | /* check if we hit one of the edges */ | ||
1091 | if (x == x1) | ||
1092 | return y1; | ||
1093 | if (x == x2) | ||
1094 | return y2; | ||
1095 | |||
1096 | /* x1 == x2 is bad, hopefully == x */ | ||
1097 | if (x2 == x1) | ||
1098 | return y1; | ||
1099 | |||
1100 | return y1 + (((y2 - y1) * (x - x1)) / (x2 - x1)); | ||
1101 | } | ||
1102 | |||
1103 | static u8 ar9170_interpolate_u8(u8 x, u8 x1, u8 y1, u8 x2, u8 y2) | ||
1104 | { | ||
1105 | #define SHIFT 8 | ||
1106 | s32 y; | ||
1107 | |||
1108 | y = ar9170_interpolate_s32(x << SHIFT, | ||
1109 | x1 << SHIFT, y1 << SHIFT, | ||
1110 | x2 << SHIFT, y2 << SHIFT); | ||
1111 | |||
1112 | /* | ||
1113 | * XXX: unwrap this expression | ||
1114 | * Isn't it just DIV_ROUND_UP(y, 1<<SHIFT)? | ||
1115 | * Can we rely on the compiler to optimise away the div? | ||
1116 | */ | ||
1117 | return (y >> SHIFT) + ((y & (1<<(SHIFT-1))) >> (SHIFT - 1)); | ||
1118 | #undef SHIFT | ||
1119 | } | ||
1120 | |||
1121 | static u8 ar9170_interpolate_val(u8 x, u8 *x_array, u8 *y_array) | ||
1122 | { | ||
1123 | int i; | ||
1124 | |||
1125 | for (i = 0; i < 3; i++) | ||
1126 | if (x <= x_array[i + 1]) | ||
1127 | break; | ||
1128 | |||
1129 | return ar9170_interpolate_u8(x, | ||
1130 | x_array[i], | ||
1131 | y_array[i], | ||
1132 | x_array[i + 1], | ||
1133 | y_array[i + 1]); | ||
1134 | } | ||
1135 | |||
1136 | static int ar9170_set_freq_cal_data(struct ar9170 *ar, | ||
1137 | struct ieee80211_channel *channel) | ||
1138 | { | ||
1139 | u8 *cal_freq_pier; | ||
1140 | u8 vpds[2][AR5416_PD_GAIN_ICEPTS]; | ||
1141 | u8 pwrs[2][AR5416_PD_GAIN_ICEPTS]; | ||
1142 | int chain, idx, i; | ||
1143 | u32 phy_data = 0; | ||
1144 | u8 f, tmp; | ||
1145 | |||
1146 | switch (channel->band) { | ||
1147 | case IEEE80211_BAND_2GHZ: | ||
1148 | f = channel->center_freq - 2300; | ||
1149 | cal_freq_pier = ar->eeprom.cal_freq_pier_2G; | ||
1150 | i = AR5416_NUM_2G_CAL_PIERS - 1; | ||
1151 | break; | ||
1152 | |||
1153 | case IEEE80211_BAND_5GHZ: | ||
1154 | f = (channel->center_freq - 4800) / 5; | ||
1155 | cal_freq_pier = ar->eeprom.cal_freq_pier_5G; | ||
1156 | i = AR5416_NUM_5G_CAL_PIERS - 1; | ||
1157 | break; | ||
1158 | |||
1159 | default: | ||
1160 | return -EINVAL; | ||
1161 | break; | ||
1162 | } | ||
1163 | |||
1164 | for (; i >= 0; i--) { | ||
1165 | if (cal_freq_pier[i] != 0xff) | ||
1166 | break; | ||
1167 | } | ||
1168 | if (i < 0) | ||
1169 | return -EINVAL; | ||
1170 | |||
1171 | idx = ar9170_find_freq_idx(i, cal_freq_pier, f); | ||
1172 | |||
1173 | ar9170_regwrite_begin(ar); | ||
1174 | |||
1175 | for (chain = 0; chain < AR5416_MAX_CHAINS; chain++) { | ||
1176 | for (i = 0; i < AR5416_PD_GAIN_ICEPTS; i++) { | ||
1177 | struct ar9170_calibration_data_per_freq *cal_pier_data; | ||
1178 | int j; | ||
1179 | |||
1180 | switch (channel->band) { | ||
1181 | case IEEE80211_BAND_2GHZ: | ||
1182 | cal_pier_data = &ar->eeprom. | ||
1183 | cal_pier_data_2G[chain][idx]; | ||
1184 | break; | ||
1185 | |||
1186 | case IEEE80211_BAND_5GHZ: | ||
1187 | cal_pier_data = &ar->eeprom. | ||
1188 | cal_pier_data_5G[chain][idx]; | ||
1189 | break; | ||
1190 | |||
1191 | default: | ||
1192 | return -EINVAL; | ||
1193 | } | ||
1194 | |||
1195 | for (j = 0; j < 2; j++) { | ||
1196 | vpds[j][i] = ar9170_interpolate_u8(f, | ||
1197 | cal_freq_pier[idx], | ||
1198 | cal_pier_data->vpd_pdg[j][i], | ||
1199 | cal_freq_pier[idx + 1], | ||
1200 | cal_pier_data[1].vpd_pdg[j][i]); | ||
1201 | |||
1202 | pwrs[j][i] = ar9170_interpolate_u8(f, | ||
1203 | cal_freq_pier[idx], | ||
1204 | cal_pier_data->pwr_pdg[j][i], | ||
1205 | cal_freq_pier[idx + 1], | ||
1206 | cal_pier_data[1].pwr_pdg[j][i]) / 2; | ||
1207 | } | ||
1208 | } | ||
1209 | |||
1210 | for (i = 0; i < 76; i++) { | ||
1211 | if (i < 25) { | ||
1212 | tmp = ar9170_interpolate_val(i, &pwrs[0][0], | ||
1213 | &vpds[0][0]); | ||
1214 | } else { | ||
1215 | tmp = ar9170_interpolate_val(i - 12, | ||
1216 | &pwrs[1][0], | ||
1217 | &vpds[1][0]); | ||
1218 | } | ||
1219 | |||
1220 | phy_data |= tmp << ((i & 3) << 3); | ||
1221 | if ((i & 3) == 3) { | ||
1222 | ar9170_regwrite(0x1c6280 + chain * 0x1000 + | ||
1223 | (i & ~3), phy_data); | ||
1224 | phy_data = 0; | ||
1225 | } | ||
1226 | } | ||
1227 | |||
1228 | for (i = 19; i < 32; i++) | ||
1229 | ar9170_regwrite(0x1c6280 + chain * 0x1000 + (i << 2), | ||
1230 | 0x0); | ||
1231 | } | ||
1232 | |||
1233 | ar9170_regwrite_finish(); | ||
1234 | return ar9170_regwrite_result(); | ||
1235 | } | ||
1236 | |||
1237 | static u8 ar9170_get_max_edge_power(struct ar9170 *ar, | ||
1238 | struct ar9170_calctl_edges edges[], | ||
1239 | u32 freq) | ||
1240 | { | ||
1241 | int i; | ||
1242 | u8 rc = AR5416_MAX_RATE_POWER; | ||
1243 | u8 f; | ||
1244 | if (freq < 3000) | ||
1245 | f = freq - 2300; | ||
1246 | else | ||
1247 | f = (freq - 4800) / 5; | ||
1248 | |||
1249 | for (i = 0; i < AR5416_NUM_BAND_EDGES; i++) { | ||
1250 | if (edges[i].channel == 0xff) | ||
1251 | break; | ||
1252 | if (f == edges[i].channel) { | ||
1253 | /* exact freq match */ | ||
1254 | rc = edges[i].power_flags & ~AR9170_CALCTL_EDGE_FLAGS; | ||
1255 | break; | ||
1256 | } | ||
1257 | if (i > 0 && f < edges[i].channel) { | ||
1258 | if (f > edges[i - 1].channel && | ||
1259 | edges[i - 1].power_flags & | ||
1260 | AR9170_CALCTL_EDGE_FLAGS) { | ||
1261 | /* lower channel has the inband flag set */ | ||
1262 | rc = edges[i - 1].power_flags & | ||
1263 | ~AR9170_CALCTL_EDGE_FLAGS; | ||
1264 | } | ||
1265 | break; | ||
1266 | } | ||
1267 | } | ||
1268 | |||
1269 | if (i == AR5416_NUM_BAND_EDGES) { | ||
1270 | if (f > edges[i - 1].channel && | ||
1271 | edges[i - 1].power_flags & AR9170_CALCTL_EDGE_FLAGS) { | ||
1272 | /* lower channel has the inband flag set */ | ||
1273 | rc = edges[i - 1].power_flags & | ||
1274 | ~AR9170_CALCTL_EDGE_FLAGS; | ||
1275 | } | ||
1276 | } | ||
1277 | return rc; | ||
1278 | } | ||
1279 | |||
1280 | static u8 ar9170_get_heavy_clip(struct ar9170 *ar, | ||
1281 | struct ar9170_calctl_edges edges[], | ||
1282 | u32 freq, enum ar9170_bw bw) | ||
1283 | { | ||
1284 | u8 f; | ||
1285 | int i; | ||
1286 | u8 rc = 0; | ||
1287 | |||
1288 | if (freq < 3000) | ||
1289 | f = freq - 2300; | ||
1290 | else | ||
1291 | f = (freq - 4800) / 5; | ||
1292 | |||
1293 | if (bw == AR9170_BW_40_BELOW || bw == AR9170_BW_40_ABOVE) | ||
1294 | rc |= 0xf0; | ||
1295 | |||
1296 | for (i = 0; i < AR5416_NUM_BAND_EDGES; i++) { | ||
1297 | if (edges[i].channel == 0xff) | ||
1298 | break; | ||
1299 | if (f == edges[i].channel) { | ||
1300 | if (!(edges[i].power_flags & AR9170_CALCTL_EDGE_FLAGS)) | ||
1301 | rc |= 0x0f; | ||
1302 | break; | ||
1303 | } | ||
1304 | } | ||
1305 | |||
1306 | return rc; | ||
1307 | } | ||
1308 | |||
1309 | /* | ||
1310 | * calculate the conformance test limits and the heavy clip parameter | ||
1311 | * and apply them to ar->power* (derived from otus hal/hpmain.c, line 3706) | ||
1312 | */ | ||
1313 | static void ar9170_calc_ctl(struct ar9170 *ar, u32 freq, enum ar9170_bw bw) | ||
1314 | { | ||
1315 | u8 ctl_grp; /* CTL group */ | ||
1316 | u8 ctl_idx; /* CTL index */ | ||
1317 | int i, j; | ||
1318 | struct ctl_modes { | ||
1319 | u8 ctl_mode; | ||
1320 | u8 max_power; | ||
1321 | u8 *pwr_cal_data; | ||
1322 | int pwr_cal_len; | ||
1323 | } *modes; | ||
1324 | |||
1325 | /* | ||
1326 | * order is relevant in the mode_list_*: we fall back to the | ||
1327 | * lower indices if any mode is missed in the EEPROM. | ||
1328 | */ | ||
1329 | struct ctl_modes mode_list_2ghz[] = { | ||
1330 | { CTL_11B, 0, ar->power_2G_cck, 4 }, | ||
1331 | { CTL_11G, 0, ar->power_2G_ofdm, 4 }, | ||
1332 | { CTL_2GHT20, 0, ar->power_2G_ht20, 8 }, | ||
1333 | { CTL_2GHT40, 0, ar->power_2G_ht40, 8 }, | ||
1334 | }; | ||
1335 | struct ctl_modes mode_list_5ghz[] = { | ||
1336 | { CTL_11A, 0, ar->power_5G_leg, 4 }, | ||
1337 | { CTL_5GHT20, 0, ar->power_5G_ht20, 8 }, | ||
1338 | { CTL_5GHT40, 0, ar->power_5G_ht40, 8 }, | ||
1339 | }; | ||
1340 | int nr_modes; | ||
1341 | |||
1342 | #define EDGES(c, n) (ar->eeprom.ctl_data[c].control_edges[n]) | ||
1343 | |||
1344 | ar->phy_heavy_clip = 0; | ||
1345 | |||
1346 | /* | ||
1347 | * TODO: investigate the differences between OTUS' | ||
1348 | * hpreg.c::zfHpGetRegulatoryDomain() and | ||
1349 | * ath/regd.c::ath_regd_get_band_ctl() - | ||
1350 | * e.g. for FCC3_WORLD the OTUS procedure | ||
1351 | * always returns CTL_FCC, while the one in ath/ delivers | ||
1352 | * CTL_ETSI for 2GHz and CTL_FCC for 5GHz. | ||
1353 | */ | ||
1354 | ctl_grp = ath_regd_get_band_ctl(&ar->common.regulatory, | ||
1355 | ar->hw->conf.channel->band); | ||
1356 | |||
1357 | /* ctl group not found - either invalid band (NO_CTL) or ww roaming */ | ||
1358 | if (ctl_grp == NO_CTL || ctl_grp == SD_NO_CTL) | ||
1359 | ctl_grp = CTL_FCC; | ||
1360 | |||
1361 | if (ctl_grp != CTL_FCC) | ||
1362 | /* skip CTL and heavy clip for CTL_MKK and CTL_ETSI */ | ||
1363 | return; | ||
1364 | |||
1365 | if (ar->hw->conf.channel->band == IEEE80211_BAND_2GHZ) { | ||
1366 | modes = mode_list_2ghz; | ||
1367 | nr_modes = ARRAY_SIZE(mode_list_2ghz); | ||
1368 | } else { | ||
1369 | modes = mode_list_5ghz; | ||
1370 | nr_modes = ARRAY_SIZE(mode_list_5ghz); | ||
1371 | } | ||
1372 | |||
1373 | for (i = 0; i < nr_modes; i++) { | ||
1374 | u8 c = ctl_grp | modes[i].ctl_mode; | ||
1375 | for (ctl_idx = 0; ctl_idx < AR5416_NUM_CTLS; ctl_idx++) | ||
1376 | if (c == ar->eeprom.ctl_index[ctl_idx]) | ||
1377 | break; | ||
1378 | if (ctl_idx < AR5416_NUM_CTLS) { | ||
1379 | int f_off = 0; | ||
1380 | |||
1381 | /* determine heav clip parameter from | ||
1382 | the 11G edges array */ | ||
1383 | if (modes[i].ctl_mode == CTL_11G) { | ||
1384 | ar->phy_heavy_clip = | ||
1385 | ar9170_get_heavy_clip(ar, | ||
1386 | EDGES(ctl_idx, 1), | ||
1387 | freq, bw); | ||
1388 | } | ||
1389 | |||
1390 | /* adjust freq for 40MHz */ | ||
1391 | if (modes[i].ctl_mode == CTL_2GHT40 || | ||
1392 | modes[i].ctl_mode == CTL_5GHT40) { | ||
1393 | if (bw == AR9170_BW_40_BELOW) | ||
1394 | f_off = -10; | ||
1395 | else | ||
1396 | f_off = 10; | ||
1397 | } | ||
1398 | |||
1399 | modes[i].max_power = | ||
1400 | ar9170_get_max_edge_power(ar, EDGES(ctl_idx, 1), | ||
1401 | freq+f_off); | ||
1402 | |||
1403 | /* | ||
1404 | * TODO: check if the regulatory max. power is | ||
1405 | * controlled by cfg80211 for DFS | ||
1406 | * (hpmain applies it to max_power itself for DFS freq) | ||
1407 | */ | ||
1408 | |||
1409 | } else { | ||
1410 | /* | ||
1411 | * Workaround in otus driver, hpmain.c, line 3906: | ||
1412 | * if no data for 5GHT20 are found, take the | ||
1413 | * legacy 5G value. | ||
1414 | * We extend this here to fallback from any other *HT or | ||
1415 | * 11G, too. | ||
1416 | */ | ||
1417 | int k = i; | ||
1418 | |||
1419 | modes[i].max_power = AR5416_MAX_RATE_POWER; | ||
1420 | while (k-- > 0) { | ||
1421 | if (modes[k].max_power != | ||
1422 | AR5416_MAX_RATE_POWER) { | ||
1423 | modes[i].max_power = modes[k].max_power; | ||
1424 | break; | ||
1425 | } | ||
1426 | } | ||
1427 | } | ||
1428 | |||
1429 | /* apply max power to pwr_cal_data (ar->power_*) */ | ||
1430 | for (j = 0; j < modes[i].pwr_cal_len; j++) { | ||
1431 | modes[i].pwr_cal_data[j] = min(modes[i].pwr_cal_data[j], | ||
1432 | modes[i].max_power); | ||
1433 | } | ||
1434 | } | ||
1435 | |||
1436 | if (ar->phy_heavy_clip & 0xf0) { | ||
1437 | ar->power_2G_ht40[0]--; | ||
1438 | ar->power_2G_ht40[1]--; | ||
1439 | ar->power_2G_ht40[2]--; | ||
1440 | } | ||
1441 | if (ar->phy_heavy_clip & 0xf) { | ||
1442 | ar->power_2G_ht20[0]++; | ||
1443 | ar->power_2G_ht20[1]++; | ||
1444 | ar->power_2G_ht20[2]++; | ||
1445 | } | ||
1446 | |||
1447 | |||
1448 | #undef EDGES | ||
1449 | } | ||
1450 | |||
1451 | static int ar9170_set_power_cal(struct ar9170 *ar, u32 freq, enum ar9170_bw bw) | ||
1452 | { | ||
1453 | struct ar9170_calibration_target_power_legacy *ctpl; | ||
1454 | struct ar9170_calibration_target_power_ht *ctph; | ||
1455 | u8 *ctpres; | ||
1456 | int ntargets; | ||
1457 | int idx, i, n; | ||
1458 | u8 ackpower, ackchains, f; | ||
1459 | u8 pwr_freqs[AR5416_MAX_NUM_TGT_PWRS]; | ||
1460 | |||
1461 | if (freq < 3000) | ||
1462 | f = freq - 2300; | ||
1463 | else | ||
1464 | f = (freq - 4800)/5; | ||
1465 | |||
1466 | /* | ||
1467 | * cycle through the various modes | ||
1468 | * | ||
1469 | * legacy modes first: 5G, 2G CCK, 2G OFDM | ||
1470 | */ | ||
1471 | for (i = 0; i < 3; i++) { | ||
1472 | switch (i) { | ||
1473 | case 0: /* 5 GHz legacy */ | ||
1474 | ctpl = &ar->eeprom.cal_tgt_pwr_5G[0]; | ||
1475 | ntargets = AR5416_NUM_5G_TARGET_PWRS; | ||
1476 | ctpres = ar->power_5G_leg; | ||
1477 | break; | ||
1478 | case 1: /* 2.4 GHz CCK */ | ||
1479 | ctpl = &ar->eeprom.cal_tgt_pwr_2G_cck[0]; | ||
1480 | ntargets = AR5416_NUM_2G_CCK_TARGET_PWRS; | ||
1481 | ctpres = ar->power_2G_cck; | ||
1482 | break; | ||
1483 | case 2: /* 2.4 GHz OFDM */ | ||
1484 | ctpl = &ar->eeprom.cal_tgt_pwr_2G_ofdm[0]; | ||
1485 | ntargets = AR5416_NUM_2G_OFDM_TARGET_PWRS; | ||
1486 | ctpres = ar->power_2G_ofdm; | ||
1487 | break; | ||
1488 | default: | ||
1489 | BUG(); | ||
1490 | } | ||
1491 | |||
1492 | for (n = 0; n < ntargets; n++) { | ||
1493 | if (ctpl[n].freq == 0xff) | ||
1494 | break; | ||
1495 | pwr_freqs[n] = ctpl[n].freq; | ||
1496 | } | ||
1497 | ntargets = n; | ||
1498 | idx = ar9170_find_freq_idx(ntargets, pwr_freqs, f); | ||
1499 | for (n = 0; n < 4; n++) | ||
1500 | ctpres[n] = ar9170_interpolate_u8( | ||
1501 | f, | ||
1502 | ctpl[idx + 0].freq, | ||
1503 | ctpl[idx + 0].power[n], | ||
1504 | ctpl[idx + 1].freq, | ||
1505 | ctpl[idx + 1].power[n]); | ||
1506 | } | ||
1507 | |||
1508 | /* | ||
1509 | * HT modes now: 5G HT20, 5G HT40, 2G CCK, 2G OFDM, 2G HT20, 2G HT40 | ||
1510 | */ | ||
1511 | for (i = 0; i < 4; i++) { | ||
1512 | switch (i) { | ||
1513 | case 0: /* 5 GHz HT 20 */ | ||
1514 | ctph = &ar->eeprom.cal_tgt_pwr_5G_ht20[0]; | ||
1515 | ntargets = AR5416_NUM_5G_TARGET_PWRS; | ||
1516 | ctpres = ar->power_5G_ht20; | ||
1517 | break; | ||
1518 | case 1: /* 5 GHz HT 40 */ | ||
1519 | ctph = &ar->eeprom.cal_tgt_pwr_5G_ht40[0]; | ||
1520 | ntargets = AR5416_NUM_5G_TARGET_PWRS; | ||
1521 | ctpres = ar->power_5G_ht40; | ||
1522 | break; | ||
1523 | case 2: /* 2.4 GHz HT 20 */ | ||
1524 | ctph = &ar->eeprom.cal_tgt_pwr_2G_ht20[0]; | ||
1525 | ntargets = AR5416_NUM_2G_OFDM_TARGET_PWRS; | ||
1526 | ctpres = ar->power_2G_ht20; | ||
1527 | break; | ||
1528 | case 3: /* 2.4 GHz HT 40 */ | ||
1529 | ctph = &ar->eeprom.cal_tgt_pwr_2G_ht40[0]; | ||
1530 | ntargets = AR5416_NUM_2G_OFDM_TARGET_PWRS; | ||
1531 | ctpres = ar->power_2G_ht40; | ||
1532 | break; | ||
1533 | default: | ||
1534 | BUG(); | ||
1535 | } | ||
1536 | |||
1537 | for (n = 0; n < ntargets; n++) { | ||
1538 | if (ctph[n].freq == 0xff) | ||
1539 | break; | ||
1540 | pwr_freqs[n] = ctph[n].freq; | ||
1541 | } | ||
1542 | ntargets = n; | ||
1543 | idx = ar9170_find_freq_idx(ntargets, pwr_freqs, f); | ||
1544 | for (n = 0; n < 8; n++) | ||
1545 | ctpres[n] = ar9170_interpolate_u8( | ||
1546 | f, | ||
1547 | ctph[idx + 0].freq, | ||
1548 | ctph[idx + 0].power[n], | ||
1549 | ctph[idx + 1].freq, | ||
1550 | ctph[idx + 1].power[n]); | ||
1551 | } | ||
1552 | |||
1553 | |||
1554 | /* calc. conformance test limits and apply to ar->power*[] */ | ||
1555 | ar9170_calc_ctl(ar, freq, bw); | ||
1556 | |||
1557 | /* set ACK/CTS TX power */ | ||
1558 | ar9170_regwrite_begin(ar); | ||
1559 | |||
1560 | if (ar->eeprom.tx_mask != 1) | ||
1561 | ackchains = AR9170_TX_PHY_TXCHAIN_2; | ||
1562 | else | ||
1563 | ackchains = AR9170_TX_PHY_TXCHAIN_1; | ||
1564 | |||
1565 | if (freq < 3000) | ||
1566 | ackpower = ar->power_2G_ofdm[0] & 0x3f; | ||
1567 | else | ||
1568 | ackpower = ar->power_5G_leg[0] & 0x3f; | ||
1569 | |||
1570 | ar9170_regwrite(0x1c3694, ackpower << 20 | ackchains << 26); | ||
1571 | ar9170_regwrite(0x1c3bb4, ackpower << 5 | ackchains << 11 | | ||
1572 | ackpower << 21 | ackchains << 27); | ||
1573 | |||
1574 | ar9170_regwrite_finish(); | ||
1575 | return ar9170_regwrite_result(); | ||
1576 | } | ||
1577 | |||
1578 | static int ar9170_calc_noise_dbm(u32 raw_noise) | ||
1579 | { | ||
1580 | if (raw_noise & 0x100) | ||
1581 | return ~((raw_noise & 0x0ff) >> 1); | ||
1582 | else | ||
1583 | return (raw_noise & 0xff) >> 1; | ||
1584 | } | ||
1585 | |||
1586 | int ar9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel, | ||
1587 | enum ar9170_rf_init_mode rfi, enum ar9170_bw bw) | ||
1588 | { | ||
1589 | const struct ar9170_phy_freq_params *freqpar; | ||
1590 | u32 cmd, tmp, offs; | ||
1591 | __le32 vals[8]; | ||
1592 | int i, err; | ||
1593 | bool bandswitch; | ||
1594 | |||
1595 | /* clear BB heavy clip enable */ | ||
1596 | err = ar9170_write_reg(ar, 0x1c59e0, 0x200); | ||
1597 | if (err) | ||
1598 | return err; | ||
1599 | |||
1600 | /* may be NULL at first setup */ | ||
1601 | if (ar->channel) | ||
1602 | bandswitch = ar->channel->band != channel->band; | ||
1603 | else | ||
1604 | bandswitch = true; | ||
1605 | |||
1606 | /* HW workaround */ | ||
1607 | if (!ar->hw->wiphy->bands[IEEE80211_BAND_5GHZ] && | ||
1608 | channel->center_freq <= 2417) | ||
1609 | bandswitch = true; | ||
1610 | |||
1611 | err = ar->exec_cmd(ar, AR9170_CMD_FREQ_START, 0, NULL, 0, NULL); | ||
1612 | if (err) | ||
1613 | return err; | ||
1614 | |||
1615 | if (rfi != AR9170_RFI_NONE || bandswitch) { | ||
1616 | u32 val = 0x400; | ||
1617 | |||
1618 | if (rfi == AR9170_RFI_COLD) | ||
1619 | val = 0x800; | ||
1620 | |||
1621 | /* warm/cold reset BB/ADDA */ | ||
1622 | err = ar9170_write_reg(ar, 0x1d4004, val); | ||
1623 | if (err) | ||
1624 | return err; | ||
1625 | |||
1626 | err = ar9170_write_reg(ar, 0x1d4004, 0x0); | ||
1627 | if (err) | ||
1628 | return err; | ||
1629 | |||
1630 | err = ar9170_init_phy(ar, channel->band); | ||
1631 | if (err) | ||
1632 | return err; | ||
1633 | |||
1634 | err = ar9170_init_rf_banks_0_7(ar, | ||
1635 | channel->band == IEEE80211_BAND_5GHZ); | ||
1636 | if (err) | ||
1637 | return err; | ||
1638 | |||
1639 | cmd = AR9170_CMD_RF_INIT; | ||
1640 | } else { | ||
1641 | cmd = AR9170_CMD_FREQUENCY; | ||
1642 | } | ||
1643 | |||
1644 | err = ar9170_init_rf_bank4_pwr(ar, | ||
1645 | channel->band == IEEE80211_BAND_5GHZ, | ||
1646 | channel->center_freq, bw); | ||
1647 | if (err) | ||
1648 | return err; | ||
1649 | |||
1650 | switch (bw) { | ||
1651 | case AR9170_BW_20: | ||
1652 | tmp = 0x240; | ||
1653 | offs = 0; | ||
1654 | break; | ||
1655 | case AR9170_BW_40_BELOW: | ||
1656 | tmp = 0x2c4; | ||
1657 | offs = 3; | ||
1658 | break; | ||
1659 | case AR9170_BW_40_ABOVE: | ||
1660 | tmp = 0x2d4; | ||
1661 | offs = 1; | ||
1662 | break; | ||
1663 | default: | ||
1664 | BUG(); | ||
1665 | return -ENOSYS; | ||
1666 | } | ||
1667 | |||
1668 | if (ar->eeprom.tx_mask != 1) | ||
1669 | tmp |= 0x100; | ||
1670 | |||
1671 | err = ar9170_write_reg(ar, 0x1c5804, tmp); | ||
1672 | if (err) | ||
1673 | return err; | ||
1674 | |||
1675 | err = ar9170_set_freq_cal_data(ar, channel); | ||
1676 | if (err) | ||
1677 | return err; | ||
1678 | |||
1679 | err = ar9170_set_power_cal(ar, channel->center_freq, bw); | ||
1680 | if (err) | ||
1681 | return err; | ||
1682 | |||
1683 | freqpar = ar9170_get_hw_dyn_params(channel, bw); | ||
1684 | |||
1685 | vals[0] = cpu_to_le32(channel->center_freq * 1000); | ||
1686 | vals[1] = cpu_to_le32(conf_is_ht40(&ar->hw->conf)); | ||
1687 | vals[2] = cpu_to_le32(offs << 2 | 1); | ||
1688 | vals[3] = cpu_to_le32(freqpar->coeff_exp); | ||
1689 | vals[4] = cpu_to_le32(freqpar->coeff_man); | ||
1690 | vals[5] = cpu_to_le32(freqpar->coeff_exp_shgi); | ||
1691 | vals[6] = cpu_to_le32(freqpar->coeff_man_shgi); | ||
1692 | vals[7] = cpu_to_le32(1000); | ||
1693 | |||
1694 | err = ar->exec_cmd(ar, cmd, sizeof(vals), (u8 *)vals, | ||
1695 | sizeof(vals), (u8 *)vals); | ||
1696 | if (err) | ||
1697 | return err; | ||
1698 | |||
1699 | if (ar->phy_heavy_clip) { | ||
1700 | err = ar9170_write_reg(ar, 0x1c59e0, | ||
1701 | 0x200 | ar->phy_heavy_clip); | ||
1702 | if (err) { | ||
1703 | if (ar9170_nag_limiter(ar)) | ||
1704 | wiphy_err(ar->hw->wiphy, | ||
1705 | "failed to set heavy clip\n"); | ||
1706 | } | ||
1707 | } | ||
1708 | |||
1709 | for (i = 0; i < 2; i++) { | ||
1710 | ar->noise[i] = ar9170_calc_noise_dbm( | ||
1711 | (le32_to_cpu(vals[2 + i]) >> 19) & 0x1ff); | ||
1712 | |||
1713 | ar->noise[i + 2] = ar9170_calc_noise_dbm( | ||
1714 | (le32_to_cpu(vals[5 + i]) >> 23) & 0x1ff); | ||
1715 | } | ||
1716 | |||
1717 | ar->channel = channel; | ||
1718 | return 0; | ||
1719 | } | ||
diff --git a/drivers/net/wireless/ath/ar9170/usb.c b/drivers/net/wireless/ath/ar9170/usb.c deleted file mode 100644 index d3be6f9816b5..000000000000 --- a/drivers/net/wireless/ath/ar9170/usb.c +++ /dev/null | |||
@@ -1,1008 +0,0 @@ | |||
1 | /* | ||
2 | * Atheros AR9170 driver | ||
3 | * | ||
4 | * USB - frontend | ||
5 | * | ||
6 | * Copyright 2008, Johannes Berg <johannes@sipsolutions.net> | ||
7 | * Copyright 2009, Christian Lamparter <chunkeey@web.de> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; see the file COPYING. If not, see | ||
21 | * http://www.gnu.org/licenses/. | ||
22 | * | ||
23 | * This file incorporates work covered by the following copyright and | ||
24 | * permission notice: | ||
25 | * Copyright (c) 2007-2008 Atheros Communications, Inc. | ||
26 | * | ||
27 | * Permission to use, copy, modify, and/or distribute this software for any | ||
28 | * purpose with or without fee is hereby granted, provided that the above | ||
29 | * copyright notice and this permission notice appear in all copies. | ||
30 | * | ||
31 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
32 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
33 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
34 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
35 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
36 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
37 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
38 | */ | ||
39 | |||
40 | #include <linux/module.h> | ||
41 | #include <linux/slab.h> | ||
42 | #include <linux/usb.h> | ||
43 | #include <linux/firmware.h> | ||
44 | #include <linux/etherdevice.h> | ||
45 | #include <linux/device.h> | ||
46 | #include <net/mac80211.h> | ||
47 | #include "ar9170.h" | ||
48 | #include "cmd.h" | ||
49 | #include "hw.h" | ||
50 | #include "usb.h" | ||
51 | |||
52 | MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>"); | ||
53 | MODULE_AUTHOR("Christian Lamparter <chunkeey@web.de>"); | ||
54 | MODULE_LICENSE("GPL"); | ||
55 | MODULE_DESCRIPTION("Atheros AR9170 802.11n USB wireless"); | ||
56 | MODULE_FIRMWARE("ar9170.fw"); | ||
57 | |||
58 | enum ar9170_requirements { | ||
59 | AR9170_REQ_FW1_ONLY = 1, | ||
60 | }; | ||
61 | |||
62 | static struct usb_device_id ar9170_usb_ids[] = { | ||
63 | /* Atheros 9170 */ | ||
64 | { USB_DEVICE(0x0cf3, 0x9170) }, | ||
65 | /* Atheros TG121N */ | ||
66 | { USB_DEVICE(0x0cf3, 0x1001) }, | ||
67 | /* TP-Link TL-WN821N v2 */ | ||
68 | { USB_DEVICE(0x0cf3, 0x1002) }, | ||
69 | /* 3Com Dual Band 802.11n USB Adapter */ | ||
70 | { USB_DEVICE(0x0cf3, 0x1010) }, | ||
71 | /* H3C Dual Band 802.11n USB Adapter */ | ||
72 | { USB_DEVICE(0x0cf3, 0x1011) }, | ||
73 | /* Cace Airpcap NX */ | ||
74 | { USB_DEVICE(0xcace, 0x0300) }, | ||
75 | /* D-Link DWA 160 A1 */ | ||
76 | { USB_DEVICE(0x07d1, 0x3c10) }, | ||
77 | /* D-Link DWA 160 A2 */ | ||
78 | { USB_DEVICE(0x07d1, 0x3a09) }, | ||
79 | /* Netgear WNA1000 */ | ||
80 | { USB_DEVICE(0x0846, 0x9040) }, | ||
81 | /* Netgear WNDA3100 */ | ||
82 | { USB_DEVICE(0x0846, 0x9010) }, | ||
83 | /* Netgear WN111 v2 */ | ||
84 | { USB_DEVICE(0x0846, 0x9001) }, | ||
85 | /* Zydas ZD1221 */ | ||
86 | { USB_DEVICE(0x0ace, 0x1221) }, | ||
87 | /* Proxim ORiNOCO 802.11n USB */ | ||
88 | { USB_DEVICE(0x1435, 0x0804) }, | ||
89 | /* WNC Generic 11n USB Dongle */ | ||
90 | { USB_DEVICE(0x1435, 0x0326) }, | ||
91 | /* ZyXEL NWD271N */ | ||
92 | { USB_DEVICE(0x0586, 0x3417) }, | ||
93 | /* Z-Com UB81 BG */ | ||
94 | { USB_DEVICE(0x0cde, 0x0023) }, | ||
95 | /* Z-Com UB82 ABG */ | ||
96 | { USB_DEVICE(0x0cde, 0x0026) }, | ||
97 | /* Sphairon Homelink 1202 */ | ||
98 | { USB_DEVICE(0x0cde, 0x0027) }, | ||
99 | /* Arcadyan WN7512 */ | ||
100 | { USB_DEVICE(0x083a, 0xf522) }, | ||
101 | /* Planex GWUS300 */ | ||
102 | { USB_DEVICE(0x2019, 0x5304) }, | ||
103 | /* IO-Data WNGDNUS2 */ | ||
104 | { USB_DEVICE(0x04bb, 0x093f) }, | ||
105 | /* AVM FRITZ!WLAN USB Stick N */ | ||
106 | { USB_DEVICE(0x057C, 0x8401) }, | ||
107 | /* NEC WL300NU-G */ | ||
108 | { USB_DEVICE(0x0409, 0x0249) }, | ||
109 | /* AVM FRITZ!WLAN USB Stick N 2.4 */ | ||
110 | { USB_DEVICE(0x057C, 0x8402), .driver_info = AR9170_REQ_FW1_ONLY }, | ||
111 | /* Qwest/Actiontec 802AIN Wireless N USB Network Adapter */ | ||
112 | { USB_DEVICE(0x1668, 0x1200) }, | ||
113 | |||
114 | /* terminate */ | ||
115 | {} | ||
116 | }; | ||
117 | MODULE_DEVICE_TABLE(usb, ar9170_usb_ids); | ||
118 | |||
119 | static void ar9170_usb_submit_urb(struct ar9170_usb *aru) | ||
120 | { | ||
121 | struct urb *urb; | ||
122 | unsigned long flags; | ||
123 | int err; | ||
124 | |||
125 | if (unlikely(!IS_STARTED(&aru->common))) | ||
126 | return ; | ||
127 | |||
128 | spin_lock_irqsave(&aru->tx_urb_lock, flags); | ||
129 | if (atomic_read(&aru->tx_submitted_urbs) >= AR9170_NUM_TX_URBS) { | ||
130 | spin_unlock_irqrestore(&aru->tx_urb_lock, flags); | ||
131 | return ; | ||
132 | } | ||
133 | atomic_inc(&aru->tx_submitted_urbs); | ||
134 | |||
135 | urb = usb_get_from_anchor(&aru->tx_pending); | ||
136 | if (!urb) { | ||
137 | atomic_dec(&aru->tx_submitted_urbs); | ||
138 | spin_unlock_irqrestore(&aru->tx_urb_lock, flags); | ||
139 | |||
140 | return ; | ||
141 | } | ||
142 | spin_unlock_irqrestore(&aru->tx_urb_lock, flags); | ||
143 | |||
144 | aru->tx_pending_urbs--; | ||
145 | usb_anchor_urb(urb, &aru->tx_submitted); | ||
146 | |||
147 | err = usb_submit_urb(urb, GFP_ATOMIC); | ||
148 | if (unlikely(err)) { | ||
149 | if (ar9170_nag_limiter(&aru->common)) | ||
150 | dev_err(&aru->udev->dev, "submit_urb failed (%d).\n", | ||
151 | err); | ||
152 | |||
153 | usb_unanchor_urb(urb); | ||
154 | atomic_dec(&aru->tx_submitted_urbs); | ||
155 | ar9170_tx_callback(&aru->common, urb->context); | ||
156 | } | ||
157 | |||
158 | usb_free_urb(urb); | ||
159 | } | ||
160 | |||
161 | static void ar9170_usb_tx_urb_complete_frame(struct urb *urb) | ||
162 | { | ||
163 | struct sk_buff *skb = urb->context; | ||
164 | struct ar9170_usb *aru = usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0)); | ||
165 | |||
166 | if (unlikely(!aru)) { | ||
167 | dev_kfree_skb_irq(skb); | ||
168 | return ; | ||
169 | } | ||
170 | |||
171 | atomic_dec(&aru->tx_submitted_urbs); | ||
172 | |||
173 | ar9170_tx_callback(&aru->common, skb); | ||
174 | |||
175 | ar9170_usb_submit_urb(aru); | ||
176 | } | ||
177 | |||
178 | static void ar9170_usb_tx_urb_complete(struct urb *urb) | ||
179 | { | ||
180 | } | ||
181 | |||
182 | static void ar9170_usb_irq_completed(struct urb *urb) | ||
183 | { | ||
184 | struct ar9170_usb *aru = urb->context; | ||
185 | |||
186 | switch (urb->status) { | ||
187 | /* everything is fine */ | ||
188 | case 0: | ||
189 | break; | ||
190 | |||
191 | /* disconnect */ | ||
192 | case -ENOENT: | ||
193 | case -ECONNRESET: | ||
194 | case -ENODEV: | ||
195 | case -ESHUTDOWN: | ||
196 | goto free; | ||
197 | |||
198 | default: | ||
199 | goto resubmit; | ||
200 | } | ||
201 | |||
202 | ar9170_handle_command_response(&aru->common, urb->transfer_buffer, | ||
203 | urb->actual_length); | ||
204 | |||
205 | resubmit: | ||
206 | usb_anchor_urb(urb, &aru->rx_submitted); | ||
207 | if (usb_submit_urb(urb, GFP_ATOMIC)) { | ||
208 | usb_unanchor_urb(urb); | ||
209 | goto free; | ||
210 | } | ||
211 | |||
212 | return; | ||
213 | |||
214 | free: | ||
215 | usb_free_coherent(aru->udev, 64, urb->transfer_buffer, urb->transfer_dma); | ||
216 | } | ||
217 | |||
218 | static void ar9170_usb_rx_completed(struct urb *urb) | ||
219 | { | ||
220 | struct sk_buff *skb = urb->context; | ||
221 | struct ar9170_usb *aru = usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0)); | ||
222 | int err; | ||
223 | |||
224 | if (!aru) | ||
225 | goto free; | ||
226 | |||
227 | switch (urb->status) { | ||
228 | /* everything is fine */ | ||
229 | case 0: | ||
230 | break; | ||
231 | |||
232 | /* disconnect */ | ||
233 | case -ENOENT: | ||
234 | case -ECONNRESET: | ||
235 | case -ENODEV: | ||
236 | case -ESHUTDOWN: | ||
237 | goto free; | ||
238 | |||
239 | default: | ||
240 | goto resubmit; | ||
241 | } | ||
242 | |||
243 | skb_put(skb, urb->actual_length); | ||
244 | ar9170_rx(&aru->common, skb); | ||
245 | |||
246 | resubmit: | ||
247 | skb_reset_tail_pointer(skb); | ||
248 | skb_trim(skb, 0); | ||
249 | |||
250 | usb_anchor_urb(urb, &aru->rx_submitted); | ||
251 | err = usb_submit_urb(urb, GFP_ATOMIC); | ||
252 | if (unlikely(err)) { | ||
253 | usb_unanchor_urb(urb); | ||
254 | goto free; | ||
255 | } | ||
256 | |||
257 | return ; | ||
258 | |||
259 | free: | ||
260 | dev_kfree_skb_irq(skb); | ||
261 | } | ||
262 | |||
263 | static int ar9170_usb_prep_rx_urb(struct ar9170_usb *aru, | ||
264 | struct urb *urb, gfp_t gfp) | ||
265 | { | ||
266 | struct sk_buff *skb; | ||
267 | |||
268 | skb = __dev_alloc_skb(AR9170_MAX_RX_BUFFER_SIZE + 32, gfp); | ||
269 | if (!skb) | ||
270 | return -ENOMEM; | ||
271 | |||
272 | /* reserve some space for mac80211's radiotap */ | ||
273 | skb_reserve(skb, 32); | ||
274 | |||
275 | usb_fill_bulk_urb(urb, aru->udev, | ||
276 | usb_rcvbulkpipe(aru->udev, AR9170_EP_RX), | ||
277 | skb->data, min(skb_tailroom(skb), | ||
278 | AR9170_MAX_RX_BUFFER_SIZE), | ||
279 | ar9170_usb_rx_completed, skb); | ||
280 | |||
281 | return 0; | ||
282 | } | ||
283 | |||
284 | static int ar9170_usb_alloc_rx_irq_urb(struct ar9170_usb *aru) | ||
285 | { | ||
286 | struct urb *urb = NULL; | ||
287 | void *ibuf; | ||
288 | int err = -ENOMEM; | ||
289 | |||
290 | /* initialize interrupt endpoint */ | ||
291 | urb = usb_alloc_urb(0, GFP_KERNEL); | ||
292 | if (!urb) | ||
293 | goto out; | ||
294 | |||
295 | ibuf = usb_alloc_coherent(aru->udev, 64, GFP_KERNEL, &urb->transfer_dma); | ||
296 | if (!ibuf) | ||
297 | goto out; | ||
298 | |||
299 | usb_fill_int_urb(urb, aru->udev, | ||
300 | usb_rcvintpipe(aru->udev, AR9170_EP_IRQ), ibuf, | ||
301 | 64, ar9170_usb_irq_completed, aru, 1); | ||
302 | urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; | ||
303 | |||
304 | usb_anchor_urb(urb, &aru->rx_submitted); | ||
305 | err = usb_submit_urb(urb, GFP_KERNEL); | ||
306 | if (err) { | ||
307 | usb_unanchor_urb(urb); | ||
308 | usb_free_coherent(aru->udev, 64, urb->transfer_buffer, | ||
309 | urb->transfer_dma); | ||
310 | } | ||
311 | |||
312 | out: | ||
313 | usb_free_urb(urb); | ||
314 | return err; | ||
315 | } | ||
316 | |||
317 | static int ar9170_usb_alloc_rx_bulk_urbs(struct ar9170_usb *aru) | ||
318 | { | ||
319 | struct urb *urb; | ||
320 | int i; | ||
321 | int err = -EINVAL; | ||
322 | |||
323 | for (i = 0; i < AR9170_NUM_RX_URBS; i++) { | ||
324 | err = -ENOMEM; | ||
325 | urb = usb_alloc_urb(0, GFP_KERNEL); | ||
326 | if (!urb) | ||
327 | goto err_out; | ||
328 | |||
329 | err = ar9170_usb_prep_rx_urb(aru, urb, GFP_KERNEL); | ||
330 | if (err) { | ||
331 | usb_free_urb(urb); | ||
332 | goto err_out; | ||
333 | } | ||
334 | |||
335 | usb_anchor_urb(urb, &aru->rx_submitted); | ||
336 | err = usb_submit_urb(urb, GFP_KERNEL); | ||
337 | if (err) { | ||
338 | usb_unanchor_urb(urb); | ||
339 | dev_kfree_skb_any((void *) urb->transfer_buffer); | ||
340 | usb_free_urb(urb); | ||
341 | goto err_out; | ||
342 | } | ||
343 | usb_free_urb(urb); | ||
344 | } | ||
345 | |||
346 | /* the device now waiting for a firmware. */ | ||
347 | aru->common.state = AR9170_IDLE; | ||
348 | return 0; | ||
349 | |||
350 | err_out: | ||
351 | |||
352 | usb_kill_anchored_urbs(&aru->rx_submitted); | ||
353 | return err; | ||
354 | } | ||
355 | |||
356 | static int ar9170_usb_flush(struct ar9170 *ar) | ||
357 | { | ||
358 | struct ar9170_usb *aru = (void *) ar; | ||
359 | struct urb *urb; | ||
360 | int ret, err = 0; | ||
361 | |||
362 | if (IS_STARTED(ar)) | ||
363 | aru->common.state = AR9170_IDLE; | ||
364 | |||
365 | usb_wait_anchor_empty_timeout(&aru->tx_pending, | ||
366 | msecs_to_jiffies(800)); | ||
367 | while ((urb = usb_get_from_anchor(&aru->tx_pending))) { | ||
368 | ar9170_tx_callback(&aru->common, (void *) urb->context); | ||
369 | usb_free_urb(urb); | ||
370 | } | ||
371 | |||
372 | /* lets wait a while until the tx - queues are dried out */ | ||
373 | ret = usb_wait_anchor_empty_timeout(&aru->tx_submitted, | ||
374 | msecs_to_jiffies(100)); | ||
375 | if (ret == 0) | ||
376 | err = -ETIMEDOUT; | ||
377 | |||
378 | usb_kill_anchored_urbs(&aru->tx_submitted); | ||
379 | |||
380 | if (IS_ACCEPTING_CMD(ar)) | ||
381 | aru->common.state = AR9170_STARTED; | ||
382 | |||
383 | return err; | ||
384 | } | ||
385 | |||
386 | static void ar9170_usb_cancel_urbs(struct ar9170_usb *aru) | ||
387 | { | ||
388 | int err; | ||
389 | |||
390 | aru->common.state = AR9170_UNKNOWN_STATE; | ||
391 | |||
392 | err = ar9170_usb_flush(&aru->common); | ||
393 | if (err) | ||
394 | dev_err(&aru->udev->dev, "stuck tx urbs!\n"); | ||
395 | |||
396 | usb_poison_anchored_urbs(&aru->tx_submitted); | ||
397 | usb_poison_anchored_urbs(&aru->rx_submitted); | ||
398 | } | ||
399 | |||
400 | static int ar9170_usb_exec_cmd(struct ar9170 *ar, enum ar9170_cmd cmd, | ||
401 | unsigned int plen, void *payload, | ||
402 | unsigned int outlen, void *out) | ||
403 | { | ||
404 | struct ar9170_usb *aru = (void *) ar; | ||
405 | struct urb *urb = NULL; | ||
406 | unsigned long flags; | ||
407 | int err = -ENOMEM; | ||
408 | |||
409 | if (unlikely(!IS_ACCEPTING_CMD(ar))) | ||
410 | return -EPERM; | ||
411 | |||
412 | if (WARN_ON(plen > AR9170_MAX_CMD_LEN - 4)) | ||
413 | return -EINVAL; | ||
414 | |||
415 | urb = usb_alloc_urb(0, GFP_ATOMIC); | ||
416 | if (unlikely(!urb)) | ||
417 | goto err_free; | ||
418 | |||
419 | ar->cmdbuf[0] = cpu_to_le32(plen); | ||
420 | ar->cmdbuf[0] |= cpu_to_le32(cmd << 8); | ||
421 | /* writing multiple regs fills this buffer already */ | ||
422 | if (plen && payload != (u8 *)(&ar->cmdbuf[1])) | ||
423 | memcpy(&ar->cmdbuf[1], payload, plen); | ||
424 | |||
425 | spin_lock_irqsave(&aru->common.cmdlock, flags); | ||
426 | aru->readbuf = (u8 *)out; | ||
427 | aru->readlen = outlen; | ||
428 | spin_unlock_irqrestore(&aru->common.cmdlock, flags); | ||
429 | |||
430 | usb_fill_int_urb(urb, aru->udev, | ||
431 | usb_sndintpipe(aru->udev, AR9170_EP_CMD), | ||
432 | aru->common.cmdbuf, plen + 4, | ||
433 | ar9170_usb_tx_urb_complete, NULL, 1); | ||
434 | |||
435 | usb_anchor_urb(urb, &aru->tx_submitted); | ||
436 | err = usb_submit_urb(urb, GFP_ATOMIC); | ||
437 | if (unlikely(err)) { | ||
438 | usb_unanchor_urb(urb); | ||
439 | usb_free_urb(urb); | ||
440 | goto err_unbuf; | ||
441 | } | ||
442 | usb_free_urb(urb); | ||
443 | |||
444 | err = wait_for_completion_timeout(&aru->cmd_wait, HZ); | ||
445 | if (err == 0) { | ||
446 | err = -ETIMEDOUT; | ||
447 | goto err_unbuf; | ||
448 | } | ||
449 | |||
450 | if (aru->readlen != outlen) { | ||
451 | err = -EMSGSIZE; | ||
452 | goto err_unbuf; | ||
453 | } | ||
454 | |||
455 | return 0; | ||
456 | |||
457 | err_unbuf: | ||
458 | /* Maybe the device was removed in the second we were waiting? */ | ||
459 | if (IS_STARTED(ar)) { | ||
460 | dev_err(&aru->udev->dev, "no command feedback " | ||
461 | "received (%d).\n", err); | ||
462 | |||
463 | /* provide some maybe useful debug information */ | ||
464 | print_hex_dump_bytes("ar9170 cmd: ", DUMP_PREFIX_NONE, | ||
465 | aru->common.cmdbuf, plen + 4); | ||
466 | dump_stack(); | ||
467 | } | ||
468 | |||
469 | /* invalidate to avoid completing the next prematurely */ | ||
470 | spin_lock_irqsave(&aru->common.cmdlock, flags); | ||
471 | aru->readbuf = NULL; | ||
472 | aru->readlen = 0; | ||
473 | spin_unlock_irqrestore(&aru->common.cmdlock, flags); | ||
474 | |||
475 | err_free: | ||
476 | |||
477 | return err; | ||
478 | } | ||
479 | |||
480 | static int ar9170_usb_tx(struct ar9170 *ar, struct sk_buff *skb) | ||
481 | { | ||
482 | struct ar9170_usb *aru = (struct ar9170_usb *) ar; | ||
483 | struct urb *urb; | ||
484 | |||
485 | if (unlikely(!IS_STARTED(ar))) { | ||
486 | /* Seriously, what were you drink... err... thinking!? */ | ||
487 | return -EPERM; | ||
488 | } | ||
489 | |||
490 | urb = usb_alloc_urb(0, GFP_ATOMIC); | ||
491 | if (unlikely(!urb)) | ||
492 | return -ENOMEM; | ||
493 | |||
494 | usb_fill_bulk_urb(urb, aru->udev, | ||
495 | usb_sndbulkpipe(aru->udev, AR9170_EP_TX), | ||
496 | skb->data, skb->len, | ||
497 | ar9170_usb_tx_urb_complete_frame, skb); | ||
498 | urb->transfer_flags |= URB_ZERO_PACKET; | ||
499 | |||
500 | usb_anchor_urb(urb, &aru->tx_pending); | ||
501 | aru->tx_pending_urbs++; | ||
502 | |||
503 | usb_free_urb(urb); | ||
504 | |||
505 | ar9170_usb_submit_urb(aru); | ||
506 | return 0; | ||
507 | } | ||
508 | |||
509 | static void ar9170_usb_callback_cmd(struct ar9170 *ar, u32 len , void *buffer) | ||
510 | { | ||
511 | struct ar9170_usb *aru = (void *) ar; | ||
512 | unsigned long flags; | ||
513 | u32 in, out; | ||
514 | |||
515 | if (unlikely(!buffer)) | ||
516 | return ; | ||
517 | |||
518 | in = le32_to_cpup((__le32 *)buffer); | ||
519 | out = le32_to_cpu(ar->cmdbuf[0]); | ||
520 | |||
521 | /* mask off length byte */ | ||
522 | out &= ~0xFF; | ||
523 | |||
524 | if (aru->readlen >= 0) { | ||
525 | /* add expected length */ | ||
526 | out |= aru->readlen; | ||
527 | } else { | ||
528 | /* add obtained length */ | ||
529 | out |= in & 0xFF; | ||
530 | } | ||
531 | |||
532 | /* | ||
533 | * Some commands (e.g: AR9170_CMD_FREQUENCY) have a variable response | ||
534 | * length and we cannot predict the correct length in advance. | ||
535 | * So we only check if we provided enough space for the data. | ||
536 | */ | ||
537 | if (unlikely(out < in)) { | ||
538 | dev_warn(&aru->udev->dev, "received invalid command response " | ||
539 | "got %d bytes, instead of %d bytes " | ||
540 | "and the resp length is %d bytes\n", | ||
541 | in, out, len); | ||
542 | print_hex_dump_bytes("ar9170 invalid resp: ", | ||
543 | DUMP_PREFIX_OFFSET, buffer, len); | ||
544 | /* | ||
545 | * Do not complete, then the command times out, | ||
546 | * and we get a stack trace from there. | ||
547 | */ | ||
548 | return ; | ||
549 | } | ||
550 | |||
551 | spin_lock_irqsave(&aru->common.cmdlock, flags); | ||
552 | if (aru->readbuf && len > 0) { | ||
553 | memcpy(aru->readbuf, buffer + 4, len - 4); | ||
554 | aru->readbuf = NULL; | ||
555 | } | ||
556 | complete(&aru->cmd_wait); | ||
557 | spin_unlock_irqrestore(&aru->common.cmdlock, flags); | ||
558 | } | ||
559 | |||
560 | static int ar9170_usb_upload(struct ar9170_usb *aru, const void *data, | ||
561 | size_t len, u32 addr, bool complete) | ||
562 | { | ||
563 | int transfer, err; | ||
564 | u8 *buf = kmalloc(4096, GFP_KERNEL); | ||
565 | |||
566 | if (!buf) | ||
567 | return -ENOMEM; | ||
568 | |||
569 | while (len) { | ||
570 | transfer = min_t(int, len, 4096); | ||
571 | memcpy(buf, data, transfer); | ||
572 | |||
573 | err = usb_control_msg(aru->udev, usb_sndctrlpipe(aru->udev, 0), | ||
574 | 0x30 /* FW DL */, 0x40 | USB_DIR_OUT, | ||
575 | addr >> 8, 0, buf, transfer, 1000); | ||
576 | |||
577 | if (err < 0) { | ||
578 | kfree(buf); | ||
579 | return err; | ||
580 | } | ||
581 | |||
582 | len -= transfer; | ||
583 | data += transfer; | ||
584 | addr += transfer; | ||
585 | } | ||
586 | kfree(buf); | ||
587 | |||
588 | if (complete) { | ||
589 | err = usb_control_msg(aru->udev, usb_sndctrlpipe(aru->udev, 0), | ||
590 | 0x31 /* FW DL COMPLETE */, | ||
591 | 0x40 | USB_DIR_OUT, 0, 0, NULL, 0, 5000); | ||
592 | } | ||
593 | |||
594 | return 0; | ||
595 | } | ||
596 | |||
597 | static int ar9170_usb_reset(struct ar9170_usb *aru) | ||
598 | { | ||
599 | int ret, lock = (aru->intf->condition != USB_INTERFACE_BINDING); | ||
600 | |||
601 | if (lock) { | ||
602 | ret = usb_lock_device_for_reset(aru->udev, aru->intf); | ||
603 | if (ret < 0) { | ||
604 | dev_err(&aru->udev->dev, "unable to lock device " | ||
605 | "for reset (%d).\n", ret); | ||
606 | return ret; | ||
607 | } | ||
608 | } | ||
609 | |||
610 | ret = usb_reset_device(aru->udev); | ||
611 | if (lock) | ||
612 | usb_unlock_device(aru->udev); | ||
613 | |||
614 | /* let it rest - for a second - */ | ||
615 | msleep(1000); | ||
616 | |||
617 | return ret; | ||
618 | } | ||
619 | |||
620 | static int ar9170_usb_upload_firmware(struct ar9170_usb *aru) | ||
621 | { | ||
622 | int err; | ||
623 | |||
624 | if (!aru->init_values) | ||
625 | goto upload_fw_start; | ||
626 | |||
627 | /* First, upload initial values to device RAM */ | ||
628 | err = ar9170_usb_upload(aru, aru->init_values->data, | ||
629 | aru->init_values->size, 0x102800, false); | ||
630 | if (err) { | ||
631 | dev_err(&aru->udev->dev, "firmware part 1 " | ||
632 | "upload failed (%d).\n", err); | ||
633 | return err; | ||
634 | } | ||
635 | |||
636 | upload_fw_start: | ||
637 | |||
638 | /* Then, upload the firmware itself and start it */ | ||
639 | return ar9170_usb_upload(aru, aru->firmware->data, aru->firmware->size, | ||
640 | 0x200000, true); | ||
641 | } | ||
642 | |||
643 | static int ar9170_usb_init_transport(struct ar9170_usb *aru) | ||
644 | { | ||
645 | struct ar9170 *ar = (void *) &aru->common; | ||
646 | int err; | ||
647 | |||
648 | ar9170_regwrite_begin(ar); | ||
649 | |||
650 | /* Set USB Rx stream mode MAX packet number to 2 */ | ||
651 | ar9170_regwrite(AR9170_USB_REG_MAX_AGG_UPLOAD, 0x4); | ||
652 | |||
653 | /* Set USB Rx stream mode timeout to 10us */ | ||
654 | ar9170_regwrite(AR9170_USB_REG_UPLOAD_TIME_CTL, 0x80); | ||
655 | |||
656 | ar9170_regwrite_finish(); | ||
657 | |||
658 | err = ar9170_regwrite_result(); | ||
659 | if (err) | ||
660 | dev_err(&aru->udev->dev, "USB setup failed (%d).\n", err); | ||
661 | |||
662 | return err; | ||
663 | } | ||
664 | |||
665 | static void ar9170_usb_stop(struct ar9170 *ar) | ||
666 | { | ||
667 | struct ar9170_usb *aru = (void *) ar; | ||
668 | int ret; | ||
669 | |||
670 | if (IS_ACCEPTING_CMD(ar)) | ||
671 | aru->common.state = AR9170_STOPPED; | ||
672 | |||
673 | ret = ar9170_usb_flush(ar); | ||
674 | if (ret) | ||
675 | dev_err(&aru->udev->dev, "kill pending tx urbs.\n"); | ||
676 | |||
677 | usb_poison_anchored_urbs(&aru->tx_submitted); | ||
678 | |||
679 | /* | ||
680 | * Note: | ||
681 | * So far we freed all tx urbs, but we won't dare to touch any rx urbs. | ||
682 | * Else we would end up with a unresponsive device... | ||
683 | */ | ||
684 | } | ||
685 | |||
686 | static int ar9170_usb_open(struct ar9170 *ar) | ||
687 | { | ||
688 | struct ar9170_usb *aru = (void *) ar; | ||
689 | int err; | ||
690 | |||
691 | usb_unpoison_anchored_urbs(&aru->tx_submitted); | ||
692 | err = ar9170_usb_init_transport(aru); | ||
693 | if (err) { | ||
694 | usb_poison_anchored_urbs(&aru->tx_submitted); | ||
695 | return err; | ||
696 | } | ||
697 | |||
698 | aru->common.state = AR9170_IDLE; | ||
699 | return 0; | ||
700 | } | ||
701 | |||
702 | static int ar9170_usb_init_device(struct ar9170_usb *aru) | ||
703 | { | ||
704 | int err; | ||
705 | |||
706 | err = ar9170_usb_alloc_rx_irq_urb(aru); | ||
707 | if (err) | ||
708 | goto err_out; | ||
709 | |||
710 | err = ar9170_usb_alloc_rx_bulk_urbs(aru); | ||
711 | if (err) | ||
712 | goto err_unrx; | ||
713 | |||
714 | err = ar9170_usb_upload_firmware(aru); | ||
715 | if (err) { | ||
716 | err = ar9170_echo_test(&aru->common, 0x60d43110); | ||
717 | if (err) { | ||
718 | /* force user invention, by disabling the device */ | ||
719 | err = usb_driver_set_configuration(aru->udev, -1); | ||
720 | dev_err(&aru->udev->dev, "device is in a bad state. " | ||
721 | "please reconnect it!\n"); | ||
722 | goto err_unrx; | ||
723 | } | ||
724 | } | ||
725 | |||
726 | return 0; | ||
727 | |||
728 | err_unrx: | ||
729 | ar9170_usb_cancel_urbs(aru); | ||
730 | |||
731 | err_out: | ||
732 | return err; | ||
733 | } | ||
734 | |||
735 | static void ar9170_usb_firmware_failed(struct ar9170_usb *aru) | ||
736 | { | ||
737 | struct device *parent = aru->udev->dev.parent; | ||
738 | struct usb_device *udev; | ||
739 | |||
740 | /* | ||
741 | * Store a copy of the usb_device pointer locally. | ||
742 | * This is because device_release_driver initiates | ||
743 | * ar9170_usb_disconnect, which in turn frees our | ||
744 | * driver context (aru). | ||
745 | */ | ||
746 | udev = aru->udev; | ||
747 | |||
748 | complete(&aru->firmware_loading_complete); | ||
749 | |||
750 | /* unbind anything failed */ | ||
751 | if (parent) | ||
752 | device_lock(parent); | ||
753 | |||
754 | device_release_driver(&udev->dev); | ||
755 | if (parent) | ||
756 | device_unlock(parent); | ||
757 | |||
758 | usb_put_dev(udev); | ||
759 | } | ||
760 | |||
761 | static void ar9170_usb_firmware_finish(const struct firmware *fw, void *context) | ||
762 | { | ||
763 | struct ar9170_usb *aru = context; | ||
764 | int err; | ||
765 | |||
766 | aru->firmware = fw; | ||
767 | |||
768 | if (!fw) { | ||
769 | dev_err(&aru->udev->dev, "firmware file not found.\n"); | ||
770 | goto err_freefw; | ||
771 | } | ||
772 | |||
773 | err = ar9170_usb_init_device(aru); | ||
774 | if (err) | ||
775 | goto err_freefw; | ||
776 | |||
777 | err = ar9170_usb_open(&aru->common); | ||
778 | if (err) | ||
779 | goto err_unrx; | ||
780 | |||
781 | err = ar9170_register(&aru->common, &aru->udev->dev); | ||
782 | |||
783 | ar9170_usb_stop(&aru->common); | ||
784 | if (err) | ||
785 | goto err_unrx; | ||
786 | |||
787 | complete(&aru->firmware_loading_complete); | ||
788 | usb_put_dev(aru->udev); | ||
789 | return; | ||
790 | |||
791 | err_unrx: | ||
792 | ar9170_usb_cancel_urbs(aru); | ||
793 | |||
794 | err_freefw: | ||
795 | ar9170_usb_firmware_failed(aru); | ||
796 | } | ||
797 | |||
798 | static void ar9170_usb_firmware_inits(const struct firmware *fw, | ||
799 | void *context) | ||
800 | { | ||
801 | struct ar9170_usb *aru = context; | ||
802 | int err; | ||
803 | |||
804 | if (!fw) { | ||
805 | dev_err(&aru->udev->dev, "file with init values not found.\n"); | ||
806 | ar9170_usb_firmware_failed(aru); | ||
807 | return; | ||
808 | } | ||
809 | |||
810 | aru->init_values = fw; | ||
811 | |||
812 | /* ok so we have the init values -- get code for two-stage */ | ||
813 | |||
814 | err = request_firmware_nowait(THIS_MODULE, 1, "ar9170-2.fw", | ||
815 | &aru->udev->dev, GFP_KERNEL, aru, | ||
816 | ar9170_usb_firmware_finish); | ||
817 | if (err) | ||
818 | ar9170_usb_firmware_failed(aru); | ||
819 | } | ||
820 | |||
821 | static void ar9170_usb_firmware_step2(const struct firmware *fw, void *context) | ||
822 | { | ||
823 | struct ar9170_usb *aru = context; | ||
824 | int err; | ||
825 | |||
826 | if (fw) { | ||
827 | ar9170_usb_firmware_finish(fw, context); | ||
828 | return; | ||
829 | } | ||
830 | |||
831 | if (aru->req_one_stage_fw) { | ||
832 | dev_err(&aru->udev->dev, "ar9170.fw firmware file " | ||
833 | "not found and is required for this device\n"); | ||
834 | ar9170_usb_firmware_failed(aru); | ||
835 | return; | ||
836 | } | ||
837 | |||
838 | dev_err(&aru->udev->dev, "ar9170.fw firmware file " | ||
839 | "not found, trying old firmware...\n"); | ||
840 | |||
841 | err = request_firmware_nowait(THIS_MODULE, 1, "ar9170-1.fw", | ||
842 | &aru->udev->dev, GFP_KERNEL, aru, | ||
843 | ar9170_usb_firmware_inits); | ||
844 | if (err) | ||
845 | ar9170_usb_firmware_failed(aru); | ||
846 | } | ||
847 | |||
848 | static bool ar9170_requires_one_stage(const struct usb_device_id *id) | ||
849 | { | ||
850 | if (!id->driver_info) | ||
851 | return false; | ||
852 | if (id->driver_info == AR9170_REQ_FW1_ONLY) | ||
853 | return true; | ||
854 | return false; | ||
855 | } | ||
856 | |||
857 | static int ar9170_usb_probe(struct usb_interface *intf, | ||
858 | const struct usb_device_id *id) | ||
859 | { | ||
860 | struct ar9170_usb *aru; | ||
861 | struct ar9170 *ar; | ||
862 | struct usb_device *udev; | ||
863 | int err; | ||
864 | |||
865 | aru = ar9170_alloc(sizeof(*aru)); | ||
866 | if (IS_ERR(aru)) { | ||
867 | err = PTR_ERR(aru); | ||
868 | goto out; | ||
869 | } | ||
870 | |||
871 | udev = interface_to_usbdev(intf); | ||
872 | usb_get_dev(udev); | ||
873 | aru->udev = udev; | ||
874 | aru->intf = intf; | ||
875 | ar = &aru->common; | ||
876 | |||
877 | aru->req_one_stage_fw = ar9170_requires_one_stage(id); | ||
878 | |||
879 | usb_set_intfdata(intf, aru); | ||
880 | SET_IEEE80211_DEV(ar->hw, &intf->dev); | ||
881 | |||
882 | init_usb_anchor(&aru->rx_submitted); | ||
883 | init_usb_anchor(&aru->tx_pending); | ||
884 | init_usb_anchor(&aru->tx_submitted); | ||
885 | init_completion(&aru->cmd_wait); | ||
886 | init_completion(&aru->firmware_loading_complete); | ||
887 | spin_lock_init(&aru->tx_urb_lock); | ||
888 | |||
889 | aru->tx_pending_urbs = 0; | ||
890 | atomic_set(&aru->tx_submitted_urbs, 0); | ||
891 | |||
892 | aru->common.stop = ar9170_usb_stop; | ||
893 | aru->common.flush = ar9170_usb_flush; | ||
894 | aru->common.open = ar9170_usb_open; | ||
895 | aru->common.tx = ar9170_usb_tx; | ||
896 | aru->common.exec_cmd = ar9170_usb_exec_cmd; | ||
897 | aru->common.callback_cmd = ar9170_usb_callback_cmd; | ||
898 | |||
899 | #ifdef CONFIG_PM | ||
900 | udev->reset_resume = 1; | ||
901 | #endif /* CONFIG_PM */ | ||
902 | err = ar9170_usb_reset(aru); | ||
903 | if (err) | ||
904 | goto err_freehw; | ||
905 | |||
906 | usb_get_dev(aru->udev); | ||
907 | return request_firmware_nowait(THIS_MODULE, 1, "ar9170.fw", | ||
908 | &aru->udev->dev, GFP_KERNEL, aru, | ||
909 | ar9170_usb_firmware_step2); | ||
910 | err_freehw: | ||
911 | usb_set_intfdata(intf, NULL); | ||
912 | usb_put_dev(udev); | ||
913 | ieee80211_free_hw(ar->hw); | ||
914 | out: | ||
915 | return err; | ||
916 | } | ||
917 | |||
918 | static void ar9170_usb_disconnect(struct usb_interface *intf) | ||
919 | { | ||
920 | struct ar9170_usb *aru = usb_get_intfdata(intf); | ||
921 | |||
922 | if (!aru) | ||
923 | return; | ||
924 | |||
925 | aru->common.state = AR9170_IDLE; | ||
926 | |||
927 | wait_for_completion(&aru->firmware_loading_complete); | ||
928 | |||
929 | ar9170_unregister(&aru->common); | ||
930 | ar9170_usb_cancel_urbs(aru); | ||
931 | |||
932 | usb_put_dev(aru->udev); | ||
933 | usb_set_intfdata(intf, NULL); | ||
934 | ieee80211_free_hw(aru->common.hw); | ||
935 | |||
936 | release_firmware(aru->init_values); | ||
937 | release_firmware(aru->firmware); | ||
938 | } | ||
939 | |||
940 | #ifdef CONFIG_PM | ||
941 | static int ar9170_suspend(struct usb_interface *intf, | ||
942 | pm_message_t message) | ||
943 | { | ||
944 | struct ar9170_usb *aru = usb_get_intfdata(intf); | ||
945 | |||
946 | if (!aru) | ||
947 | return -ENODEV; | ||
948 | |||
949 | aru->common.state = AR9170_IDLE; | ||
950 | ar9170_usb_cancel_urbs(aru); | ||
951 | |||
952 | return 0; | ||
953 | } | ||
954 | |||
955 | static int ar9170_resume(struct usb_interface *intf) | ||
956 | { | ||
957 | struct ar9170_usb *aru = usb_get_intfdata(intf); | ||
958 | int err; | ||
959 | |||
960 | if (!aru) | ||
961 | return -ENODEV; | ||
962 | |||
963 | usb_unpoison_anchored_urbs(&aru->rx_submitted); | ||
964 | usb_unpoison_anchored_urbs(&aru->tx_submitted); | ||
965 | |||
966 | err = ar9170_usb_init_device(aru); | ||
967 | if (err) | ||
968 | goto err_unrx; | ||
969 | |||
970 | err = ar9170_usb_open(&aru->common); | ||
971 | if (err) | ||
972 | goto err_unrx; | ||
973 | |||
974 | return 0; | ||
975 | |||
976 | err_unrx: | ||
977 | aru->common.state = AR9170_IDLE; | ||
978 | ar9170_usb_cancel_urbs(aru); | ||
979 | |||
980 | return err; | ||
981 | } | ||
982 | #endif /* CONFIG_PM */ | ||
983 | |||
984 | static struct usb_driver ar9170_driver = { | ||
985 | .name = "ar9170usb", | ||
986 | .probe = ar9170_usb_probe, | ||
987 | .disconnect = ar9170_usb_disconnect, | ||
988 | .id_table = ar9170_usb_ids, | ||
989 | .soft_unbind = 1, | ||
990 | #ifdef CONFIG_PM | ||
991 | .suspend = ar9170_suspend, | ||
992 | .resume = ar9170_resume, | ||
993 | .reset_resume = ar9170_resume, | ||
994 | #endif /* CONFIG_PM */ | ||
995 | }; | ||
996 | |||
997 | static int __init ar9170_init(void) | ||
998 | { | ||
999 | return usb_register(&ar9170_driver); | ||
1000 | } | ||
1001 | |||
1002 | static void __exit ar9170_exit(void) | ||
1003 | { | ||
1004 | usb_deregister(&ar9170_driver); | ||
1005 | } | ||
1006 | |||
1007 | module_init(ar9170_init); | ||
1008 | module_exit(ar9170_exit); | ||
diff --git a/drivers/net/wireless/ath/ar9170/usb.h b/drivers/net/wireless/ath/ar9170/usb.h deleted file mode 100644 index 919b06046eb3..000000000000 --- a/drivers/net/wireless/ath/ar9170/usb.h +++ /dev/null | |||
@@ -1,82 +0,0 @@ | |||
1 | /* | ||
2 | * Atheros AR9170 USB driver | ||
3 | * | ||
4 | * Driver specific definitions | ||
5 | * | ||
6 | * Copyright 2008, Johannes Berg <johannes@sipsolutions.net> | ||
7 | * Copyright 2009, Christian Lamparter <chunkeey@web.de> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; see the file COPYING. If not, see | ||
21 | * http://www.gnu.org/licenses/. | ||
22 | * | ||
23 | * This file incorporates work covered by the following copyright and | ||
24 | * permission notice: | ||
25 | * Copyright (c) 2007-2008 Atheros Communications, Inc. | ||
26 | * | ||
27 | * Permission to use, copy, modify, and/or distribute this software for any | ||
28 | * purpose with or without fee is hereby granted, provided that the above | ||
29 | * copyright notice and this permission notice appear in all copies. | ||
30 | * | ||
31 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
32 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
33 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
34 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
35 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
36 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
37 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
38 | */ | ||
39 | #ifndef __USB_H | ||
40 | #define __USB_H | ||
41 | |||
42 | #include <linux/usb.h> | ||
43 | #include <linux/completion.h> | ||
44 | #include <linux/spinlock.h> | ||
45 | #include <linux/leds.h> | ||
46 | #include <net/cfg80211.h> | ||
47 | #include <net/mac80211.h> | ||
48 | #include <linux/firmware.h> | ||
49 | #include "eeprom.h" | ||
50 | #include "hw.h" | ||
51 | #include "ar9170.h" | ||
52 | |||
53 | #define AR9170_NUM_RX_URBS 16 | ||
54 | #define AR9170_NUM_TX_URBS 8 | ||
55 | |||
56 | struct firmware; | ||
57 | |||
58 | struct ar9170_usb { | ||
59 | struct ar9170 common; | ||
60 | struct usb_device *udev; | ||
61 | struct usb_interface *intf; | ||
62 | |||
63 | struct usb_anchor rx_submitted; | ||
64 | struct usb_anchor tx_pending; | ||
65 | struct usb_anchor tx_submitted; | ||
66 | |||
67 | bool req_one_stage_fw; | ||
68 | |||
69 | spinlock_t tx_urb_lock; | ||
70 | atomic_t tx_submitted_urbs; | ||
71 | unsigned int tx_pending_urbs; | ||
72 | |||
73 | struct completion cmd_wait; | ||
74 | struct completion firmware_loading_complete; | ||
75 | int readlen; | ||
76 | u8 *readbuf; | ||
77 | |||
78 | const struct firmware *init_values; | ||
79 | const struct firmware *firmware; | ||
80 | }; | ||
81 | |||
82 | #endif /* __USB_H */ | ||
diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index a6c6a466000f..6d7105b7e8f1 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h | |||
@@ -119,6 +119,7 @@ struct ath_ops { | |||
119 | void (*write)(void *, u32 val, u32 reg_offset); | 119 | void (*write)(void *, u32 val, u32 reg_offset); |
120 | void (*enable_write_buffer)(void *); | 120 | void (*enable_write_buffer)(void *); |
121 | void (*write_flush) (void *); | 121 | void (*write_flush) (void *); |
122 | u32 (*rmw)(void *, u32 reg_offset, u32 set, u32 clr); | ||
122 | }; | 123 | }; |
123 | 124 | ||
124 | struct ath_common; | 125 | struct ath_common; |
diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c index 106c0b06cf55..4bf9dab4f2b3 100644 --- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c | |||
@@ -44,6 +44,34 @@ static const int m1ThreshExt_off = 127; | |||
44 | static const int m2ThreshExt_off = 127; | 44 | static const int m2ThreshExt_off = 127; |
45 | 45 | ||
46 | 46 | ||
47 | static void ar5008_rf_bank_setup(u32 *bank, struct ar5416IniArray *array, | ||
48 | int col) | ||
49 | { | ||
50 | int i; | ||
51 | |||
52 | for (i = 0; i < array->ia_rows; i++) | ||
53 | bank[i] = INI_RA(array, i, col); | ||
54 | } | ||
55 | |||
56 | |||
57 | #define REG_WRITE_RF_ARRAY(iniarray, regData, regWr) \ | ||
58 | ar5008_write_rf_array(ah, iniarray, regData, &(regWr)) | ||
59 | |||
60 | static void ar5008_write_rf_array(struct ath_hw *ah, struct ar5416IniArray *array, | ||
61 | u32 *data, unsigned int *writecnt) | ||
62 | { | ||
63 | int r; | ||
64 | |||
65 | ENABLE_REGWRITE_BUFFER(ah); | ||
66 | |||
67 | for (r = 0; r < array->ia_rows; r++) { | ||
68 | REG_WRITE(ah, INI_RA(array, r, 0), data[r]); | ||
69 | DO_DELAY(*writecnt); | ||
70 | } | ||
71 | |||
72 | REGWRITE_BUFFER_FLUSH(ah); | ||
73 | } | ||
74 | |||
47 | /** | 75 | /** |
48 | * ar5008_hw_phy_modify_rx_buffer() - perform analog swizzling of parameters | 76 | * ar5008_hw_phy_modify_rx_buffer() - perform analog swizzling of parameters |
49 | * @rfbuf: | 77 | * @rfbuf: |
@@ -530,16 +558,16 @@ static bool ar5008_hw_set_rf_regs(struct ath_hw *ah, | |||
530 | eepMinorRev = ah->eep_ops->get_eeprom(ah, EEP_MINOR_REV); | 558 | eepMinorRev = ah->eep_ops->get_eeprom(ah, EEP_MINOR_REV); |
531 | 559 | ||
532 | /* Setup Bank 0 Write */ | 560 | /* Setup Bank 0 Write */ |
533 | RF_BANK_SETUP(ah->analogBank0Data, &ah->iniBank0, 1); | 561 | ar5008_rf_bank_setup(ah->analogBank0Data, &ah->iniBank0, 1); |
534 | 562 | ||
535 | /* Setup Bank 1 Write */ | 563 | /* Setup Bank 1 Write */ |
536 | RF_BANK_SETUP(ah->analogBank1Data, &ah->iniBank1, 1); | 564 | ar5008_rf_bank_setup(ah->analogBank1Data, &ah->iniBank1, 1); |
537 | 565 | ||
538 | /* Setup Bank 2 Write */ | 566 | /* Setup Bank 2 Write */ |
539 | RF_BANK_SETUP(ah->analogBank2Data, &ah->iniBank2, 1); | 567 | ar5008_rf_bank_setup(ah->analogBank2Data, &ah->iniBank2, 1); |
540 | 568 | ||
541 | /* Setup Bank 6 Write */ | 569 | /* Setup Bank 6 Write */ |
542 | RF_BANK_SETUP(ah->analogBank3Data, &ah->iniBank3, | 570 | ar5008_rf_bank_setup(ah->analogBank3Data, &ah->iniBank3, |
543 | modesIndex); | 571 | modesIndex); |
544 | { | 572 | { |
545 | int i; | 573 | int i; |
@@ -569,7 +597,7 @@ static bool ar5008_hw_set_rf_regs(struct ath_hw *ah, | |||
569 | } | 597 | } |
570 | 598 | ||
571 | /* Setup Bank 7 Setup */ | 599 | /* Setup Bank 7 Setup */ |
572 | RF_BANK_SETUP(ah->analogBank7Data, &ah->iniBank7, 1); | 600 | ar5008_rf_bank_setup(ah->analogBank7Data, &ah->iniBank7, 1); |
573 | 601 | ||
574 | /* Write Analog registers */ | 602 | /* Write Analog registers */ |
575 | REG_WRITE_RF_ARRAY(&ah->iniBank0, ah->analogBank0Data, | 603 | REG_WRITE_RF_ARRAY(&ah->iniBank0, ah->analogBank0Data, |
@@ -729,6 +757,7 @@ static int ar5008_hw_process_ini(struct ath_hw *ah, | |||
729 | struct ath9k_channel *chan) | 757 | struct ath9k_channel *chan) |
730 | { | 758 | { |
731 | struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); | 759 | struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); |
760 | struct ath_common *common = ath9k_hw_common(ah); | ||
732 | int i, regWrites = 0; | 761 | int i, regWrites = 0; |
733 | struct ieee80211_channel *channel = chan->chan; | 762 | struct ieee80211_channel *channel = chan->chan; |
734 | u32 modesIndex, freqIndex; | 763 | u32 modesIndex, freqIndex; |
@@ -805,7 +834,8 @@ static int ar5008_hw_process_ini(struct ath_hw *ah, | |||
805 | REG_WRITE(ah, reg, val); | 834 | REG_WRITE(ah, reg, val); |
806 | 835 | ||
807 | if (reg >= 0x7800 && reg < 0x78a0 | 836 | if (reg >= 0x7800 && reg < 0x78a0 |
808 | && ah->config.analog_shiftreg) { | 837 | && ah->config.analog_shiftreg |
838 | && (common->bus_ops->ath_bus_type != ATH_USB)) { | ||
809 | udelay(100); | 839 | udelay(100); |
810 | } | 840 | } |
811 | 841 | ||
@@ -835,7 +865,8 @@ static int ar5008_hw_process_ini(struct ath_hw *ah, | |||
835 | REG_WRITE(ah, reg, val); | 865 | REG_WRITE(ah, reg, val); |
836 | 866 | ||
837 | if (reg >= 0x7800 && reg < 0x78a0 | 867 | if (reg >= 0x7800 && reg < 0x78a0 |
838 | && ah->config.analog_shiftreg) { | 868 | && ah->config.analog_shiftreg |
869 | && (common->bus_ops->ath_bus_type != ATH_USB)) { | ||
839 | udelay(100); | 870 | udelay(100); |
840 | } | 871 | } |
841 | 872 | ||
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_calib.c b/drivers/net/wireless/ath/ath9k/ar9002_calib.c index 76388c6d6692..cb611b287b35 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_calib.c | |||
@@ -26,6 +26,27 @@ enum ar9002_cal_types { | |||
26 | IQ_MISMATCH_CAL = BIT(2), | 26 | IQ_MISMATCH_CAL = BIT(2), |
27 | }; | 27 | }; |
28 | 28 | ||
29 | static bool ar9002_hw_is_cal_supported(struct ath_hw *ah, | ||
30 | struct ath9k_channel *chan, | ||
31 | enum ar9002_cal_types cal_type) | ||
32 | { | ||
33 | bool supported = false; | ||
34 | switch (ah->supp_cals & cal_type) { | ||
35 | case IQ_MISMATCH_CAL: | ||
36 | /* Run IQ Mismatch for non-CCK only */ | ||
37 | if (!IS_CHAN_B(chan)) | ||
38 | supported = true; | ||
39 | break; | ||
40 | case ADC_GAIN_CAL: | ||
41 | case ADC_DC_CAL: | ||
42 | /* Run ADC Gain Cal for non-CCK & non 2GHz-HT20 only */ | ||
43 | if (!IS_CHAN_B(chan) && | ||
44 | !(IS_CHAN_2GHZ(chan) && IS_CHAN_HT20(chan))) | ||
45 | supported = true; | ||
46 | break; | ||
47 | } | ||
48 | return supported; | ||
49 | } | ||
29 | 50 | ||
30 | static void ar9002_hw_setup_calibration(struct ath_hw *ah, | 51 | static void ar9002_hw_setup_calibration(struct ath_hw *ah, |
31 | struct ath9k_cal_list *currCal) | 52 | struct ath9k_cal_list *currCal) |
@@ -858,26 +879,32 @@ static bool ar9002_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan) | |||
858 | if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) { | 879 | if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) { |
859 | ah->supp_cals = IQ_MISMATCH_CAL; | 880 | ah->supp_cals = IQ_MISMATCH_CAL; |
860 | 881 | ||
861 | if (AR_SREV_9160_10_OR_LATER(ah) && | 882 | if (AR_SREV_9160_10_OR_LATER(ah)) |
862 | !(IS_CHAN_2GHZ(chan) && IS_CHAN_HT20(chan))) { | ||
863 | ah->supp_cals |= ADC_GAIN_CAL | ADC_DC_CAL; | 883 | ah->supp_cals |= ADC_GAIN_CAL | ADC_DC_CAL; |
864 | 884 | ||
885 | if (AR_SREV_9287(ah)) | ||
886 | ah->supp_cals &= ~ADC_GAIN_CAL; | ||
865 | 887 | ||
888 | if (ar9002_hw_is_cal_supported(ah, chan, ADC_GAIN_CAL)) { | ||
866 | INIT_CAL(&ah->adcgain_caldata); | 889 | INIT_CAL(&ah->adcgain_caldata); |
867 | INSERT_CAL(ah, &ah->adcgain_caldata); | 890 | INSERT_CAL(ah, &ah->adcgain_caldata); |
868 | ath_dbg(common, ATH_DBG_CALIBRATE, | 891 | ath_dbg(common, ATH_DBG_CALIBRATE, |
869 | "enabling ADC Gain Calibration.\n"); | 892 | "enabling ADC Gain Calibration.\n"); |
893 | } | ||
870 | 894 | ||
895 | if (ar9002_hw_is_cal_supported(ah, chan, ADC_DC_CAL)) { | ||
871 | INIT_CAL(&ah->adcdc_caldata); | 896 | INIT_CAL(&ah->adcdc_caldata); |
872 | INSERT_CAL(ah, &ah->adcdc_caldata); | 897 | INSERT_CAL(ah, &ah->adcdc_caldata); |
873 | ath_dbg(common, ATH_DBG_CALIBRATE, | 898 | ath_dbg(common, ATH_DBG_CALIBRATE, |
874 | "enabling ADC DC Calibration.\n"); | 899 | "enabling ADC DC Calibration.\n"); |
875 | } | 900 | } |
876 | 901 | ||
877 | INIT_CAL(&ah->iq_caldata); | 902 | if (ar9002_hw_is_cal_supported(ah, chan, IQ_MISMATCH_CAL)) { |
878 | INSERT_CAL(ah, &ah->iq_caldata); | 903 | INIT_CAL(&ah->iq_caldata); |
879 | ath_dbg(common, ATH_DBG_CALIBRATE, | 904 | INSERT_CAL(ah, &ah->iq_caldata); |
880 | "enabling IQ Calibration.\n"); | 905 | ath_dbg(common, ATH_DBG_CALIBRATE, |
906 | "enabling IQ Calibration.\n"); | ||
907 | } | ||
881 | 908 | ||
882 | ah->cal_list_curr = ah->cal_list; | 909 | ah->cal_list_curr = ah->cal_list; |
883 | 910 | ||
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_mac.c b/drivers/net/wireless/ath/ath9k/ar9002_mac.c index 399ab3bb299b..8dd8f6308502 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_mac.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_mac.c | |||
@@ -415,17 +415,6 @@ static void ar9002_hw_set11n_burstduration(struct ath_hw *ah, void *ds, | |||
415 | ads->ds_ctl2 |= SM(burstDuration, AR_BurstDur); | 415 | ads->ds_ctl2 |= SM(burstDuration, AR_BurstDur); |
416 | } | 416 | } |
417 | 417 | ||
418 | static void ar9002_hw_set11n_virtualmorefrag(struct ath_hw *ah, void *ds, | ||
419 | u32 vmf) | ||
420 | { | ||
421 | struct ar5416_desc *ads = AR5416DESC(ds); | ||
422 | |||
423 | if (vmf) | ||
424 | ads->ds_ctl0 |= AR_VirtMoreFrag; | ||
425 | else | ||
426 | ads->ds_ctl0 &= ~AR_VirtMoreFrag; | ||
427 | } | ||
428 | |||
429 | void ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds, | 418 | void ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds, |
430 | u32 size, u32 flags) | 419 | u32 size, u32 flags) |
431 | { | 420 | { |
@@ -459,5 +448,4 @@ void ar9002_hw_attach_mac_ops(struct ath_hw *ah) | |||
459 | ops->set11n_aggr_last = ar9002_hw_set11n_aggr_last; | 448 | ops->set11n_aggr_last = ar9002_hw_set11n_aggr_last; |
460 | ops->clr11n_aggr = ar9002_hw_clr11n_aggr; | 449 | ops->clr11n_aggr = ar9002_hw_clr11n_aggr; |
461 | ops->set11n_burstduration = ar9002_hw_set11n_burstduration; | 450 | ops->set11n_burstduration = ar9002_hw_set11n_burstduration; |
462 | ops->set11n_virtualmorefrag = ar9002_hw_set11n_virtualmorefrag; | ||
463 | } | 451 | } |
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c index 7f5de6e4448b..aebaad97b190 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c | |||
@@ -66,8 +66,8 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) | |||
66 | 66 | ||
67 | /* rx/tx gain */ | 67 | /* rx/tx gain */ |
68 | INIT_INI_ARRAY(&ah->iniModesRxGain, | 68 | INIT_INI_ARRAY(&ah->iniModesRxGain, |
69 | ar9485_common_rx_gain_1_1, | 69 | ar9485Common_wo_xlna_rx_gain_1_1, |
70 | ARRAY_SIZE(ar9485_common_rx_gain_1_1), 2); | 70 | ARRAY_SIZE(ar9485Common_wo_xlna_rx_gain_1_1), 2); |
71 | INIT_INI_ARRAY(&ah->iniModesTxGain, | 71 | INIT_INI_ARRAY(&ah->iniModesTxGain, |
72 | ar9485_modes_lowest_ob_db_tx_gain_1_1, | 72 | ar9485_modes_lowest_ob_db_tx_gain_1_1, |
73 | ARRAY_SIZE(ar9485_modes_lowest_ob_db_tx_gain_1_1), | 73 | ARRAY_SIZE(ar9485_modes_lowest_ob_db_tx_gain_1_1), |
@@ -88,66 +88,6 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) | |||
88 | ar9485_1_1_pcie_phy_clkreq_disable_L1, | 88 | ar9485_1_1_pcie_phy_clkreq_disable_L1, |
89 | ARRAY_SIZE(ar9485_1_1_pcie_phy_clkreq_disable_L1), | 89 | ARRAY_SIZE(ar9485_1_1_pcie_phy_clkreq_disable_L1), |
90 | 2); | 90 | 2); |
91 | } else if (AR_SREV_9485(ah)) { | ||
92 | /* mac */ | ||
93 | INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0); | ||
94 | INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], | ||
95 | ar9485_1_0_mac_core, | ||
96 | ARRAY_SIZE(ar9485_1_0_mac_core), 2); | ||
97 | INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST], | ||
98 | ar9485_1_0_mac_postamble, | ||
99 | ARRAY_SIZE(ar9485_1_0_mac_postamble), 5); | ||
100 | |||
101 | /* bb */ | ||
102 | INIT_INI_ARRAY(&ah->iniBB[ATH_INI_PRE], ar9485_1_0, | ||
103 | ARRAY_SIZE(ar9485_1_0), 2); | ||
104 | INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE], | ||
105 | ar9485_1_0_baseband_core, | ||
106 | ARRAY_SIZE(ar9485_1_0_baseband_core), 2); | ||
107 | INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST], | ||
108 | ar9485_1_0_baseband_postamble, | ||
109 | ARRAY_SIZE(ar9485_1_0_baseband_postamble), 5); | ||
110 | |||
111 | /* radio */ | ||
112 | INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_PRE], NULL, 0, 0); | ||
113 | INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE], | ||
114 | ar9485_1_0_radio_core, | ||
115 | ARRAY_SIZE(ar9485_1_0_radio_core), 2); | ||
116 | INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST], | ||
117 | ar9485_1_0_radio_postamble, | ||
118 | ARRAY_SIZE(ar9485_1_0_radio_postamble), 2); | ||
119 | |||
120 | /* soc */ | ||
121 | INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE], | ||
122 | ar9485_1_0_soc_preamble, | ||
123 | ARRAY_SIZE(ar9485_1_0_soc_preamble), 2); | ||
124 | INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_CORE], NULL, 0, 0); | ||
125 | INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST], NULL, 0, 0); | ||
126 | |||
127 | /* rx/tx gain */ | ||
128 | INIT_INI_ARRAY(&ah->iniModesRxGain, | ||
129 | ar9485Common_rx_gain_1_0, | ||
130 | ARRAY_SIZE(ar9485Common_rx_gain_1_0), 2); | ||
131 | INIT_INI_ARRAY(&ah->iniModesTxGain, | ||
132 | ar9485Modes_lowest_ob_db_tx_gain_1_0, | ||
133 | ARRAY_SIZE(ar9485Modes_lowest_ob_db_tx_gain_1_0), | ||
134 | 5); | ||
135 | |||
136 | /* Load PCIE SERDES settings from INI */ | ||
137 | |||
138 | /* Awake Setting */ | ||
139 | |||
140 | INIT_INI_ARRAY(&ah->iniPcieSerdes, | ||
141 | ar9485_1_0_pcie_phy_pll_on_clkreq_disable_L1, | ||
142 | ARRAY_SIZE(ar9485_1_0_pcie_phy_pll_on_clkreq_disable_L1), | ||
143 | 2); | ||
144 | |||
145 | /* Sleep Setting */ | ||
146 | |||
147 | INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower, | ||
148 | ar9485_1_0_pcie_phy_pll_on_clkreq_disable_L1, | ||
149 | ARRAY_SIZE(ar9485_1_0_pcie_phy_pll_on_clkreq_disable_L1), | ||
150 | 2); | ||
151 | } else { | 91 | } else { |
152 | /* mac */ | 92 | /* mac */ |
153 | INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0); | 93 | INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0); |
@@ -228,11 +168,6 @@ static void ar9003_tx_gain_table_apply(struct ath_hw *ah) | |||
228 | ar9485_modes_lowest_ob_db_tx_gain_1_1, | 168 | ar9485_modes_lowest_ob_db_tx_gain_1_1, |
229 | ARRAY_SIZE(ar9485_modes_lowest_ob_db_tx_gain_1_1), | 169 | ARRAY_SIZE(ar9485_modes_lowest_ob_db_tx_gain_1_1), |
230 | 5); | 170 | 5); |
231 | else if (AR_SREV_9485(ah)) | ||
232 | INIT_INI_ARRAY(&ah->iniModesTxGain, | ||
233 | ar9485Modes_lowest_ob_db_tx_gain_1_0, | ||
234 | ARRAY_SIZE(ar9485Modes_lowest_ob_db_tx_gain_1_0), | ||
235 | 5); | ||
236 | else | 171 | else |
237 | INIT_INI_ARRAY(&ah->iniModesTxGain, | 172 | INIT_INI_ARRAY(&ah->iniModesTxGain, |
238 | ar9300Modes_lowest_ob_db_tx_gain_table_2p2, | 173 | ar9300Modes_lowest_ob_db_tx_gain_table_2p2, |
@@ -245,11 +180,6 @@ static void ar9003_tx_gain_table_apply(struct ath_hw *ah) | |||
245 | ar9485Modes_high_ob_db_tx_gain_1_1, | 180 | ar9485Modes_high_ob_db_tx_gain_1_1, |
246 | ARRAY_SIZE(ar9485Modes_high_ob_db_tx_gain_1_1), | 181 | ARRAY_SIZE(ar9485Modes_high_ob_db_tx_gain_1_1), |
247 | 5); | 182 | 5); |
248 | else if (AR_SREV_9485(ah)) | ||
249 | INIT_INI_ARRAY(&ah->iniModesTxGain, | ||
250 | ar9485Modes_high_ob_db_tx_gain_1_0, | ||
251 | ARRAY_SIZE(ar9485Modes_high_ob_db_tx_gain_1_0), | ||
252 | 5); | ||
253 | else | 183 | else |
254 | INIT_INI_ARRAY(&ah->iniModesTxGain, | 184 | INIT_INI_ARRAY(&ah->iniModesTxGain, |
255 | ar9300Modes_high_ob_db_tx_gain_table_2p2, | 185 | ar9300Modes_high_ob_db_tx_gain_table_2p2, |
@@ -262,11 +192,6 @@ static void ar9003_tx_gain_table_apply(struct ath_hw *ah) | |||
262 | ar9485Modes_low_ob_db_tx_gain_1_1, | 192 | ar9485Modes_low_ob_db_tx_gain_1_1, |
263 | ARRAY_SIZE(ar9485Modes_low_ob_db_tx_gain_1_1), | 193 | ARRAY_SIZE(ar9485Modes_low_ob_db_tx_gain_1_1), |
264 | 5); | 194 | 5); |
265 | else if (AR_SREV_9485(ah)) | ||
266 | INIT_INI_ARRAY(&ah->iniModesTxGain, | ||
267 | ar9485Modes_low_ob_db_tx_gain_1_0, | ||
268 | ARRAY_SIZE(ar9485Modes_low_ob_db_tx_gain_1_0), | ||
269 | 5); | ||
270 | else | 195 | else |
271 | INIT_INI_ARRAY(&ah->iniModesTxGain, | 196 | INIT_INI_ARRAY(&ah->iniModesTxGain, |
272 | ar9300Modes_low_ob_db_tx_gain_table_2p2, | 197 | ar9300Modes_low_ob_db_tx_gain_table_2p2, |
@@ -279,11 +204,6 @@ static void ar9003_tx_gain_table_apply(struct ath_hw *ah) | |||
279 | ar9485Modes_high_power_tx_gain_1_1, | 204 | ar9485Modes_high_power_tx_gain_1_1, |
280 | ARRAY_SIZE(ar9485Modes_high_power_tx_gain_1_1), | 205 | ARRAY_SIZE(ar9485Modes_high_power_tx_gain_1_1), |
281 | 5); | 206 | 5); |
282 | else if (AR_SREV_9485(ah)) | ||
283 | INIT_INI_ARRAY(&ah->iniModesTxGain, | ||
284 | ar9485Modes_high_power_tx_gain_1_0, | ||
285 | ARRAY_SIZE(ar9485Modes_high_power_tx_gain_1_0), | ||
286 | 5); | ||
287 | else | 207 | else |
288 | INIT_INI_ARRAY(&ah->iniModesTxGain, | 208 | INIT_INI_ARRAY(&ah->iniModesTxGain, |
289 | ar9300Modes_high_power_tx_gain_table_2p2, | 209 | ar9300Modes_high_power_tx_gain_table_2p2, |
@@ -300,13 +220,8 @@ static void ar9003_rx_gain_table_apply(struct ath_hw *ah) | |||
300 | default: | 220 | default: |
301 | if (AR_SREV_9485_11(ah)) | 221 | if (AR_SREV_9485_11(ah)) |
302 | INIT_INI_ARRAY(&ah->iniModesRxGain, | 222 | INIT_INI_ARRAY(&ah->iniModesRxGain, |
303 | ar9485_common_rx_gain_1_1, | 223 | ar9485Common_wo_xlna_rx_gain_1_1, |
304 | ARRAY_SIZE(ar9485_common_rx_gain_1_1), | 224 | ARRAY_SIZE(ar9485Common_wo_xlna_rx_gain_1_1), |
305 | 2); | ||
306 | else if (AR_SREV_9485(ah)) | ||
307 | INIT_INI_ARRAY(&ah->iniModesRxGain, | ||
308 | ar9485Common_rx_gain_1_0, | ||
309 | ARRAY_SIZE(ar9485Common_rx_gain_1_0), | ||
310 | 2); | 225 | 2); |
311 | else | 226 | else |
312 | INIT_INI_ARRAY(&ah->iniModesRxGain, | 227 | INIT_INI_ARRAY(&ah->iniModesRxGain, |
@@ -320,11 +235,6 @@ static void ar9003_rx_gain_table_apply(struct ath_hw *ah) | |||
320 | ar9485Common_wo_xlna_rx_gain_1_1, | 235 | ar9485Common_wo_xlna_rx_gain_1_1, |
321 | ARRAY_SIZE(ar9485Common_wo_xlna_rx_gain_1_1), | 236 | ARRAY_SIZE(ar9485Common_wo_xlna_rx_gain_1_1), |
322 | 2); | 237 | 2); |
323 | else if (AR_SREV_9485(ah)) | ||
324 | INIT_INI_ARRAY(&ah->iniModesRxGain, | ||
325 | ar9485Common_wo_xlna_rx_gain_1_0, | ||
326 | ARRAY_SIZE(ar9485Common_wo_xlna_rx_gain_1_0), | ||
327 | 2); | ||
328 | else | 238 | else |
329 | INIT_INI_ARRAY(&ah->iniModesRxGain, | 239 | INIT_INI_ARRAY(&ah->iniModesRxGain, |
330 | ar9300Common_wo_xlna_rx_gain_table_2p2, | 240 | ar9300Common_wo_xlna_rx_gain_table_2p2, |
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.c b/drivers/net/wireless/ath/ath9k/ar9003_mac.c index 038a0cbfc6e7..724ac2464ad5 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c | |||
@@ -485,17 +485,6 @@ static void ar9003_hw_set11n_burstduration(struct ath_hw *ah, void *ds, | |||
485 | 485 | ||
486 | } | 486 | } |
487 | 487 | ||
488 | static void ar9003_hw_set11n_virtualmorefrag(struct ath_hw *ah, void *ds, | ||
489 | u32 vmf) | ||
490 | { | ||
491 | struct ar9003_txc *ads = (struct ar9003_txc *) ds; | ||
492 | |||
493 | if (vmf) | ||
494 | ads->ctl11 |= AR_VirtMoreFrag; | ||
495 | else | ||
496 | ads->ctl11 &= ~AR_VirtMoreFrag; | ||
497 | } | ||
498 | |||
499 | void ar9003_hw_set_paprd_txdesc(struct ath_hw *ah, void *ds, u8 chains) | 488 | void ar9003_hw_set_paprd_txdesc(struct ath_hw *ah, void *ds, u8 chains) |
500 | { | 489 | { |
501 | struct ar9003_txc *ads = ds; | 490 | struct ar9003_txc *ads = ds; |
@@ -521,7 +510,6 @@ void ar9003_hw_attach_mac_ops(struct ath_hw *hw) | |||
521 | ops->set11n_aggr_last = ar9003_hw_set11n_aggr_last; | 510 | ops->set11n_aggr_last = ar9003_hw_set11n_aggr_last; |
522 | ops->clr11n_aggr = ar9003_hw_clr11n_aggr; | 511 | ops->clr11n_aggr = ar9003_hw_clr11n_aggr; |
523 | ops->set11n_burstduration = ar9003_hw_set11n_burstduration; | 512 | ops->set11n_burstduration = ar9003_hw_set11n_burstduration; |
524 | ops->set11n_virtualmorefrag = ar9003_hw_set11n_virtualmorefrag; | ||
525 | } | 513 | } |
526 | 514 | ||
527 | void ath9k_hw_set_rx_bufsize(struct ath_hw *ah, u16 buf_size) | 515 | void ath9k_hw_set_rx_bufsize(struct ath_hw *ah, u16 buf_size) |
diff --git a/drivers/net/wireless/ath/ath9k/ar9485_initvals.h b/drivers/net/wireless/ath/ath9k/ar9485_initvals.h index 71cc0a3a29fb..f91f73e50d00 100644 --- a/drivers/net/wireless/ath/ath9k/ar9485_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9485_initvals.h | |||
@@ -17,931 +17,6 @@ | |||
17 | #ifndef INITVALS_9485_H | 17 | #ifndef INITVALS_9485_H |
18 | #define INITVALS_9485_H | 18 | #define INITVALS_9485_H |
19 | 19 | ||
20 | static const u32 ar9485Common_1_0[][2] = { | ||
21 | /* Addr allmodes */ | ||
22 | {0x00007010, 0x00000022}, | ||
23 | {0x00007020, 0x00000000}, | ||
24 | {0x00007034, 0x00000002}, | ||
25 | {0x00007038, 0x000004c2}, | ||
26 | }; | ||
27 | |||
28 | static const u32 ar9485_1_0_mac_postamble[][5] = { | ||
29 | /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ | ||
30 | {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160}, | ||
31 | {0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c}, | ||
32 | {0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38}, | ||
33 | {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00}, | ||
34 | {0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b}, | ||
35 | {0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810}, | ||
36 | {0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a}, | ||
37 | {0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440}, | ||
38 | }; | ||
39 | |||
40 | static const u32 ar9485_1_0_pcie_phy_pll_on_clkreq_disable_L1[][2] = { | ||
41 | /* Addr allmodes */ | ||
42 | {0x00018c00, 0x10212e5e}, | ||
43 | {0x00018c04, 0x000801d8}, | ||
44 | {0x00018c08, 0x0000580c}, | ||
45 | }; | ||
46 | |||
47 | static const u32 ar9485Common_wo_xlna_rx_gain_1_0[][2] = { | ||
48 | /* Addr allmodes */ | ||
49 | {0x0000a000, 0x00010000}, | ||
50 | {0x0000a004, 0x00030002}, | ||
51 | {0x0000a008, 0x00050004}, | ||
52 | {0x0000a00c, 0x00810080}, | ||
53 | {0x0000a010, 0x01800082}, | ||
54 | {0x0000a014, 0x01820181}, | ||
55 | {0x0000a018, 0x01840183}, | ||
56 | {0x0000a01c, 0x01880185}, | ||
57 | {0x0000a020, 0x018a0189}, | ||
58 | {0x0000a024, 0x02850284}, | ||
59 | {0x0000a028, 0x02890288}, | ||
60 | {0x0000a02c, 0x03850384}, | ||
61 | {0x0000a030, 0x03890388}, | ||
62 | {0x0000a034, 0x038b038a}, | ||
63 | {0x0000a038, 0x038d038c}, | ||
64 | {0x0000a03c, 0x03910390}, | ||
65 | {0x0000a040, 0x03930392}, | ||
66 | {0x0000a044, 0x03950394}, | ||
67 | {0x0000a048, 0x00000396}, | ||
68 | {0x0000a04c, 0x00000000}, | ||
69 | {0x0000a050, 0x00000000}, | ||
70 | {0x0000a054, 0x00000000}, | ||
71 | {0x0000a058, 0x00000000}, | ||
72 | {0x0000a05c, 0x00000000}, | ||
73 | {0x0000a060, 0x00000000}, | ||
74 | {0x0000a064, 0x00000000}, | ||
75 | {0x0000a068, 0x00000000}, | ||
76 | {0x0000a06c, 0x00000000}, | ||
77 | {0x0000a070, 0x00000000}, | ||
78 | {0x0000a074, 0x00000000}, | ||
79 | {0x0000a078, 0x00000000}, | ||
80 | {0x0000a07c, 0x00000000}, | ||
81 | {0x0000a080, 0x28282828}, | ||
82 | {0x0000a084, 0x28282828}, | ||
83 | {0x0000a088, 0x28282828}, | ||
84 | {0x0000a08c, 0x28282828}, | ||
85 | {0x0000a090, 0x28282828}, | ||
86 | {0x0000a094, 0x21212128}, | ||
87 | {0x0000a098, 0x171c1c1c}, | ||
88 | {0x0000a09c, 0x02020212}, | ||
89 | {0x0000a0a0, 0x00000202}, | ||
90 | {0x0000a0a4, 0x00000000}, | ||
91 | {0x0000a0a8, 0x00000000}, | ||
92 | {0x0000a0ac, 0x00000000}, | ||
93 | {0x0000a0b0, 0x00000000}, | ||
94 | {0x0000a0b4, 0x00000000}, | ||
95 | {0x0000a0b8, 0x00000000}, | ||
96 | {0x0000a0bc, 0x00000000}, | ||
97 | {0x0000a0c0, 0x001f0000}, | ||
98 | {0x0000a0c4, 0x111f1100}, | ||
99 | {0x0000a0c8, 0x111d111e}, | ||
100 | {0x0000a0cc, 0x111b111c}, | ||
101 | {0x0000a0d0, 0x22032204}, | ||
102 | {0x0000a0d4, 0x22012202}, | ||
103 | {0x0000a0d8, 0x221f2200}, | ||
104 | {0x0000a0dc, 0x221d221e}, | ||
105 | {0x0000a0e0, 0x33013302}, | ||
106 | {0x0000a0e4, 0x331f3300}, | ||
107 | {0x0000a0e8, 0x4402331e}, | ||
108 | {0x0000a0ec, 0x44004401}, | ||
109 | {0x0000a0f0, 0x441e441f}, | ||
110 | {0x0000a0f4, 0x55015502}, | ||
111 | {0x0000a0f8, 0x551f5500}, | ||
112 | {0x0000a0fc, 0x6602551e}, | ||
113 | {0x0000a100, 0x66006601}, | ||
114 | {0x0000a104, 0x661e661f}, | ||
115 | {0x0000a108, 0x7703661d}, | ||
116 | {0x0000a10c, 0x77017702}, | ||
117 | {0x0000a110, 0x00007700}, | ||
118 | {0x0000a114, 0x00000000}, | ||
119 | {0x0000a118, 0x00000000}, | ||
120 | {0x0000a11c, 0x00000000}, | ||
121 | {0x0000a120, 0x00000000}, | ||
122 | {0x0000a124, 0x00000000}, | ||
123 | {0x0000a128, 0x00000000}, | ||
124 | {0x0000a12c, 0x00000000}, | ||
125 | {0x0000a130, 0x00000000}, | ||
126 | {0x0000a134, 0x00000000}, | ||
127 | {0x0000a138, 0x00000000}, | ||
128 | {0x0000a13c, 0x00000000}, | ||
129 | {0x0000a140, 0x001f0000}, | ||
130 | {0x0000a144, 0x111f1100}, | ||
131 | {0x0000a148, 0x111d111e}, | ||
132 | {0x0000a14c, 0x111b111c}, | ||
133 | {0x0000a150, 0x22032204}, | ||
134 | {0x0000a154, 0x22012202}, | ||
135 | {0x0000a158, 0x221f2200}, | ||
136 | {0x0000a15c, 0x221d221e}, | ||
137 | {0x0000a160, 0x33013302}, | ||
138 | {0x0000a164, 0x331f3300}, | ||
139 | {0x0000a168, 0x4402331e}, | ||
140 | {0x0000a16c, 0x44004401}, | ||
141 | {0x0000a170, 0x441e441f}, | ||
142 | {0x0000a174, 0x55015502}, | ||
143 | {0x0000a178, 0x551f5500}, | ||
144 | {0x0000a17c, 0x6602551e}, | ||
145 | {0x0000a180, 0x66006601}, | ||
146 | {0x0000a184, 0x661e661f}, | ||
147 | {0x0000a188, 0x7703661d}, | ||
148 | {0x0000a18c, 0x77017702}, | ||
149 | {0x0000a190, 0x00007700}, | ||
150 | {0x0000a194, 0x00000000}, | ||
151 | {0x0000a198, 0x00000000}, | ||
152 | {0x0000a19c, 0x00000000}, | ||
153 | {0x0000a1a0, 0x00000000}, | ||
154 | {0x0000a1a4, 0x00000000}, | ||
155 | {0x0000a1a8, 0x00000000}, | ||
156 | {0x0000a1ac, 0x00000000}, | ||
157 | {0x0000a1b0, 0x00000000}, | ||
158 | {0x0000a1b4, 0x00000000}, | ||
159 | {0x0000a1b8, 0x00000000}, | ||
160 | {0x0000a1bc, 0x00000000}, | ||
161 | {0x0000a1c0, 0x00000000}, | ||
162 | {0x0000a1c4, 0x00000000}, | ||
163 | {0x0000a1c8, 0x00000000}, | ||
164 | {0x0000a1cc, 0x00000000}, | ||
165 | {0x0000a1d0, 0x00000000}, | ||
166 | {0x0000a1d4, 0x00000000}, | ||
167 | {0x0000a1d8, 0x00000000}, | ||
168 | {0x0000a1dc, 0x00000000}, | ||
169 | {0x0000a1e0, 0x00000000}, | ||
170 | {0x0000a1e4, 0x00000000}, | ||
171 | {0x0000a1e8, 0x00000000}, | ||
172 | {0x0000a1ec, 0x00000000}, | ||
173 | {0x0000a1f0, 0x00000396}, | ||
174 | {0x0000a1f4, 0x00000396}, | ||
175 | {0x0000a1f8, 0x00000396}, | ||
176 | {0x0000a1fc, 0x00000296}, | ||
177 | }; | ||
178 | |||
179 | static const u32 ar9485Modes_high_power_tx_gain_1_0[][5] = { | ||
180 | /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ | ||
181 | {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8}, | ||
182 | {0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000}, | ||
183 | {0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002}, | ||
184 | {0x0000a508, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004}, | ||
185 | {0x0000a50c, 0x11062202, 0x11062202, 0x0d000200, 0x0d000200}, | ||
186 | {0x0000a510, 0x17022e00, 0x17022e00, 0x11000202, 0x11000202}, | ||
187 | {0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x15000400, 0x15000400}, | ||
188 | {0x0000a518, 0x25020ec0, 0x25020ec0, 0x19000402, 0x19000402}, | ||
189 | {0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x1d000404, 0x1d000404}, | ||
190 | {0x0000a520, 0x2f001f04, 0x2f001f04, 0x21000603, 0x21000603}, | ||
191 | {0x0000a524, 0x35001fc4, 0x35001fc4, 0x25000605, 0x25000605}, | ||
192 | {0x0000a528, 0x3c022f04, 0x3c022f04, 0x2a000a03, 0x2a000a03}, | ||
193 | {0x0000a52c, 0x41023e85, 0x41023e85, 0x2c000a04, 0x2c000a04}, | ||
194 | {0x0000a530, 0x48023ec6, 0x48023ec6, 0x2e000a20, 0x2e000a20}, | ||
195 | {0x0000a534, 0x4d023f01, 0x4d023f01, 0x34000e20, 0x34000e20}, | ||
196 | {0x0000a538, 0x53023f4b, 0x53023f4b, 0x38000e22, 0x38000e22}, | ||
197 | {0x0000a53c, 0x5a027f09, 0x5a027f09, 0x3c000e24, 0x3c000e24}, | ||
198 | {0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x40000e26, 0x40000e26}, | ||
199 | {0x0000a544, 0x6502feca, 0x6502feca, 0x43001640, 0x43001640}, | ||
200 | {0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x46001660, 0x46001660}, | ||
201 | {0x0000a54c, 0x7203feca, 0x7203feca, 0x49001861, 0x49001861}, | ||
202 | {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x4c001a81, 0x4c001a81}, | ||
203 | {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x4f001a83, 0x4f001a83}, | ||
204 | {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x54001c85, 0x54001c85}, | ||
205 | {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x58001ce5, 0x58001ce5}, | ||
206 | {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5b001ce9, 0x5b001ce9}, | ||
207 | {0x0000a564, 0x960fffcb, 0x960fffcb, 0x60001eeb, 0x60001eeb}, | ||
208 | {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, | ||
209 | {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, | ||
210 | {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, | ||
211 | {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, | ||
212 | {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, | ||
213 | {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, | ||
214 | {0x00016044, 0x05b6b2db, 0x05b6b2db, 0x05b6b2db, 0x05b6b2db}, | ||
215 | }; | ||
216 | |||
217 | static const u32 ar9485_1_0[][2] = { | ||
218 | /* Addr allmodes */ | ||
219 | {0x0000a580, 0x00000000}, | ||
220 | {0x0000a584, 0x00000000}, | ||
221 | {0x0000a588, 0x00000000}, | ||
222 | {0x0000a58c, 0x00000000}, | ||
223 | {0x0000a590, 0x00000000}, | ||
224 | {0x0000a594, 0x00000000}, | ||
225 | {0x0000a598, 0x00000000}, | ||
226 | {0x0000a59c, 0x00000000}, | ||
227 | {0x0000a5a0, 0x00000000}, | ||
228 | {0x0000a5a4, 0x00000000}, | ||
229 | {0x0000a5a8, 0x00000000}, | ||
230 | {0x0000a5ac, 0x00000000}, | ||
231 | {0x0000a5b0, 0x00000000}, | ||
232 | {0x0000a5b4, 0x00000000}, | ||
233 | {0x0000a5b8, 0x00000000}, | ||
234 | {0x0000a5bc, 0x00000000}, | ||
235 | }; | ||
236 | |||
237 | static const u32 ar9485_1_0_radio_core[][2] = { | ||
238 | /* Addr allmodes */ | ||
239 | {0x00016000, 0x36db6db6}, | ||
240 | {0x00016004, 0x6db6db40}, | ||
241 | {0x00016008, 0x73800000}, | ||
242 | {0x0001600c, 0x00000000}, | ||
243 | {0x00016040, 0x7f80fff8}, | ||
244 | {0x00016048, 0x6c92426e}, | ||
245 | {0x0001604c, 0x000f0278}, | ||
246 | {0x00016050, 0x6db6db6c}, | ||
247 | {0x00016054, 0x6db60000}, | ||
248 | {0x00016080, 0x00080000}, | ||
249 | {0x00016084, 0x0e48048c}, | ||
250 | {0x00016088, 0x14214514}, | ||
251 | {0x0001608c, 0x119f081e}, | ||
252 | {0x00016090, 0x24926490}, | ||
253 | {0x00016098, 0xd28b3330}, | ||
254 | {0x000160a0, 0xc2108ffe}, | ||
255 | {0x000160a4, 0x812fc370}, | ||
256 | {0x000160a8, 0x423c8000}, | ||
257 | {0x000160b4, 0x92480040}, | ||
258 | {0x000160c0, 0x006db6db}, | ||
259 | {0x000160c4, 0x0186db60}, | ||
260 | {0x000160c8, 0x6db6db6c}, | ||
261 | {0x000160cc, 0x6de6fbe0}, | ||
262 | {0x000160d0, 0xf7dfcf3c}, | ||
263 | {0x00016100, 0x04cb0001}, | ||
264 | {0x00016104, 0xfff80015}, | ||
265 | {0x00016108, 0x00080010}, | ||
266 | {0x00016144, 0x01884080}, | ||
267 | {0x00016148, 0x00008040}, | ||
268 | {0x00016180, 0x08453333}, | ||
269 | {0x00016184, 0x18e82f01}, | ||
270 | {0x00016188, 0x00000000}, | ||
271 | {0x0001618c, 0x00000000}, | ||
272 | {0x00016240, 0x08400000}, | ||
273 | {0x00016244, 0x1bf90f00}, | ||
274 | {0x00016248, 0x00000000}, | ||
275 | {0x0001624c, 0x00000000}, | ||
276 | {0x00016280, 0x01000015}, | ||
277 | {0x00016284, 0x00d30000}, | ||
278 | {0x00016288, 0x00318000}, | ||
279 | {0x0001628c, 0x50000000}, | ||
280 | {0x00016290, 0x4b96210f}, | ||
281 | {0x00016380, 0x00000000}, | ||
282 | {0x00016384, 0x00000000}, | ||
283 | {0x00016388, 0x00800700}, | ||
284 | {0x0001638c, 0x00800700}, | ||
285 | {0x00016390, 0x00800700}, | ||
286 | {0x00016394, 0x00000000}, | ||
287 | {0x00016398, 0x00000000}, | ||
288 | {0x0001639c, 0x00000000}, | ||
289 | {0x000163a0, 0x00000001}, | ||
290 | {0x000163a4, 0x00000001}, | ||
291 | {0x000163a8, 0x00000000}, | ||
292 | {0x000163ac, 0x00000000}, | ||
293 | {0x000163b0, 0x00000000}, | ||
294 | {0x000163b4, 0x00000000}, | ||
295 | {0x000163b8, 0x00000000}, | ||
296 | {0x000163bc, 0x00000000}, | ||
297 | {0x000163c0, 0x000000a0}, | ||
298 | {0x000163c4, 0x000c0000}, | ||
299 | {0x000163c8, 0x14021402}, | ||
300 | {0x000163cc, 0x00001402}, | ||
301 | {0x000163d0, 0x00000000}, | ||
302 | {0x000163d4, 0x00000000}, | ||
303 | {0x00016c40, 0x1319c178}, | ||
304 | {0x00016c44, 0x10000000}, | ||
305 | }; | ||
306 | |||
307 | static const u32 ar9485Modes_lowest_ob_db_tx_gain_1_0[][5] = { | ||
308 | /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ | ||
309 | {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8}, | ||
310 | {0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000}, | ||
311 | {0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002}, | ||
312 | {0x0000a508, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004}, | ||
313 | {0x0000a50c, 0x11062202, 0x11062202, 0x0d000200, 0x0d000200}, | ||
314 | {0x0000a510, 0x17022e00, 0x17022e00, 0x11000202, 0x11000202}, | ||
315 | {0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x15000400, 0x15000400}, | ||
316 | {0x0000a518, 0x25020ec0, 0x25020ec0, 0x19000402, 0x19000402}, | ||
317 | {0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x1d000404, 0x1d000404}, | ||
318 | {0x0000a520, 0x2f001f04, 0x2f001f04, 0x21000603, 0x21000603}, | ||
319 | {0x0000a524, 0x35001fc4, 0x35001fc4, 0x25000605, 0x25000605}, | ||
320 | {0x0000a528, 0x3c022f04, 0x3c022f04, 0x2a000a03, 0x2a000a03}, | ||
321 | {0x0000a52c, 0x41023e85, 0x41023e85, 0x2c000a04, 0x2c000a04}, | ||
322 | {0x0000a530, 0x48023ec6, 0x48023ec6, 0x2e000a20, 0x2e000a20}, | ||
323 | {0x0000a534, 0x4d023f01, 0x4d023f01, 0x34000e20, 0x34000e20}, | ||
324 | {0x0000a538, 0x53023f4b, 0x53023f4b, 0x38000e22, 0x38000e22}, | ||
325 | {0x0000a53c, 0x5a027f09, 0x5a027f09, 0x3c000e24, 0x3c000e24}, | ||
326 | {0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x40000e26, 0x40000e26}, | ||
327 | {0x0000a544, 0x6502feca, 0x6502feca, 0x43001640, 0x43001640}, | ||
328 | {0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x46001660, 0x46001660}, | ||
329 | {0x0000a54c, 0x7203feca, 0x7203feca, 0x49001861, 0x49001861}, | ||
330 | {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x4c001a81, 0x4c001a81}, | ||
331 | {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x4f001a83, 0x4f001a83}, | ||
332 | {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x54001c85, 0x54001c85}, | ||
333 | {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x58001ce5, 0x58001ce5}, | ||
334 | {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5b001ce9, 0x5b001ce9}, | ||
335 | {0x0000a564, 0x960fffcb, 0x960fffcb, 0x60001eeb, 0x60001eeb}, | ||
336 | {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, | ||
337 | {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, | ||
338 | {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, | ||
339 | {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, | ||
340 | {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, | ||
341 | {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, | ||
342 | {0x00016044, 0x05b6b2db, 0x05b6b2db, 0x05b6b2db, 0x05b6b2db}, | ||
343 | }; | ||
344 | |||
345 | static const u32 ar9485_1_0_baseband_core[][2] = { | ||
346 | /* Addr allmodes */ | ||
347 | {0x00009800, 0xafe68e30}, | ||
348 | {0x00009804, 0xfd14e000}, | ||
349 | {0x00009808, 0x9c0a8f6b}, | ||
350 | {0x0000980c, 0x04800000}, | ||
351 | {0x00009814, 0x9280c00a}, | ||
352 | {0x00009818, 0x00000000}, | ||
353 | {0x0000981c, 0x00020028}, | ||
354 | {0x00009834, 0x5f3ca3de}, | ||
355 | {0x00009838, 0x0108ecff}, | ||
356 | {0x0000983c, 0x14750600}, | ||
357 | {0x00009880, 0x201fff00}, | ||
358 | {0x00009884, 0x00001042}, | ||
359 | {0x000098a4, 0x00200400}, | ||
360 | {0x000098b0, 0x52440bbe}, | ||
361 | {0x000098bc, 0x00000002}, | ||
362 | {0x000098d0, 0x004b6a8e}, | ||
363 | {0x000098d4, 0x00000820}, | ||
364 | {0x000098dc, 0x00000000}, | ||
365 | {0x000098f0, 0x00000000}, | ||
366 | {0x000098f4, 0x00000000}, | ||
367 | {0x00009c04, 0x00000000}, | ||
368 | {0x00009c08, 0x03200000}, | ||
369 | {0x00009c0c, 0x00000000}, | ||
370 | {0x00009c10, 0x00000000}, | ||
371 | {0x00009c14, 0x00046384}, | ||
372 | {0x00009c18, 0x05b6b440}, | ||
373 | {0x00009c1c, 0x00b6b440}, | ||
374 | {0x00009d00, 0xc080a333}, | ||
375 | {0x00009d04, 0x40206c10}, | ||
376 | {0x00009d08, 0x009c4060}, | ||
377 | {0x00009d0c, 0x1883800a}, | ||
378 | {0x00009d10, 0x01834061}, | ||
379 | {0x00009d14, 0x00c00400}, | ||
380 | {0x00009d18, 0x00000000}, | ||
381 | {0x00009d1c, 0x00000000}, | ||
382 | {0x00009e08, 0x0038233c}, | ||
383 | {0x00009e24, 0x990bb515}, | ||
384 | {0x00009e28, 0x0a6f0000}, | ||
385 | {0x00009e30, 0x06336f77}, | ||
386 | {0x00009e34, 0x6af6532f}, | ||
387 | {0x00009e38, 0x0cc80c00}, | ||
388 | {0x00009e40, 0x0d261820}, | ||
389 | {0x00009e4c, 0x00001004}, | ||
390 | {0x00009e50, 0x00ff03f1}, | ||
391 | {0x00009fc0, 0x80be4788}, | ||
392 | {0x00009fc4, 0x0001efb5}, | ||
393 | {0x00009fcc, 0x40000014}, | ||
394 | {0x0000a20c, 0x00000000}, | ||
395 | {0x0000a210, 0x00000000}, | ||
396 | {0x0000a220, 0x00000000}, | ||
397 | {0x0000a224, 0x00000000}, | ||
398 | {0x0000a228, 0x10002310}, | ||
399 | {0x0000a23c, 0x00000000}, | ||
400 | {0x0000a244, 0x0c000000}, | ||
401 | {0x0000a2a0, 0x00000001}, | ||
402 | {0x0000a2c0, 0x00000001}, | ||
403 | {0x0000a2c8, 0x00000000}, | ||
404 | {0x0000a2cc, 0x18c43433}, | ||
405 | {0x0000a2d4, 0x00000000}, | ||
406 | {0x0000a2dc, 0x00000000}, | ||
407 | {0x0000a2e0, 0x00000000}, | ||
408 | {0x0000a2e4, 0x00000000}, | ||
409 | {0x0000a2e8, 0x00000000}, | ||
410 | {0x0000a2ec, 0x00000000}, | ||
411 | {0x0000a2f0, 0x00000000}, | ||
412 | {0x0000a2f4, 0x00000000}, | ||
413 | {0x0000a2f8, 0x00000000}, | ||
414 | {0x0000a344, 0x00000000}, | ||
415 | {0x0000a34c, 0x00000000}, | ||
416 | {0x0000a350, 0x0000a000}, | ||
417 | {0x0000a364, 0x00000000}, | ||
418 | {0x0000a370, 0x00000000}, | ||
419 | {0x0000a390, 0x00000001}, | ||
420 | {0x0000a394, 0x00000444}, | ||
421 | {0x0000a398, 0x001f0e0f}, | ||
422 | {0x0000a39c, 0x0075393f}, | ||
423 | {0x0000a3a0, 0xb79f6427}, | ||
424 | {0x0000a3a4, 0x00000000}, | ||
425 | {0x0000a3a8, 0xaaaaaaaa}, | ||
426 | {0x0000a3ac, 0x3c466478}, | ||
427 | {0x0000a3c0, 0x20202020}, | ||
428 | {0x0000a3c4, 0x22222220}, | ||
429 | {0x0000a3c8, 0x20200020}, | ||
430 | {0x0000a3cc, 0x20202020}, | ||
431 | {0x0000a3d0, 0x20202020}, | ||
432 | {0x0000a3d4, 0x20202020}, | ||
433 | {0x0000a3d8, 0x20202020}, | ||
434 | {0x0000a3dc, 0x20202020}, | ||
435 | {0x0000a3e0, 0x20202020}, | ||
436 | {0x0000a3e4, 0x20202020}, | ||
437 | {0x0000a3e8, 0x20202020}, | ||
438 | {0x0000a3ec, 0x20202020}, | ||
439 | {0x0000a3f0, 0x00000000}, | ||
440 | {0x0000a3f4, 0x00000006}, | ||
441 | {0x0000a3f8, 0x0cdbd380}, | ||
442 | {0x0000a3fc, 0x000f0f01}, | ||
443 | {0x0000a400, 0x8fa91f01}, | ||
444 | {0x0000a404, 0x00000000}, | ||
445 | {0x0000a408, 0x0e79e5c6}, | ||
446 | {0x0000a40c, 0x00820820}, | ||
447 | {0x0000a414, 0x1ce739ce}, | ||
448 | {0x0000a418, 0x2d0011ce}, | ||
449 | {0x0000a41c, 0x1ce739ce}, | ||
450 | {0x0000a420, 0x000001ce}, | ||
451 | {0x0000a424, 0x1ce739ce}, | ||
452 | {0x0000a428, 0x000001ce}, | ||
453 | {0x0000a42c, 0x1ce739ce}, | ||
454 | {0x0000a430, 0x1ce739ce}, | ||
455 | {0x0000a434, 0x00000000}, | ||
456 | {0x0000a438, 0x00001801}, | ||
457 | {0x0000a43c, 0x00000000}, | ||
458 | {0x0000a440, 0x00000000}, | ||
459 | {0x0000a444, 0x00000000}, | ||
460 | {0x0000a448, 0x04000000}, | ||
461 | {0x0000a44c, 0x00000001}, | ||
462 | {0x0000a450, 0x00010000}, | ||
463 | {0x0000a458, 0x00000000}, | ||
464 | {0x0000a5c4, 0x3fad9d74}, | ||
465 | {0x0000a5c8, 0x0048060a}, | ||
466 | {0x0000a5cc, 0x00000637}, | ||
467 | {0x0000a760, 0x03020100}, | ||
468 | {0x0000a764, 0x09080504}, | ||
469 | {0x0000a768, 0x0d0c0b0a}, | ||
470 | {0x0000a76c, 0x13121110}, | ||
471 | {0x0000a770, 0x31301514}, | ||
472 | {0x0000a774, 0x35343332}, | ||
473 | {0x0000a778, 0x00000036}, | ||
474 | {0x0000a780, 0x00000838}, | ||
475 | {0x0000a7c0, 0x00000000}, | ||
476 | {0x0000a7c4, 0xfffffffc}, | ||
477 | {0x0000a7c8, 0x00000000}, | ||
478 | {0x0000a7cc, 0x00000000}, | ||
479 | {0x0000a7d0, 0x00000000}, | ||
480 | {0x0000a7d4, 0x00000004}, | ||
481 | {0x0000a7dc, 0x00000001}, | ||
482 | }; | ||
483 | |||
484 | static const u32 ar9485Modes_high_ob_db_tx_gain_1_0[][5] = { | ||
485 | /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ | ||
486 | {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8}, | ||
487 | {0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000}, | ||
488 | {0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002}, | ||
489 | {0x0000a508, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004}, | ||
490 | {0x0000a50c, 0x11062202, 0x11062202, 0x0d000200, 0x0d000200}, | ||
491 | {0x0000a510, 0x17022e00, 0x17022e00, 0x11000202, 0x11000202}, | ||
492 | {0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x15000400, 0x15000400}, | ||
493 | {0x0000a518, 0x25020ec0, 0x25020ec0, 0x19000402, 0x19000402}, | ||
494 | {0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x1d000404, 0x1d000404}, | ||
495 | {0x0000a520, 0x2f001f04, 0x2f001f04, 0x21000603, 0x21000603}, | ||
496 | {0x0000a524, 0x35001fc4, 0x35001fc4, 0x25000605, 0x25000605}, | ||
497 | {0x0000a528, 0x3c022f04, 0x3c022f04, 0x2a000a03, 0x2a000a03}, | ||
498 | {0x0000a52c, 0x41023e85, 0x41023e85, 0x2c000a04, 0x2c000a04}, | ||
499 | {0x0000a530, 0x48023ec6, 0x48023ec6, 0x2e000a20, 0x2e000a20}, | ||
500 | {0x0000a534, 0x4d023f01, 0x4d023f01, 0x34000e20, 0x34000e20}, | ||
501 | {0x0000a538, 0x53023f4b, 0x53023f4b, 0x38000e22, 0x38000e22}, | ||
502 | {0x0000a53c, 0x5a027f09, 0x5a027f09, 0x3c000e24, 0x3c000e24}, | ||
503 | {0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x40000e26, 0x40000e26}, | ||
504 | {0x0000a544, 0x6502feca, 0x6502feca, 0x43001640, 0x43001640}, | ||
505 | {0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x46001660, 0x46001660}, | ||
506 | {0x0000a54c, 0x7203feca, 0x7203feca, 0x49001861, 0x49001861}, | ||
507 | {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x4c001a81, 0x4c001a81}, | ||
508 | {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x4f001a83, 0x4f001a83}, | ||
509 | {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x54001c85, 0x54001c85}, | ||
510 | {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x58001ce5, 0x58001ce5}, | ||
511 | {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5b001ce9, 0x5b001ce9}, | ||
512 | {0x0000a564, 0x960fffcb, 0x960fffcb, 0x60001eeb, 0x60001eeb}, | ||
513 | {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, | ||
514 | {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, | ||
515 | {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, | ||
516 | {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, | ||
517 | {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, | ||
518 | {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, | ||
519 | {0x00016044, 0x05b6b2db, 0x05b6b2db, 0x05b6b2db, 0x05b6b2db}, | ||
520 | }; | ||
521 | |||
522 | static const u32 ar9485Common_rx_gain_1_0[][2] = { | ||
523 | /* Addr allmodes */ | ||
524 | {0x0000a000, 0x00010000}, | ||
525 | {0x0000a004, 0x00030002}, | ||
526 | {0x0000a008, 0x00050004}, | ||
527 | {0x0000a00c, 0x00810080}, | ||
528 | {0x0000a010, 0x01800082}, | ||
529 | {0x0000a014, 0x01820181}, | ||
530 | {0x0000a018, 0x01840183}, | ||
531 | {0x0000a01c, 0x01880185}, | ||
532 | {0x0000a020, 0x018a0189}, | ||
533 | {0x0000a024, 0x02850284}, | ||
534 | {0x0000a028, 0x02890288}, | ||
535 | {0x0000a02c, 0x03850384}, | ||
536 | {0x0000a030, 0x03890388}, | ||
537 | {0x0000a034, 0x038b038a}, | ||
538 | {0x0000a038, 0x038d038c}, | ||
539 | {0x0000a03c, 0x03910390}, | ||
540 | {0x0000a040, 0x03930392}, | ||
541 | {0x0000a044, 0x03950394}, | ||
542 | {0x0000a048, 0x00000396}, | ||
543 | {0x0000a04c, 0x00000000}, | ||
544 | {0x0000a050, 0x00000000}, | ||
545 | {0x0000a054, 0x00000000}, | ||
546 | {0x0000a058, 0x00000000}, | ||
547 | {0x0000a05c, 0x00000000}, | ||
548 | {0x0000a060, 0x00000000}, | ||
549 | {0x0000a064, 0x00000000}, | ||
550 | {0x0000a068, 0x00000000}, | ||
551 | {0x0000a06c, 0x00000000}, | ||
552 | {0x0000a070, 0x00000000}, | ||
553 | {0x0000a074, 0x00000000}, | ||
554 | {0x0000a078, 0x00000000}, | ||
555 | {0x0000a07c, 0x00000000}, | ||
556 | {0x0000a080, 0x28282828}, | ||
557 | {0x0000a084, 0x28282828}, | ||
558 | {0x0000a088, 0x28282828}, | ||
559 | {0x0000a08c, 0x28282828}, | ||
560 | {0x0000a090, 0x28282828}, | ||
561 | {0x0000a094, 0x21212128}, | ||
562 | {0x0000a098, 0x171c1c1c}, | ||
563 | {0x0000a09c, 0x02020212}, | ||
564 | {0x0000a0a0, 0x00000202}, | ||
565 | {0x0000a0a4, 0x00000000}, | ||
566 | {0x0000a0a8, 0x00000000}, | ||
567 | {0x0000a0ac, 0x00000000}, | ||
568 | {0x0000a0b0, 0x00000000}, | ||
569 | {0x0000a0b4, 0x00000000}, | ||
570 | {0x0000a0b8, 0x00000000}, | ||
571 | {0x0000a0bc, 0x00000000}, | ||
572 | {0x0000a0c0, 0x001f0000}, | ||
573 | {0x0000a0c4, 0x111f1100}, | ||
574 | {0x0000a0c8, 0x111d111e}, | ||
575 | {0x0000a0cc, 0x111b111c}, | ||
576 | {0x0000a0d0, 0x22032204}, | ||
577 | {0x0000a0d4, 0x22012202}, | ||
578 | {0x0000a0d8, 0x221f2200}, | ||
579 | {0x0000a0dc, 0x221d221e}, | ||
580 | {0x0000a0e0, 0x33013302}, | ||
581 | {0x0000a0e4, 0x331f3300}, | ||
582 | {0x0000a0e8, 0x4402331e}, | ||
583 | {0x0000a0ec, 0x44004401}, | ||
584 | {0x0000a0f0, 0x441e441f}, | ||
585 | {0x0000a0f4, 0x55015502}, | ||
586 | {0x0000a0f8, 0x551f5500}, | ||
587 | {0x0000a0fc, 0x6602551e}, | ||
588 | {0x0000a100, 0x66006601}, | ||
589 | {0x0000a104, 0x661e661f}, | ||
590 | {0x0000a108, 0x7703661d}, | ||
591 | {0x0000a10c, 0x77017702}, | ||
592 | {0x0000a110, 0x00007700}, | ||
593 | {0x0000a114, 0x00000000}, | ||
594 | {0x0000a118, 0x00000000}, | ||
595 | {0x0000a11c, 0x00000000}, | ||
596 | {0x0000a120, 0x00000000}, | ||
597 | {0x0000a124, 0x00000000}, | ||
598 | {0x0000a128, 0x00000000}, | ||
599 | {0x0000a12c, 0x00000000}, | ||
600 | {0x0000a130, 0x00000000}, | ||
601 | {0x0000a134, 0x00000000}, | ||
602 | {0x0000a138, 0x00000000}, | ||
603 | {0x0000a13c, 0x00000000}, | ||
604 | {0x0000a140, 0x001f0000}, | ||
605 | {0x0000a144, 0x111f1100}, | ||
606 | {0x0000a148, 0x111d111e}, | ||
607 | {0x0000a14c, 0x111b111c}, | ||
608 | {0x0000a150, 0x22032204}, | ||
609 | {0x0000a154, 0x22012202}, | ||
610 | {0x0000a158, 0x221f2200}, | ||
611 | {0x0000a15c, 0x221d221e}, | ||
612 | {0x0000a160, 0x33013302}, | ||
613 | {0x0000a164, 0x331f3300}, | ||
614 | {0x0000a168, 0x4402331e}, | ||
615 | {0x0000a16c, 0x44004401}, | ||
616 | {0x0000a170, 0x441e441f}, | ||
617 | {0x0000a174, 0x55015502}, | ||
618 | {0x0000a178, 0x551f5500}, | ||
619 | {0x0000a17c, 0x6602551e}, | ||
620 | {0x0000a180, 0x66006601}, | ||
621 | {0x0000a184, 0x661e661f}, | ||
622 | {0x0000a188, 0x7703661d}, | ||
623 | {0x0000a18c, 0x77017702}, | ||
624 | {0x0000a190, 0x00007700}, | ||
625 | {0x0000a194, 0x00000000}, | ||
626 | {0x0000a198, 0x00000000}, | ||
627 | {0x0000a19c, 0x00000000}, | ||
628 | {0x0000a1a0, 0x00000000}, | ||
629 | {0x0000a1a4, 0x00000000}, | ||
630 | {0x0000a1a8, 0x00000000}, | ||
631 | {0x0000a1ac, 0x00000000}, | ||
632 | {0x0000a1b0, 0x00000000}, | ||
633 | {0x0000a1b4, 0x00000000}, | ||
634 | {0x0000a1b8, 0x00000000}, | ||
635 | {0x0000a1bc, 0x00000000}, | ||
636 | {0x0000a1c0, 0x00000000}, | ||
637 | {0x0000a1c4, 0x00000000}, | ||
638 | {0x0000a1c8, 0x00000000}, | ||
639 | {0x0000a1cc, 0x00000000}, | ||
640 | {0x0000a1d0, 0x00000000}, | ||
641 | {0x0000a1d4, 0x00000000}, | ||
642 | {0x0000a1d8, 0x00000000}, | ||
643 | {0x0000a1dc, 0x00000000}, | ||
644 | {0x0000a1e0, 0x00000000}, | ||
645 | {0x0000a1e4, 0x00000000}, | ||
646 | {0x0000a1e8, 0x00000000}, | ||
647 | {0x0000a1ec, 0x00000000}, | ||
648 | {0x0000a1f0, 0x00000396}, | ||
649 | {0x0000a1f4, 0x00000396}, | ||
650 | {0x0000a1f8, 0x00000396}, | ||
651 | {0x0000a1fc, 0x00000296}, | ||
652 | }; | ||
653 | |||
654 | static const u32 ar9485_1_0_pcie_phy_pll_on_clkreq_enable_L1[][2] = { | ||
655 | /* Addr allmodes */ | ||
656 | {0x00018c00, 0x10252e5e}, | ||
657 | {0x00018c04, 0x000801d8}, | ||
658 | {0x00018c08, 0x0000580c}, | ||
659 | }; | ||
660 | |||
661 | static const u32 ar9485_1_0_pcie_phy_clkreq_enable_L1[][2] = { | ||
662 | /* Addr allmodes */ | ||
663 | {0x00018c00, 0x10253e5e}, | ||
664 | {0x00018c04, 0x000801d8}, | ||
665 | {0x00018c08, 0x0000580c}, | ||
666 | }; | ||
667 | |||
668 | static const u32 ar9485_1_0_soc_preamble[][2] = { | ||
669 | /* Addr allmodes */ | ||
670 | {0x00004090, 0x00aa10aa}, | ||
671 | {0x000040a4, 0x00a0c9c9}, | ||
672 | {0x00007048, 0x00000004}, | ||
673 | }; | ||
674 | |||
675 | static const u32 ar9485_fast_clock_1_0_baseband_postamble[][3] = { | ||
676 | /* Addr 5G_HT20 5G_HT40 */ | ||
677 | {0x00009e00, 0x03721821, 0x03721821}, | ||
678 | {0x0000a230, 0x0000400b, 0x00004016}, | ||
679 | {0x0000a254, 0x00000898, 0x00001130}, | ||
680 | }; | ||
681 | |||
682 | static const u32 ar9485_1_0_baseband_postamble[][5] = { | ||
683 | /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ | ||
684 | {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8005, 0xd00a8005}, | ||
685 | {0x00009820, 0x206a002e, 0x206a002e, 0x206a002e, 0x206a002e}, | ||
686 | {0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0}, | ||
687 | {0x00009828, 0x06903081, 0x06903081, 0x06903881, 0x06903881}, | ||
688 | {0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4}, | ||
689 | {0x00009830, 0x0000059c, 0x0000059c, 0x0000059c, 0x0000059c}, | ||
690 | {0x00009c00, 0x00000044, 0x00000044, 0x00000044, 0x00000044}, | ||
691 | {0x00009e00, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0}, | ||
692 | {0x00009e04, 0x00182020, 0x00182020, 0x00182020, 0x00182020}, | ||
693 | {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2}, | ||
694 | {0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec80d2e, 0x7ec80d2e}, | ||
695 | {0x00009e14, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e}, | ||
696 | {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, | ||
697 | {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c}, | ||
698 | {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce}, | ||
699 | {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021}, | ||
700 | {0x00009e3c, 0xcf946220, 0xcf946220, 0xcf946222, 0xcf946222}, | ||
701 | {0x00009e44, 0x02321e27, 0x02321e27, 0x02282324, 0x02282324}, | ||
702 | {0x00009e48, 0x5030201a, 0x5030201a, 0x50302010, 0x50302010}, | ||
703 | {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000}, | ||
704 | {0x0000a204, 0x01303fc0, 0x01303fc4, 0x01303fc4, 0x01303fc0}, | ||
705 | {0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004}, | ||
706 | {0x0000a230, 0x0000400a, 0x00004014, 0x00004016, 0x0000400b}, | ||
707 | {0x0000a234, 0x10000fff, 0x10000fff, 0x10000fff, 0x10000fff}, | ||
708 | {0x0000a238, 0xffb81018, 0xffb81018, 0xffb81018, 0xffb81018}, | ||
709 | {0x0000a250, 0x00000000, 0x00000000, 0x00000210, 0x00000108}, | ||
710 | {0x0000a254, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898}, | ||
711 | {0x0000a258, 0x02020002, 0x02020002, 0x02020002, 0x02020002}, | ||
712 | {0x0000a25c, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e}, | ||
713 | {0x0000a260, 0x3a021501, 0x3a021501, 0x3a021501, 0x3a021501}, | ||
714 | {0x0000a264, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e}, | ||
715 | {0x0000a280, 0x00000007, 0x00000007, 0x0000000b, 0x0000000b}, | ||
716 | {0x0000a284, 0x00000000, 0x00000000, 0x000002a0, 0x000002a0}, | ||
717 | {0x0000a288, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, | ||
718 | {0x0000a28c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, | ||
719 | {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18}, | ||
720 | {0x0000a2d0, 0x00071981, 0x00071981, 0x00071981, 0x00071982}, | ||
721 | {0x0000a2d8, 0xf999a83a, 0xf999a83a, 0xf999a83a, 0xf999a83a}, | ||
722 | {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, | ||
723 | {0x0000be04, 0x00802020, 0x00802020, 0x00802020, 0x00802020}, | ||
724 | {0x0000be18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, | ||
725 | }; | ||
726 | |||
727 | static const u32 ar9485Modes_low_ob_db_tx_gain_1_0[][5] = { | ||
728 | /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ | ||
729 | {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8}, | ||
730 | {0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000}, | ||
731 | {0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002}, | ||
732 | {0x0000a508, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004}, | ||
733 | {0x0000a50c, 0x11062202, 0x11062202, 0x0d000200, 0x0d000200}, | ||
734 | {0x0000a510, 0x17022e00, 0x17022e00, 0x11000202, 0x11000202}, | ||
735 | {0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x15000400, 0x15000400}, | ||
736 | {0x0000a518, 0x25020ec0, 0x25020ec0, 0x19000402, 0x19000402}, | ||
737 | {0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x1d000404, 0x1d000404}, | ||
738 | {0x0000a520, 0x2f001f04, 0x2f001f04, 0x21000603, 0x21000603}, | ||
739 | {0x0000a524, 0x35001fc4, 0x35001fc4, 0x25000605, 0x25000605}, | ||
740 | {0x0000a528, 0x3c022f04, 0x3c022f04, 0x2a000a03, 0x2a000a03}, | ||
741 | {0x0000a52c, 0x41023e85, 0x41023e85, 0x2c000a04, 0x2c000a04}, | ||
742 | {0x0000a530, 0x48023ec6, 0x48023ec6, 0x2e000a20, 0x2e000a20}, | ||
743 | {0x0000a534, 0x4d023f01, 0x4d023f01, 0x34000e20, 0x34000e20}, | ||
744 | {0x0000a538, 0x53023f4b, 0x53023f4b, 0x38000e22, 0x38000e22}, | ||
745 | {0x0000a53c, 0x5a027f09, 0x5a027f09, 0x3c000e24, 0x3c000e24}, | ||
746 | {0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x40000e26, 0x40000e26}, | ||
747 | {0x0000a544, 0x6502feca, 0x6502feca, 0x43001640, 0x43001640}, | ||
748 | {0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x46001660, 0x46001660}, | ||
749 | {0x0000a54c, 0x7203feca, 0x7203feca, 0x49001861, 0x49001861}, | ||
750 | {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x4c001a81, 0x4c001a81}, | ||
751 | {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x4f001a83, 0x4f001a83}, | ||
752 | {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x54001c85, 0x54001c85}, | ||
753 | {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x58001ce5, 0x58001ce5}, | ||
754 | {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5b001ce9, 0x5b001ce9}, | ||
755 | {0x0000a564, 0x960fffcb, 0x960fffcb, 0x60001eeb, 0x60001eeb}, | ||
756 | {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, | ||
757 | {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, | ||
758 | {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, | ||
759 | {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, | ||
760 | {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, | ||
761 | {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, | ||
762 | {0x00016044, 0x05b6b2db, 0x05b6b2db, 0x05b6b2db, 0x05b6b2db}, | ||
763 | }; | ||
764 | |||
765 | static const u32 ar9485_1_0_pcie_phy_clkreq_disable_L1[][2] = { | ||
766 | /* Addr allmodes */ | ||
767 | {0x00018c00, 0x10213e5e}, | ||
768 | {0x00018c04, 0x000801d8}, | ||
769 | {0x00018c08, 0x0000580c}, | ||
770 | }; | ||
771 | |||
772 | static const u32 ar9485_1_0_radio_postamble[][2] = { | ||
773 | /* Addr allmodes */ | ||
774 | {0x0001609c, 0x0b283f31}, | ||
775 | {0x000160ac, 0x24611800}, | ||
776 | {0x000160b0, 0x03284f3e}, | ||
777 | {0x0001610c, 0x00170000}, | ||
778 | {0x00016140, 0x10804008}, | ||
779 | }; | ||
780 | |||
781 | static const u32 ar9485_1_0_mac_core[][2] = { | ||
782 | /* Addr allmodes */ | ||
783 | {0x00000008, 0x00000000}, | ||
784 | {0x00000030, 0x00020085}, | ||
785 | {0x00000034, 0x00000005}, | ||
786 | {0x00000040, 0x00000000}, | ||
787 | {0x00000044, 0x00000000}, | ||
788 | {0x00000048, 0x00000008}, | ||
789 | {0x0000004c, 0x00000010}, | ||
790 | {0x00000050, 0x00000000}, | ||
791 | {0x00001040, 0x002ffc0f}, | ||
792 | {0x00001044, 0x002ffc0f}, | ||
793 | {0x00001048, 0x002ffc0f}, | ||
794 | {0x0000104c, 0x002ffc0f}, | ||
795 | {0x00001050, 0x002ffc0f}, | ||
796 | {0x00001054, 0x002ffc0f}, | ||
797 | {0x00001058, 0x002ffc0f}, | ||
798 | {0x0000105c, 0x002ffc0f}, | ||
799 | {0x00001060, 0x002ffc0f}, | ||
800 | {0x00001064, 0x002ffc0f}, | ||
801 | {0x000010f0, 0x00000100}, | ||
802 | {0x00001270, 0x00000000}, | ||
803 | {0x000012b0, 0x00000000}, | ||
804 | {0x000012f0, 0x00000000}, | ||
805 | {0x0000143c, 0x00000000}, | ||
806 | {0x0000147c, 0x00000000}, | ||
807 | {0x00008000, 0x00000000}, | ||
808 | {0x00008004, 0x00000000}, | ||
809 | {0x00008008, 0x00000000}, | ||
810 | {0x0000800c, 0x00000000}, | ||
811 | {0x00008018, 0x00000000}, | ||
812 | {0x00008020, 0x00000000}, | ||
813 | {0x00008038, 0x00000000}, | ||
814 | {0x0000803c, 0x00000000}, | ||
815 | {0x00008040, 0x00000000}, | ||
816 | {0x00008044, 0x00000000}, | ||
817 | {0x00008048, 0x00000000}, | ||
818 | {0x0000804c, 0xffffffff}, | ||
819 | {0x00008054, 0x00000000}, | ||
820 | {0x00008058, 0x00000000}, | ||
821 | {0x0000805c, 0x000fc78f}, | ||
822 | {0x00008060, 0x0000000f}, | ||
823 | {0x00008064, 0x00000000}, | ||
824 | {0x00008070, 0x00000310}, | ||
825 | {0x00008074, 0x00000020}, | ||
826 | {0x00008078, 0x00000000}, | ||
827 | {0x0000809c, 0x0000000f}, | ||
828 | {0x000080a0, 0x00000000}, | ||
829 | {0x000080a4, 0x02ff0000}, | ||
830 | {0x000080a8, 0x0e070605}, | ||
831 | {0x000080ac, 0x0000000d}, | ||
832 | {0x000080b0, 0x00000000}, | ||
833 | {0x000080b4, 0x00000000}, | ||
834 | {0x000080b8, 0x00000000}, | ||
835 | {0x000080bc, 0x00000000}, | ||
836 | {0x000080c0, 0x2a800000}, | ||
837 | {0x000080c4, 0x06900168}, | ||
838 | {0x000080c8, 0x13881c20}, | ||
839 | {0x000080cc, 0x01f40000}, | ||
840 | {0x000080d0, 0x00252500}, | ||
841 | {0x000080d4, 0x00a00000}, | ||
842 | {0x000080d8, 0x00400000}, | ||
843 | {0x000080dc, 0x00000000}, | ||
844 | {0x000080e0, 0xffffffff}, | ||
845 | {0x000080e4, 0x0000ffff}, | ||
846 | {0x000080e8, 0x3f3f3f3f}, | ||
847 | {0x000080ec, 0x00000000}, | ||
848 | {0x000080f0, 0x00000000}, | ||
849 | {0x000080f4, 0x00000000}, | ||
850 | {0x000080fc, 0x00020000}, | ||
851 | {0x00008100, 0x00000000}, | ||
852 | {0x00008108, 0x00000052}, | ||
853 | {0x0000810c, 0x00000000}, | ||
854 | {0x00008110, 0x00000000}, | ||
855 | {0x00008114, 0x000007ff}, | ||
856 | {0x00008118, 0x000000aa}, | ||
857 | {0x0000811c, 0x00003210}, | ||
858 | {0x00008124, 0x00000000}, | ||
859 | {0x00008128, 0x00000000}, | ||
860 | {0x0000812c, 0x00000000}, | ||
861 | {0x00008130, 0x00000000}, | ||
862 | {0x00008134, 0x00000000}, | ||
863 | {0x00008138, 0x00000000}, | ||
864 | {0x0000813c, 0x0000ffff}, | ||
865 | {0x00008144, 0xffffffff}, | ||
866 | {0x00008168, 0x00000000}, | ||
867 | {0x0000816c, 0x00000000}, | ||
868 | {0x00008170, 0x18486200}, | ||
869 | {0x00008174, 0x33332210}, | ||
870 | {0x00008178, 0x00000000}, | ||
871 | {0x0000817c, 0x00020000}, | ||
872 | {0x000081c0, 0x00000000}, | ||
873 | {0x000081c4, 0x33332210}, | ||
874 | {0x000081c8, 0x00000000}, | ||
875 | {0x000081cc, 0x00000000}, | ||
876 | {0x000081d4, 0x00000000}, | ||
877 | {0x000081ec, 0x00000000}, | ||
878 | {0x000081f0, 0x00000000}, | ||
879 | {0x000081f4, 0x00000000}, | ||
880 | {0x000081f8, 0x00000000}, | ||
881 | {0x000081fc, 0x00000000}, | ||
882 | {0x00008240, 0x00100000}, | ||
883 | {0x00008244, 0x0010f400}, | ||
884 | {0x00008248, 0x00000800}, | ||
885 | {0x0000824c, 0x0001e800}, | ||
886 | {0x00008250, 0x00000000}, | ||
887 | {0x00008254, 0x00000000}, | ||
888 | {0x00008258, 0x00000000}, | ||
889 | {0x0000825c, 0x40000000}, | ||
890 | {0x00008260, 0x00080922}, | ||
891 | {0x00008264, 0x9ca00010}, | ||
892 | {0x00008268, 0xffffffff}, | ||
893 | {0x0000826c, 0x0000ffff}, | ||
894 | {0x00008270, 0x00000000}, | ||
895 | {0x00008274, 0x40000000}, | ||
896 | {0x00008278, 0x003e4180}, | ||
897 | {0x0000827c, 0x00000004}, | ||
898 | {0x00008284, 0x0000002c}, | ||
899 | {0x00008288, 0x0000002c}, | ||
900 | {0x0000828c, 0x000000ff}, | ||
901 | {0x00008294, 0x00000000}, | ||
902 | {0x00008298, 0x00000000}, | ||
903 | {0x0000829c, 0x00000000}, | ||
904 | {0x00008300, 0x00000140}, | ||
905 | {0x00008314, 0x00000000}, | ||
906 | {0x0000831c, 0x0000010d}, | ||
907 | {0x00008328, 0x00000000}, | ||
908 | {0x0000832c, 0x00000007}, | ||
909 | {0x00008330, 0x00000302}, | ||
910 | {0x00008334, 0x00000700}, | ||
911 | {0x00008338, 0x00ff0000}, | ||
912 | {0x0000833c, 0x02400000}, | ||
913 | {0x00008340, 0x000107ff}, | ||
914 | {0x00008344, 0xa248105b}, | ||
915 | {0x00008348, 0x008f0000}, | ||
916 | {0x0000835c, 0x00000000}, | ||
917 | {0x00008360, 0xffffffff}, | ||
918 | {0x00008364, 0xffffffff}, | ||
919 | {0x00008368, 0x00000000}, | ||
920 | {0x00008370, 0x00000000}, | ||
921 | {0x00008374, 0x000000ff}, | ||
922 | {0x00008378, 0x00000000}, | ||
923 | {0x0000837c, 0x00000000}, | ||
924 | {0x00008380, 0xffffffff}, | ||
925 | {0x00008384, 0xffffffff}, | ||
926 | {0x00008390, 0xffffffff}, | ||
927 | {0x00008394, 0xffffffff}, | ||
928 | {0x00008398, 0x00000000}, | ||
929 | {0x0000839c, 0x00000000}, | ||
930 | {0x000083a0, 0x00000000}, | ||
931 | {0x000083a4, 0x0000fa14}, | ||
932 | {0x000083a8, 0x000f0c00}, | ||
933 | {0x000083ac, 0x33332210}, | ||
934 | {0x000083b0, 0x33332210}, | ||
935 | {0x000083b4, 0x33332210}, | ||
936 | {0x000083b8, 0x33332210}, | ||
937 | {0x000083bc, 0x00000000}, | ||
938 | {0x000083c0, 0x00000000}, | ||
939 | {0x000083c4, 0x00000000}, | ||
940 | {0x000083c8, 0x00000000}, | ||
941 | {0x000083cc, 0x00000200}, | ||
942 | {0x000083d0, 0x000301ff}, | ||
943 | }; | ||
944 | |||
945 | static const u32 ar9485_1_1_mac_core[][2] = { | 20 | static const u32 ar9485_1_1_mac_core[][2] = { |
946 | /* Addr allmodes */ | 21 | /* Addr allmodes */ |
947 | {0x00000008, 0x00000000}, | 22 | {0x00000008, 0x00000000}, |
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 099bd4183ad0..38835bc324b2 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h | |||
@@ -120,13 +120,11 @@ void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd, | |||
120 | /* RX / TX */ | 120 | /* RX / TX */ |
121 | /***********/ | 121 | /***********/ |
122 | 122 | ||
123 | #define ATH_MAX_ANTENNA 3 | ||
124 | #define ATH_RXBUF 512 | 123 | #define ATH_RXBUF 512 |
125 | #define ATH_TXBUF 512 | 124 | #define ATH_TXBUF 512 |
126 | #define ATH_TXBUF_RESERVE 5 | 125 | #define ATH_TXBUF_RESERVE 5 |
127 | #define ATH_MAX_QDEPTH (ATH_TXBUF / 4 - ATH_TXBUF_RESERVE) | 126 | #define ATH_MAX_QDEPTH (ATH_TXBUF / 4 - ATH_TXBUF_RESERVE) |
128 | #define ATH_TXMAXTRY 13 | 127 | #define ATH_TXMAXTRY 13 |
129 | #define ATH_MGT_TXMAXTRY 4 | ||
130 | 128 | ||
131 | #define TID_TO_WME_AC(_tid) \ | 129 | #define TID_TO_WME_AC(_tid) \ |
132 | ((((_tid) == 0) || ((_tid) == 3)) ? WME_AC_BE : \ | 130 | ((((_tid) == 0) || ((_tid) == 3)) ? WME_AC_BE : \ |
@@ -346,11 +344,9 @@ void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid | |||
346 | 344 | ||
347 | struct ath_vif { | 345 | struct ath_vif { |
348 | int av_bslot; | 346 | int av_bslot; |
349 | bool is_bslot_active; | 347 | bool is_bslot_active, primary_sta_vif; |
350 | __le64 tsf_adjust; /* TSF adjustment for staggered beacons */ | 348 | __le64 tsf_adjust; /* TSF adjustment for staggered beacons */ |
351 | enum nl80211_iftype av_opmode; | ||
352 | struct ath_buf *av_bcbuf; | 349 | struct ath_buf *av_bcbuf; |
353 | u8 bssid[ETH_ALEN]; /* current BSSID from config_interface */ | ||
354 | }; | 350 | }; |
355 | 351 | ||
356 | /*******************/ | 352 | /*******************/ |
@@ -362,7 +358,7 @@ struct ath_vif { | |||
362 | * number of BSSIDs) if a given beacon does not go out even after waiting this | 358 | * number of BSSIDs) if a given beacon does not go out even after waiting this |
363 | * number of beacon intervals, the game's up. | 359 | * number of beacon intervals, the game's up. |
364 | */ | 360 | */ |
365 | #define BSTUCK_THRESH (9 * ATH_BCBUF) | 361 | #define BSTUCK_THRESH 9 |
366 | #define ATH_BCBUF 4 | 362 | #define ATH_BCBUF 4 |
367 | #define ATH_DEFAULT_BINTVAL 100 /* TU */ | 363 | #define ATH_DEFAULT_BINTVAL 100 /* TU */ |
368 | #define ATH_DEFAULT_BMISS_LIMIT 10 | 364 | #define ATH_DEFAULT_BMISS_LIMIT 10 |
@@ -386,7 +382,7 @@ struct ath_beacon { | |||
386 | u32 beaconq; | 382 | u32 beaconq; |
387 | u32 bmisscnt; | 383 | u32 bmisscnt; |
388 | u32 ast_be_xmit; | 384 | u32 ast_be_xmit; |
389 | u64 bc_tstamp; | 385 | u32 bc_tstamp; |
390 | struct ieee80211_vif *bslot[ATH_BCBUF]; | 386 | struct ieee80211_vif *bslot[ATH_BCBUF]; |
391 | int slottime; | 387 | int slottime; |
392 | int slotupdate; | 388 | int slotupdate; |
@@ -401,6 +397,7 @@ void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif); | |||
401 | int ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_vif *vif); | 397 | int ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_vif *vif); |
402 | void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp); | 398 | void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp); |
403 | int ath_beaconq_config(struct ath_softc *sc); | 399 | int ath_beaconq_config(struct ath_softc *sc); |
400 | void ath_set_beacon(struct ath_softc *sc); | ||
404 | void ath9k_set_beaconing_status(struct ath_softc *sc, bool status); | 401 | void ath9k_set_beaconing_status(struct ath_softc *sc, bool status); |
405 | 402 | ||
406 | /*******/ | 403 | /*******/ |
@@ -550,6 +547,7 @@ struct ath_ant_comb { | |||
550 | #define SC_OP_BT_SCAN BIT(13) | 547 | #define SC_OP_BT_SCAN BIT(13) |
551 | #define SC_OP_ANI_RUN BIT(14) | 548 | #define SC_OP_ANI_RUN BIT(14) |
552 | #define SC_OP_ENABLE_APM BIT(15) | 549 | #define SC_OP_ENABLE_APM BIT(15) |
550 | #define SC_OP_PRIM_STA_VIF BIT(16) | ||
553 | 551 | ||
554 | /* Powersave flags */ | 552 | /* Powersave flags */ |
555 | #define PS_WAIT_FOR_BEACON BIT(0) | 553 | #define PS_WAIT_FOR_BEACON BIT(0) |
@@ -688,8 +686,6 @@ void ath9k_ps_restore(struct ath_softc *sc); | |||
688 | 686 | ||
689 | u8 ath_txchainmask_reduction(struct ath_softc *sc, u8 chainmask, u32 rate); | 687 | u8 ath_txchainmask_reduction(struct ath_softc *sc, u8 chainmask, u32 rate); |
690 | 688 | ||
691 | void ath9k_set_bssid_mask(struct ieee80211_hw *hw, struct ieee80211_vif *vif); | ||
692 | |||
693 | void ath_start_rfkill_poll(struct ath_softc *sc); | 689 | void ath_start_rfkill_poll(struct ath_softc *sc); |
694 | extern void ath9k_rfkill_poll_state(struct ieee80211_hw *hw); | 690 | extern void ath9k_rfkill_poll_state(struct ieee80211_hw *hw); |
695 | void ath9k_calculate_iter_data(struct ieee80211_hw *hw, | 691 | void ath9k_calculate_iter_data(struct ieee80211_hw *hw, |
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 6d2a545fc35e..eccb0ec87adb 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c | |||
@@ -57,8 +57,8 @@ int ath_beaconq_config(struct ath_softc *sc) | |||
57 | 57 | ||
58 | /* | 58 | /* |
59 | * Associates the beacon frame buffer with a transmit descriptor. Will set | 59 | * Associates the beacon frame buffer with a transmit descriptor. Will set |
60 | * up all required antenna switch parameters, rate codes, and channel flags. | 60 | * up rate codes, and channel flags. Beacons are always sent out at the |
61 | * Beacons are always sent out at the lowest rate, and are not retried. | 61 | * lowest rate, and are not retried. |
62 | */ | 62 | */ |
63 | static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp, | 63 | static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp, |
64 | struct ath_buf *bf, int rateidx) | 64 | struct ath_buf *bf, int rateidx) |
@@ -68,7 +68,7 @@ static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp, | |||
68 | struct ath_common *common = ath9k_hw_common(ah); | 68 | struct ath_common *common = ath9k_hw_common(ah); |
69 | struct ath_desc *ds; | 69 | struct ath_desc *ds; |
70 | struct ath9k_11n_rate_series series[4]; | 70 | struct ath9k_11n_rate_series series[4]; |
71 | int flags, antenna, ctsrate = 0, ctsduration = 0; | 71 | int flags, ctsrate = 0, ctsduration = 0; |
72 | struct ieee80211_supported_band *sband; | 72 | struct ieee80211_supported_band *sband; |
73 | u8 rate = 0; | 73 | u8 rate = 0; |
74 | 74 | ||
@@ -76,12 +76,6 @@ static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp, | |||
76 | flags = ATH9K_TXDESC_NOACK; | 76 | flags = ATH9K_TXDESC_NOACK; |
77 | 77 | ||
78 | ds->ds_link = 0; | 78 | ds->ds_link = 0; |
79 | /* | ||
80 | * Switch antenna every beacon. | ||
81 | * Should only switch every beacon period, not for every SWBA | ||
82 | * XXX assumes two antennae | ||
83 | */ | ||
84 | antenna = ((sc->beacon.ast_be_xmit / sc->nbcnvifs) & 1 ? 2 : 1); | ||
85 | 79 | ||
86 | sband = &sc->sbands[common->hw->conf.channel->band]; | 80 | sband = &sc->sbands[common->hw->conf.channel->band]; |
87 | rate = sband->bitrates[rateidx].hw_value; | 81 | rate = sband->bitrates[rateidx].hw_value; |
@@ -278,7 +272,7 @@ int ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_vif *vif) | |||
278 | return -ENOMEM; | 272 | return -ENOMEM; |
279 | 273 | ||
280 | tstamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp; | 274 | tstamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp; |
281 | sc->beacon.bc_tstamp = le64_to_cpu(tstamp); | 275 | sc->beacon.bc_tstamp = (u32) le64_to_cpu(tstamp); |
282 | /* Calculate a TSF adjustment factor required for staggered beacons. */ | 276 | /* Calculate a TSF adjustment factor required for staggered beacons. */ |
283 | if (avp->av_bslot > 0) { | 277 | if (avp->av_bslot > 0) { |
284 | u64 tsfadjust; | 278 | u64 tsfadjust; |
@@ -294,8 +288,8 @@ int ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_vif *vif) | |||
294 | * adjustment. Other slots are adjusted to get the timestamp | 288 | * adjustment. Other slots are adjusted to get the timestamp |
295 | * close to the TBTT for the BSS. | 289 | * close to the TBTT for the BSS. |
296 | */ | 290 | */ |
297 | tsfadjust = intval * avp->av_bslot / ATH_BCBUF; | 291 | tsfadjust = TU_TO_USEC(intval * avp->av_bslot) / ATH_BCBUF; |
298 | avp->tsf_adjust = cpu_to_le64(TU_TO_USEC(tsfadjust)); | 292 | avp->tsf_adjust = cpu_to_le64(tsfadjust); |
299 | 293 | ||
300 | ath_dbg(common, ATH_DBG_BEACON, | 294 | ath_dbg(common, ATH_DBG_BEACON, |
301 | "stagger beacons, bslot %d intval %u tsfadjust %llu\n", | 295 | "stagger beacons, bslot %d intval %u tsfadjust %llu\n", |
@@ -329,6 +323,7 @@ void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp) | |||
329 | if (avp->av_bslot != -1) { | 323 | if (avp->av_bslot != -1) { |
330 | sc->beacon.bslot[avp->av_bslot] = NULL; | 324 | sc->beacon.bslot[avp->av_bslot] = NULL; |
331 | sc->nbcnvifs--; | 325 | sc->nbcnvifs--; |
326 | avp->av_bslot = -1; | ||
332 | } | 327 | } |
333 | 328 | ||
334 | bf = avp->av_bcbuf; | 329 | bf = avp->av_bcbuf; |
@@ -369,12 +364,13 @@ void ath_beacon_tasklet(unsigned long data) | |||
369 | if (ath9k_hw_numtxpending(ah, sc->beacon.beaconq) != 0) { | 364 | if (ath9k_hw_numtxpending(ah, sc->beacon.beaconq) != 0) { |
370 | sc->beacon.bmisscnt++; | 365 | sc->beacon.bmisscnt++; |
371 | 366 | ||
372 | if (sc->beacon.bmisscnt < BSTUCK_THRESH) { | 367 | if (sc->beacon.bmisscnt < BSTUCK_THRESH * sc->nbcnvifs) { |
373 | ath_dbg(common, ATH_DBG_BSTUCK, | 368 | ath_dbg(common, ATH_DBG_BSTUCK, |
374 | "missed %u consecutive beacons\n", | 369 | "missed %u consecutive beacons\n", |
375 | sc->beacon.bmisscnt); | 370 | sc->beacon.bmisscnt); |
376 | ath9k_hw_stop_dma_queue(ah, sc->beacon.beaconq); | 371 | ath9k_hw_stop_dma_queue(ah, sc->beacon.beaconq); |
377 | ath9k_hw_bstuck_nfcal(ah); | 372 | if (sc->beacon.bmisscnt > 3) |
373 | ath9k_hw_bstuck_nfcal(ah); | ||
378 | } else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) { | 374 | } else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) { |
379 | ath_dbg(common, ATH_DBG_BSTUCK, | 375 | ath_dbg(common, ATH_DBG_BSTUCK, |
380 | "beacon is officially stuck\n"); | 376 | "beacon is officially stuck\n"); |
@@ -385,13 +381,6 @@ void ath_beacon_tasklet(unsigned long data) | |||
385 | return; | 381 | return; |
386 | } | 382 | } |
387 | 383 | ||
388 | if (sc->beacon.bmisscnt != 0) { | ||
389 | ath_dbg(common, ATH_DBG_BSTUCK, | ||
390 | "resume beacon xmit after %u misses\n", | ||
391 | sc->beacon.bmisscnt); | ||
392 | sc->beacon.bmisscnt = 0; | ||
393 | } | ||
394 | |||
395 | /* | 384 | /* |
396 | * Generate beacon frames. we are sending frames | 385 | * Generate beacon frames. we are sending frames |
397 | * staggered so calculate the slot for this frame based | 386 | * staggered so calculate the slot for this frame based |
@@ -401,21 +390,14 @@ void ath_beacon_tasklet(unsigned long data) | |||
401 | intval = cur_conf->beacon_interval ? : ATH_DEFAULT_BINTVAL; | 390 | intval = cur_conf->beacon_interval ? : ATH_DEFAULT_BINTVAL; |
402 | 391 | ||
403 | tsf = ath9k_hw_gettsf64(ah); | 392 | tsf = ath9k_hw_gettsf64(ah); |
404 | tsftu = TSF_TO_TU(tsf>>32, tsf); | 393 | tsf += TU_TO_USEC(ah->config.sw_beacon_response_time); |
405 | slot = ((tsftu % intval) * ATH_BCBUF) / intval; | 394 | tsftu = TSF_TO_TU((tsf * ATH_BCBUF) >>32, tsf * ATH_BCBUF); |
406 | /* | 395 | slot = (tsftu % (intval * ATH_BCBUF)) / intval; |
407 | * Reverse the slot order to get slot 0 on the TBTT offset that does | ||
408 | * not require TSF adjustment and other slots adding | ||
409 | * slot/ATH_BCBUF * beacon_int to timestamp. For example, with | ||
410 | * ATH_BCBUF = 4, we process beacon slots as follows: 3 2 1 0 3 2 1 .. | ||
411 | * and slot 0 is at correct offset to TBTT. | ||
412 | */ | ||
413 | slot = ATH_BCBUF - slot - 1; | ||
414 | vif = sc->beacon.bslot[slot]; | 396 | vif = sc->beacon.bslot[slot]; |
415 | 397 | ||
416 | ath_dbg(common, ATH_DBG_BEACON, | 398 | ath_dbg(common, ATH_DBG_BEACON, |
417 | "slot %d [tsf %llu tsftu %u intval %u] vif %p\n", | 399 | "slot %d [tsf %llu tsftu %u intval %u] vif %p\n", |
418 | slot, tsf, tsftu, intval, vif); | 400 | slot, tsf, tsftu / ATH_BCBUF, intval, vif); |
419 | 401 | ||
420 | bfaddr = 0; | 402 | bfaddr = 0; |
421 | if (vif) { | 403 | if (vif) { |
@@ -424,6 +406,13 @@ void ath_beacon_tasklet(unsigned long data) | |||
424 | bfaddr = bf->bf_daddr; | 406 | bfaddr = bf->bf_daddr; |
425 | bc = 1; | 407 | bc = 1; |
426 | } | 408 | } |
409 | |||
410 | if (sc->beacon.bmisscnt != 0) { | ||
411 | ath_dbg(common, ATH_DBG_BSTUCK, | ||
412 | "resume beacon xmit after %u misses\n", | ||
413 | sc->beacon.bmisscnt); | ||
414 | sc->beacon.bmisscnt = 0; | ||
415 | } | ||
427 | } | 416 | } |
428 | 417 | ||
429 | /* | 418 | /* |
@@ -463,13 +452,17 @@ static void ath9k_beacon_init(struct ath_softc *sc, | |||
463 | u32 next_beacon, | 452 | u32 next_beacon, |
464 | u32 beacon_period) | 453 | u32 beacon_period) |
465 | { | 454 | { |
466 | if (beacon_period & ATH9K_BEACON_RESET_TSF) | 455 | if (sc->sc_flags & SC_OP_TSF_RESET) { |
467 | ath9k_ps_wakeup(sc); | 456 | ath9k_ps_wakeup(sc); |
457 | ath9k_hw_reset_tsf(sc->sc_ah); | ||
458 | } | ||
468 | 459 | ||
469 | ath9k_hw_beaconinit(sc->sc_ah, next_beacon, beacon_period); | 460 | ath9k_hw_beaconinit(sc->sc_ah, next_beacon, beacon_period); |
470 | 461 | ||
471 | if (beacon_period & ATH9K_BEACON_RESET_TSF) | 462 | if (sc->sc_flags & SC_OP_TSF_RESET) { |
472 | ath9k_ps_restore(sc); | 463 | ath9k_ps_restore(sc); |
464 | sc->sc_flags &= ~SC_OP_TSF_RESET; | ||
465 | } | ||
473 | } | 466 | } |
474 | 467 | ||
475 | /* | 468 | /* |
@@ -484,18 +477,14 @@ static void ath_beacon_config_ap(struct ath_softc *sc, | |||
484 | u32 nexttbtt, intval; | 477 | u32 nexttbtt, intval; |
485 | 478 | ||
486 | /* NB: the beacon interval is kept internally in TU's */ | 479 | /* NB: the beacon interval is kept internally in TU's */ |
487 | intval = conf->beacon_interval & ATH9K_BEACON_PERIOD; | 480 | intval = TU_TO_USEC(conf->beacon_interval & ATH9K_BEACON_PERIOD); |
488 | intval /= ATH_BCBUF; /* for staggered beacons */ | 481 | intval /= ATH_BCBUF; /* for staggered beacons */ |
489 | nexttbtt = intval; | 482 | nexttbtt = intval; |
490 | 483 | ||
491 | if (sc->sc_flags & SC_OP_TSF_RESET) | ||
492 | intval |= ATH9K_BEACON_RESET_TSF; | ||
493 | |||
494 | /* | 484 | /* |
495 | * In AP mode we enable the beacon timers and SWBA interrupts to | 485 | * In AP mode we enable the beacon timers and SWBA interrupts to |
496 | * prepare beacon frames. | 486 | * prepare beacon frames. |
497 | */ | 487 | */ |
498 | intval |= ATH9K_BEACON_ENA; | ||
499 | ah->imask |= ATH9K_INT_SWBA; | 488 | ah->imask |= ATH9K_INT_SWBA; |
500 | ath_beaconq_config(sc); | 489 | ath_beaconq_config(sc); |
501 | 490 | ||
@@ -505,11 +494,6 @@ static void ath_beacon_config_ap(struct ath_softc *sc, | |||
505 | ath9k_beacon_init(sc, nexttbtt, intval); | 494 | ath9k_beacon_init(sc, nexttbtt, intval); |
506 | sc->beacon.bmisscnt = 0; | 495 | sc->beacon.bmisscnt = 0; |
507 | ath9k_hw_set_interrupts(ah, ah->imask); | 496 | ath9k_hw_set_interrupts(ah, ah->imask); |
508 | |||
509 | /* Clear the reset TSF flag, so that subsequent beacon updation | ||
510 | will not reset the HW TSF. */ | ||
511 | |||
512 | sc->sc_flags &= ~SC_OP_TSF_RESET; | ||
513 | } | 497 | } |
514 | 498 | ||
515 | /* | 499 | /* |
@@ -643,25 +627,20 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc, | |||
643 | { | 627 | { |
644 | struct ath_hw *ah = sc->sc_ah; | 628 | struct ath_hw *ah = sc->sc_ah; |
645 | struct ath_common *common = ath9k_hw_common(ah); | 629 | struct ath_common *common = ath9k_hw_common(ah); |
646 | u64 tsf; | 630 | u32 tsf, delta, intval, nexttbtt; |
647 | u32 tsftu, intval, nexttbtt; | 631 | |
648 | 632 | tsf = ath9k_hw_gettsf32(ah) + TU_TO_USEC(FUDGE); | |
649 | intval = conf->beacon_interval & ATH9K_BEACON_PERIOD; | 633 | intval = TU_TO_USEC(conf->beacon_interval & ATH9K_BEACON_PERIOD); |
650 | 634 | ||
651 | 635 | if (!sc->beacon.bc_tstamp) | |
652 | /* Pull nexttbtt forward to reflect the current TSF */ | 636 | nexttbtt = tsf + intval; |
653 | 637 | else { | |
654 | nexttbtt = TSF_TO_TU(sc->beacon.bc_tstamp >> 32, sc->beacon.bc_tstamp); | 638 | if (tsf > sc->beacon.bc_tstamp) |
655 | if (nexttbtt == 0) | 639 | delta = (tsf - sc->beacon.bc_tstamp); |
656 | nexttbtt = intval; | 640 | else |
657 | else if (intval) | 641 | delta = (tsf + 1 + (~0U - sc->beacon.bc_tstamp)); |
658 | nexttbtt = roundup(nexttbtt, intval); | 642 | nexttbtt = tsf + roundup(delta, intval); |
659 | 643 | } | |
660 | tsf = ath9k_hw_gettsf64(ah); | ||
661 | tsftu = TSF_TO_TU((u32)(tsf>>32), (u32)tsf) + FUDGE; | ||
662 | do { | ||
663 | nexttbtt += intval; | ||
664 | } while (nexttbtt < tsftu); | ||
665 | 644 | ||
666 | ath_dbg(common, ATH_DBG_BEACON, | 645 | ath_dbg(common, ATH_DBG_BEACON, |
667 | "IBSS nexttbtt %u intval %u (%u)\n", | 646 | "IBSS nexttbtt %u intval %u (%u)\n", |
@@ -672,7 +651,6 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc, | |||
672 | * if we need to manually prepare beacon frames. Otherwise we use a | 651 | * if we need to manually prepare beacon frames. Otherwise we use a |
673 | * self-linked tx descriptor and let the hardware deal with things. | 652 | * self-linked tx descriptor and let the hardware deal with things. |
674 | */ | 653 | */ |
675 | intval |= ATH9K_BEACON_ENA; | ||
676 | ah->imask |= ATH9K_INT_SWBA; | 654 | ah->imask |= ATH9K_INT_SWBA; |
677 | 655 | ||
678 | ath_beaconq_config(sc); | 656 | ath_beaconq_config(sc); |
@@ -685,22 +663,63 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc, | |||
685 | ath9k_hw_set_interrupts(ah, ah->imask); | 663 | ath9k_hw_set_interrupts(ah, ah->imask); |
686 | } | 664 | } |
687 | 665 | ||
688 | void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif) | 666 | static bool ath9k_allow_beacon_config(struct ath_softc *sc, |
667 | struct ieee80211_vif *vif) | ||
689 | { | 668 | { |
690 | struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; | 669 | struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; |
691 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | 670 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); |
692 | enum nl80211_iftype iftype; | 671 | struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; |
672 | struct ath_vif *avp = (void *)vif->drv_priv; | ||
693 | 673 | ||
694 | /* Setup the beacon configuration parameters */ | 674 | /* |
695 | if (vif) { | 675 | * Can not have different beacon interval on multiple |
696 | struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; | 676 | * AP interface case |
697 | iftype = vif->type; | 677 | */ |
698 | cur_conf->beacon_interval = bss_conf->beacon_int; | 678 | if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) && |
699 | cur_conf->dtim_period = bss_conf->dtim_period; | 679 | (sc->nbcnvifs > 1) && |
700 | } else { | 680 | (vif->type == NL80211_IFTYPE_AP) && |
701 | iftype = sc->sc_ah->opmode; | 681 | (cur_conf->beacon_interval != bss_conf->beacon_int)) { |
682 | ath_dbg(common, ATH_DBG_CONFIG, | ||
683 | "Changing beacon interval of multiple \ | ||
684 | AP interfaces !\n"); | ||
685 | return false; | ||
702 | } | 686 | } |
687 | /* | ||
688 | * Can not configure station vif's beacon config | ||
689 | * while on AP opmode | ||
690 | */ | ||
691 | if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) && | ||
692 | (vif->type != NL80211_IFTYPE_AP)) { | ||
693 | ath_dbg(common, ATH_DBG_CONFIG, | ||
694 | "STA vif's beacon not allowed on AP mode\n"); | ||
695 | return false; | ||
696 | } | ||
697 | /* | ||
698 | * Do not allow beacon config if HW was already configured | ||
699 | * with another STA vif | ||
700 | */ | ||
701 | if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) && | ||
702 | (vif->type == NL80211_IFTYPE_STATION) && | ||
703 | (sc->sc_flags & SC_OP_BEACONS) && | ||
704 | !avp->primary_sta_vif) { | ||
705 | ath_dbg(common, ATH_DBG_CONFIG, | ||
706 | "Beacon already configured for a station interface\n"); | ||
707 | return false; | ||
708 | } | ||
709 | return true; | ||
710 | } | ||
711 | |||
712 | void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif) | ||
713 | { | ||
714 | struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; | ||
715 | struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; | ||
716 | |||
717 | if (!ath9k_allow_beacon_config(sc, vif)) | ||
718 | return; | ||
703 | 719 | ||
720 | /* Setup the beacon configuration parameters */ | ||
721 | cur_conf->beacon_interval = bss_conf->beacon_int; | ||
722 | cur_conf->dtim_period = bss_conf->dtim_period; | ||
704 | cur_conf->listen_interval = 1; | 723 | cur_conf->listen_interval = 1; |
705 | cur_conf->dtim_count = 1; | 724 | cur_conf->dtim_count = 1; |
706 | cur_conf->bmiss_timeout = | 725 | cur_conf->bmiss_timeout = |
@@ -723,7 +742,16 @@ void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif) | |||
723 | if (cur_conf->dtim_period == 0) | 742 | if (cur_conf->dtim_period == 0) |
724 | cur_conf->dtim_period = 1; | 743 | cur_conf->dtim_period = 1; |
725 | 744 | ||
726 | switch (iftype) { | 745 | ath_set_beacon(sc); |
746 | sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON; | ||
747 | } | ||
748 | |||
749 | void ath_set_beacon(struct ath_softc *sc) | ||
750 | { | ||
751 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | ||
752 | struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; | ||
753 | |||
754 | switch (sc->sc_ah->opmode) { | ||
727 | case NL80211_IFTYPE_AP: | 755 | case NL80211_IFTYPE_AP: |
728 | ath_beacon_config_ap(sc, cur_conf); | 756 | ath_beacon_config_ap(sc, cur_conf); |
729 | break; | 757 | break; |
@@ -750,22 +778,23 @@ void ath9k_set_beaconing_status(struct ath_softc *sc, bool status) | |||
750 | int slot; | 778 | int slot; |
751 | bool found = false; | 779 | bool found = false; |
752 | 780 | ||
753 | ath9k_ps_wakeup(sc); | 781 | for (slot = 0; slot < ATH_BCBUF; slot++) { |
754 | if (status) { | 782 | if (sc->beacon.bslot[slot]) { |
755 | for (slot = 0; slot < ATH_BCBUF; slot++) { | 783 | avp = (void *)sc->beacon.bslot[slot]->drv_priv; |
756 | if (sc->beacon.bslot[slot]) { | 784 | if (avp->is_bslot_active) { |
757 | avp = (void *)sc->beacon.bslot[slot]->drv_priv; | 785 | found = true; |
758 | if (avp->is_bslot_active) { | 786 | break; |
759 | found = true; | ||
760 | break; | ||
761 | } | ||
762 | } | 787 | } |
763 | } | 788 | } |
764 | if (found) { | 789 | } |
765 | /* Re-enable beaconing */ | 790 | if (!found) |
766 | ah->imask |= ATH9K_INT_SWBA; | 791 | return; |
767 | ath9k_hw_set_interrupts(ah, ah->imask); | 792 | |
768 | } | 793 | ath9k_ps_wakeup(sc); |
794 | if (status) { | ||
795 | /* Re-enable beaconing */ | ||
796 | ah->imask |= ATH9K_INT_SWBA; | ||
797 | ath9k_hw_set_interrupts(ah, ah->imask); | ||
769 | } else { | 798 | } else { |
770 | /* Disable SWBA interrupt */ | 799 | /* Disable SWBA interrupt */ |
771 | ah->imask &= ~ATH9K_INT_SWBA; | 800 | ah->imask &= ~ATH9K_INT_SWBA; |
diff --git a/drivers/net/wireless/ath/ath9k/common.c b/drivers/net/wireless/ath/ath9k/common.c index 615e68276e72..16ba8c67fbd5 100644 --- a/drivers/net/wireless/ath/ath9k/common.c +++ b/drivers/net/wireless/ath/ath9k/common.c | |||
@@ -116,7 +116,7 @@ void ath9k_cmn_update_ichannel(struct ath9k_channel *ichan, | |||
116 | 116 | ||
117 | if (chan->band == IEEE80211_BAND_2GHZ) { | 117 | if (chan->band == IEEE80211_BAND_2GHZ) { |
118 | ichan->chanmode = CHANNEL_G; | 118 | ichan->chanmode = CHANNEL_G; |
119 | ichan->channelFlags = CHANNEL_2GHZ | CHANNEL_OFDM | CHANNEL_G; | 119 | ichan->channelFlags = CHANNEL_2GHZ | CHANNEL_OFDM; |
120 | } else { | 120 | } else { |
121 | ichan->chanmode = CHANNEL_A; | 121 | ichan->chanmode = CHANNEL_A; |
122 | ichan->channelFlags = CHANNEL_5GHZ | CHANNEL_OFDM; | 122 | ichan->channelFlags = CHANNEL_5GHZ | CHANNEL_OFDM; |
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 8df5a92a20f1..a762cadb3ab7 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c | |||
@@ -1088,67 +1088,43 @@ int ath9k_init_debug(struct ath_hw *ah) | |||
1088 | return -ENOMEM; | 1088 | return -ENOMEM; |
1089 | 1089 | ||
1090 | #ifdef CONFIG_ATH_DEBUG | 1090 | #ifdef CONFIG_ATH_DEBUG |
1091 | if (!debugfs_create_file("debug", S_IRUSR | S_IWUSR, | 1091 | debugfs_create_file("debug", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, |
1092 | sc->debug.debugfs_phy, sc, &fops_debug)) | 1092 | sc, &fops_debug); |
1093 | goto err; | ||
1094 | #endif | 1093 | #endif |
1095 | 1094 | debugfs_create_file("dma", S_IRUSR, sc->debug.debugfs_phy, sc, | |
1096 | if (!debugfs_create_file("dma", S_IRUSR, sc->debug.debugfs_phy, | 1095 | &fops_dma); |
1097 | sc, &fops_dma)) | 1096 | debugfs_create_file("interrupt", S_IRUSR, sc->debug.debugfs_phy, sc, |
1098 | goto err; | 1097 | &fops_interrupt); |
1099 | 1098 | debugfs_create_file("wiphy", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, | |
1100 | if (!debugfs_create_file("interrupt", S_IRUSR, sc->debug.debugfs_phy, | 1099 | sc, &fops_wiphy); |
1101 | sc, &fops_interrupt)) | 1100 | debugfs_create_file("xmit", S_IRUSR, sc->debug.debugfs_phy, sc, |
1102 | goto err; | 1101 | &fops_xmit); |
1103 | 1102 | debugfs_create_file("stations", S_IRUSR, sc->debug.debugfs_phy, sc, | |
1104 | if (!debugfs_create_file("wiphy", S_IRUSR | S_IWUSR, | 1103 | &fops_stations); |
1105 | sc->debug.debugfs_phy, sc, &fops_wiphy)) | 1104 | debugfs_create_file("misc", S_IRUSR, sc->debug.debugfs_phy, sc, |
1106 | goto err; | 1105 | &fops_misc); |
1107 | 1106 | debugfs_create_file("recv", S_IRUSR, sc->debug.debugfs_phy, sc, | |
1108 | if (!debugfs_create_file("xmit", S_IRUSR, sc->debug.debugfs_phy, | 1107 | &fops_recv); |
1109 | sc, &fops_xmit)) | 1108 | debugfs_create_file("rx_chainmask", S_IRUSR | S_IWUSR, |
1110 | goto err; | 1109 | sc->debug.debugfs_phy, sc, &fops_rx_chainmask); |
1111 | 1110 | debugfs_create_file("tx_chainmask", S_IRUSR | S_IWUSR, | |
1112 | if (!debugfs_create_file("stations", S_IRUSR, sc->debug.debugfs_phy, | 1111 | sc->debug.debugfs_phy, sc, &fops_tx_chainmask); |
1113 | sc, &fops_stations)) | 1112 | debugfs_create_file("regidx", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, |
1114 | goto err; | 1113 | sc, &fops_regidx); |
1115 | 1114 | debugfs_create_file("regval", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, | |
1116 | if (!debugfs_create_file("misc", S_IRUSR, sc->debug.debugfs_phy, | 1115 | sc, &fops_regval); |
1117 | sc, &fops_misc)) | 1116 | debugfs_create_bool("ignore_extcca", S_IRUSR | S_IWUSR, |
1118 | goto err; | 1117 | sc->debug.debugfs_phy, |
1119 | 1118 | &ah->config.cwm_ignore_extcca); | |
1120 | if (!debugfs_create_file("recv", S_IRUSR, sc->debug.debugfs_phy, | 1119 | debugfs_create_file("regdump", S_IRUSR, sc->debug.debugfs_phy, sc, |
1121 | sc, &fops_recv)) | 1120 | &fops_regdump); |
1122 | goto err; | 1121 | |
1123 | 1122 | debugfs_create_u32("gpio_mask", S_IRUSR | S_IWUSR, | |
1124 | if (!debugfs_create_file("rx_chainmask", S_IRUSR | S_IWUSR, | 1123 | sc->debug.debugfs_phy, &sc->sc_ah->gpio_mask); |
1125 | sc->debug.debugfs_phy, sc, &fops_rx_chainmask)) | 1124 | |
1126 | goto err; | 1125 | debugfs_create_u32("gpio_val", S_IRUSR | S_IWUSR, |
1127 | 1126 | sc->debug.debugfs_phy, &sc->sc_ah->gpio_val); | |
1128 | if (!debugfs_create_file("tx_chainmask", S_IRUSR | S_IWUSR, | ||
1129 | sc->debug.debugfs_phy, sc, &fops_tx_chainmask)) | ||
1130 | goto err; | ||
1131 | |||
1132 | if (!debugfs_create_file("regidx", S_IRUSR | S_IWUSR, | ||
1133 | sc->debug.debugfs_phy, sc, &fops_regidx)) | ||
1134 | goto err; | ||
1135 | |||
1136 | if (!debugfs_create_file("regval", S_IRUSR | S_IWUSR, | ||
1137 | sc->debug.debugfs_phy, sc, &fops_regval)) | ||
1138 | goto err; | ||
1139 | |||
1140 | if (!debugfs_create_bool("ignore_extcca", S_IRUSR | S_IWUSR, | ||
1141 | sc->debug.debugfs_phy, &ah->config.cwm_ignore_extcca)) | ||
1142 | goto err; | ||
1143 | |||
1144 | if (!debugfs_create_file("regdump", S_IRUSR, sc->debug.debugfs_phy, | ||
1145 | sc, &fops_regdump)) | ||
1146 | goto err; | ||
1147 | 1127 | ||
1148 | sc->debug.regidx = 0; | 1128 | sc->debug.regidx = 0; |
1149 | return 0; | 1129 | return 0; |
1150 | err: | ||
1151 | debugfs_remove_recursive(sc->debug.debugfs_phy); | ||
1152 | sc->debug.debugfs_phy = NULL; | ||
1153 | return -ENOMEM; | ||
1154 | } | 1130 | } |
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_9287.c b/drivers/net/wireless/ath/ath9k/eeprom_9287.c index 8cd8333cc086..2f0712ea49a6 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c | |||
@@ -392,6 +392,8 @@ static void ath9k_hw_set_ar9287_power_cal_table(struct ath_hw *ah, | |||
392 | numXpdGain); | 392 | numXpdGain); |
393 | } | 393 | } |
394 | 394 | ||
395 | ENABLE_REGWRITE_BUFFER(ah); | ||
396 | |||
395 | if (i == 0) { | 397 | if (i == 0) { |
396 | if (!ath9k_hw_ar9287_get_eeprom(ah, | 398 | if (!ath9k_hw_ar9287_get_eeprom(ah, |
397 | EEP_OL_PWRCTRL)) { | 399 | EEP_OL_PWRCTRL)) { |
@@ -442,6 +444,7 @@ static void ath9k_hw_set_ar9287_power_cal_table(struct ath_hw *ah, | |||
442 | regOffset += 4; | 444 | regOffset += 4; |
443 | } | 445 | } |
444 | } | 446 | } |
447 | REGWRITE_BUFFER_FLUSH(ah); | ||
445 | } | 448 | } |
446 | } | 449 | } |
447 | 450 | ||
@@ -757,6 +760,8 @@ static void ath9k_hw_ar9287_set_txpower(struct ath_hw *ah, | |||
757 | ratesArray[i] -= AR9287_PWR_TABLE_OFFSET_DB * 2; | 760 | ratesArray[i] -= AR9287_PWR_TABLE_OFFSET_DB * 2; |
758 | } | 761 | } |
759 | 762 | ||
763 | ENABLE_REGWRITE_BUFFER(ah); | ||
764 | |||
760 | /* OFDM power per rate */ | 765 | /* OFDM power per rate */ |
761 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, | 766 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, |
762 | ATH9K_POW_SM(ratesArray[rate18mb], 24) | 767 | ATH9K_POW_SM(ratesArray[rate18mb], 24) |
@@ -840,6 +845,7 @@ static void ath9k_hw_ar9287_set_txpower(struct ath_hw *ah, | |||
840 | | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) | 845 | | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) |
841 | | ATH9K_POW_SM(ratesArray[rateDupCck], 0)); | 846 | | ATH9K_POW_SM(ratesArray[rateDupCck], 0)); |
842 | } | 847 | } |
848 | REGWRITE_BUFFER_FLUSH(ah); | ||
843 | } | 849 | } |
844 | 850 | ||
845 | static void ath9k_hw_ar9287_set_addac(struct ath_hw *ah, | 851 | static void ath9k_hw_ar9287_set_addac(struct ath_hw *ah, |
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_def.c b/drivers/net/wireless/ath/ath9k/eeprom_def.c index fccd87df7300..995949ddd63e 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_def.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c | |||
@@ -799,6 +799,8 @@ static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah, | |||
799 | pwr_table_offset, | 799 | pwr_table_offset, |
800 | &diff); | 800 | &diff); |
801 | 801 | ||
802 | ENABLE_REGWRITE_BUFFER(ah); | ||
803 | |||
802 | if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah)) { | 804 | if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah)) { |
803 | if (OLC_FOR_AR9280_20_LATER) { | 805 | if (OLC_FOR_AR9280_20_LATER) { |
804 | REG_WRITE(ah, | 806 | REG_WRITE(ah, |
@@ -847,6 +849,7 @@ static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah, | |||
847 | 849 | ||
848 | regOffset += 4; | 850 | regOffset += 4; |
849 | } | 851 | } |
852 | REGWRITE_BUFFER_FLUSH(ah); | ||
850 | } | 853 | } |
851 | } | 854 | } |
852 | 855 | ||
@@ -1205,6 +1208,8 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah, | |||
1205 | } | 1208 | } |
1206 | } | 1209 | } |
1207 | 1210 | ||
1211 | ENABLE_REGWRITE_BUFFER(ah); | ||
1212 | |||
1208 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, | 1213 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, |
1209 | ATH9K_POW_SM(ratesArray[rate18mb], 24) | 1214 | ATH9K_POW_SM(ratesArray[rate18mb], 24) |
1210 | | ATH9K_POW_SM(ratesArray[rate12mb], 16) | 1215 | | ATH9K_POW_SM(ratesArray[rate12mb], 16) |
@@ -1291,6 +1296,8 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah, | |||
1291 | REG_WRITE(ah, AR_PHY_POWER_TX_SUB, | 1296 | REG_WRITE(ah, AR_PHY_POWER_TX_SUB, |
1292 | ATH9K_POW_SM(pModal->pwrDecreaseFor3Chain, 6) | 1297 | ATH9K_POW_SM(pModal->pwrDecreaseFor3Chain, 6) |
1293 | | ATH9K_POW_SM(pModal->pwrDecreaseFor2Chain, 0)); | 1298 | | ATH9K_POW_SM(pModal->pwrDecreaseFor2Chain, 0)); |
1299 | |||
1300 | REGWRITE_BUFFER_FLUSH(ah); | ||
1294 | } | 1301 | } |
1295 | 1302 | ||
1296 | static u16 ath9k_hw_def_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz) | 1303 | static u16 ath9k_hw_def_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz) |
diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c index 0fb8f8ac275a..44a0a886124d 100644 --- a/drivers/net/wireless/ath/ath9k/gpio.c +++ b/drivers/net/wireless/ath/ath9k/gpio.c | |||
@@ -41,12 +41,14 @@ void ath_init_leds(struct ath_softc *sc) | |||
41 | { | 41 | { |
42 | int ret; | 42 | int ret; |
43 | 43 | ||
44 | if (AR_SREV_9287(sc->sc_ah)) | 44 | if (sc->sc_ah->led_pin < 0) { |
45 | sc->sc_ah->led_pin = ATH_LED_PIN_9287; | 45 | if (AR_SREV_9287(sc->sc_ah)) |
46 | else if (AR_SREV_9485(sc->sc_ah)) | 46 | sc->sc_ah->led_pin = ATH_LED_PIN_9287; |
47 | sc->sc_ah->led_pin = ATH_LED_PIN_9485; | 47 | else if (AR_SREV_9485(sc->sc_ah)) |
48 | else | 48 | sc->sc_ah->led_pin = ATH_LED_PIN_9485; |
49 | sc->sc_ah->led_pin = ATH_LED_PIN_DEF; | 49 | else |
50 | sc->sc_ah->led_pin = ATH_LED_PIN_DEF; | ||
51 | } | ||
50 | 52 | ||
51 | /* Configure gpio 1 for output */ | 53 | /* Configure gpio 1 for output */ |
52 | ath9k_hw_cfg_output(sc->sc_ah, sc->sc_ah->led_pin, | 54 | ath9k_hw_cfg_output(sc->sc_ah, sc->sc_ah->led_pin, |
diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 753a245c5ad1..ec47be94b74f 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h | |||
@@ -328,7 +328,7 @@ struct ath9k_debug { | |||
328 | #endif /* CONFIG_ATH9K_HTC_DEBUGFS */ | 328 | #endif /* CONFIG_ATH9K_HTC_DEBUGFS */ |
329 | 329 | ||
330 | #define ATH_LED_PIN_DEF 1 | 330 | #define ATH_LED_PIN_DEF 1 |
331 | #define ATH_LED_PIN_9287 8 | 331 | #define ATH_LED_PIN_9287 10 |
332 | #define ATH_LED_PIN_9271 15 | 332 | #define ATH_LED_PIN_9271 15 |
333 | #define ATH_LED_PIN_7010 12 | 333 | #define ATH_LED_PIN_7010 12 |
334 | #define ATH_LED_ON_DURATION_IDLE 350 /* in msecs */ | 334 | #define ATH_LED_ON_DURATION_IDLE 350 /* in msecs */ |
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c index 8d1d8792436d..8f56158e5887 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c | |||
@@ -155,7 +155,7 @@ static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv, | |||
155 | nexttbtt = intval; | 155 | nexttbtt = intval; |
156 | 156 | ||
157 | if (priv->op_flags & OP_TSF_RESET) { | 157 | if (priv->op_flags & OP_TSF_RESET) { |
158 | intval |= ATH9K_BEACON_RESET_TSF; | 158 | ath9k_hw_reset_tsf(priv->ah); |
159 | priv->op_flags &= ~OP_TSF_RESET; | 159 | priv->op_flags &= ~OP_TSF_RESET; |
160 | } else { | 160 | } else { |
161 | /* | 161 | /* |
@@ -168,8 +168,6 @@ static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv, | |||
168 | } while (nexttbtt < tsftu); | 168 | } while (nexttbtt < tsftu); |
169 | } | 169 | } |
170 | 170 | ||
171 | intval |= ATH9K_BEACON_ENA; | ||
172 | |||
173 | if (priv->op_flags & OP_ENABLE_BEACON) | 171 | if (priv->op_flags & OP_ENABLE_BEACON) |
174 | imask |= ATH9K_INT_SWBA; | 172 | imask |= ATH9K_INT_SWBA; |
175 | 173 | ||
@@ -178,7 +176,7 @@ static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv, | |||
178 | bss_conf->beacon_interval, nexttbtt, imask); | 176 | bss_conf->beacon_interval, nexttbtt, imask); |
179 | 177 | ||
180 | WMI_CMD(WMI_DISABLE_INTR_CMDID); | 178 | WMI_CMD(WMI_DISABLE_INTR_CMDID); |
181 | ath9k_hw_beaconinit(priv->ah, nexttbtt, intval); | 179 | ath9k_hw_beaconinit(priv->ah, TU_TO_USEC(nexttbtt), TU_TO_USEC(intval)); |
182 | priv->bmiss_cnt = 0; | 180 | priv->bmiss_cnt = 0; |
183 | htc_imask = cpu_to_be32(imask); | 181 | htc_imask = cpu_to_be32(imask); |
184 | WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask); | 182 | WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask); |
@@ -207,7 +205,6 @@ static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv, | |||
207 | nexttbtt += intval; | 205 | nexttbtt += intval; |
208 | } while (nexttbtt < tsftu); | 206 | } while (nexttbtt < tsftu); |
209 | 207 | ||
210 | intval |= ATH9K_BEACON_ENA; | ||
211 | if (priv->op_flags & OP_ENABLE_BEACON) | 208 | if (priv->op_flags & OP_ENABLE_BEACON) |
212 | imask |= ATH9K_INT_SWBA; | 209 | imask |= ATH9K_INT_SWBA; |
213 | 210 | ||
@@ -216,7 +213,7 @@ static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv, | |||
216 | bss_conf->beacon_interval, nexttbtt, imask); | 213 | bss_conf->beacon_interval, nexttbtt, imask); |
217 | 214 | ||
218 | WMI_CMD(WMI_DISABLE_INTR_CMDID); | 215 | WMI_CMD(WMI_DISABLE_INTR_CMDID); |
219 | ath9k_hw_beaconinit(priv->ah, nexttbtt, intval); | 216 | ath9k_hw_beaconinit(priv->ah, TU_TO_USEC(nexttbtt), TU_TO_USEC(intval)); |
220 | priv->bmiss_cnt = 0; | 217 | priv->bmiss_cnt = 0; |
221 | htc_imask = cpu_to_be32(imask); | 218 | htc_imask = cpu_to_be32(imask); |
222 | WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask); | 219 | WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask); |
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index fc67c937e172..8303b34bdc90 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c | |||
@@ -430,13 +430,16 @@ static void ath9k_regwrite_flush(void *hw_priv) | |||
430 | mutex_unlock(&priv->wmi->multi_write_mutex); | 430 | mutex_unlock(&priv->wmi->multi_write_mutex); |
431 | } | 431 | } |
432 | 432 | ||
433 | static const struct ath_ops ath9k_common_ops = { | 433 | static u32 ath9k_reg_rmw(void *hw_priv, u32 reg_offset, u32 set, u32 clr) |
434 | .read = ath9k_regread, | 434 | { |
435 | .multi_read = ath9k_multi_regread, | 435 | u32 val; |
436 | .write = ath9k_regwrite, | 436 | |
437 | .enable_write_buffer = ath9k_enable_regwrite_buffer, | 437 | val = ath9k_regread(hw_priv, reg_offset); |
438 | .write_flush = ath9k_regwrite_flush, | 438 | val &= ~clr; |
439 | }; | 439 | val |= set; |
440 | ath9k_regwrite(hw_priv, val, reg_offset); | ||
441 | return val; | ||
442 | } | ||
440 | 443 | ||
441 | static void ath_usb_read_cachesize(struct ath_common *common, int *csz) | 444 | static void ath_usb_read_cachesize(struct ath_common *common, int *csz) |
442 | { | 445 | { |
@@ -561,13 +564,7 @@ static void ath9k_init_crypto(struct ath9k_htc_priv *priv) | |||
561 | int i = 0; | 564 | int i = 0; |
562 | 565 | ||
563 | /* Get the hardware key cache size. */ | 566 | /* Get the hardware key cache size. */ |
564 | common->keymax = priv->ah->caps.keycache_size; | 567 | common->keymax = AR_KEYTABLE_SIZE; |
565 | if (common->keymax > ATH_KEYMAX) { | ||
566 | ath_dbg(common, ATH_DBG_ANY, | ||
567 | "Warning, using only %u entries in %u key cache\n", | ||
568 | ATH_KEYMAX, common->keymax); | ||
569 | common->keymax = ATH_KEYMAX; | ||
570 | } | ||
571 | 568 | ||
572 | if (priv->ah->misc_mode & AR_PCU_MIC_NEW_LOC_ENA) | 569 | if (priv->ah->misc_mode & AR_PCU_MIC_NEW_LOC_ENA) |
573 | common->crypt_caps |= ATH_CRYPT_CAP_MIC_COMBINED; | 570 | common->crypt_caps |= ATH_CRYPT_CAP_MIC_COMBINED; |
@@ -658,10 +655,16 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv, | |||
658 | ah->hw_version.subsysid = 0; /* FIXME */ | 655 | ah->hw_version.subsysid = 0; /* FIXME */ |
659 | ah->hw_version.usbdev = drv_info; | 656 | ah->hw_version.usbdev = drv_info; |
660 | ah->ah_flags |= AH_USE_EEPROM; | 657 | ah->ah_flags |= AH_USE_EEPROM; |
658 | ah->reg_ops.read = ath9k_regread; | ||
659 | ah->reg_ops.multi_read = ath9k_multi_regread; | ||
660 | ah->reg_ops.write = ath9k_regwrite; | ||
661 | ah->reg_ops.enable_write_buffer = ath9k_enable_regwrite_buffer; | ||
662 | ah->reg_ops.write_flush = ath9k_regwrite_flush; | ||
663 | ah->reg_ops.rmw = ath9k_reg_rmw; | ||
661 | priv->ah = ah; | 664 | priv->ah = ah; |
662 | 665 | ||
663 | common = ath9k_hw_common(ah); | 666 | common = ath9k_hw_common(ah); |
664 | common->ops = &ath9k_common_ops; | 667 | common->ops = &ah->reg_ops; |
665 | common->bus_ops = &ath9k_usb_bus_ops; | 668 | common->bus_ops = &ath9k_usb_bus_ops; |
666 | common->ah = ah; | 669 | common->ah = ah; |
667 | common->hw = priv->hw; | 670 | common->hw = priv->hw; |
diff --git a/drivers/net/wireless/ath/ath9k/hw-ops.h b/drivers/net/wireless/ath/ath9k/hw-ops.h index c8f254fe0f0b..22ee888b0baf 100644 --- a/drivers/net/wireless/ath/ath9k/hw-ops.h +++ b/drivers/net/wireless/ath/ath9k/hw-ops.h | |||
@@ -122,12 +122,6 @@ static inline void ath9k_hw_set11n_burstduration(struct ath_hw *ah, void *ds, | |||
122 | ath9k_hw_ops(ah)->set11n_burstduration(ah, ds, burstDuration); | 122 | ath9k_hw_ops(ah)->set11n_burstduration(ah, ds, burstDuration); |
123 | } | 123 | } |
124 | 124 | ||
125 | static inline void ath9k_hw_set11n_virtualmorefrag(struct ath_hw *ah, void *ds, | ||
126 | u32 vmf) | ||
127 | { | ||
128 | ath9k_hw_ops(ah)->set11n_virtualmorefrag(ah, ds, vmf); | ||
129 | } | ||
130 | |||
131 | /* Private hardware call ops */ | 125 | /* Private hardware call ops */ |
132 | 126 | ||
133 | /* PHY ops */ | 127 | /* PHY ops */ |
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 1ec9bcd6b281..1b5bd13b0a6c 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c | |||
@@ -130,6 +130,20 @@ bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout) | |||
130 | } | 130 | } |
131 | EXPORT_SYMBOL(ath9k_hw_wait); | 131 | EXPORT_SYMBOL(ath9k_hw_wait); |
132 | 132 | ||
133 | void ath9k_hw_write_array(struct ath_hw *ah, struct ar5416IniArray *array, | ||
134 | int column, unsigned int *writecnt) | ||
135 | { | ||
136 | int r; | ||
137 | |||
138 | ENABLE_REGWRITE_BUFFER(ah); | ||
139 | for (r = 0; r < array->ia_rows; r++) { | ||
140 | REG_WRITE(ah, INI_RA(array, r, 0), | ||
141 | INI_RA(array, r, column)); | ||
142 | DO_DELAY(*writecnt); | ||
143 | } | ||
144 | REGWRITE_BUFFER_FLUSH(ah); | ||
145 | } | ||
146 | |||
133 | u32 ath9k_hw_reverse_bits(u32 val, u32 n) | 147 | u32 ath9k_hw_reverse_bits(u32 val, u32 n) |
134 | { | 148 | { |
135 | u32 retval; | 149 | u32 retval; |
@@ -142,25 +156,6 @@ u32 ath9k_hw_reverse_bits(u32 val, u32 n) | |||
142 | return retval; | 156 | return retval; |
143 | } | 157 | } |
144 | 158 | ||
145 | bool ath9k_get_channel_edges(struct ath_hw *ah, | ||
146 | u16 flags, u16 *low, | ||
147 | u16 *high) | ||
148 | { | ||
149 | struct ath9k_hw_capabilities *pCap = &ah->caps; | ||
150 | |||
151 | if (flags & CHANNEL_5GHZ) { | ||
152 | *low = pCap->low_5ghz_chan; | ||
153 | *high = pCap->high_5ghz_chan; | ||
154 | return true; | ||
155 | } | ||
156 | if ((flags & CHANNEL_2GHZ)) { | ||
157 | *low = pCap->low_2ghz_chan; | ||
158 | *high = pCap->high_2ghz_chan; | ||
159 | return true; | ||
160 | } | ||
161 | return false; | ||
162 | } | ||
163 | |||
164 | u16 ath9k_hw_computetxtime(struct ath_hw *ah, | 159 | u16 ath9k_hw_computetxtime(struct ath_hw *ah, |
165 | u8 phy, int kbps, | 160 | u8 phy, int kbps, |
166 | u32 frameLen, u16 rateix, | 161 | u32 frameLen, u16 rateix, |
@@ -364,11 +359,6 @@ static void ath9k_hw_init_config(struct ath_hw *ah) | |||
364 | ah->config.spurchans[i][1] = AR_NO_SPUR; | 359 | ah->config.spurchans[i][1] = AR_NO_SPUR; |
365 | } | 360 | } |
366 | 361 | ||
367 | if (ah->hw_version.devid != AR2427_DEVID_PCIE) | ||
368 | ah->config.ht_enable = 1; | ||
369 | else | ||
370 | ah->config.ht_enable = 0; | ||
371 | |||
372 | /* PAPRD needs some more work to be enabled */ | 362 | /* PAPRD needs some more work to be enabled */ |
373 | ah->config.paprd_disable = 1; | 363 | ah->config.paprd_disable = 1; |
374 | 364 | ||
@@ -410,6 +400,8 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah) | |||
410 | ah->sta_id1_defaults = | 400 | ah->sta_id1_defaults = |
411 | AR_STA_ID1_CRPT_MIC_ENABLE | | 401 | AR_STA_ID1_CRPT_MIC_ENABLE | |
412 | AR_STA_ID1_MCAST_KSRCH; | 402 | AR_STA_ID1_MCAST_KSRCH; |
403 | if (AR_SREV_9100(ah)) | ||
404 | ah->sta_id1_defaults |= AR_STA_ID1_AR9100_BA_FIX; | ||
413 | ah->enable_32kHz_clock = DONT_USE_32KHZ; | 405 | ah->enable_32kHz_clock = DONT_USE_32KHZ; |
414 | ah->slottime = 20; | 406 | ah->slottime = 20; |
415 | ah->globaltxtimeout = (u32) -1; | 407 | ah->globaltxtimeout = (u32) -1; |
@@ -673,14 +665,14 @@ static void ath9k_hw_init_qos(struct ath_hw *ah) | |||
673 | 665 | ||
674 | unsigned long ar9003_get_pll_sqsum_dvc(struct ath_hw *ah) | 666 | unsigned long ar9003_get_pll_sqsum_dvc(struct ath_hw *ah) |
675 | { | 667 | { |
676 | REG_WRITE(ah, PLL3, (REG_READ(ah, PLL3) & ~(PLL3_DO_MEAS_MASK))); | 668 | REG_CLR_BIT(ah, PLL3, PLL3_DO_MEAS_MASK); |
677 | udelay(100); | 669 | udelay(100); |
678 | REG_WRITE(ah, PLL3, (REG_READ(ah, PLL3) | PLL3_DO_MEAS_MASK)); | 670 | REG_SET_BIT(ah, PLL3, PLL3_DO_MEAS_MASK); |
679 | 671 | ||
680 | while ((REG_READ(ah, PLL4) & PLL4_MEAS_DONE) == 0) | 672 | while ((REG_READ(ah, PLL4) & PLL4_MEAS_DONE) == 0) |
681 | udelay(100); | 673 | udelay(100); |
682 | 674 | ||
683 | return (REG_READ(ah, PLL3) & SQSUM_DVC_MASK) >> 3; | 675 | return (REG_READ(ah, PLL3) & SQSUM_DVC_MASK) >> 3; |
684 | } | 676 | } |
685 | EXPORT_SYMBOL(ar9003_get_pll_sqsum_dvc); | 677 | EXPORT_SYMBOL(ar9003_get_pll_sqsum_dvc); |
686 | 678 | ||
@@ -830,8 +822,7 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah) | |||
830 | ah->misc_mode); | 822 | ah->misc_mode); |
831 | 823 | ||
832 | if (ah->misc_mode != 0) | 824 | if (ah->misc_mode != 0) |
833 | REG_WRITE(ah, AR_PCU_MISC, | 825 | REG_SET_BIT(ah, AR_PCU_MISC, ah->misc_mode); |
834 | REG_READ(ah, AR_PCU_MISC) | ah->misc_mode); | ||
835 | 826 | ||
836 | if (conf->channel && conf->channel->band == IEEE80211_BAND_5GHZ) | 827 | if (conf->channel && conf->channel->band == IEEE80211_BAND_5GHZ) |
837 | sifstime = 16; | 828 | sifstime = 16; |
@@ -899,23 +890,19 @@ u32 ath9k_regd_get_ctl(struct ath_regulatory *reg, struct ath9k_channel *chan) | |||
899 | static inline void ath9k_hw_set_dma(struct ath_hw *ah) | 890 | static inline void ath9k_hw_set_dma(struct ath_hw *ah) |
900 | { | 891 | { |
901 | struct ath_common *common = ath9k_hw_common(ah); | 892 | struct ath_common *common = ath9k_hw_common(ah); |
902 | u32 regval; | ||
903 | 893 | ||
904 | ENABLE_REGWRITE_BUFFER(ah); | 894 | ENABLE_REGWRITE_BUFFER(ah); |
905 | 895 | ||
906 | /* | 896 | /* |
907 | * set AHB_MODE not to do cacheline prefetches | 897 | * set AHB_MODE not to do cacheline prefetches |
908 | */ | 898 | */ |
909 | if (!AR_SREV_9300_20_OR_LATER(ah)) { | 899 | if (!AR_SREV_9300_20_OR_LATER(ah)) |
910 | regval = REG_READ(ah, AR_AHB_MODE); | 900 | REG_SET_BIT(ah, AR_AHB_MODE, AR_AHB_PREFETCH_RD_EN); |
911 | REG_WRITE(ah, AR_AHB_MODE, regval | AR_AHB_PREFETCH_RD_EN); | ||
912 | } | ||
913 | 901 | ||
914 | /* | 902 | /* |
915 | * let mac dma reads be in 128 byte chunks | 903 | * let mac dma reads be in 128 byte chunks |
916 | */ | 904 | */ |
917 | regval = REG_READ(ah, AR_TXCFG) & ~AR_TXCFG_DMASZ_MASK; | 905 | REG_RMW(ah, AR_TXCFG, AR_TXCFG_DMASZ_128B, AR_TXCFG_DMASZ_MASK); |
918 | REG_WRITE(ah, AR_TXCFG, regval | AR_TXCFG_DMASZ_128B); | ||
919 | 906 | ||
920 | REGWRITE_BUFFER_FLUSH(ah); | 907 | REGWRITE_BUFFER_FLUSH(ah); |
921 | 908 | ||
@@ -932,8 +919,7 @@ static inline void ath9k_hw_set_dma(struct ath_hw *ah) | |||
932 | /* | 919 | /* |
933 | * let mac dma writes be in 128 byte chunks | 920 | * let mac dma writes be in 128 byte chunks |
934 | */ | 921 | */ |
935 | regval = REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_DMASZ_MASK; | 922 | REG_RMW(ah, AR_RXCFG, AR_RXCFG_DMASZ_128B, AR_RXCFG_DMASZ_MASK); |
936 | REG_WRITE(ah, AR_RXCFG, regval | AR_RXCFG_DMASZ_128B); | ||
937 | 923 | ||
938 | /* | 924 | /* |
939 | * Setup receive FIFO threshold to hold off TX activities | 925 | * Setup receive FIFO threshold to hold off TX activities |
@@ -972,30 +958,27 @@ static inline void ath9k_hw_set_dma(struct ath_hw *ah) | |||
972 | 958 | ||
973 | static void ath9k_hw_set_operating_mode(struct ath_hw *ah, int opmode) | 959 | static void ath9k_hw_set_operating_mode(struct ath_hw *ah, int opmode) |
974 | { | 960 | { |
975 | u32 val; | 961 | u32 mask = AR_STA_ID1_STA_AP | AR_STA_ID1_ADHOC; |
962 | u32 set = AR_STA_ID1_KSRCH_MODE; | ||
976 | 963 | ||
977 | val = REG_READ(ah, AR_STA_ID1); | ||
978 | val &= ~(AR_STA_ID1_STA_AP | AR_STA_ID1_ADHOC); | ||
979 | switch (opmode) { | 964 | switch (opmode) { |
980 | case NL80211_IFTYPE_AP: | ||
981 | REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_STA_AP | ||
982 | | AR_STA_ID1_KSRCH_MODE); | ||
983 | REG_CLR_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION); | ||
984 | break; | ||
985 | case NL80211_IFTYPE_ADHOC: | 965 | case NL80211_IFTYPE_ADHOC: |
986 | case NL80211_IFTYPE_MESH_POINT: | 966 | case NL80211_IFTYPE_MESH_POINT: |
987 | REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_ADHOC | 967 | set |= AR_STA_ID1_ADHOC; |
988 | | AR_STA_ID1_KSRCH_MODE); | ||
989 | REG_SET_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION); | 968 | REG_SET_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION); |
990 | break; | 969 | break; |
970 | case NL80211_IFTYPE_AP: | ||
971 | set |= AR_STA_ID1_STA_AP; | ||
972 | /* fall through */ | ||
991 | case NL80211_IFTYPE_STATION: | 973 | case NL80211_IFTYPE_STATION: |
992 | REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_KSRCH_MODE); | 974 | REG_CLR_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION); |
993 | break; | 975 | break; |
994 | default: | 976 | default: |
995 | if (ah->is_monitoring) | 977 | if (!ah->is_monitoring) |
996 | REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_KSRCH_MODE); | 978 | set = 0; |
997 | break; | 979 | break; |
998 | } | 980 | } |
981 | REG_RMW(ah, AR_STA_ID1, set, mask); | ||
999 | } | 982 | } |
1000 | 983 | ||
1001 | void ath9k_hw_get_delta_slope_vals(struct ath_hw *ah, u32 coef_scaled, | 984 | void ath9k_hw_get_delta_slope_vals(struct ath_hw *ah, u32 coef_scaled, |
@@ -1021,10 +1004,8 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type) | |||
1021 | u32 tmpReg; | 1004 | u32 tmpReg; |
1022 | 1005 | ||
1023 | if (AR_SREV_9100(ah)) { | 1006 | if (AR_SREV_9100(ah)) { |
1024 | u32 val = REG_READ(ah, AR_RTC_DERIVED_CLK); | 1007 | REG_RMW_FIELD(ah, AR_RTC_DERIVED_CLK, |
1025 | val &= ~AR_RTC_DERIVED_CLK_PERIOD; | 1008 | AR_RTC_DERIVED_CLK_PERIOD, 1); |
1026 | val |= SM(1, AR_RTC_DERIVED_CLK_PERIOD); | ||
1027 | REG_WRITE(ah, AR_RTC_DERIVED_CLK, val); | ||
1028 | (void)REG_READ(ah, AR_RTC_DERIVED_CLK); | 1009 | (void)REG_READ(ah, AR_RTC_DERIVED_CLK); |
1029 | } | 1010 | } |
1030 | 1011 | ||
@@ -1212,6 +1193,20 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah, | |||
1212 | return true; | 1193 | return true; |
1213 | } | 1194 | } |
1214 | 1195 | ||
1196 | static void ath9k_hw_apply_gpio_override(struct ath_hw *ah) | ||
1197 | { | ||
1198 | u32 gpio_mask = ah->gpio_mask; | ||
1199 | int i; | ||
1200 | |||
1201 | for (i = 0; gpio_mask; i++, gpio_mask >>= 1) { | ||
1202 | if (!(gpio_mask & 1)) | ||
1203 | continue; | ||
1204 | |||
1205 | ath9k_hw_cfg_output(ah, i, AR_GPIO_OUTPUT_MUX_AS_OUTPUT); | ||
1206 | ath9k_hw_set_gpio(ah, i, !!(ah->gpio_val & BIT(i))); | ||
1207 | } | ||
1208 | } | ||
1209 | |||
1215 | bool ath9k_hw_check_alive(struct ath_hw *ah) | 1210 | bool ath9k_hw_check_alive(struct ath_hw *ah) |
1216 | { | 1211 | { |
1217 | int count = 50; | 1212 | int count = 50; |
@@ -1418,7 +1413,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, | |||
1418 | REGWRITE_BUFFER_FLUSH(ah); | 1413 | REGWRITE_BUFFER_FLUSH(ah); |
1419 | 1414 | ||
1420 | ah->intr_txqs = 0; | 1415 | ah->intr_txqs = 0; |
1421 | for (i = 0; i < ah->caps.total_queues; i++) | 1416 | for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) |
1422 | ath9k_hw_resettxqueue(ah, i); | 1417 | ath9k_hw_resettxqueue(ah, i); |
1423 | 1418 | ||
1424 | ath9k_hw_init_interrupt_masks(ah, ah->opmode); | 1419 | ath9k_hw_init_interrupt_masks(ah, ah->opmode); |
@@ -1435,8 +1430,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, | |||
1435 | ar9002_hw_enable_wep_aggregation(ah); | 1430 | ar9002_hw_enable_wep_aggregation(ah); |
1436 | } | 1431 | } |
1437 | 1432 | ||
1438 | REG_WRITE(ah, AR_STA_ID1, | 1433 | REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PRESERVE_SEQNUM); |
1439 | REG_READ(ah, AR_STA_ID1) | AR_STA_ID1_PRESERVE_SEQNUM); | ||
1440 | 1434 | ||
1441 | ath9k_hw_set_dma(ah); | 1435 | ath9k_hw_set_dma(ah); |
1442 | 1436 | ||
@@ -1500,6 +1494,8 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, | |||
1500 | if (AR_SREV_9300_20_OR_LATER(ah)) | 1494 | if (AR_SREV_9300_20_OR_LATER(ah)) |
1501 | ar9003_hw_bb_watchdog_config(ah); | 1495 | ar9003_hw_bb_watchdog_config(ah); |
1502 | 1496 | ||
1497 | ath9k_hw_apply_gpio_override(ah); | ||
1498 | |||
1503 | return 0; | 1499 | return 0; |
1504 | } | 1500 | } |
1505 | EXPORT_SYMBOL(ath9k_hw_reset); | 1501 | EXPORT_SYMBOL(ath9k_hw_reset); |
@@ -1679,21 +1675,15 @@ void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period) | |||
1679 | case NL80211_IFTYPE_MESH_POINT: | 1675 | case NL80211_IFTYPE_MESH_POINT: |
1680 | REG_SET_BIT(ah, AR_TXCFG, | 1676 | REG_SET_BIT(ah, AR_TXCFG, |
1681 | AR_TXCFG_ADHOC_BEACON_ATIM_TX_POLICY); | 1677 | AR_TXCFG_ADHOC_BEACON_ATIM_TX_POLICY); |
1682 | REG_WRITE(ah, AR_NEXT_NDP_TIMER, | 1678 | REG_WRITE(ah, AR_NEXT_NDP_TIMER, next_beacon + |
1683 | TU_TO_USEC(next_beacon + | 1679 | TU_TO_USEC(ah->atim_window ? ah->atim_window : 1)); |
1684 | (ah->atim_window ? ah-> | ||
1685 | atim_window : 1))); | ||
1686 | flags |= AR_NDP_TIMER_EN; | 1680 | flags |= AR_NDP_TIMER_EN; |
1687 | case NL80211_IFTYPE_AP: | 1681 | case NL80211_IFTYPE_AP: |
1688 | REG_WRITE(ah, AR_NEXT_TBTT_TIMER, TU_TO_USEC(next_beacon)); | 1682 | REG_WRITE(ah, AR_NEXT_TBTT_TIMER, next_beacon); |
1689 | REG_WRITE(ah, AR_NEXT_DMA_BEACON_ALERT, | 1683 | REG_WRITE(ah, AR_NEXT_DMA_BEACON_ALERT, next_beacon - |
1690 | TU_TO_USEC(next_beacon - | 1684 | TU_TO_USEC(ah->config.dma_beacon_response_time)); |
1691 | ah->config. | 1685 | REG_WRITE(ah, AR_NEXT_SWBA, next_beacon - |
1692 | dma_beacon_response_time)); | 1686 | TU_TO_USEC(ah->config.sw_beacon_response_time)); |
1693 | REG_WRITE(ah, AR_NEXT_SWBA, | ||
1694 | TU_TO_USEC(next_beacon - | ||
1695 | ah->config. | ||
1696 | sw_beacon_response_time)); | ||
1697 | flags |= | 1687 | flags |= |
1698 | AR_TBTT_TIMER_EN | AR_DBA_TIMER_EN | AR_SWBA_TIMER_EN; | 1688 | AR_TBTT_TIMER_EN | AR_DBA_TIMER_EN | AR_SWBA_TIMER_EN; |
1699 | break; | 1689 | break; |
@@ -1705,18 +1695,13 @@ void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period) | |||
1705 | break; | 1695 | break; |
1706 | } | 1696 | } |
1707 | 1697 | ||
1708 | REG_WRITE(ah, AR_BEACON_PERIOD, TU_TO_USEC(beacon_period)); | 1698 | REG_WRITE(ah, AR_BEACON_PERIOD, beacon_period); |
1709 | REG_WRITE(ah, AR_DMA_BEACON_PERIOD, TU_TO_USEC(beacon_period)); | 1699 | REG_WRITE(ah, AR_DMA_BEACON_PERIOD, beacon_period); |
1710 | REG_WRITE(ah, AR_SWBA_PERIOD, TU_TO_USEC(beacon_period)); | 1700 | REG_WRITE(ah, AR_SWBA_PERIOD, beacon_period); |
1711 | REG_WRITE(ah, AR_NDP_PERIOD, TU_TO_USEC(beacon_period)); | 1701 | REG_WRITE(ah, AR_NDP_PERIOD, beacon_period); |
1712 | 1702 | ||
1713 | REGWRITE_BUFFER_FLUSH(ah); | 1703 | REGWRITE_BUFFER_FLUSH(ah); |
1714 | 1704 | ||
1715 | beacon_period &= ~ATH9K_BEACON_ENA; | ||
1716 | if (beacon_period & ATH9K_BEACON_RESET_TSF) { | ||
1717 | ath9k_hw_reset_tsf(ah); | ||
1718 | } | ||
1719 | |||
1720 | REG_SET_BIT(ah, AR_TIMER_MODE, flags); | 1705 | REG_SET_BIT(ah, AR_TIMER_MODE, flags); |
1721 | } | 1706 | } |
1722 | EXPORT_SYMBOL(ath9k_hw_beaconinit); | 1707 | EXPORT_SYMBOL(ath9k_hw_beaconinit); |
@@ -1851,6 +1836,8 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) | |||
1851 | !(AR_SREV_9271(ah))) | 1836 | !(AR_SREV_9271(ah))) |
1852 | /* CB71: GPIO 0 is pulled down to indicate 3 rx chains */ | 1837 | /* CB71: GPIO 0 is pulled down to indicate 3 rx chains */ |
1853 | pCap->rx_chainmask = ath9k_hw_gpio_get(ah, 0) ? 0x5 : 0x7; | 1838 | pCap->rx_chainmask = ath9k_hw_gpio_get(ah, 0) ? 0x5 : 0x7; |
1839 | else if (AR_SREV_9100(ah)) | ||
1840 | pCap->rx_chainmask = 0x7; | ||
1854 | else | 1841 | else |
1855 | /* Use rx_chainmask from EEPROM. */ | 1842 | /* Use rx_chainmask from EEPROM. */ |
1856 | pCap->rx_chainmask = ah->eep_ops->get_eeprom(ah, EEP_RX_MASK); | 1843 | pCap->rx_chainmask = ah->eep_ops->get_eeprom(ah, EEP_RX_MASK); |
@@ -1861,36 +1848,13 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) | |||
1861 | if (AR_SREV_9300_20_OR_LATER(ah)) | 1848 | if (AR_SREV_9300_20_OR_LATER(ah)) |
1862 | ah->misc_mode |= AR_PCU_ALWAYS_PERFORM_KEYSEARCH; | 1849 | ah->misc_mode |= AR_PCU_ALWAYS_PERFORM_KEYSEARCH; |
1863 | 1850 | ||
1864 | pCap->low_2ghz_chan = 2312; | ||
1865 | pCap->high_2ghz_chan = 2732; | ||
1866 | |||
1867 | pCap->low_5ghz_chan = 4920; | ||
1868 | pCap->high_5ghz_chan = 6100; | ||
1869 | |||
1870 | common->crypt_caps |= ATH_CRYPT_CAP_CIPHER_AESCCM; | 1851 | common->crypt_caps |= ATH_CRYPT_CAP_CIPHER_AESCCM; |
1871 | 1852 | ||
1872 | if (ah->config.ht_enable) | 1853 | if (ah->hw_version.devid != AR2427_DEVID_PCIE) |
1873 | pCap->hw_caps |= ATH9K_HW_CAP_HT; | 1854 | pCap->hw_caps |= ATH9K_HW_CAP_HT; |
1874 | else | 1855 | else |
1875 | pCap->hw_caps &= ~ATH9K_HW_CAP_HT; | 1856 | pCap->hw_caps &= ~ATH9K_HW_CAP_HT; |
1876 | 1857 | ||
1877 | if (capField & AR_EEPROM_EEPCAP_MAXQCU) | ||
1878 | pCap->total_queues = | ||
1879 | MS(capField, AR_EEPROM_EEPCAP_MAXQCU); | ||
1880 | else | ||
1881 | pCap->total_queues = ATH9K_NUM_TX_QUEUES; | ||
1882 | |||
1883 | if (capField & AR_EEPROM_EEPCAP_KC_ENTRIES) | ||
1884 | pCap->keycache_size = | ||
1885 | 1 << MS(capField, AR_EEPROM_EEPCAP_KC_ENTRIES); | ||
1886 | else | ||
1887 | pCap->keycache_size = AR_KEYTABLE_SIZE; | ||
1888 | |||
1889 | if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) | ||
1890 | pCap->tx_triglevel_max = MAX_TX_FIFO_THRESHOLD >> 1; | ||
1891 | else | ||
1892 | pCap->tx_triglevel_max = MAX_TX_FIFO_THRESHOLD; | ||
1893 | |||
1894 | if (AR_SREV_9271(ah)) | 1858 | if (AR_SREV_9271(ah)) |
1895 | pCap->num_gpio_pins = AR9271_NUM_GPIO; | 1859 | pCap->num_gpio_pins = AR9271_NUM_GPIO; |
1896 | else if (AR_DEVID_7010(ah)) | 1860 | else if (AR_DEVID_7010(ah)) |
@@ -1909,8 +1873,6 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) | |||
1909 | pCap->rts_aggr_limit = (8 * 1024); | 1873 | pCap->rts_aggr_limit = (8 * 1024); |
1910 | } | 1874 | } |
1911 | 1875 | ||
1912 | pCap->hw_caps |= ATH9K_HW_CAP_ENHANCEDPM; | ||
1913 | |||
1914 | #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) | 1876 | #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) |
1915 | ah->rfsilent = ah->eep_ops->get_eeprom(ah, EEP_RF_SILENT); | 1877 | ah->rfsilent = ah->eep_ops->get_eeprom(ah, EEP_RF_SILENT); |
1916 | if (ah->rfsilent & EEP_RFSILENT_ENABLED) { | 1878 | if (ah->rfsilent & EEP_RFSILENT_ENABLED) { |
@@ -1932,23 +1894,6 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) | |||
1932 | else | 1894 | else |
1933 | pCap->hw_caps |= ATH9K_HW_CAP_4KB_SPLITTRANS; | 1895 | pCap->hw_caps |= ATH9K_HW_CAP_4KB_SPLITTRANS; |
1934 | 1896 | ||
1935 | if (regulatory->current_rd_ext & (1 << REG_EXT_JAPAN_MIDBAND)) { | ||
1936 | pCap->reg_cap = | ||
1937 | AR_EEPROM_EEREGCAP_EN_KK_NEW_11A | | ||
1938 | AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN | | ||
1939 | AR_EEPROM_EEREGCAP_EN_KK_U2 | | ||
1940 | AR_EEPROM_EEREGCAP_EN_KK_MIDBAND; | ||
1941 | } else { | ||
1942 | pCap->reg_cap = | ||
1943 | AR_EEPROM_EEREGCAP_EN_KK_NEW_11A | | ||
1944 | AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN; | ||
1945 | } | ||
1946 | |||
1947 | /* Advertise midband for AR5416 with FCC midband set in eeprom */ | ||
1948 | if (regulatory->current_rd_ext & (1 << REG_EXT_FCC_MIDBAND) && | ||
1949 | AR_SREV_5416(ah)) | ||
1950 | pCap->reg_cap |= AR_EEPROM_EEREGCAP_EN_FCC_MIDBAND; | ||
1951 | |||
1952 | if (AR_SREV_9280_20_OR_LATER(ah) && common->btcoex_enabled) { | 1897 | if (AR_SREV_9280_20_OR_LATER(ah) && common->btcoex_enabled) { |
1953 | btcoex_hw->btactive_gpio = ATH_BTACTIVE_GPIO; | 1898 | btcoex_hw->btactive_gpio = ATH_BTACTIVE_GPIO; |
1954 | btcoex_hw->wlanactive_gpio = ATH_WLANACTIVE_GPIO; | 1899 | btcoex_hw->wlanactive_gpio = ATH_WLANACTIVE_GPIO; |
@@ -2195,11 +2140,9 @@ void ath9k_hw_setrxfilter(struct ath_hw *ah, u32 bits) | |||
2195 | REG_WRITE(ah, AR_PHY_ERR, phybits); | 2140 | REG_WRITE(ah, AR_PHY_ERR, phybits); |
2196 | 2141 | ||
2197 | if (phybits) | 2142 | if (phybits) |
2198 | REG_WRITE(ah, AR_RXCFG, | 2143 | REG_SET_BIT(ah, AR_RXCFG, AR_RXCFG_ZLFDMA); |
2199 | REG_READ(ah, AR_RXCFG) | AR_RXCFG_ZLFDMA); | ||
2200 | else | 2144 | else |
2201 | REG_WRITE(ah, AR_RXCFG, | 2145 | REG_CLR_BIT(ah, AR_RXCFG, AR_RXCFG_ZLFDMA); |
2202 | REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_ZLFDMA); | ||
2203 | 2146 | ||
2204 | REGWRITE_BUFFER_FLUSH(ah); | 2147 | REGWRITE_BUFFER_FLUSH(ah); |
2205 | } | 2148 | } |
@@ -2375,10 +2318,11 @@ static u32 rightmost_index(struct ath_gen_timer_table *timer_table, u32 *mask) | |||
2375 | return timer_table->gen_timer_index[b]; | 2318 | return timer_table->gen_timer_index[b]; |
2376 | } | 2319 | } |
2377 | 2320 | ||
2378 | static u32 ath9k_hw_gettsf32(struct ath_hw *ah) | 2321 | u32 ath9k_hw_gettsf32(struct ath_hw *ah) |
2379 | { | 2322 | { |
2380 | return REG_READ(ah, AR_TSF_L32); | 2323 | return REG_READ(ah, AR_TSF_L32); |
2381 | } | 2324 | } |
2325 | EXPORT_SYMBOL(ath9k_hw_gettsf32); | ||
2382 | 2326 | ||
2383 | struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah, | 2327 | struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah, |
2384 | void (*trigger)(void *), | 2328 | void (*trigger)(void *), |
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 6650fd48415c..a778b66f4438 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h | |||
@@ -65,53 +65,49 @@ | |||
65 | 65 | ||
66 | /* Register read/write primitives */ | 66 | /* Register read/write primitives */ |
67 | #define REG_WRITE(_ah, _reg, _val) \ | 67 | #define REG_WRITE(_ah, _reg, _val) \ |
68 | ath9k_hw_common(_ah)->ops->write((_ah), (_val), (_reg)) | 68 | (_ah)->reg_ops.write((_ah), (_val), (_reg)) |
69 | 69 | ||
70 | #define REG_READ(_ah, _reg) \ | 70 | #define REG_READ(_ah, _reg) \ |
71 | ath9k_hw_common(_ah)->ops->read((_ah), (_reg)) | 71 | (_ah)->reg_ops.read((_ah), (_reg)) |
72 | 72 | ||
73 | #define REG_READ_MULTI(_ah, _addr, _val, _cnt) \ | 73 | #define REG_READ_MULTI(_ah, _addr, _val, _cnt) \ |
74 | ath9k_hw_common(_ah)->ops->multi_read((_ah), (_addr), (_val), (_cnt)) | 74 | (_ah)->reg_ops.multi_read((_ah), (_addr), (_val), (_cnt)) |
75 | |||
76 | #define REG_RMW(_ah, _reg, _set, _clr) \ | ||
77 | (_ah)->reg_ops.rmw((_ah), (_reg), (_set), (_clr)) | ||
75 | 78 | ||
76 | #define ENABLE_REGWRITE_BUFFER(_ah) \ | 79 | #define ENABLE_REGWRITE_BUFFER(_ah) \ |
77 | do { \ | 80 | do { \ |
78 | if (ath9k_hw_common(_ah)->ops->enable_write_buffer) \ | 81 | if ((_ah)->reg_ops.enable_write_buffer) \ |
79 | ath9k_hw_common(_ah)->ops->enable_write_buffer((_ah)); \ | 82 | (_ah)->reg_ops.enable_write_buffer((_ah)); \ |
80 | } while (0) | 83 | } while (0) |
81 | 84 | ||
82 | #define REGWRITE_BUFFER_FLUSH(_ah) \ | 85 | #define REGWRITE_BUFFER_FLUSH(_ah) \ |
83 | do { \ | 86 | do { \ |
84 | if (ath9k_hw_common(_ah)->ops->write_flush) \ | 87 | if ((_ah)->reg_ops.write_flush) \ |
85 | ath9k_hw_common(_ah)->ops->write_flush((_ah)); \ | 88 | (_ah)->reg_ops.write_flush((_ah)); \ |
86 | } while (0) | 89 | } while (0) |
87 | 90 | ||
88 | #define SM(_v, _f) (((_v) << _f##_S) & _f) | 91 | #define SM(_v, _f) (((_v) << _f##_S) & _f) |
89 | #define MS(_v, _f) (((_v) & _f) >> _f##_S) | 92 | #define MS(_v, _f) (((_v) & _f) >> _f##_S) |
90 | #define REG_RMW(_a, _r, _set, _clr) \ | ||
91 | REG_WRITE(_a, _r, (REG_READ(_a, _r) & ~(_clr)) | (_set)) | ||
92 | #define REG_RMW_FIELD(_a, _r, _f, _v) \ | 93 | #define REG_RMW_FIELD(_a, _r, _f, _v) \ |
93 | REG_WRITE(_a, _r, \ | 94 | REG_RMW(_a, _r, (((_v) << _f##_S) & _f), (_f)) |
94 | (REG_READ(_a, _r) & ~_f) | (((_v) << _f##_S) & _f)) | ||
95 | #define REG_READ_FIELD(_a, _r, _f) \ | 95 | #define REG_READ_FIELD(_a, _r, _f) \ |
96 | (((REG_READ(_a, _r) & _f) >> _f##_S)) | 96 | (((REG_READ(_a, _r) & _f) >> _f##_S)) |
97 | #define REG_SET_BIT(_a, _r, _f) \ | 97 | #define REG_SET_BIT(_a, _r, _f) \ |
98 | REG_WRITE(_a, _r, REG_READ(_a, _r) | (_f)) | 98 | REG_RMW(_a, _r, (_f), 0) |
99 | #define REG_CLR_BIT(_a, _r, _f) \ | 99 | #define REG_CLR_BIT(_a, _r, _f) \ |
100 | REG_WRITE(_a, _r, REG_READ(_a, _r) & ~(_f)) | 100 | REG_RMW(_a, _r, 0, (_f)) |
101 | 101 | ||
102 | #define DO_DELAY(x) do { \ | 102 | #define DO_DELAY(x) do { \ |
103 | if ((++(x) % 64) == 0) \ | 103 | if (((++(x) % 64) == 0) && \ |
104 | udelay(1); \ | 104 | (ath9k_hw_common(ah)->bus_ops->ath_bus_type \ |
105 | != ATH_USB)) \ | ||
106 | udelay(1); \ | ||
105 | } while (0) | 107 | } while (0) |
106 | 108 | ||
107 | #define REG_WRITE_ARRAY(iniarray, column, regWr) do { \ | 109 | #define REG_WRITE_ARRAY(iniarray, column, regWr) \ |
108 | int r; \ | 110 | ath9k_hw_write_array(ah, iniarray, column, &(regWr)) |
109 | for (r = 0; r < ((iniarray)->ia_rows); r++) { \ | ||
110 | REG_WRITE(ah, INI_RA((iniarray), (r), 0), \ | ||
111 | INI_RA((iniarray), r, (column))); \ | ||
112 | DO_DELAY(regWr); \ | ||
113 | } \ | ||
114 | } while (0) | ||
115 | 111 | ||
116 | #define AR_GPIO_OUTPUT_MUX_AS_OUTPUT 0 | 112 | #define AR_GPIO_OUTPUT_MUX_AS_OUTPUT 0 |
117 | #define AR_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED 1 | 113 | #define AR_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED 1 |
@@ -178,7 +174,6 @@ enum ath9k_hw_caps { | |||
178 | ATH9K_HW_CAP_HT = BIT(0), | 174 | ATH9K_HW_CAP_HT = BIT(0), |
179 | ATH9K_HW_CAP_RFSILENT = BIT(1), | 175 | ATH9K_HW_CAP_RFSILENT = BIT(1), |
180 | ATH9K_HW_CAP_CST = BIT(2), | 176 | ATH9K_HW_CAP_CST = BIT(2), |
181 | ATH9K_HW_CAP_ENHANCEDPM = BIT(3), | ||
182 | ATH9K_HW_CAP_AUTOSLEEP = BIT(4), | 177 | ATH9K_HW_CAP_AUTOSLEEP = BIT(4), |
183 | ATH9K_HW_CAP_4KB_SPLITTRANS = BIT(5), | 178 | ATH9K_HW_CAP_4KB_SPLITTRANS = BIT(5), |
184 | ATH9K_HW_CAP_EDMA = BIT(6), | 179 | ATH9K_HW_CAP_EDMA = BIT(6), |
@@ -195,17 +190,11 @@ enum ath9k_hw_caps { | |||
195 | 190 | ||
196 | struct ath9k_hw_capabilities { | 191 | struct ath9k_hw_capabilities { |
197 | u32 hw_caps; /* ATH9K_HW_CAP_* from ath9k_hw_caps */ | 192 | u32 hw_caps; /* ATH9K_HW_CAP_* from ath9k_hw_caps */ |
198 | u16 total_queues; | ||
199 | u16 keycache_size; | ||
200 | u16 low_5ghz_chan, high_5ghz_chan; | ||
201 | u16 low_2ghz_chan, high_2ghz_chan; | ||
202 | u16 rts_aggr_limit; | 193 | u16 rts_aggr_limit; |
203 | u8 tx_chainmask; | 194 | u8 tx_chainmask; |
204 | u8 rx_chainmask; | 195 | u8 rx_chainmask; |
205 | u8 max_txchains; | 196 | u8 max_txchains; |
206 | u8 max_rxchains; | 197 | u8 max_rxchains; |
207 | u16 tx_triglevel_max; | ||
208 | u16 reg_cap; | ||
209 | u8 num_gpio_pins; | 198 | u8 num_gpio_pins; |
210 | u8 rx_hp_qdepth; | 199 | u8 rx_hp_qdepth; |
211 | u8 rx_lp_qdepth; | 200 | u8 rx_lp_qdepth; |
@@ -227,7 +216,6 @@ struct ath9k_ops_config { | |||
227 | u8 pcie_clock_req; | 216 | u8 pcie_clock_req; |
228 | u32 pcie_waen; | 217 | u32 pcie_waen; |
229 | u8 analog_shiftreg; | 218 | u8 analog_shiftreg; |
230 | u8 ht_enable; | ||
231 | u8 paprd_disable; | 219 | u8 paprd_disable; |
232 | u32 ofdm_trig_low; | 220 | u32 ofdm_trig_low; |
233 | u32 ofdm_trig_high; | 221 | u32 ofdm_trig_high; |
@@ -412,8 +400,6 @@ struct ath9k_beacon_state { | |||
412 | u32 bs_nextdtim; | 400 | u32 bs_nextdtim; |
413 | u32 bs_intval; | 401 | u32 bs_intval; |
414 | #define ATH9K_BEACON_PERIOD 0x0000ffff | 402 | #define ATH9K_BEACON_PERIOD 0x0000ffff |
415 | #define ATH9K_BEACON_ENA 0x00800000 | ||
416 | #define ATH9K_BEACON_RESET_TSF 0x01000000 | ||
417 | #define ATH9K_TSFOOR_THRESHOLD 0x00004240 /* 16k us */ | 403 | #define ATH9K_TSFOOR_THRESHOLD 0x00004240 /* 16k us */ |
418 | u32 bs_dtimperiod; | 404 | u32 bs_dtimperiod; |
419 | u16 bs_cfpperiod; | 405 | u16 bs_cfpperiod; |
@@ -640,8 +626,6 @@ struct ath_hw_ops { | |||
640 | void (*clr11n_aggr)(struct ath_hw *ah, void *ds); | 626 | void (*clr11n_aggr)(struct ath_hw *ah, void *ds); |
641 | void (*set11n_burstduration)(struct ath_hw *ah, void *ds, | 627 | void (*set11n_burstduration)(struct ath_hw *ah, void *ds, |
642 | u32 burstDuration); | 628 | u32 burstDuration); |
643 | void (*set11n_virtualmorefrag)(struct ath_hw *ah, void *ds, | ||
644 | u32 vmf); | ||
645 | }; | 629 | }; |
646 | 630 | ||
647 | struct ath_nf_limits { | 631 | struct ath_nf_limits { |
@@ -655,6 +639,8 @@ struct ath_nf_limits { | |||
655 | #define AH_UNPLUGGED 0x2 /* The card has been physically removed. */ | 639 | #define AH_UNPLUGGED 0x2 /* The card has been physically removed. */ |
656 | 640 | ||
657 | struct ath_hw { | 641 | struct ath_hw { |
642 | struct ath_ops reg_ops; | ||
643 | |||
658 | struct ieee80211_hw *hw; | 644 | struct ieee80211_hw *hw; |
659 | struct ath_common common; | 645 | struct ath_common common; |
660 | struct ath9k_hw_version hw_version; | 646 | struct ath9k_hw_version hw_version; |
@@ -794,7 +780,9 @@ struct ath_hw { | |||
794 | u32 originalGain[22]; | 780 | u32 originalGain[22]; |
795 | int initPDADC; | 781 | int initPDADC; |
796 | int PDADCdelta; | 782 | int PDADCdelta; |
797 | u8 led_pin; | 783 | int led_pin; |
784 | u32 gpio_mask; | ||
785 | u32 gpio_val; | ||
798 | 786 | ||
799 | struct ar5416IniArray iniModes; | 787 | struct ar5416IniArray iniModes; |
800 | struct ar5416IniArray iniCommon; | 788 | struct ar5416IniArray iniCommon; |
@@ -907,8 +895,9 @@ void ath9k_hw_antdiv_comb_conf_set(struct ath_hw *ah, | |||
907 | 895 | ||
908 | /* General Operation */ | 896 | /* General Operation */ |
909 | bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout); | 897 | bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout); |
898 | void ath9k_hw_write_array(struct ath_hw *ah, struct ar5416IniArray *array, | ||
899 | int column, unsigned int *writecnt); | ||
910 | u32 ath9k_hw_reverse_bits(u32 val, u32 n); | 900 | u32 ath9k_hw_reverse_bits(u32 val, u32 n); |
911 | bool ath9k_get_channel_edges(struct ath_hw *ah, u16 flags, u16 *low, u16 *high); | ||
912 | u16 ath9k_hw_computetxtime(struct ath_hw *ah, | 901 | u16 ath9k_hw_computetxtime(struct ath_hw *ah, |
913 | u8 phy, int kbps, | 902 | u8 phy, int kbps, |
914 | u32 frameLen, u16 rateix, bool shortPreamble); | 903 | u32 frameLen, u16 rateix, bool shortPreamble); |
@@ -924,6 +913,7 @@ void ath9k_hw_setopmode(struct ath_hw *ah); | |||
924 | void ath9k_hw_setmcastfilter(struct ath_hw *ah, u32 filter0, u32 filter1); | 913 | void ath9k_hw_setmcastfilter(struct ath_hw *ah, u32 filter0, u32 filter1); |
925 | void ath9k_hw_setbssidmask(struct ath_hw *ah); | 914 | void ath9k_hw_setbssidmask(struct ath_hw *ah); |
926 | void ath9k_hw_write_associd(struct ath_hw *ah); | 915 | void ath9k_hw_write_associd(struct ath_hw *ah); |
916 | u32 ath9k_hw_gettsf32(struct ath_hw *ah); | ||
927 | u64 ath9k_hw_gettsf64(struct ath_hw *ah); | 917 | u64 ath9k_hw_gettsf64(struct ath_hw *ah); |
928 | void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64); | 918 | void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64); |
929 | void ath9k_hw_reset_tsf(struct ath_hw *ah); | 919 | void ath9k_hw_reset_tsf(struct ath_hw *ah); |
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 79aec983279f..1ac8318d82a3 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c | |||
@@ -15,6 +15,7 @@ | |||
15 | */ | 15 | */ |
16 | 16 | ||
17 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
18 | #include <linux/ath9k_platform.h> | ||
18 | 19 | ||
19 | #include "ath9k.h" | 20 | #include "ath9k.h" |
20 | 21 | ||
@@ -195,10 +196,27 @@ static unsigned int ath9k_ioread32(void *hw_priv, u32 reg_offset) | |||
195 | return val; | 196 | return val; |
196 | } | 197 | } |
197 | 198 | ||
198 | static const struct ath_ops ath9k_common_ops = { | 199 | static unsigned int ath9k_reg_rmw(void *hw_priv, u32 reg_offset, u32 set, u32 clr) |
199 | .read = ath9k_ioread32, | 200 | { |
200 | .write = ath9k_iowrite32, | 201 | struct ath_hw *ah = (struct ath_hw *) hw_priv; |
201 | }; | 202 | struct ath_common *common = ath9k_hw_common(ah); |
203 | struct ath_softc *sc = (struct ath_softc *) common->priv; | ||
204 | unsigned long uninitialized_var(flags); | ||
205 | u32 val; | ||
206 | |||
207 | if (ah->config.serialize_regmode == SER_REG_MODE_ON) | ||
208 | spin_lock_irqsave(&sc->sc_serial_rw, flags); | ||
209 | |||
210 | val = ioread32(sc->mem + reg_offset); | ||
211 | val &= ~clr; | ||
212 | val |= set; | ||
213 | iowrite32(val, sc->mem + reg_offset); | ||
214 | |||
215 | if (ah->config.serialize_regmode == SER_REG_MODE_ON) | ||
216 | spin_unlock_irqrestore(&sc->sc_serial_rw, flags); | ||
217 | |||
218 | return val; | ||
219 | } | ||
202 | 220 | ||
203 | /**************************/ | 221 | /**************************/ |
204 | /* Initialization */ | 222 | /* Initialization */ |
@@ -389,13 +407,7 @@ void ath9k_init_crypto(struct ath_softc *sc) | |||
389 | int i = 0; | 407 | int i = 0; |
390 | 408 | ||
391 | /* Get the hardware key cache size. */ | 409 | /* Get the hardware key cache size. */ |
392 | common->keymax = sc->sc_ah->caps.keycache_size; | 410 | common->keymax = AR_KEYTABLE_SIZE; |
393 | if (common->keymax > ATH_KEYMAX) { | ||
394 | ath_dbg(common, ATH_DBG_ANY, | ||
395 | "Warning, using only %u entries in %u key cache\n", | ||
396 | ATH_KEYMAX, common->keymax); | ||
397 | common->keymax = ATH_KEYMAX; | ||
398 | } | ||
399 | 411 | ||
400 | /* | 412 | /* |
401 | * Reset the key cache since some parts do not | 413 | * Reset the key cache since some parts do not |
@@ -537,6 +549,7 @@ static void ath9k_init_misc(struct ath_softc *sc) | |||
537 | static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid, | 549 | static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid, |
538 | const struct ath_bus_ops *bus_ops) | 550 | const struct ath_bus_ops *bus_ops) |
539 | { | 551 | { |
552 | struct ath9k_platform_data *pdata = sc->dev->platform_data; | ||
540 | struct ath_hw *ah = NULL; | 553 | struct ath_hw *ah = NULL; |
541 | struct ath_common *common; | 554 | struct ath_common *common; |
542 | int ret = 0, i; | 555 | int ret = 0, i; |
@@ -549,13 +562,22 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid, | |||
549 | ah->hw = sc->hw; | 562 | ah->hw = sc->hw; |
550 | ah->hw_version.devid = devid; | 563 | ah->hw_version.devid = devid; |
551 | ah->hw_version.subsysid = subsysid; | 564 | ah->hw_version.subsysid = subsysid; |
565 | ah->reg_ops.read = ath9k_ioread32; | ||
566 | ah->reg_ops.write = ath9k_iowrite32; | ||
567 | ah->reg_ops.rmw = ath9k_reg_rmw; | ||
552 | sc->sc_ah = ah; | 568 | sc->sc_ah = ah; |
553 | 569 | ||
554 | if (!sc->dev->platform_data) | 570 | if (!pdata) { |
555 | ah->ah_flags |= AH_USE_EEPROM; | 571 | ah->ah_flags |= AH_USE_EEPROM; |
572 | sc->sc_ah->led_pin = -1; | ||
573 | } else { | ||
574 | sc->sc_ah->gpio_mask = pdata->gpio_mask; | ||
575 | sc->sc_ah->gpio_val = pdata->gpio_val; | ||
576 | sc->sc_ah->led_pin = pdata->led_pin; | ||
577 | } | ||
556 | 578 | ||
557 | common = ath9k_hw_common(ah); | 579 | common = ath9k_hw_common(ah); |
558 | common->ops = &ath9k_common_ops; | 580 | common->ops = &ah->reg_ops; |
559 | common->bus_ops = bus_ops; | 581 | common->bus_ops = bus_ops; |
560 | common->ah = ah; | 582 | common->ah = ah; |
561 | common->hw = sc->hw; | 583 | common->hw = sc->hw; |
@@ -587,6 +609,9 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid, | |||
587 | if (ret) | 609 | if (ret) |
588 | goto err_hw; | 610 | goto err_hw; |
589 | 611 | ||
612 | if (pdata && pdata->macaddr) | ||
613 | memcpy(common->macaddr, pdata->macaddr, ETH_ALEN); | ||
614 | |||
590 | ret = ath9k_init_queues(sc); | 615 | ret = ath9k_init_queues(sc); |
591 | if (ret) | 616 | if (ret) |
592 | goto err_queues; | 617 | goto err_queues; |
@@ -679,6 +704,8 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) | |||
679 | if (AR_SREV_5416(sc->sc_ah)) | 704 | if (AR_SREV_5416(sc->sc_ah)) |
680 | hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; | 705 | hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; |
681 | 706 | ||
707 | hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; | ||
708 | |||
682 | hw->queues = 4; | 709 | hw->queues = 4; |
683 | hw->max_rates = 4; | 710 | hw->max_rates = 4; |
684 | hw->channel_change_time = 5000; | 711 | hw->channel_change_time = 5000; |
diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index 562257ac52cf..6f431cbff38a 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c | |||
@@ -209,15 +209,8 @@ bool ath9k_hw_set_txq_props(struct ath_hw *ah, int q, | |||
209 | { | 209 | { |
210 | u32 cw; | 210 | u32 cw; |
211 | struct ath_common *common = ath9k_hw_common(ah); | 211 | struct ath_common *common = ath9k_hw_common(ah); |
212 | struct ath9k_hw_capabilities *pCap = &ah->caps; | ||
213 | struct ath9k_tx_queue_info *qi; | 212 | struct ath9k_tx_queue_info *qi; |
214 | 213 | ||
215 | if (q >= pCap->total_queues) { | ||
216 | ath_dbg(common, ATH_DBG_QUEUE, | ||
217 | "Set TXQ properties, invalid queue: %u\n", q); | ||
218 | return false; | ||
219 | } | ||
220 | |||
221 | qi = &ah->txq[q]; | 214 | qi = &ah->txq[q]; |
222 | if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { | 215 | if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { |
223 | ath_dbg(common, ATH_DBG_QUEUE, | 216 | ath_dbg(common, ATH_DBG_QUEUE, |
@@ -280,15 +273,8 @@ bool ath9k_hw_get_txq_props(struct ath_hw *ah, int q, | |||
280 | struct ath9k_tx_queue_info *qinfo) | 273 | struct ath9k_tx_queue_info *qinfo) |
281 | { | 274 | { |
282 | struct ath_common *common = ath9k_hw_common(ah); | 275 | struct ath_common *common = ath9k_hw_common(ah); |
283 | struct ath9k_hw_capabilities *pCap = &ah->caps; | ||
284 | struct ath9k_tx_queue_info *qi; | 276 | struct ath9k_tx_queue_info *qi; |
285 | 277 | ||
286 | if (q >= pCap->total_queues) { | ||
287 | ath_dbg(common, ATH_DBG_QUEUE, | ||
288 | "Get TXQ properties, invalid queue: %u\n", q); | ||
289 | return false; | ||
290 | } | ||
291 | |||
292 | qi = &ah->txq[q]; | 278 | qi = &ah->txq[q]; |
293 | if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { | 279 | if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { |
294 | ath_dbg(common, ATH_DBG_QUEUE, | 280 | ath_dbg(common, ATH_DBG_QUEUE, |
@@ -320,28 +306,27 @@ int ath9k_hw_setuptxqueue(struct ath_hw *ah, enum ath9k_tx_queue type, | |||
320 | { | 306 | { |
321 | struct ath_common *common = ath9k_hw_common(ah); | 307 | struct ath_common *common = ath9k_hw_common(ah); |
322 | struct ath9k_tx_queue_info *qi; | 308 | struct ath9k_tx_queue_info *qi; |
323 | struct ath9k_hw_capabilities *pCap = &ah->caps; | ||
324 | int q; | 309 | int q; |
325 | 310 | ||
326 | switch (type) { | 311 | switch (type) { |
327 | case ATH9K_TX_QUEUE_BEACON: | 312 | case ATH9K_TX_QUEUE_BEACON: |
328 | q = pCap->total_queues - 1; | 313 | q = ATH9K_NUM_TX_QUEUES - 1; |
329 | break; | 314 | break; |
330 | case ATH9K_TX_QUEUE_CAB: | 315 | case ATH9K_TX_QUEUE_CAB: |
331 | q = pCap->total_queues - 2; | 316 | q = ATH9K_NUM_TX_QUEUES - 2; |
332 | break; | 317 | break; |
333 | case ATH9K_TX_QUEUE_PSPOLL: | 318 | case ATH9K_TX_QUEUE_PSPOLL: |
334 | q = 1; | 319 | q = 1; |
335 | break; | 320 | break; |
336 | case ATH9K_TX_QUEUE_UAPSD: | 321 | case ATH9K_TX_QUEUE_UAPSD: |
337 | q = pCap->total_queues - 3; | 322 | q = ATH9K_NUM_TX_QUEUES - 3; |
338 | break; | 323 | break; |
339 | case ATH9K_TX_QUEUE_DATA: | 324 | case ATH9K_TX_QUEUE_DATA: |
340 | for (q = 0; q < pCap->total_queues; q++) | 325 | for (q = 0; q < ATH9K_NUM_TX_QUEUES; q++) |
341 | if (ah->txq[q].tqi_type == | 326 | if (ah->txq[q].tqi_type == |
342 | ATH9K_TX_QUEUE_INACTIVE) | 327 | ATH9K_TX_QUEUE_INACTIVE) |
343 | break; | 328 | break; |
344 | if (q == pCap->total_queues) { | 329 | if (q == ATH9K_NUM_TX_QUEUES) { |
345 | ath_err(common, "No available TX queue\n"); | 330 | ath_err(common, "No available TX queue\n"); |
346 | return -1; | 331 | return -1; |
347 | } | 332 | } |
@@ -382,15 +367,9 @@ EXPORT_SYMBOL(ath9k_hw_setuptxqueue); | |||
382 | 367 | ||
383 | bool ath9k_hw_releasetxqueue(struct ath_hw *ah, u32 q) | 368 | bool ath9k_hw_releasetxqueue(struct ath_hw *ah, u32 q) |
384 | { | 369 | { |
385 | struct ath9k_hw_capabilities *pCap = &ah->caps; | ||
386 | struct ath_common *common = ath9k_hw_common(ah); | 370 | struct ath_common *common = ath9k_hw_common(ah); |
387 | struct ath9k_tx_queue_info *qi; | 371 | struct ath9k_tx_queue_info *qi; |
388 | 372 | ||
389 | if (q >= pCap->total_queues) { | ||
390 | ath_dbg(common, ATH_DBG_QUEUE, | ||
391 | "Release TXQ, invalid queue: %u\n", q); | ||
392 | return false; | ||
393 | } | ||
394 | qi = &ah->txq[q]; | 373 | qi = &ah->txq[q]; |
395 | if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { | 374 | if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { |
396 | ath_dbg(common, ATH_DBG_QUEUE, | 375 | ath_dbg(common, ATH_DBG_QUEUE, |
@@ -414,18 +393,11 @@ EXPORT_SYMBOL(ath9k_hw_releasetxqueue); | |||
414 | 393 | ||
415 | bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q) | 394 | bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q) |
416 | { | 395 | { |
417 | struct ath9k_hw_capabilities *pCap = &ah->caps; | ||
418 | struct ath_common *common = ath9k_hw_common(ah); | 396 | struct ath_common *common = ath9k_hw_common(ah); |
419 | struct ath9k_channel *chan = ah->curchan; | 397 | struct ath9k_channel *chan = ah->curchan; |
420 | struct ath9k_tx_queue_info *qi; | 398 | struct ath9k_tx_queue_info *qi; |
421 | u32 cwMin, chanCwMin, value; | 399 | u32 cwMin, chanCwMin, value; |
422 | 400 | ||
423 | if (q >= pCap->total_queues) { | ||
424 | ath_dbg(common, ATH_DBG_QUEUE, | ||
425 | "Reset TXQ, invalid queue: %u\n", q); | ||
426 | return false; | ||
427 | } | ||
428 | |||
429 | qi = &ah->txq[q]; | 401 | qi = &ah->txq[q]; |
430 | if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { | 402 | if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { |
431 | ath_dbg(common, ATH_DBG_QUEUE, | 403 | ath_dbg(common, ATH_DBG_QUEUE, |
@@ -465,10 +437,9 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q) | |||
465 | REG_WRITE(ah, AR_QCBRCFG(q), | 437 | REG_WRITE(ah, AR_QCBRCFG(q), |
466 | SM(qi->tqi_cbrPeriod, AR_Q_CBRCFG_INTERVAL) | | 438 | SM(qi->tqi_cbrPeriod, AR_Q_CBRCFG_INTERVAL) | |
467 | SM(qi->tqi_cbrOverflowLimit, AR_Q_CBRCFG_OVF_THRESH)); | 439 | SM(qi->tqi_cbrOverflowLimit, AR_Q_CBRCFG_OVF_THRESH)); |
468 | REG_WRITE(ah, AR_QMISC(q), | 440 | REG_SET_BIT(ah, AR_QMISC(q), AR_Q_MISC_FSP_CBR | |
469 | REG_READ(ah, AR_QMISC(q)) | AR_Q_MISC_FSP_CBR | | 441 | (qi->tqi_cbrOverflowLimit ? |
470 | (qi->tqi_cbrOverflowLimit ? | 442 | AR_Q_MISC_CBR_EXP_CNTR_LIMIT_EN : 0)); |
471 | AR_Q_MISC_CBR_EXP_CNTR_LIMIT_EN : 0)); | ||
472 | } | 443 | } |
473 | if (qi->tqi_readyTime && (qi->tqi_type != ATH9K_TX_QUEUE_CAB)) { | 444 | if (qi->tqi_readyTime && (qi->tqi_type != ATH9K_TX_QUEUE_CAB)) { |
474 | REG_WRITE(ah, AR_QRDYTIMECFG(q), | 445 | REG_WRITE(ah, AR_QRDYTIMECFG(q), |
@@ -481,40 +452,31 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q) | |||
481 | (qi->tqi_burstTime ? AR_D_CHNTIME_EN : 0)); | 452 | (qi->tqi_burstTime ? AR_D_CHNTIME_EN : 0)); |
482 | 453 | ||
483 | if (qi->tqi_burstTime | 454 | if (qi->tqi_burstTime |
484 | && (qi->tqi_qflags & TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE)) { | 455 | && (qi->tqi_qflags & TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE)) |
485 | REG_WRITE(ah, AR_QMISC(q), | 456 | REG_SET_BIT(ah, AR_QMISC(q), AR_Q_MISC_RDYTIME_EXP_POLICY); |
486 | REG_READ(ah, AR_QMISC(q)) | | ||
487 | AR_Q_MISC_RDYTIME_EXP_POLICY); | ||
488 | |||
489 | } | ||
490 | 457 | ||
491 | if (qi->tqi_qflags & TXQ_FLAG_BACKOFF_DISABLE) { | 458 | if (qi->tqi_qflags & TXQ_FLAG_BACKOFF_DISABLE) |
492 | REG_WRITE(ah, AR_DMISC(q), | 459 | REG_SET_BIT(ah, AR_DMISC(q), AR_D_MISC_POST_FR_BKOFF_DIS); |
493 | REG_READ(ah, AR_DMISC(q)) | | ||
494 | AR_D_MISC_POST_FR_BKOFF_DIS); | ||
495 | } | ||
496 | 460 | ||
497 | REGWRITE_BUFFER_FLUSH(ah); | 461 | REGWRITE_BUFFER_FLUSH(ah); |
498 | 462 | ||
499 | if (qi->tqi_qflags & TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE) { | 463 | if (qi->tqi_qflags & TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE) |
500 | REG_WRITE(ah, AR_DMISC(q), | 464 | REG_SET_BIT(ah, AR_DMISC(q), AR_D_MISC_FRAG_BKOFF_EN); |
501 | REG_READ(ah, AR_DMISC(q)) | | 465 | |
502 | AR_D_MISC_FRAG_BKOFF_EN); | ||
503 | } | ||
504 | switch (qi->tqi_type) { | 466 | switch (qi->tqi_type) { |
505 | case ATH9K_TX_QUEUE_BEACON: | 467 | case ATH9K_TX_QUEUE_BEACON: |
506 | ENABLE_REGWRITE_BUFFER(ah); | 468 | ENABLE_REGWRITE_BUFFER(ah); |
507 | 469 | ||
508 | REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q)) | 470 | REG_SET_BIT(ah, AR_QMISC(q), |
509 | | AR_Q_MISC_FSP_DBA_GATED | 471 | AR_Q_MISC_FSP_DBA_GATED |
510 | | AR_Q_MISC_BEACON_USE | 472 | | AR_Q_MISC_BEACON_USE |
511 | | AR_Q_MISC_CBR_INCR_DIS1); | 473 | | AR_Q_MISC_CBR_INCR_DIS1); |
512 | 474 | ||
513 | REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q)) | 475 | REG_SET_BIT(ah, AR_DMISC(q), |
514 | | (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL << | 476 | (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL << |
515 | AR_D_MISC_ARB_LOCKOUT_CNTRL_S) | 477 | AR_D_MISC_ARB_LOCKOUT_CNTRL_S) |
516 | | AR_D_MISC_BEACON_USE | 478 | | AR_D_MISC_BEACON_USE |
517 | | AR_D_MISC_POST_FR_BKOFF_DIS); | 479 | | AR_D_MISC_POST_FR_BKOFF_DIS); |
518 | 480 | ||
519 | REGWRITE_BUFFER_FLUSH(ah); | 481 | REGWRITE_BUFFER_FLUSH(ah); |
520 | 482 | ||
@@ -533,41 +495,38 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q) | |||
533 | case ATH9K_TX_QUEUE_CAB: | 495 | case ATH9K_TX_QUEUE_CAB: |
534 | ENABLE_REGWRITE_BUFFER(ah); | 496 | ENABLE_REGWRITE_BUFFER(ah); |
535 | 497 | ||
536 | REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q)) | 498 | REG_SET_BIT(ah, AR_QMISC(q), |
537 | | AR_Q_MISC_FSP_DBA_GATED | 499 | AR_Q_MISC_FSP_DBA_GATED |
538 | | AR_Q_MISC_CBR_INCR_DIS1 | 500 | | AR_Q_MISC_CBR_INCR_DIS1 |
539 | | AR_Q_MISC_CBR_INCR_DIS0); | 501 | | AR_Q_MISC_CBR_INCR_DIS0); |
540 | value = (qi->tqi_readyTime - | 502 | value = (qi->tqi_readyTime - |
541 | (ah->config.sw_beacon_response_time - | 503 | (ah->config.sw_beacon_response_time - |
542 | ah->config.dma_beacon_response_time) - | 504 | ah->config.dma_beacon_response_time) - |
543 | ah->config.additional_swba_backoff) * 1024; | 505 | ah->config.additional_swba_backoff) * 1024; |
544 | REG_WRITE(ah, AR_QRDYTIMECFG(q), | 506 | REG_WRITE(ah, AR_QRDYTIMECFG(q), |
545 | value | AR_Q_RDYTIMECFG_EN); | 507 | value | AR_Q_RDYTIMECFG_EN); |
546 | REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q)) | 508 | REG_SET_BIT(ah, AR_DMISC(q), |
547 | | (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL << | 509 | (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL << |
548 | AR_D_MISC_ARB_LOCKOUT_CNTRL_S)); | 510 | AR_D_MISC_ARB_LOCKOUT_CNTRL_S)); |
549 | 511 | ||
550 | REGWRITE_BUFFER_FLUSH(ah); | 512 | REGWRITE_BUFFER_FLUSH(ah); |
551 | 513 | ||
552 | break; | 514 | break; |
553 | case ATH9K_TX_QUEUE_PSPOLL: | 515 | case ATH9K_TX_QUEUE_PSPOLL: |
554 | REG_WRITE(ah, AR_QMISC(q), | 516 | REG_SET_BIT(ah, AR_QMISC(q), AR_Q_MISC_CBR_INCR_DIS1); |
555 | REG_READ(ah, AR_QMISC(q)) | AR_Q_MISC_CBR_INCR_DIS1); | ||
556 | break; | 517 | break; |
557 | case ATH9K_TX_QUEUE_UAPSD: | 518 | case ATH9K_TX_QUEUE_UAPSD: |
558 | REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q)) | | 519 | REG_SET_BIT(ah, AR_DMISC(q), AR_D_MISC_POST_FR_BKOFF_DIS); |
559 | AR_D_MISC_POST_FR_BKOFF_DIS); | ||
560 | break; | 520 | break; |
561 | default: | 521 | default: |
562 | break; | 522 | break; |
563 | } | 523 | } |
564 | 524 | ||
565 | if (qi->tqi_intFlags & ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS) { | 525 | if (qi->tqi_intFlags & ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS) { |
566 | REG_WRITE(ah, AR_DMISC(q), | 526 | REG_SET_BIT(ah, AR_DMISC(q), |
567 | REG_READ(ah, AR_DMISC(q)) | | 527 | SM(AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL, |
568 | SM(AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL, | 528 | AR_D_MISC_ARB_LOCKOUT_CNTRL) | |
569 | AR_D_MISC_ARB_LOCKOUT_CNTRL) | | 529 | AR_D_MISC_POST_FR_BKOFF_DIS); |
570 | AR_D_MISC_POST_FR_BKOFF_DIS); | ||
571 | } | 530 | } |
572 | 531 | ||
573 | if (AR_SREV_9300_20_OR_LATER(ah)) | 532 | if (AR_SREV_9300_20_OR_LATER(ah)) |
@@ -754,7 +713,6 @@ EXPORT_SYMBOL(ath9k_hw_abortpcurecv); | |||
754 | bool ath9k_hw_stopdmarecv(struct ath_hw *ah) | 713 | bool ath9k_hw_stopdmarecv(struct ath_hw *ah) |
755 | { | 714 | { |
756 | #define AH_RX_STOP_DMA_TIMEOUT 10000 /* usec */ | 715 | #define AH_RX_STOP_DMA_TIMEOUT 10000 /* usec */ |
757 | #define AH_RX_TIME_QUANTUM 100 /* usec */ | ||
758 | struct ath_common *common = ath9k_hw_common(ah); | 716 | struct ath_common *common = ath9k_hw_common(ah); |
759 | int i; | 717 | int i; |
760 | 718 | ||
@@ -778,7 +736,6 @@ bool ath9k_hw_stopdmarecv(struct ath_hw *ah) | |||
778 | return true; | 736 | return true; |
779 | } | 737 | } |
780 | 738 | ||
781 | #undef AH_RX_TIME_QUANTUM | ||
782 | #undef AH_RX_STOP_DMA_TIMEOUT | 739 | #undef AH_RX_STOP_DMA_TIMEOUT |
783 | } | 740 | } |
784 | EXPORT_SYMBOL(ath9k_hw_stopdmarecv); | 741 | EXPORT_SYMBOL(ath9k_hw_stopdmarecv); |
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 17d04ff8d678..4c5c9997dac6 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c | |||
@@ -299,7 +299,7 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, | |||
299 | 299 | ||
300 | if (!(sc->sc_flags & (SC_OP_OFFCHANNEL))) { | 300 | if (!(sc->sc_flags & (SC_OP_OFFCHANNEL))) { |
301 | if (sc->sc_flags & SC_OP_BEACONS) | 301 | if (sc->sc_flags & SC_OP_BEACONS) |
302 | ath_beacon_config(sc, NULL); | 302 | ath_set_beacon(sc); |
303 | ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0); | 303 | ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0); |
304 | ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/2); | 304 | ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/2); |
305 | ath_start_ani(common); | 305 | ath_start_ani(common); |
@@ -828,48 +828,6 @@ chip_reset: | |||
828 | #undef SCHED_INTR | 828 | #undef SCHED_INTR |
829 | } | 829 | } |
830 | 830 | ||
831 | static void ath9k_bss_assoc_info(struct ath_softc *sc, | ||
832 | struct ieee80211_hw *hw, | ||
833 | struct ieee80211_vif *vif, | ||
834 | struct ieee80211_bss_conf *bss_conf) | ||
835 | { | ||
836 | struct ath_hw *ah = sc->sc_ah; | ||
837 | struct ath_common *common = ath9k_hw_common(ah); | ||
838 | |||
839 | if (bss_conf->assoc) { | ||
840 | ath_dbg(common, ATH_DBG_CONFIG, | ||
841 | "Bss Info ASSOC %d, bssid: %pM\n", | ||
842 | bss_conf->aid, common->curbssid); | ||
843 | |||
844 | /* New association, store aid */ | ||
845 | common->curaid = bss_conf->aid; | ||
846 | ath9k_hw_write_associd(ah); | ||
847 | |||
848 | /* | ||
849 | * Request a re-configuration of Beacon related timers | ||
850 | * on the receipt of the first Beacon frame (i.e., | ||
851 | * after time sync with the AP). | ||
852 | */ | ||
853 | sc->ps_flags |= PS_BEACON_SYNC; | ||
854 | |||
855 | /* Configure the beacon */ | ||
856 | ath_beacon_config(sc, vif); | ||
857 | |||
858 | /* Reset rssi stats */ | ||
859 | sc->last_rssi = ATH_RSSI_DUMMY_MARKER; | ||
860 | sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER; | ||
861 | |||
862 | sc->sc_flags |= SC_OP_ANI_RUN; | ||
863 | ath_start_ani(common); | ||
864 | } else { | ||
865 | ath_dbg(common, ATH_DBG_CONFIG, "Bss Info DISASSOC\n"); | ||
866 | common->curaid = 0; | ||
867 | /* Stop ANI */ | ||
868 | sc->sc_flags &= ~SC_OP_ANI_RUN; | ||
869 | del_timer_sync(&common->ani.timer); | ||
870 | } | ||
871 | } | ||
872 | |||
873 | void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw) | 831 | void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw) |
874 | { | 832 | { |
875 | struct ath_hw *ah = sc->sc_ah; | 833 | struct ath_hw *ah = sc->sc_ah; |
@@ -899,7 +857,7 @@ void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw) | |||
899 | goto out; | 857 | goto out; |
900 | } | 858 | } |
901 | if (sc->sc_flags & SC_OP_BEACONS) | 859 | if (sc->sc_flags & SC_OP_BEACONS) |
902 | ath_beacon_config(sc, NULL); /* restart beacons */ | 860 | ath_set_beacon(sc); /* restart beacons */ |
903 | 861 | ||
904 | /* Re-Enable interrupts */ | 862 | /* Re-Enable interrupts */ |
905 | ath9k_hw_set_interrupts(ah, ah->imask); | 863 | ath9k_hw_set_interrupts(ah, ah->imask); |
@@ -1006,7 +964,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) | |||
1006 | sc->config.txpowlimit, &sc->curtxpow); | 964 | sc->config.txpowlimit, &sc->curtxpow); |
1007 | 965 | ||
1008 | if ((sc->sc_flags & SC_OP_BEACONS) || !(sc->sc_flags & (SC_OP_OFFCHANNEL))) | 966 | if ((sc->sc_flags & SC_OP_BEACONS) || !(sc->sc_flags & (SC_OP_OFFCHANNEL))) |
1009 | ath_beacon_config(sc, NULL); /* restart beacons */ | 967 | ath_set_beacon(sc); /* restart beacons */ |
1010 | 968 | ||
1011 | ath9k_hw_set_interrupts(ah, ah->imask); | 969 | ath9k_hw_set_interrupts(ah, ah->imask); |
1012 | 970 | ||
@@ -1415,9 +1373,6 @@ static void ath9k_calculate_summary_state(struct ieee80211_hw *hw, | |||
1415 | if ((iter_data.naps + iter_data.nadhocs) > 0) { | 1373 | if ((iter_data.naps + iter_data.nadhocs) > 0) { |
1416 | sc->sc_flags |= SC_OP_ANI_RUN; | 1374 | sc->sc_flags |= SC_OP_ANI_RUN; |
1417 | ath_start_ani(common); | 1375 | ath_start_ani(common); |
1418 | } else { | ||
1419 | sc->sc_flags &= ~SC_OP_ANI_RUN; | ||
1420 | del_timer_sync(&common->ani.timer); | ||
1421 | } | 1376 | } |
1422 | } | 1377 | } |
1423 | 1378 | ||
@@ -1452,7 +1407,6 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, | |||
1452 | struct ath_softc *sc = hw->priv; | 1407 | struct ath_softc *sc = hw->priv; |
1453 | struct ath_hw *ah = sc->sc_ah; | 1408 | struct ath_hw *ah = sc->sc_ah; |
1454 | struct ath_common *common = ath9k_hw_common(ah); | 1409 | struct ath_common *common = ath9k_hw_common(ah); |
1455 | struct ath_vif *avp = (void *)vif->drv_priv; | ||
1456 | int ret = 0; | 1410 | int ret = 0; |
1457 | 1411 | ||
1458 | ath9k_ps_wakeup(sc); | 1412 | ath9k_ps_wakeup(sc); |
@@ -1482,8 +1436,9 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, | |||
1482 | } | 1436 | } |
1483 | } | 1437 | } |
1484 | 1438 | ||
1485 | if ((vif->type == NL80211_IFTYPE_ADHOC) && | 1439 | if ((ah->opmode == NL80211_IFTYPE_ADHOC) || |
1486 | sc->nvifs > 0) { | 1440 | ((vif->type == NL80211_IFTYPE_ADHOC) && |
1441 | sc->nvifs > 0)) { | ||
1487 | ath_err(common, "Cannot create ADHOC interface when other" | 1442 | ath_err(common, "Cannot create ADHOC interface when other" |
1488 | " interfaces already exist.\n"); | 1443 | " interfaces already exist.\n"); |
1489 | ret = -EINVAL; | 1444 | ret = -EINVAL; |
@@ -1493,10 +1448,6 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, | |||
1493 | ath_dbg(common, ATH_DBG_CONFIG, | 1448 | ath_dbg(common, ATH_DBG_CONFIG, |
1494 | "Attach a VIF of type: %d\n", vif->type); | 1449 | "Attach a VIF of type: %d\n", vif->type); |
1495 | 1450 | ||
1496 | /* Set the VIF opmode */ | ||
1497 | avp->av_opmode = vif->type; | ||
1498 | avp->av_bslot = -1; | ||
1499 | |||
1500 | sc->nvifs++; | 1451 | sc->nvifs++; |
1501 | 1452 | ||
1502 | ath9k_do_vif_add_setup(hw, vif); | 1453 | ath9k_do_vif_add_setup(hw, vif); |
@@ -1855,6 +1806,20 @@ static int ath9k_set_key(struct ieee80211_hw *hw, | |||
1855 | if (ath9k_modparam_nohwcrypt) | 1806 | if (ath9k_modparam_nohwcrypt) |
1856 | return -ENOSPC; | 1807 | return -ENOSPC; |
1857 | 1808 | ||
1809 | if (vif->type == NL80211_IFTYPE_ADHOC && | ||
1810 | (key->cipher == WLAN_CIPHER_SUITE_TKIP || | ||
1811 | key->cipher == WLAN_CIPHER_SUITE_CCMP) && | ||
1812 | !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) { | ||
1813 | /* | ||
1814 | * For now, disable hw crypto for the RSN IBSS group keys. This | ||
1815 | * could be optimized in the future to use a modified key cache | ||
1816 | * design to support per-STA RX GTK, but until that gets | ||
1817 | * implemented, use of software crypto for group addressed | ||
1818 | * frames is a acceptable to allow RSN IBSS to be used. | ||
1819 | */ | ||
1820 | return -EOPNOTSUPP; | ||
1821 | } | ||
1822 | |||
1858 | mutex_lock(&sc->mutex); | 1823 | mutex_lock(&sc->mutex); |
1859 | ath9k_ps_wakeup(sc); | 1824 | ath9k_ps_wakeup(sc); |
1860 | ath_dbg(common, ATH_DBG_CONFIG, "Set HW Key\n"); | 1825 | ath_dbg(common, ATH_DBG_CONFIG, "Set HW Key\n"); |
@@ -1886,6 +1851,86 @@ static int ath9k_set_key(struct ieee80211_hw *hw, | |||
1886 | 1851 | ||
1887 | return ret; | 1852 | return ret; |
1888 | } | 1853 | } |
1854 | static void ath9k_bss_iter(void *data, u8 *mac, struct ieee80211_vif *vif) | ||
1855 | { | ||
1856 | struct ath_softc *sc = data; | ||
1857 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | ||
1858 | struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; | ||
1859 | struct ath_vif *avp = (void *)vif->drv_priv; | ||
1860 | |||
1861 | switch (sc->sc_ah->opmode) { | ||
1862 | case NL80211_IFTYPE_ADHOC: | ||
1863 | /* There can be only one vif available */ | ||
1864 | memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); | ||
1865 | common->curaid = bss_conf->aid; | ||
1866 | ath9k_hw_write_associd(sc->sc_ah); | ||
1867 | /* configure beacon */ | ||
1868 | if (bss_conf->enable_beacon) | ||
1869 | ath_beacon_config(sc, vif); | ||
1870 | break; | ||
1871 | case NL80211_IFTYPE_STATION: | ||
1872 | /* | ||
1873 | * Skip iteration if primary station vif's bss info | ||
1874 | * was not changed | ||
1875 | */ | ||
1876 | if (sc->sc_flags & SC_OP_PRIM_STA_VIF) | ||
1877 | break; | ||
1878 | |||
1879 | if (bss_conf->assoc) { | ||
1880 | sc->sc_flags |= SC_OP_PRIM_STA_VIF; | ||
1881 | avp->primary_sta_vif = true; | ||
1882 | memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); | ||
1883 | common->curaid = bss_conf->aid; | ||
1884 | ath9k_hw_write_associd(sc->sc_ah); | ||
1885 | ath_dbg(common, ATH_DBG_CONFIG, | ||
1886 | "Bss Info ASSOC %d, bssid: %pM\n", | ||
1887 | bss_conf->aid, common->curbssid); | ||
1888 | ath_beacon_config(sc, vif); | ||
1889 | /* Reset rssi stats */ | ||
1890 | sc->last_rssi = ATH_RSSI_DUMMY_MARKER; | ||
1891 | sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER; | ||
1892 | |||
1893 | sc->sc_flags |= SC_OP_ANI_RUN; | ||
1894 | ath_start_ani(common); | ||
1895 | } | ||
1896 | break; | ||
1897 | default: | ||
1898 | break; | ||
1899 | } | ||
1900 | } | ||
1901 | |||
1902 | static void ath9k_config_bss(struct ath_softc *sc, struct ieee80211_vif *vif) | ||
1903 | { | ||
1904 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | ||
1905 | struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; | ||
1906 | struct ath_vif *avp = (void *)vif->drv_priv; | ||
1907 | |||
1908 | /* Reconfigure bss info */ | ||
1909 | if (avp->primary_sta_vif && !bss_conf->assoc) { | ||
1910 | ath_dbg(common, ATH_DBG_CONFIG, | ||
1911 | "Bss Info DISASSOC %d, bssid %pM\n", | ||
1912 | common->curaid, common->curbssid); | ||
1913 | sc->sc_flags &= ~(SC_OP_PRIM_STA_VIF | SC_OP_BEACONS); | ||
1914 | avp->primary_sta_vif = false; | ||
1915 | memset(common->curbssid, 0, ETH_ALEN); | ||
1916 | common->curaid = 0; | ||
1917 | } | ||
1918 | |||
1919 | ieee80211_iterate_active_interfaces_atomic( | ||
1920 | sc->hw, ath9k_bss_iter, sc); | ||
1921 | |||
1922 | /* | ||
1923 | * None of station vifs are associated. | ||
1924 | * Clear bssid & aid | ||
1925 | */ | ||
1926 | if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) && | ||
1927 | !(sc->sc_flags & SC_OP_PRIM_STA_VIF)) { | ||
1928 | ath9k_hw_write_associd(sc->sc_ah); | ||
1929 | /* Stop ANI */ | ||
1930 | sc->sc_flags &= ~SC_OP_ANI_RUN; | ||
1931 | del_timer_sync(&common->ani.timer); | ||
1932 | } | ||
1933 | } | ||
1889 | 1934 | ||
1890 | static void ath9k_bss_info_changed(struct ieee80211_hw *hw, | 1935 | static void ath9k_bss_info_changed(struct ieee80211_hw *hw, |
1891 | struct ieee80211_vif *vif, | 1936 | struct ieee80211_vif *vif, |
@@ -1893,7 +1938,6 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, | |||
1893 | u32 changed) | 1938 | u32 changed) |
1894 | { | 1939 | { |
1895 | struct ath_softc *sc = hw->priv; | 1940 | struct ath_softc *sc = hw->priv; |
1896 | struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; | ||
1897 | struct ath_hw *ah = sc->sc_ah; | 1941 | struct ath_hw *ah = sc->sc_ah; |
1898 | struct ath_common *common = ath9k_hw_common(ah); | 1942 | struct ath_common *common = ath9k_hw_common(ah); |
1899 | struct ath_vif *avp = (void *)vif->drv_priv; | 1943 | struct ath_vif *avp = (void *)vif->drv_priv; |
@@ -1904,20 +1948,13 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, | |||
1904 | mutex_lock(&sc->mutex); | 1948 | mutex_lock(&sc->mutex); |
1905 | 1949 | ||
1906 | if (changed & BSS_CHANGED_BSSID) { | 1950 | if (changed & BSS_CHANGED_BSSID) { |
1907 | /* Set BSSID */ | 1951 | ath9k_config_bss(sc, vif); |
1908 | memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); | ||
1909 | memcpy(avp->bssid, bss_conf->bssid, ETH_ALEN); | ||
1910 | common->curaid = 0; | ||
1911 | ath9k_hw_write_associd(ah); | ||
1912 | 1952 | ||
1913 | /* Set aggregation protection mode parameters */ | 1953 | /* Set aggregation protection mode parameters */ |
1914 | sc->config.ath_aggr_prot = 0; | 1954 | sc->config.ath_aggr_prot = 0; |
1915 | 1955 | ||
1916 | ath_dbg(common, ATH_DBG_CONFIG, "BSSID: %pM aid: 0x%x\n", | 1956 | ath_dbg(common, ATH_DBG_CONFIG, "BSSID: %pM aid: 0x%x\n", |
1917 | common->curbssid, common->curaid); | 1957 | common->curbssid, common->curaid); |
1918 | |||
1919 | /* need to reconfigure the beacon */ | ||
1920 | sc->sc_flags &= ~SC_OP_BEACONS ; | ||
1921 | } | 1958 | } |
1922 | 1959 | ||
1923 | /* Enable transmission of beacons (AP, IBSS, MESH) */ | 1960 | /* Enable transmission of beacons (AP, IBSS, MESH) */ |
@@ -1958,7 +1995,6 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, | |||
1958 | } | 1995 | } |
1959 | 1996 | ||
1960 | if (changed & BSS_CHANGED_BEACON_INT) { | 1997 | if (changed & BSS_CHANGED_BEACON_INT) { |
1961 | cur_conf->beacon_interval = bss_conf->beacon_int; | ||
1962 | /* | 1998 | /* |
1963 | * In case of AP mode, the HW TSF has to be reset | 1999 | * In case of AP mode, the HW TSF has to be reset |
1964 | * when the beacon interval changes. | 2000 | * when the beacon interval changes. |
@@ -1970,9 +2006,8 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, | |||
1970 | if (!error) | 2006 | if (!error) |
1971 | ath_beacon_config(sc, vif); | 2007 | ath_beacon_config(sc, vif); |
1972 | ath9k_set_beaconing_status(sc, true); | 2008 | ath9k_set_beaconing_status(sc, true); |
1973 | } else { | 2009 | } else |
1974 | ath_beacon_config(sc, vif); | 2010 | ath_beacon_config(sc, vif); |
1975 | } | ||
1976 | } | 2011 | } |
1977 | 2012 | ||
1978 | if (changed & BSS_CHANGED_ERP_PREAMBLE) { | 2013 | if (changed & BSS_CHANGED_ERP_PREAMBLE) { |
@@ -1994,12 +2029,6 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, | |||
1994 | sc->sc_flags &= ~SC_OP_PROTECT_ENABLE; | 2029 | sc->sc_flags &= ~SC_OP_PROTECT_ENABLE; |
1995 | } | 2030 | } |
1996 | 2031 | ||
1997 | if (changed & BSS_CHANGED_ASSOC) { | ||
1998 | ath_dbg(common, ATH_DBG_CONFIG, "BSS Changed ASSOC %d\n", | ||
1999 | bss_conf->assoc); | ||
2000 | ath9k_bss_assoc_info(sc, hw, vif, bss_conf); | ||
2001 | } | ||
2002 | |||
2003 | mutex_unlock(&sc->mutex); | 2032 | mutex_unlock(&sc->mutex); |
2004 | ath9k_ps_restore(sc); | 2033 | ath9k_ps_restore(sc); |
2005 | } | 2034 | } |
diff --git a/drivers/net/wireless/ath/ath9k/phy.h b/drivers/net/wireless/ath/ath9k/phy.h index 5e3d7496986e..f50e2c29f71e 100644 --- a/drivers/net/wireless/ath/ath9k/phy.h +++ b/drivers/net/wireless/ath/ath9k/phy.h | |||
@@ -38,25 +38,11 @@ | |||
38 | #define AR_PHY_CLC_Q0 0x0000ffd0 | 38 | #define AR_PHY_CLC_Q0 0x0000ffd0 |
39 | #define AR_PHY_CLC_Q0_S 5 | 39 | #define AR_PHY_CLC_Q0_S 5 |
40 | 40 | ||
41 | #define REG_WRITE_RF_ARRAY(iniarray, regData, regWr) do { \ | ||
42 | int r; \ | ||
43 | for (r = 0; r < ((iniarray)->ia_rows); r++) { \ | ||
44 | REG_WRITE(ah, INI_RA((iniarray), r, 0), (regData)[r]); \ | ||
45 | DO_DELAY(regWr); \ | ||
46 | } \ | ||
47 | } while (0) | ||
48 | |||
49 | #define ANTSWAP_AB 0x0001 | 41 | #define ANTSWAP_AB 0x0001 |
50 | #define REDUCE_CHAIN_0 0x00000050 | 42 | #define REDUCE_CHAIN_0 0x00000050 |
51 | #define REDUCE_CHAIN_1 0x00000051 | 43 | #define REDUCE_CHAIN_1 0x00000051 |
52 | #define AR_PHY_CHIP_ID 0x9818 | 44 | #define AR_PHY_CHIP_ID 0x9818 |
53 | 45 | ||
54 | #define RF_BANK_SETUP(_bank, _iniarray, _col) do { \ | ||
55 | int i; \ | ||
56 | for (i = 0; i < (_iniarray)->ia_rows; i++) \ | ||
57 | (_bank)[i] = INI_RA((_iniarray), i, _col);; \ | ||
58 | } while (0) | ||
59 | |||
60 | #define AR_PHY_TIMING11_SPUR_FREQ_SD 0x3FF00000 | 46 | #define AR_PHY_TIMING11_SPUR_FREQ_SD 0x3FF00000 |
61 | #define AR_PHY_TIMING11_SPUR_FREQ_SD_S 20 | 47 | #define AR_PHY_TIMING11_SPUR_FREQ_SD_S 20 |
62 | 48 | ||
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index a9c3f4672aa0..3842b7518661 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c | |||
@@ -574,7 +574,7 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) | |||
574 | sc->ps_flags &= ~PS_BEACON_SYNC; | 574 | sc->ps_flags &= ~PS_BEACON_SYNC; |
575 | ath_dbg(common, ATH_DBG_PS, | 575 | ath_dbg(common, ATH_DBG_PS, |
576 | "Reconfigure Beacon timers based on timestamp from the AP\n"); | 576 | "Reconfigure Beacon timers based on timestamp from the AP\n"); |
577 | ath_beacon_config(sc, NULL); | 577 | ath_set_beacon(sc); |
578 | } | 578 | } |
579 | 579 | ||
580 | if (ath_beacon_dtim_pending_cab(skb)) { | 580 | if (ath_beacon_dtim_pending_cab(skb)) { |
diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index 8fa8acfde62e..693d543937b5 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h | |||
@@ -1396,6 +1396,7 @@ enum { | |||
1396 | #define AR_STA_ID1_PCF 0x00100000 | 1396 | #define AR_STA_ID1_PCF 0x00100000 |
1397 | #define AR_STA_ID1_USE_DEFANT 0x00200000 | 1397 | #define AR_STA_ID1_USE_DEFANT 0x00200000 |
1398 | #define AR_STA_ID1_DEFANT_UPDATE 0x00400000 | 1398 | #define AR_STA_ID1_DEFANT_UPDATE 0x00400000 |
1399 | #define AR_STA_ID1_AR9100_BA_FIX 0x00400000 | ||
1399 | #define AR_STA_ID1_RTS_USE_DEF 0x00800000 | 1400 | #define AR_STA_ID1_RTS_USE_DEF 0x00800000 |
1400 | #define AR_STA_ID1_ACKCTS_6MB 0x01000000 | 1401 | #define AR_STA_ID1_ACKCTS_6MB 0x01000000 |
1401 | #define AR_STA_ID1_BASE_RATE_11B 0x02000000 | 1402 | #define AR_STA_ID1_BASE_RATE_11B 0x02000000 |
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 88fa7fdffd05..3cea3f76e373 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c | |||
@@ -1980,7 +1980,7 @@ static void ath_tx_rc_status(struct ath_softc *sc, struct ath_buf *bf, | |||
1980 | if (ieee80211_is_data(hdr->frame_control) && | 1980 | if (ieee80211_is_data(hdr->frame_control) && |
1981 | (ts->ts_flags & (ATH9K_TX_DATA_UNDERRUN | | 1981 | (ts->ts_flags & (ATH9K_TX_DATA_UNDERRUN | |
1982 | ATH9K_TX_DELIM_UNDERRUN)) && | 1982 | ATH9K_TX_DELIM_UNDERRUN)) && |
1983 | ah->tx_trig_level >= sc->sc_ah->caps.tx_triglevel_max) | 1983 | ah->tx_trig_level >= sc->sc_ah->config.max_txtrig_level) |
1984 | tx_info->status.rates[tx_rateindex].count = | 1984 | tx_info->status.rates[tx_rateindex].count = |
1985 | hw->max_rate_tries; | 1985 | hw->max_rate_tries; |
1986 | } | 1986 | } |
@@ -2144,33 +2144,6 @@ static void ath_tx_complete_poll_work(struct work_struct *work) | |||
2144 | } else { | 2144 | } else { |
2145 | txq->axq_tx_inprogress = true; | 2145 | txq->axq_tx_inprogress = true; |
2146 | } | 2146 | } |
2147 | } else { | ||
2148 | /* If the queue has pending buffers, then it | ||
2149 | * should be doing tx work (and have axq_depth). | ||
2150 | * Shouldn't get to this state I think..but | ||
2151 | * we do. | ||
2152 | */ | ||
2153 | if (!(sc->sc_flags & (SC_OP_OFFCHANNEL)) && | ||
2154 | (txq->pending_frames > 0 || | ||
2155 | !list_empty(&txq->axq_acq) || | ||
2156 | txq->stopped)) { | ||
2157 | ath_err(ath9k_hw_common(sc->sc_ah), | ||
2158 | "txq: %p axq_qnum: %u," | ||
2159 | " mac80211_qnum: %i" | ||
2160 | " axq_link: %p" | ||
2161 | " pending frames: %i" | ||
2162 | " axq_acq empty: %i" | ||
2163 | " stopped: %i" | ||
2164 | " axq_depth: 0 Attempting to" | ||
2165 | " restart tx logic.\n", | ||
2166 | txq, txq->axq_qnum, | ||
2167 | txq->mac80211_qnum, | ||
2168 | txq->axq_link, | ||
2169 | txq->pending_frames, | ||
2170 | list_empty(&txq->axq_acq), | ||
2171 | txq->stopped); | ||
2172 | ath_txq_schedule(sc, txq); | ||
2173 | } | ||
2174 | } | 2147 | } |
2175 | spin_unlock_bh(&txq->axq_lock); | 2148 | spin_unlock_bh(&txq->axq_lock); |
2176 | } | 2149 | } |
diff --git a/drivers/net/wireless/ath/key.c b/drivers/net/wireless/ath/key.c index 37b8e115375a..0d4f39cbdcab 100644 --- a/drivers/net/wireless/ath/key.c +++ b/drivers/net/wireless/ath/key.c | |||
@@ -23,6 +23,14 @@ | |||
23 | 23 | ||
24 | #define REG_READ (common->ops->read) | 24 | #define REG_READ (common->ops->read) |
25 | #define REG_WRITE(_ah, _reg, _val) (common->ops->write)(_ah, _val, _reg) | 25 | #define REG_WRITE(_ah, _reg, _val) (common->ops->write)(_ah, _val, _reg) |
26 | #define ENABLE_REGWRITE_BUFFER(_ah) \ | ||
27 | if (common->ops->enable_write_buffer) \ | ||
28 | common->ops->enable_write_buffer((_ah)); | ||
29 | |||
30 | #define REGWRITE_BUFFER_FLUSH(_ah) \ | ||
31 | if (common->ops->write_flush) \ | ||
32 | common->ops->write_flush((_ah)); | ||
33 | |||
26 | 34 | ||
27 | #define IEEE80211_WEP_NKID 4 /* number of key ids */ | 35 | #define IEEE80211_WEP_NKID 4 /* number of key ids */ |
28 | 36 | ||
@@ -42,6 +50,8 @@ bool ath_hw_keyreset(struct ath_common *common, u16 entry) | |||
42 | 50 | ||
43 | keyType = REG_READ(ah, AR_KEYTABLE_TYPE(entry)); | 51 | keyType = REG_READ(ah, AR_KEYTABLE_TYPE(entry)); |
44 | 52 | ||
53 | ENABLE_REGWRITE_BUFFER(ah); | ||
54 | |||
45 | REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), 0); | 55 | REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), 0); |
46 | REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), 0); | 56 | REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), 0); |
47 | REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), 0); | 57 | REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), 0); |
@@ -66,6 +76,8 @@ bool ath_hw_keyreset(struct ath_common *common, u16 entry) | |||
66 | 76 | ||
67 | } | 77 | } |
68 | 78 | ||
79 | REGWRITE_BUFFER_FLUSH(ah); | ||
80 | |||
69 | return true; | 81 | return true; |
70 | } | 82 | } |
71 | EXPORT_SYMBOL(ath_hw_keyreset); | 83 | EXPORT_SYMBOL(ath_hw_keyreset); |
@@ -104,9 +116,13 @@ static bool ath_hw_keysetmac(struct ath_common *common, | |||
104 | } else { | 116 | } else { |
105 | macLo = macHi = 0; | 117 | macLo = macHi = 0; |
106 | } | 118 | } |
119 | ENABLE_REGWRITE_BUFFER(ah); | ||
120 | |||
107 | REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), macLo); | 121 | REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), macLo); |
108 | REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), macHi | unicast_flag); | 122 | REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), macHi | unicast_flag); |
109 | 123 | ||
124 | REGWRITE_BUFFER_FLUSH(ah); | ||
125 | |||
110 | return true; | 126 | return true; |
111 | } | 127 | } |
112 | 128 | ||
@@ -223,6 +239,8 @@ static bool ath_hw_set_keycache_entry(struct ath_common *common, u16 entry, | |||
223 | mic3 = get_unaligned_le16(k->kv_txmic + 0) & 0xffff; | 239 | mic3 = get_unaligned_le16(k->kv_txmic + 0) & 0xffff; |
224 | mic4 = get_unaligned_le32(k->kv_txmic + 4); | 240 | mic4 = get_unaligned_le32(k->kv_txmic + 4); |
225 | 241 | ||
242 | ENABLE_REGWRITE_BUFFER(ah); | ||
243 | |||
226 | /* Write RX[31:0] and TX[31:16] */ | 244 | /* Write RX[31:0] and TX[31:16] */ |
227 | REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0); | 245 | REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0); |
228 | REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), mic1); | 246 | REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), mic1); |
@@ -236,6 +254,8 @@ static bool ath_hw_set_keycache_entry(struct ath_common *common, u16 entry, | |||
236 | REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry), | 254 | REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry), |
237 | AR_KEYTABLE_TYPE_CLR); | 255 | AR_KEYTABLE_TYPE_CLR); |
238 | 256 | ||
257 | REGWRITE_BUFFER_FLUSH(ah); | ||
258 | |||
239 | } else { | 259 | } else { |
240 | /* | 260 | /* |
241 | * TKIP uses four key cache entries (two for group | 261 | * TKIP uses four key cache entries (two for group |
@@ -258,6 +278,8 @@ static bool ath_hw_set_keycache_entry(struct ath_common *common, u16 entry, | |||
258 | mic0 = get_unaligned_le32(k->kv_mic + 0); | 278 | mic0 = get_unaligned_le32(k->kv_mic + 0); |
259 | mic2 = get_unaligned_le32(k->kv_mic + 4); | 279 | mic2 = get_unaligned_le32(k->kv_mic + 4); |
260 | 280 | ||
281 | ENABLE_REGWRITE_BUFFER(ah); | ||
282 | |||
261 | /* Write MIC key[31:0] */ | 283 | /* Write MIC key[31:0] */ |
262 | REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0); | 284 | REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0); |
263 | REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0); | 285 | REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0); |
@@ -270,8 +292,12 @@ static bool ath_hw_set_keycache_entry(struct ath_common *common, u16 entry, | |||
270 | REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), 0); | 292 | REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), 0); |
271 | REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry), | 293 | REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry), |
272 | AR_KEYTABLE_TYPE_CLR); | 294 | AR_KEYTABLE_TYPE_CLR); |
295 | |||
296 | REGWRITE_BUFFER_FLUSH(ah); | ||
273 | } | 297 | } |
274 | 298 | ||
299 | ENABLE_REGWRITE_BUFFER(ah); | ||
300 | |||
275 | /* MAC address registers are reserved for the MIC entry */ | 301 | /* MAC address registers are reserved for the MIC entry */ |
276 | REG_WRITE(ah, AR_KEYTABLE_MAC0(micentry), 0); | 302 | REG_WRITE(ah, AR_KEYTABLE_MAC0(micentry), 0); |
277 | REG_WRITE(ah, AR_KEYTABLE_MAC1(micentry), 0); | 303 | REG_WRITE(ah, AR_KEYTABLE_MAC1(micentry), 0); |
@@ -283,7 +309,11 @@ static bool ath_hw_set_keycache_entry(struct ath_common *common, u16 entry, | |||
283 | */ | 309 | */ |
284 | REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0); | 310 | REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0); |
285 | REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1); | 311 | REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1); |
312 | |||
313 | REGWRITE_BUFFER_FLUSH(ah); | ||
286 | } else { | 314 | } else { |
315 | ENABLE_REGWRITE_BUFFER(ah); | ||
316 | |||
287 | /* Write key[47:0] */ | 317 | /* Write key[47:0] */ |
288 | REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0); | 318 | REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0); |
289 | REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1); | 319 | REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1); |
@@ -296,6 +326,8 @@ static bool ath_hw_set_keycache_entry(struct ath_common *common, u16 entry, | |||
296 | REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4); | 326 | REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4); |
297 | REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType); | 327 | REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType); |
298 | 328 | ||
329 | REGWRITE_BUFFER_FLUSH(ah); | ||
330 | |||
299 | /* Write MAC address for the entry */ | 331 | /* Write MAC address for the entry */ |
300 | (void) ath_hw_keysetmac(common, entry, mac); | 332 | (void) ath_hw_keysetmac(common, entry, mac); |
301 | } | 333 | } |
diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile index 9d6ee836426c..3652931753e0 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile | |||
@@ -2,7 +2,7 @@ | |||
2 | obj-$(CONFIG_IWLAGN) += iwlagn.o | 2 | obj-$(CONFIG_IWLAGN) += iwlagn.o |
3 | iwlagn-objs := iwl-agn.o iwl-agn-rs.o iwl-agn-led.o | 3 | iwlagn-objs := iwl-agn.o iwl-agn-rs.o iwl-agn-led.o |
4 | iwlagn-objs += iwl-agn-ucode.o iwl-agn-tx.o | 4 | iwlagn-objs += iwl-agn-ucode.o iwl-agn-tx.o |
5 | iwlagn-objs += iwl-agn-lib.o iwl-agn-calib.o | 5 | iwlagn-objs += iwl-agn-lib.o iwl-agn-calib.o iwl-io.o |
6 | iwlagn-objs += iwl-agn-tt.o iwl-agn-sta.o iwl-agn-eeprom.o | 6 | iwlagn-objs += iwl-agn-tt.o iwl-agn-sta.o iwl-agn-eeprom.o |
7 | 7 | ||
8 | iwlagn-objs += iwl-core.o iwl-eeprom.o iwl-hcmd.o iwl-power.o | 8 | iwlagn-objs += iwl-core.o iwl-eeprom.o iwl-hcmd.o iwl-power.o |
diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 27c5007e577c..1b2799291834 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | * | 2 | * |
3 | * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. | 3 | * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify it | 5 | * This program is free software; you can redistribute it and/or modify it |
6 | * under the terms of version 2 of the GNU General Public License as | 6 | * under the terms of version 2 of the GNU General Public License as |
@@ -141,7 +141,6 @@ static int iwl1000_hw_set_hw_params(struct iwl_priv *priv) | |||
141 | priv->hw_params.max_data_size = IWLAGN_RTC_DATA_SIZE; | 141 | priv->hw_params.max_data_size = IWLAGN_RTC_DATA_SIZE; |
142 | priv->hw_params.max_inst_size = IWLAGN_RTC_INST_SIZE; | 142 | priv->hw_params.max_inst_size = IWLAGN_RTC_INST_SIZE; |
143 | 143 | ||
144 | priv->hw_params.max_bsm_size = 0; | ||
145 | priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) | | 144 | priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) | |
146 | BIT(IEEE80211_BAND_5GHZ); | 145 | BIT(IEEE80211_BAND_5GHZ); |
147 | priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR; | 146 | priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR; |
@@ -179,21 +178,16 @@ static struct iwl_lib_ops iwl1000_lib = { | |||
179 | .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl, | 178 | .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl, |
180 | .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl, | 179 | .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl, |
181 | .txq_set_sched = iwlagn_txq_set_sched, | 180 | .txq_set_sched = iwlagn_txq_set_sched, |
182 | .txq_agg_enable = iwlagn_txq_agg_enable, | ||
183 | .txq_agg_disable = iwlagn_txq_agg_disable, | ||
184 | .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd, | 181 | .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd, |
185 | .txq_free_tfd = iwl_hw_txq_free_tfd, | 182 | .txq_free_tfd = iwl_hw_txq_free_tfd, |
186 | .txq_init = iwl_hw_tx_queue_init, | 183 | .txq_init = iwl_hw_tx_queue_init, |
187 | .rx_handler_setup = iwlagn_rx_handler_setup, | 184 | .rx_handler_setup = iwlagn_rx_handler_setup, |
188 | .setup_deferred_work = iwlagn_setup_deferred_work, | 185 | .setup_deferred_work = iwlagn_setup_deferred_work, |
189 | .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr, | 186 | .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr, |
190 | .load_ucode = iwlagn_load_ucode, | ||
191 | .dump_nic_event_log = iwl_dump_nic_event_log, | 187 | .dump_nic_event_log = iwl_dump_nic_event_log, |
192 | .dump_nic_error_log = iwl_dump_nic_error_log, | 188 | .dump_nic_error_log = iwl_dump_nic_error_log, |
193 | .dump_csr = iwl_dump_csr, | 189 | .dump_csr = iwl_dump_csr, |
194 | .dump_fh = iwl_dump_fh, | 190 | .dump_fh = iwl_dump_fh, |
195 | .init_alive_start = iwlagn_init_alive_start, | ||
196 | .alive_notify = iwlagn_alive_notify, | ||
197 | .send_tx_power = iwlagn_send_tx_power, | 191 | .send_tx_power = iwlagn_send_tx_power, |
198 | .update_chain_flags = iwl_update_chain_flags, | 192 | .update_chain_flags = iwl_update_chain_flags, |
199 | .apm_ops = { | 193 | .apm_ops = { |
@@ -215,13 +209,6 @@ static struct iwl_lib_ops iwl1000_lib = { | |||
215 | .calib_version = iwlagn_eeprom_calib_version, | 209 | .calib_version = iwlagn_eeprom_calib_version, |
216 | .query_addr = iwlagn_eeprom_query_addr, | 210 | .query_addr = iwlagn_eeprom_query_addr, |
217 | }, | 211 | }, |
218 | .isr_ops = { | ||
219 | .isr = iwl_isr_ict, | ||
220 | .free = iwl_free_isr_ict, | ||
221 | .alloc = iwl_alloc_isr_ict, | ||
222 | .reset = iwl_reset_ict, | ||
223 | .disable = iwl_disable_ict, | ||
224 | }, | ||
225 | .temp_ops = { | 212 | .temp_ops = { |
226 | .temperature = iwlagn_temperature, | 213 | .temperature = iwlagn_temperature, |
227 | }, | 214 | }, |
@@ -255,7 +242,6 @@ static struct iwl_base_params iwl1000_base_params = { | |||
255 | .eeprom_size = OTP_LOW_IMAGE_SIZE, | 242 | .eeprom_size = OTP_LOW_IMAGE_SIZE, |
256 | .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL, | 243 | .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL, |
257 | .set_l0s = true, | 244 | .set_l0s = true, |
258 | .use_bsm = false, | ||
259 | .max_ll_items = OTP_MAX_LL_ITEMS_1000, | 245 | .max_ll_items = OTP_MAX_LL_ITEMS_1000, |
260 | .shadow_ram_support = false, | 246 | .shadow_ram_support = false, |
261 | .led_compensation = 51, | 247 | .led_compensation = 51, |
diff --git a/drivers/net/wireless/iwlwifi/iwl-2000.c b/drivers/net/wireless/iwlwifi/iwl-2000.c index d7b6126408c9..f602af4b9408 100644 --- a/drivers/net/wireless/iwlwifi/iwl-2000.c +++ b/drivers/net/wireless/iwlwifi/iwl-2000.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | * | 2 | * |
3 | * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. | 3 | * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify it | 5 | * This program is free software; you can redistribute it and/or modify it |
6 | * under the terms of version 2 of the GNU General Public License as | 6 | * under the terms of version 2 of the GNU General Public License as |
@@ -147,7 +147,6 @@ static int iwl2000_hw_set_hw_params(struct iwl_priv *priv) | |||
147 | priv->hw_params.max_data_size = IWL60_RTC_DATA_SIZE; | 147 | priv->hw_params.max_data_size = IWL60_RTC_DATA_SIZE; |
148 | priv->hw_params.max_inst_size = IWL60_RTC_INST_SIZE; | 148 | priv->hw_params.max_inst_size = IWL60_RTC_INST_SIZE; |
149 | 149 | ||
150 | priv->hw_params.max_bsm_size = 0; | ||
151 | priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) | | 150 | priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) | |
152 | BIT(IEEE80211_BAND_5GHZ); | 151 | BIT(IEEE80211_BAND_5GHZ); |
153 | priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR; | 152 | priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR; |
@@ -259,8 +258,6 @@ static struct iwl_lib_ops iwl2000_lib = { | |||
259 | .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl, | 258 | .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl, |
260 | .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl, | 259 | .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl, |
261 | .txq_set_sched = iwlagn_txq_set_sched, | 260 | .txq_set_sched = iwlagn_txq_set_sched, |
262 | .txq_agg_enable = iwlagn_txq_agg_enable, | ||
263 | .txq_agg_disable = iwlagn_txq_agg_disable, | ||
264 | .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd, | 261 | .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd, |
265 | .txq_free_tfd = iwl_hw_txq_free_tfd, | 262 | .txq_free_tfd = iwl_hw_txq_free_tfd, |
266 | .txq_init = iwl_hw_tx_queue_init, | 263 | .txq_init = iwl_hw_tx_queue_init, |
@@ -268,13 +265,10 @@ static struct iwl_lib_ops iwl2000_lib = { | |||
268 | .setup_deferred_work = iwlagn_bt_setup_deferred_work, | 265 | .setup_deferred_work = iwlagn_bt_setup_deferred_work, |
269 | .cancel_deferred_work = iwlagn_bt_cancel_deferred_work, | 266 | .cancel_deferred_work = iwlagn_bt_cancel_deferred_work, |
270 | .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr, | 267 | .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr, |
271 | .load_ucode = iwlagn_load_ucode, | ||
272 | .dump_nic_event_log = iwl_dump_nic_event_log, | 268 | .dump_nic_event_log = iwl_dump_nic_event_log, |
273 | .dump_nic_error_log = iwl_dump_nic_error_log, | 269 | .dump_nic_error_log = iwl_dump_nic_error_log, |
274 | .dump_csr = iwl_dump_csr, | 270 | .dump_csr = iwl_dump_csr, |
275 | .dump_fh = iwl_dump_fh, | 271 | .dump_fh = iwl_dump_fh, |
276 | .init_alive_start = iwlagn_init_alive_start, | ||
277 | .alive_notify = iwlagn_alive_notify, | ||
278 | .send_tx_power = iwlagn_send_tx_power, | 272 | .send_tx_power = iwlagn_send_tx_power, |
279 | .update_chain_flags = iwl_update_chain_flags, | 273 | .update_chain_flags = iwl_update_chain_flags, |
280 | .set_channel_switch = iwl2030_hw_channel_switch, | 274 | .set_channel_switch = iwl2030_hw_channel_switch, |
@@ -298,13 +292,6 @@ static struct iwl_lib_ops iwl2000_lib = { | |||
298 | .query_addr = iwlagn_eeprom_query_addr, | 292 | .query_addr = iwlagn_eeprom_query_addr, |
299 | .update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower, | 293 | .update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower, |
300 | }, | 294 | }, |
301 | .isr_ops = { | ||
302 | .isr = iwl_isr_ict, | ||
303 | .free = iwl_free_isr_ict, | ||
304 | .alloc = iwl_alloc_isr_ict, | ||
305 | .reset = iwl_reset_ict, | ||
306 | .disable = iwl_disable_ict, | ||
307 | }, | ||
308 | .temp_ops = { | 295 | .temp_ops = { |
309 | .temperature = iwlagn_temperature, | 296 | .temperature = iwlagn_temperature, |
310 | }, | 297 | }, |
@@ -362,7 +349,6 @@ static struct iwl_base_params iwl2000_base_params = { | |||
362 | .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, | 349 | .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, |
363 | .pll_cfg_val = 0, | 350 | .pll_cfg_val = 0, |
364 | .set_l0s = true, | 351 | .set_l0s = true, |
365 | .use_bsm = false, | ||
366 | .max_ll_items = OTP_MAX_LL_ITEMS_2x00, | 352 | .max_ll_items = OTP_MAX_LL_ITEMS_2x00, |
367 | .shadow_ram_support = true, | 353 | .shadow_ram_support = true, |
368 | .led_compensation = 51, | 354 | .led_compensation = 51, |
@@ -386,7 +372,6 @@ static struct iwl_base_params iwl2030_base_params = { | |||
386 | .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, | 372 | .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, |
387 | .pll_cfg_val = 0, | 373 | .pll_cfg_val = 0, |
388 | .set_l0s = true, | 374 | .set_l0s = true, |
389 | .use_bsm = false, | ||
390 | .max_ll_items = OTP_MAX_LL_ITEMS_2x00, | 375 | .max_ll_items = OTP_MAX_LL_ITEMS_2x00, |
391 | .shadow_ram_support = true, | 376 | .shadow_ram_support = true, |
392 | .led_compensation = 57, | 377 | .led_compensation = 57, |
@@ -471,37 +456,6 @@ struct iwl_cfg iwl2030_2bg_cfg = { | |||
471 | IWL_DEVICE_2030, | 456 | IWL_DEVICE_2030, |
472 | }; | 457 | }; |
473 | 458 | ||
474 | #define IWL_DEVICE_6035 \ | ||
475 | .fw_name_pre = IWL2030_FW_PRE, \ | ||
476 | .ucode_api_max = IWL2030_UCODE_API_MAX, \ | ||
477 | .ucode_api_min = IWL2030_UCODE_API_MIN, \ | ||
478 | .eeprom_ver = EEPROM_6035_EEPROM_VERSION, \ | ||
479 | .eeprom_calib_ver = EEPROM_6035_TX_POWER_VERSION, \ | ||
480 | .ops = &iwl2030_ops, \ | ||
481 | .mod_params = &iwlagn_mod_params, \ | ||
482 | .base_params = &iwl2030_base_params, \ | ||
483 | .bt_params = &iwl2030_bt_params, \ | ||
484 | .need_dc_calib = true, \ | ||
485 | .need_temp_offset_calib = true, \ | ||
486 | .led_mode = IWL_LED_RF_STATE, \ | ||
487 | .adv_pm = true \ | ||
488 | |||
489 | struct iwl_cfg iwl6035_2agn_cfg = { | ||
490 | .name = "2000 Series 2x2 AGN/BT", | ||
491 | IWL_DEVICE_6035, | ||
492 | .ht_params = &iwl2000_ht_params, | ||
493 | }; | ||
494 | |||
495 | struct iwl_cfg iwl6035_2abg_cfg = { | ||
496 | .name = "2000 Series 2x2 ABG/BT", | ||
497 | IWL_DEVICE_6035, | ||
498 | }; | ||
499 | |||
500 | struct iwl_cfg iwl6035_2bg_cfg = { | ||
501 | .name = "2000 Series 2x2 BG/BT", | ||
502 | IWL_DEVICE_6035, | ||
503 | }; | ||
504 | |||
505 | #define IWL_DEVICE_200 \ | 459 | #define IWL_DEVICE_200 \ |
506 | .fw_name_pre = IWL200_FW_PRE, \ | 460 | .fw_name_pre = IWL200_FW_PRE, \ |
507 | .ucode_api_max = IWL200_UCODE_API_MAX, \ | 461 | .ucode_api_max = IWL200_UCODE_API_MAX, \ |
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h index 3975e45e7500..05ad47628b63 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h | |||
@@ -5,7 +5,7 @@ | |||
5 | * | 5 | * |
6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
7 | * | 7 | * |
8 | * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved. |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of version 2 of the GNU General Public License as | 11 | * it under the terms of version 2 of the GNU General Public License as |
@@ -30,7 +30,7 @@ | |||
30 | * | 30 | * |
31 | * BSD LICENSE | 31 | * BSD LICENSE |
32 | * | 32 | * |
33 | * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. | 33 | * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. |
34 | * All rights reserved. | 34 | * All rights reserved. |
35 | * | 35 | * |
36 | * Redistribution and use in source and binary forms, with or without | 36 | * Redistribution and use in source and binary forms, with or without |
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 22e045b5bcee..66f5fe8fe1ac 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | * | 2 | * |
3 | * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved. | 3 | * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved. |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify it | 5 | * This program is free software; you can redistribute it and/or modify it |
6 | * under the terms of version 2 of the GNU General Public License as | 6 | * under the terms of version 2 of the GNU General Public License as |
@@ -185,7 +185,6 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) | |||
185 | priv->hw_params.max_data_size = IWLAGN_RTC_DATA_SIZE; | 185 | priv->hw_params.max_data_size = IWLAGN_RTC_DATA_SIZE; |
186 | priv->hw_params.max_inst_size = IWLAGN_RTC_INST_SIZE; | 186 | priv->hw_params.max_inst_size = IWLAGN_RTC_INST_SIZE; |
187 | 187 | ||
188 | priv->hw_params.max_bsm_size = 0; | ||
189 | priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) | | 188 | priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) | |
190 | BIT(IEEE80211_BAND_5GHZ); | 189 | BIT(IEEE80211_BAND_5GHZ); |
191 | priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR; | 190 | priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR; |
@@ -231,7 +230,6 @@ static int iwl5150_hw_set_hw_params(struct iwl_priv *priv) | |||
231 | priv->hw_params.max_data_size = IWLAGN_RTC_DATA_SIZE; | 230 | priv->hw_params.max_data_size = IWLAGN_RTC_DATA_SIZE; |
232 | priv->hw_params.max_inst_size = IWLAGN_RTC_INST_SIZE; | 231 | priv->hw_params.max_inst_size = IWLAGN_RTC_INST_SIZE; |
233 | 232 | ||
234 | priv->hw_params.max_bsm_size = 0; | ||
235 | priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) | | 233 | priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) | |
236 | BIT(IEEE80211_BAND_5GHZ); | 234 | BIT(IEEE80211_BAND_5GHZ); |
237 | priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR; | 235 | priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR; |
@@ -348,8 +346,6 @@ static struct iwl_lib_ops iwl5000_lib = { | |||
348 | .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl, | 346 | .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl, |
349 | .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl, | 347 | .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl, |
350 | .txq_set_sched = iwlagn_txq_set_sched, | 348 | .txq_set_sched = iwlagn_txq_set_sched, |
351 | .txq_agg_enable = iwlagn_txq_agg_enable, | ||
352 | .txq_agg_disable = iwlagn_txq_agg_disable, | ||
353 | .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd, | 349 | .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd, |
354 | .txq_free_tfd = iwl_hw_txq_free_tfd, | 350 | .txq_free_tfd = iwl_hw_txq_free_tfd, |
355 | .txq_init = iwl_hw_tx_queue_init, | 351 | .txq_init = iwl_hw_tx_queue_init, |
@@ -360,9 +356,6 @@ static struct iwl_lib_ops iwl5000_lib = { | |||
360 | .dump_nic_error_log = iwl_dump_nic_error_log, | 356 | .dump_nic_error_log = iwl_dump_nic_error_log, |
361 | .dump_csr = iwl_dump_csr, | 357 | .dump_csr = iwl_dump_csr, |
362 | .dump_fh = iwl_dump_fh, | 358 | .dump_fh = iwl_dump_fh, |
363 | .load_ucode = iwlagn_load_ucode, | ||
364 | .init_alive_start = iwlagn_init_alive_start, | ||
365 | .alive_notify = iwlagn_alive_notify, | ||
366 | .send_tx_power = iwlagn_send_tx_power, | 359 | .send_tx_power = iwlagn_send_tx_power, |
367 | .update_chain_flags = iwl_update_chain_flags, | 360 | .update_chain_flags = iwl_update_chain_flags, |
368 | .set_channel_switch = iwl5000_hw_channel_switch, | 361 | .set_channel_switch = iwl5000_hw_channel_switch, |
@@ -385,13 +378,6 @@ static struct iwl_lib_ops iwl5000_lib = { | |||
385 | .calib_version = iwlagn_eeprom_calib_version, | 378 | .calib_version = iwlagn_eeprom_calib_version, |
386 | .query_addr = iwlagn_eeprom_query_addr, | 379 | .query_addr = iwlagn_eeprom_query_addr, |
387 | }, | 380 | }, |
388 | .isr_ops = { | ||
389 | .isr = iwl_isr_ict, | ||
390 | .free = iwl_free_isr_ict, | ||
391 | .alloc = iwl_alloc_isr_ict, | ||
392 | .reset = iwl_reset_ict, | ||
393 | .disable = iwl_disable_ict, | ||
394 | }, | ||
395 | .temp_ops = { | 381 | .temp_ops = { |
396 | .temperature = iwlagn_temperature, | 382 | .temperature = iwlagn_temperature, |
397 | }, | 383 | }, |
@@ -416,8 +402,6 @@ static struct iwl_lib_ops iwl5150_lib = { | |||
416 | .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl, | 402 | .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl, |
417 | .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl, | 403 | .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl, |
418 | .txq_set_sched = iwlagn_txq_set_sched, | 404 | .txq_set_sched = iwlagn_txq_set_sched, |
419 | .txq_agg_enable = iwlagn_txq_agg_enable, | ||
420 | .txq_agg_disable = iwlagn_txq_agg_disable, | ||
421 | .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd, | 405 | .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd, |
422 | .txq_free_tfd = iwl_hw_txq_free_tfd, | 406 | .txq_free_tfd = iwl_hw_txq_free_tfd, |
423 | .txq_init = iwl_hw_tx_queue_init, | 407 | .txq_init = iwl_hw_tx_queue_init, |
@@ -427,9 +411,6 @@ static struct iwl_lib_ops iwl5150_lib = { | |||
427 | .dump_nic_event_log = iwl_dump_nic_event_log, | 411 | .dump_nic_event_log = iwl_dump_nic_event_log, |
428 | .dump_nic_error_log = iwl_dump_nic_error_log, | 412 | .dump_nic_error_log = iwl_dump_nic_error_log, |
429 | .dump_csr = iwl_dump_csr, | 413 | .dump_csr = iwl_dump_csr, |
430 | .load_ucode = iwlagn_load_ucode, | ||
431 | .init_alive_start = iwlagn_init_alive_start, | ||
432 | .alive_notify = iwlagn_alive_notify, | ||
433 | .send_tx_power = iwlagn_send_tx_power, | 414 | .send_tx_power = iwlagn_send_tx_power, |
434 | .update_chain_flags = iwl_update_chain_flags, | 415 | .update_chain_flags = iwl_update_chain_flags, |
435 | .set_channel_switch = iwl5000_hw_channel_switch, | 416 | .set_channel_switch = iwl5000_hw_channel_switch, |
@@ -452,13 +433,6 @@ static struct iwl_lib_ops iwl5150_lib = { | |||
452 | .calib_version = iwlagn_eeprom_calib_version, | 433 | .calib_version = iwlagn_eeprom_calib_version, |
453 | .query_addr = iwlagn_eeprom_query_addr, | 434 | .query_addr = iwlagn_eeprom_query_addr, |
454 | }, | 435 | }, |
455 | .isr_ops = { | ||
456 | .isr = iwl_isr_ict, | ||
457 | .free = iwl_free_isr_ict, | ||
458 | .alloc = iwl_alloc_isr_ict, | ||
459 | .reset = iwl_reset_ict, | ||
460 | .disable = iwl_disable_ict, | ||
461 | }, | ||
462 | .temp_ops = { | 436 | .temp_ops = { |
463 | .temperature = iwl5150_temperature, | 437 | .temperature = iwl5150_temperature, |
464 | }, | 438 | }, |
@@ -500,7 +474,6 @@ static struct iwl_base_params iwl5000_base_params = { | |||
500 | .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, | 474 | .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, |
501 | .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL, | 475 | .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL, |
502 | .set_l0s = true, | 476 | .set_l0s = true, |
503 | .use_bsm = false, | ||
504 | .led_compensation = 51, | 477 | .led_compensation = 51, |
505 | .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, | 478 | .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, |
506 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, | 479 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, |
diff --git a/drivers/net/wireless/iwlwifi/iwl-6000-hw.h b/drivers/net/wireless/iwlwifi/iwl-6000-hw.h index 47891e16a758..b27986e57c92 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-6000-hw.h | |||
@@ -5,7 +5,7 @@ | |||
5 | * | 5 | * |
6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
7 | * | 7 | * |
8 | * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved. |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of version 2 of the GNU General Public License as | 11 | * it under the terms of version 2 of the GNU General Public License as |
@@ -30,7 +30,7 @@ | |||
30 | * | 30 | * |
31 | * BSD LICENSE | 31 | * BSD LICENSE |
32 | * | 32 | * |
33 | * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. | 33 | * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. |
34 | * All rights reserved. | 34 | * All rights reserved. |
35 | * | 35 | * |
36 | * Redistribution and use in source and binary forms, with or without | 36 | * Redistribution and use in source and binary forms, with or without |
diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index a745b01c0ec1..24d105b29aec 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | * | 2 | * |
3 | * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. | 3 | * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify it | 5 | * This program is free software; you can redistribute it and/or modify it |
6 | * under the terms of version 2 of the GNU General Public License as | 6 | * under the terms of version 2 of the GNU General Public License as |
@@ -176,7 +176,6 @@ static int iwl6000_hw_set_hw_params(struct iwl_priv *priv) | |||
176 | priv->hw_params.max_data_size = IWL60_RTC_DATA_SIZE; | 176 | priv->hw_params.max_data_size = IWL60_RTC_DATA_SIZE; |
177 | priv->hw_params.max_inst_size = IWL60_RTC_INST_SIZE; | 177 | priv->hw_params.max_inst_size = IWL60_RTC_INST_SIZE; |
178 | 178 | ||
179 | priv->hw_params.max_bsm_size = 0; | ||
180 | priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) | | 179 | priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) | |
181 | BIT(IEEE80211_BAND_5GHZ); | 180 | BIT(IEEE80211_BAND_5GHZ); |
182 | priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR; | 181 | priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR; |
@@ -288,21 +287,16 @@ static struct iwl_lib_ops iwl6000_lib = { | |||
288 | .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl, | 287 | .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl, |
289 | .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl, | 288 | .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl, |
290 | .txq_set_sched = iwlagn_txq_set_sched, | 289 | .txq_set_sched = iwlagn_txq_set_sched, |
291 | .txq_agg_enable = iwlagn_txq_agg_enable, | ||
292 | .txq_agg_disable = iwlagn_txq_agg_disable, | ||
293 | .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd, | 290 | .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd, |
294 | .txq_free_tfd = iwl_hw_txq_free_tfd, | 291 | .txq_free_tfd = iwl_hw_txq_free_tfd, |
295 | .txq_init = iwl_hw_tx_queue_init, | 292 | .txq_init = iwl_hw_tx_queue_init, |
296 | .rx_handler_setup = iwlagn_rx_handler_setup, | 293 | .rx_handler_setup = iwlagn_rx_handler_setup, |
297 | .setup_deferred_work = iwlagn_setup_deferred_work, | 294 | .setup_deferred_work = iwlagn_setup_deferred_work, |
298 | .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr, | 295 | .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr, |
299 | .load_ucode = iwlagn_load_ucode, | ||
300 | .dump_nic_event_log = iwl_dump_nic_event_log, | 296 | .dump_nic_event_log = iwl_dump_nic_event_log, |
301 | .dump_nic_error_log = iwl_dump_nic_error_log, | 297 | .dump_nic_error_log = iwl_dump_nic_error_log, |
302 | .dump_csr = iwl_dump_csr, | 298 | .dump_csr = iwl_dump_csr, |
303 | .dump_fh = iwl_dump_fh, | 299 | .dump_fh = iwl_dump_fh, |
304 | .init_alive_start = iwlagn_init_alive_start, | ||
305 | .alive_notify = iwlagn_alive_notify, | ||
306 | .send_tx_power = iwlagn_send_tx_power, | 300 | .send_tx_power = iwlagn_send_tx_power, |
307 | .update_chain_flags = iwl_update_chain_flags, | 301 | .update_chain_flags = iwl_update_chain_flags, |
308 | .set_channel_switch = iwl6000_hw_channel_switch, | 302 | .set_channel_switch = iwl6000_hw_channel_switch, |
@@ -326,13 +320,6 @@ static struct iwl_lib_ops iwl6000_lib = { | |||
326 | .query_addr = iwlagn_eeprom_query_addr, | 320 | .query_addr = iwlagn_eeprom_query_addr, |
327 | .update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower, | 321 | .update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower, |
328 | }, | 322 | }, |
329 | .isr_ops = { | ||
330 | .isr = iwl_isr_ict, | ||
331 | .free = iwl_free_isr_ict, | ||
332 | .alloc = iwl_alloc_isr_ict, | ||
333 | .reset = iwl_reset_ict, | ||
334 | .disable = iwl_disable_ict, | ||
335 | }, | ||
336 | .temp_ops = { | 323 | .temp_ops = { |
337 | .temperature = iwlagn_temperature, | 324 | .temperature = iwlagn_temperature, |
338 | }, | 325 | }, |
@@ -357,8 +344,6 @@ static struct iwl_lib_ops iwl6030_lib = { | |||
357 | .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl, | 344 | .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl, |
358 | .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl, | 345 | .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl, |
359 | .txq_set_sched = iwlagn_txq_set_sched, | 346 | .txq_set_sched = iwlagn_txq_set_sched, |
360 | .txq_agg_enable = iwlagn_txq_agg_enable, | ||
361 | .txq_agg_disable = iwlagn_txq_agg_disable, | ||
362 | .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd, | 347 | .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd, |
363 | .txq_free_tfd = iwl_hw_txq_free_tfd, | 348 | .txq_free_tfd = iwl_hw_txq_free_tfd, |
364 | .txq_init = iwl_hw_tx_queue_init, | 349 | .txq_init = iwl_hw_tx_queue_init, |
@@ -366,13 +351,10 @@ static struct iwl_lib_ops iwl6030_lib = { | |||
366 | .setup_deferred_work = iwlagn_bt_setup_deferred_work, | 351 | .setup_deferred_work = iwlagn_bt_setup_deferred_work, |
367 | .cancel_deferred_work = iwlagn_bt_cancel_deferred_work, | 352 | .cancel_deferred_work = iwlagn_bt_cancel_deferred_work, |
368 | .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr, | 353 | .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr, |
369 | .load_ucode = iwlagn_load_ucode, | ||
370 | .dump_nic_event_log = iwl_dump_nic_event_log, | 354 | .dump_nic_event_log = iwl_dump_nic_event_log, |
371 | .dump_nic_error_log = iwl_dump_nic_error_log, | 355 | .dump_nic_error_log = iwl_dump_nic_error_log, |
372 | .dump_csr = iwl_dump_csr, | 356 | .dump_csr = iwl_dump_csr, |
373 | .dump_fh = iwl_dump_fh, | 357 | .dump_fh = iwl_dump_fh, |
374 | .init_alive_start = iwlagn_init_alive_start, | ||
375 | .alive_notify = iwlagn_alive_notify, | ||
376 | .send_tx_power = iwlagn_send_tx_power, | 358 | .send_tx_power = iwlagn_send_tx_power, |
377 | .update_chain_flags = iwl_update_chain_flags, | 359 | .update_chain_flags = iwl_update_chain_flags, |
378 | .set_channel_switch = iwl6000_hw_channel_switch, | 360 | .set_channel_switch = iwl6000_hw_channel_switch, |
@@ -396,13 +378,6 @@ static struct iwl_lib_ops iwl6030_lib = { | |||
396 | .query_addr = iwlagn_eeprom_query_addr, | 378 | .query_addr = iwlagn_eeprom_query_addr, |
397 | .update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower, | 379 | .update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower, |
398 | }, | 380 | }, |
399 | .isr_ops = { | ||
400 | .isr = iwl_isr_ict, | ||
401 | .free = iwl_free_isr_ict, | ||
402 | .alloc = iwl_alloc_isr_ict, | ||
403 | .reset = iwl_reset_ict, | ||
404 | .disable = iwl_disable_ict, | ||
405 | }, | ||
406 | .temp_ops = { | 381 | .temp_ops = { |
407 | .temperature = iwlagn_temperature, | 382 | .temperature = iwlagn_temperature, |
408 | }, | 383 | }, |
@@ -470,7 +445,6 @@ static struct iwl_base_params iwl6000_base_params = { | |||
470 | .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, | 445 | .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, |
471 | .pll_cfg_val = 0, | 446 | .pll_cfg_val = 0, |
472 | .set_l0s = true, | 447 | .set_l0s = true, |
473 | .use_bsm = false, | ||
474 | .max_ll_items = OTP_MAX_LL_ITEMS_6x00, | 448 | .max_ll_items = OTP_MAX_LL_ITEMS_6x00, |
475 | .shadow_ram_support = true, | 449 | .shadow_ram_support = true, |
476 | .led_compensation = 51, | 450 | .led_compensation = 51, |
@@ -493,7 +467,6 @@ static struct iwl_base_params iwl6050_base_params = { | |||
493 | .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, | 467 | .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, |
494 | .pll_cfg_val = 0, | 468 | .pll_cfg_val = 0, |
495 | .set_l0s = true, | 469 | .set_l0s = true, |
496 | .use_bsm = false, | ||
497 | .max_ll_items = OTP_MAX_LL_ITEMS_6x50, | 470 | .max_ll_items = OTP_MAX_LL_ITEMS_6x50, |
498 | .shadow_ram_support = true, | 471 | .shadow_ram_support = true, |
499 | .led_compensation = 51, | 472 | .led_compensation = 51, |
@@ -515,7 +488,6 @@ static struct iwl_base_params iwl6000_g2_base_params = { | |||
515 | .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, | 488 | .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, |
516 | .pll_cfg_val = 0, | 489 | .pll_cfg_val = 0, |
517 | .set_l0s = true, | 490 | .set_l0s = true, |
518 | .use_bsm = false, | ||
519 | .max_ll_items = OTP_MAX_LL_ITEMS_6x00, | 491 | .max_ll_items = OTP_MAX_LL_ITEMS_6x00, |
520 | .shadow_ram_support = true, | 492 | .shadow_ram_support = true, |
521 | .led_compensation = 57, | 493 | .led_compensation = 57, |
@@ -613,6 +585,22 @@ struct iwl_cfg iwl6030_2bg_cfg = { | |||
613 | IWL_DEVICE_6030, | 585 | IWL_DEVICE_6030, |
614 | }; | 586 | }; |
615 | 587 | ||
588 | struct iwl_cfg iwl6035_2agn_cfg = { | ||
589 | .name = "6035 Series 2x2 AGN/BT", | ||
590 | IWL_DEVICE_6030, | ||
591 | .ht_params = &iwl6000_ht_params, | ||
592 | }; | ||
593 | |||
594 | struct iwl_cfg iwl6035_2abg_cfg = { | ||
595 | .name = "6035 Series 2x2 ABG/BT", | ||
596 | IWL_DEVICE_6030, | ||
597 | }; | ||
598 | |||
599 | struct iwl_cfg iwl6035_2bg_cfg = { | ||
600 | .name = "6035 Series 2x2 BG/BT", | ||
601 | IWL_DEVICE_6030, | ||
602 | }; | ||
603 | |||
616 | struct iwl_cfg iwl1030_bgn_cfg = { | 604 | struct iwl_cfg iwl1030_bgn_cfg = { |
617 | .name = "Intel(R) Centrino(R) Wireless-N 1030 BGN", | 605 | .name = "Intel(R) Centrino(R) Wireless-N 1030 BGN", |
618 | IWL_DEVICE_6030, | 606 | IWL_DEVICE_6030, |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-calib.c b/drivers/net/wireless/iwlwifi/iwl-agn-calib.c index 9006293e740c..7b761de77b0a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-calib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-calib.c | |||
@@ -5,7 +5,7 @@ | |||
5 | * | 5 | * |
6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
7 | * | 7 | * |
8 | * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of version 2 of the GNU General Public License as | 11 | * it under the terms of version 2 of the GNU General Public License as |
@@ -30,7 +30,7 @@ | |||
30 | * | 30 | * |
31 | * BSD LICENSE | 31 | * BSD LICENSE |
32 | * | 32 | * |
33 | * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. | 33 | * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. |
34 | * All rights reserved. | 34 | * All rights reserved. |
35 | * | 35 | * |
36 | * Redistribution and use in source and binary forms, with or without | 36 | * Redistribution and use in source and binary forms, with or without |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-calib.h b/drivers/net/wireless/iwlwifi/iwl-agn-calib.h index e37ae7261630..ef4d5079a7ed 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-calib.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn-calib.h | |||
@@ -5,7 +5,7 @@ | |||
5 | * | 5 | * |
6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
7 | * | 7 | * |
8 | * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of version 2 of the GNU General Public License as | 11 | * it under the terms of version 2 of the GNU General Public License as |
@@ -30,7 +30,7 @@ | |||
30 | * | 30 | * |
31 | * BSD LICENSE | 31 | * BSD LICENSE |
32 | * | 32 | * |
33 | * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. | 33 | * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. |
34 | * All rights reserved. | 34 | * All rights reserved. |
35 | * | 35 | * |
36 | * Redistribution and use in source and binary forms, with or without | 36 | * Redistribution and use in source and binary forms, with or without |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c index b500aaae53ec..d1834aa7edf0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c | |||
@@ -1,30 +1,30 @@ | |||
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | * | 2 | * |
3 | * GPL LICENSE SUMMARY | 3 | * GPL LICENSE SUMMARY |
4 | * | 4 | * |
5 | * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. | 5 | * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of version 2 of the GNU General Public License as | 8 | * it under the terms of version 2 of the GNU General Public License as |
9 | * published by the Free Software Foundation. | 9 | * published by the Free Software Foundation. |
10 | * | 10 | * |
11 | * This program is distributed in the hope that it will be useful, but | 11 | * This program is distributed in the hope that it will be useful, but |
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 | * General Public License for more details. | 14 | * General Public License for more details. |
15 | * | 15 | * |
16 | * You should have received a copy of the GNU General Public License | 16 | * You should have received a copy of the GNU General Public License |
17 | * along with this program; if not, write to the Free Software | 17 | * along with this program; if not, write to the Free Software |
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, | 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, |
19 | * USA | 19 | * USA |
20 | * | 20 | * |
21 | * The full GNU General Public License is included in this distribution | 21 | * The full GNU General Public License is included in this distribution |
22 | * in the file called LICENSE.GPL. | 22 | * in the file called LICENSE.GPL. |
23 | * | 23 | * |
24 | * Contact Information: | 24 | * Contact Information: |
25 | * Intel Linux Wireless <ilw@linux.intel.com> | 25 | * Intel Linux Wireless <ilw@linux.intel.com> |
26 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | 26 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 |
27 | *****************************************************************************/ | 27 | *****************************************************************************/ |
28 | #include "iwl-agn.h" | 28 | #include "iwl-agn.h" |
29 | #include "iwl-agn-debugfs.h" | 29 | #include "iwl-agn-debugfs.h" |
30 | 30 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.h b/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.h index f2573b5486cd..9a3f329e508f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.h | |||
@@ -2,7 +2,7 @@ | |||
2 | * | 2 | * |
3 | * GPL LICENSE SUMMARY | 3 | * GPL LICENSE SUMMARY |
4 | * | 4 | * |
5 | * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. | 5 | * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of version 2 of the GNU General Public License as | 8 | * it under the terms of version 2 of the GNU General Public License as |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c index 27b5a3eec9dc..3bcaa10f9929 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c | |||
@@ -5,7 +5,7 @@ | |||
5 | * | 5 | * |
6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
7 | * | 7 | * |
8 | * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of version 2 of the GNU General Public License as | 11 | * it under the terms of version 2 of the GNU General Public License as |
@@ -30,7 +30,7 @@ | |||
30 | * | 30 | * |
31 | * BSD LICENSE | 31 | * BSD LICENSE |
32 | * | 32 | * |
33 | * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. | 33 | * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. |
34 | * All rights reserved. | 34 | * All rights reserved. |
35 | * | 35 | * |
36 | * Redistribution and use in source and binary forms, with or without | 36 | * Redistribution and use in source and binary forms, with or without |
@@ -103,7 +103,7 @@ int iwlcore_eeprom_acquire_semaphore(struct iwl_priv *priv) | |||
103 | CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM, | 103 | CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM, |
104 | EEPROM_SEM_TIMEOUT); | 104 | EEPROM_SEM_TIMEOUT); |
105 | if (ret >= 0) { | 105 | if (ret >= 0) { |
106 | IWL_DEBUG_IO(priv, | 106 | IWL_DEBUG_EEPROM(priv, |
107 | "Acquired semaphore after %d tries.\n", | 107 | "Acquired semaphore after %d tries.\n", |
108 | count+1); | 108 | count+1); |
109 | return ret; | 109 | return ret; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c index 41543ad4cb84..861cc93957a9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * | 2 | * |
3 | * GPL LICENSE SUMMARY | 3 | * GPL LICENSE SUMMARY |
4 | * | 4 | * |
5 | * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. | 5 | * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of version 2 of the GNU General Public License as | 8 | * it under the terms of version 2 of the GNU General Public License as |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-hw.h b/drivers/net/wireless/iwlwifi/iwl-agn-hw.h index a52b82c8e7a6..7bd19f4e66de 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn-hw.h | |||
@@ -5,7 +5,7 @@ | |||
5 | * | 5 | * |
6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
7 | * | 7 | * |
8 | * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved. |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of version 2 of the GNU General Public License as | 11 | * it under the terms of version 2 of the GNU General Public License as |
@@ -30,7 +30,7 @@ | |||
30 | * | 30 | * |
31 | * BSD LICENSE | 31 | * BSD LICENSE |
32 | * | 32 | * |
33 | * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. | 33 | * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. |
34 | * All rights reserved. | 34 | * All rights reserved. |
35 | * | 35 | * |
36 | * Redistribution and use in source and binary forms, with or without | 36 | * Redistribution and use in source and binary forms, with or without |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ict.c b/drivers/net/wireless/iwlwifi/iwl-agn-ict.c index ed0148d714de..0d5fda44c3a3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-ict.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-ict.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * | 2 | * |
3 | * GPL LICENSE SUMMARY | 3 | * GPL LICENSE SUMMARY |
4 | * | 4 | * |
5 | * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. | 5 | * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of version 2 of the GNU General Public License as | 8 | * it under the terms of version 2 of the GNU General Public License as |
@@ -59,8 +59,6 @@ void iwl_free_isr_ict(struct iwl_priv *priv) | |||
59 | int iwl_alloc_isr_ict(struct iwl_priv *priv) | 59 | int iwl_alloc_isr_ict(struct iwl_priv *priv) |
60 | { | 60 | { |
61 | 61 | ||
62 | if (priv->cfg->base_params->use_isr_legacy) | ||
63 | return 0; | ||
64 | /* allocate shrared data table */ | 62 | /* allocate shrared data table */ |
65 | priv->_agn.ict_tbl_vir = | 63 | priv->_agn.ict_tbl_vir = |
66 | dma_alloc_coherent(&priv->pci_dev->dev, | 64 | dma_alloc_coherent(&priv->pci_dev->dev, |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-led.c b/drivers/net/wireless/iwlwifi/iwl-agn-led.c index c1190d965614..4bb877e600c7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-led.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | * | 2 | * |
3 | * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. | 3 | * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify it | 5 | * This program is free software; you can redistribute it and/or modify it |
6 | * under the terms of version 2 of the GNU General Public License as | 6 | * under the terms of version 2 of the GNU General Public License as |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-led.h b/drivers/net/wireless/iwlwifi/iwl-agn-led.h index 96f323dc5dd6..c0b7611b72c3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-led.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn-led.h | |||
@@ -1,6 +1,6 @@ | |||
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | * | 2 | * |
3 | * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. | 3 | * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify it | 5 | * This program is free software; you can redistribute it and/or modify it |
6 | * under the terms of version 2 of the GNU General Public License as | 6 | * under the terms of version 2 of the GNU General Public License as |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index 08ccb9496f76..9e47be6a7393 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * | 2 | * |
3 | * GPL LICENSE SUMMARY | 3 | * GPL LICENSE SUMMARY |
4 | * | 4 | * |
5 | * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. | 5 | * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of version 2 of the GNU General Public License as | 8 | * it under the terms of version 2 of the GNU General Public License as |
@@ -652,8 +652,7 @@ int iwlagn_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq) | |||
652 | const u32 rfdnlog = RX_QUEUE_SIZE_LOG; /* 256 RBDs */ | 652 | const u32 rfdnlog = RX_QUEUE_SIZE_LOG; /* 256 RBDs */ |
653 | u32 rb_timeout = 0; /* FIXME: RX_RB_TIMEOUT for all devices? */ | 653 | u32 rb_timeout = 0; /* FIXME: RX_RB_TIMEOUT for all devices? */ |
654 | 654 | ||
655 | if (!priv->cfg->base_params->use_isr_legacy) | 655 | rb_timeout = RX_RB_TIMEOUT; |
656 | rb_timeout = RX_RB_TIMEOUT; | ||
657 | 656 | ||
658 | if (priv->cfg->mod_params->amsdu_size_8K) | 657 | if (priv->cfg->mod_params->amsdu_size_8K) |
659 | rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K; | 658 | rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K; |
@@ -913,7 +912,6 @@ void iwlagn_rx_allocate(struct iwl_priv *priv, gfp_t priority) | |||
913 | 912 | ||
914 | list_add_tail(&rxb->list, &rxq->rx_free); | 913 | list_add_tail(&rxb->list, &rxq->rx_free); |
915 | rxq->free_count++; | 914 | rxq->free_count++; |
916 | priv->alloc_rxb_page++; | ||
917 | 915 | ||
918 | spin_unlock_irqrestore(&rxq->lock, flags); | 916 | spin_unlock_irqrestore(&rxq->lock, flags); |
919 | } | 917 | } |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index d03b4734c892..dbe6295bbf23 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | * | 2 | * |
3 | * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. | 3 | * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify it | 5 | * This program is free software; you can redistribute it and/or modify it |
6 | * under the terms of version 2 of the GNU General Public License as | 6 | * under the terms of version 2 of the GNU General Public License as |
@@ -115,13 +115,18 @@ const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT] = { | |||
115 | /* FIXME:RS: ^^ should be INV (legacy) */ | 115 | /* FIXME:RS: ^^ should be INV (legacy) */ |
116 | }; | 116 | }; |
117 | 117 | ||
118 | static inline u8 rs_extract_rate(u32 rate_n_flags) | ||
119 | { | ||
120 | return (u8)(rate_n_flags & RATE_MCS_RATE_MSK); | ||
121 | } | ||
122 | |||
118 | static int iwl_hwrate_to_plcp_idx(u32 rate_n_flags) | 123 | static int iwl_hwrate_to_plcp_idx(u32 rate_n_flags) |
119 | { | 124 | { |
120 | int idx = 0; | 125 | int idx = 0; |
121 | 126 | ||
122 | /* HT rate format */ | 127 | /* HT rate format */ |
123 | if (rate_n_flags & RATE_MCS_HT_MSK) { | 128 | if (rate_n_flags & RATE_MCS_HT_MSK) { |
124 | idx = (rate_n_flags & 0xff); | 129 | idx = rs_extract_rate(rate_n_flags); |
125 | 130 | ||
126 | if (idx >= IWL_RATE_MIMO3_6M_PLCP) | 131 | if (idx >= IWL_RATE_MIMO3_6M_PLCP) |
127 | idx = idx - IWL_RATE_MIMO3_6M_PLCP; | 132 | idx = idx - IWL_RATE_MIMO3_6M_PLCP; |
@@ -138,7 +143,8 @@ static int iwl_hwrate_to_plcp_idx(u32 rate_n_flags) | |||
138 | /* legacy rate format, search for match in table */ | 143 | /* legacy rate format, search for match in table */ |
139 | } else { | 144 | } else { |
140 | for (idx = 0; idx < ARRAY_SIZE(iwl_rates); idx++) | 145 | for (idx = 0; idx < ARRAY_SIZE(iwl_rates); idx++) |
141 | if (iwl_rates[idx].plcp == (rate_n_flags & 0xFF)) | 146 | if (iwl_rates[idx].plcp == |
147 | rs_extract_rate(rate_n_flags)) | ||
142 | return idx; | 148 | return idx; |
143 | } | 149 | } |
144 | 150 | ||
@@ -239,11 +245,6 @@ static const struct iwl_rate_mcs_info iwl_rate_mcs[IWL_RATE_COUNT] = { | |||
239 | 245 | ||
240 | #define MCS_INDEX_PER_STREAM (8) | 246 | #define MCS_INDEX_PER_STREAM (8) |
241 | 247 | ||
242 | static inline u8 rs_extract_rate(u32 rate_n_flags) | ||
243 | { | ||
244 | return (u8)(rate_n_flags & 0xFF); | ||
245 | } | ||
246 | |||
247 | static void rs_rate_scale_clear_window(struct iwl_rate_scale_data *window) | 248 | static void rs_rate_scale_clear_window(struct iwl_rate_scale_data *window) |
248 | { | 249 | { |
249 | window->data = 0; | 250 | window->data = 0; |
@@ -2770,16 +2771,13 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta, | |||
2770 | static void *rs_alloc_sta(void *priv_rate, struct ieee80211_sta *sta, | 2771 | static void *rs_alloc_sta(void *priv_rate, struct ieee80211_sta *sta, |
2771 | gfp_t gfp) | 2772 | gfp_t gfp) |
2772 | { | 2773 | { |
2773 | struct iwl_lq_sta *lq_sta; | ||
2774 | struct iwl_station_priv *sta_priv = (struct iwl_station_priv *) sta->drv_priv; | 2774 | struct iwl_station_priv *sta_priv = (struct iwl_station_priv *) sta->drv_priv; |
2775 | struct iwl_priv *priv; | 2775 | struct iwl_priv *priv; |
2776 | 2776 | ||
2777 | priv = (struct iwl_priv *)priv_rate; | 2777 | priv = (struct iwl_priv *)priv_rate; |
2778 | IWL_DEBUG_RATE(priv, "create station rate scale window\n"); | 2778 | IWL_DEBUG_RATE(priv, "create station rate scale window\n"); |
2779 | 2779 | ||
2780 | lq_sta = &sta_priv->lq_sta; | 2780 | return &sta_priv->lq_sta; |
2781 | |||
2782 | return lq_sta; | ||
2783 | } | 2781 | } |
2784 | 2782 | ||
2785 | /* | 2783 | /* |
@@ -2912,7 +2910,8 @@ static void rs_fill_link_cmd(struct iwl_priv *priv, | |||
2912 | ant_toggle_cnt = 1; | 2910 | ant_toggle_cnt = 1; |
2913 | repeat_rate = IWL_NUMBER_TRY; | 2911 | repeat_rate = IWL_NUMBER_TRY; |
2914 | } else { | 2912 | } else { |
2915 | repeat_rate = IWL_HT_NUMBER_TRY; | 2913 | repeat_rate = min(IWL_HT_NUMBER_TRY, |
2914 | LINK_QUAL_AGG_DISABLE_START_DEF - 1); | ||
2916 | } | 2915 | } |
2917 | 2916 | ||
2918 | lq_cmd->general_params.mimo_delimiter = | 2917 | lq_cmd->general_params.mimo_delimiter = |
@@ -3257,7 +3256,6 @@ static ssize_t rs_sta_dbgfs_rate_scale_data_read(struct file *file, | |||
3257 | { | 3256 | { |
3258 | char buff[120]; | 3257 | char buff[120]; |
3259 | int desc = 0; | 3258 | int desc = 0; |
3260 | ssize_t ret; | ||
3261 | 3259 | ||
3262 | struct iwl_lq_sta *lq_sta = file->private_data; | 3260 | struct iwl_lq_sta *lq_sta = file->private_data; |
3263 | struct iwl_priv *priv; | 3261 | struct iwl_priv *priv; |
@@ -3274,8 +3272,7 @@ static ssize_t rs_sta_dbgfs_rate_scale_data_read(struct file *file, | |||
3274 | "Bit Rate= %d Mb/s\n", | 3272 | "Bit Rate= %d Mb/s\n", |
3275 | iwl_rates[lq_sta->last_txrate_idx].ieee >> 1); | 3273 | iwl_rates[lq_sta->last_txrate_idx].ieee >> 1); |
3276 | 3274 | ||
3277 | ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc); | 3275 | return simple_read_from_buffer(user_buf, count, ppos, buff, desc); |
3278 | return ret; | ||
3279 | } | 3276 | } |
3280 | 3277 | ||
3281 | static const struct file_operations rs_sta_dbgfs_rate_scale_data_ops = { | 3278 | static const struct file_operations rs_sta_dbgfs_rate_scale_data_ops = { |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h index 184828c72b31..69a29932babc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h | |||
@@ -1,6 +1,6 @@ | |||
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | * | 2 | * |
3 | * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. | 3 | * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify it | 5 | * This program is free software; you can redistribute it and/or modify it |
6 | * under the terms of version 2 of the GNU General Public License as | 6 | * under the terms of version 2 of the GNU General Public License as |
@@ -41,20 +41,6 @@ struct iwl_rate_info { | |||
41 | u8 next_rs_tgg; /* next rate used in TGG rs algo */ | 41 | u8 next_rs_tgg; /* next rate used in TGG rs algo */ |
42 | }; | 42 | }; |
43 | 43 | ||
44 | struct iwl3945_rate_info { | ||
45 | u8 plcp; /* uCode API: IWL_RATE_6M_PLCP, etc. */ | ||
46 | u8 ieee; /* MAC header: IWL_RATE_6M_IEEE, etc. */ | ||
47 | u8 prev_ieee; /* previous rate in IEEE speeds */ | ||
48 | u8 next_ieee; /* next rate in IEEE speeds */ | ||
49 | u8 prev_rs; /* previous rate used in rs algo */ | ||
50 | u8 next_rs; /* next rate used in rs algo */ | ||
51 | u8 prev_rs_tgg; /* previous rate used in TGG rs algo */ | ||
52 | u8 next_rs_tgg; /* next rate used in TGG rs algo */ | ||
53 | u8 table_rs_index; /* index in rate scale table cmd */ | ||
54 | u8 prev_table_rs; /* prev in rate table cmd */ | ||
55 | }; | ||
56 | |||
57 | |||
58 | /* | 44 | /* |
59 | * These serve as indexes into | 45 | * These serve as indexes into |
60 | * struct iwl_rate_info iwl_rates[IWL_RATE_COUNT]; | 46 | * struct iwl_rate_info iwl_rates[IWL_RATE_COUNT]; |
@@ -75,7 +61,6 @@ enum { | |||
75 | IWL_RATE_60M_INDEX, | 61 | IWL_RATE_60M_INDEX, |
76 | IWL_RATE_COUNT, /*FIXME:RS:change to IWL_RATE_INDEX_COUNT,*/ | 62 | IWL_RATE_COUNT, /*FIXME:RS:change to IWL_RATE_INDEX_COUNT,*/ |
77 | IWL_RATE_COUNT_LEGACY = IWL_RATE_COUNT - 1, /* Excluding 60M */ | 63 | IWL_RATE_COUNT_LEGACY = IWL_RATE_COUNT - 1, /* Excluding 60M */ |
78 | IWL_RATE_COUNT_3945 = IWL_RATE_COUNT - 1, | ||
79 | IWL_RATE_INVM_INDEX = IWL_RATE_COUNT, | 64 | IWL_RATE_INVM_INDEX = IWL_RATE_COUNT, |
80 | IWL_RATE_INVALID = IWL_RATE_COUNT, | 65 | IWL_RATE_INVALID = IWL_RATE_COUNT, |
81 | }; | 66 | }; |
@@ -213,7 +198,6 @@ enum { | |||
213 | IWL_CCK_BASIC_RATES_MASK) | 198 | IWL_CCK_BASIC_RATES_MASK) |
214 | 199 | ||
215 | #define IWL_RATES_MASK ((1 << IWL_RATE_COUNT) - 1) | 200 | #define IWL_RATES_MASK ((1 << IWL_RATE_COUNT) - 1) |
216 | #define IWL_RATES_MASK_3945 ((1 << IWL_RATE_COUNT_3945) - 1) | ||
217 | 201 | ||
218 | #define IWL_INVALID_VALUE -1 | 202 | #define IWL_INVALID_VALUE -1 |
219 | 203 | ||
@@ -453,19 +437,9 @@ static inline u8 first_antenna(u8 mask) | |||
453 | } | 437 | } |
454 | 438 | ||
455 | 439 | ||
456 | /** | ||
457 | * iwl3945_rate_scale_init - Initialize the rate scale table based on assoc info | ||
458 | * | ||
459 | * The specific throughput table used is based on the type of network | ||
460 | * the associated with, including A, B, G, and G w/ TGG protection | ||
461 | */ | ||
462 | extern void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id); | ||
463 | |||
464 | /* Initialize station's rate scaling information after adding station */ | 440 | /* Initialize station's rate scaling information after adding station */ |
465 | extern void iwl_rs_rate_init(struct iwl_priv *priv, | 441 | extern void iwl_rs_rate_init(struct iwl_priv *priv, |
466 | struct ieee80211_sta *sta, u8 sta_id); | 442 | struct ieee80211_sta *sta, u8 sta_id); |
467 | extern void iwl3945_rs_rate_init(struct iwl_priv *priv, | ||
468 | struct ieee80211_sta *sta, u8 sta_id); | ||
469 | 443 | ||
470 | /** | 444 | /** |
471 | * iwl_rate_control_register - Register the rate control algorithm callbacks | 445 | * iwl_rate_control_register - Register the rate control algorithm callbacks |
@@ -478,7 +452,6 @@ extern void iwl3945_rs_rate_init(struct iwl_priv *priv, | |||
478 | * | 452 | * |
479 | */ | 453 | */ |
480 | extern int iwlagn_rate_control_register(void); | 454 | extern int iwlagn_rate_control_register(void); |
481 | extern int iwl3945_rate_control_register(void); | ||
482 | 455 | ||
483 | /** | 456 | /** |
484 | * iwl_rate_control_unregister - Unregister the rate control callbacks | 457 | * iwl_rate_control_unregister - Unregister the rate control callbacks |
@@ -487,6 +460,5 @@ extern int iwl3945_rate_control_register(void); | |||
487 | * the driver is unloaded. | 460 | * the driver is unloaded. |
488 | */ | 461 | */ |
489 | extern void iwlagn_rate_control_unregister(void); | 462 | extern void iwlagn_rate_control_unregister(void); |
490 | extern void iwl3945_rate_control_unregister(void); | ||
491 | 463 | ||
492 | #endif /* __iwl_agn__rs__ */ | 464 | #endif /* __iwl_agn__rs__ */ |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c index dfdbea6e8f99..c335ee6883ee 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | * | 2 | * |
3 | * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. | 3 | * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify it | 5 | * This program is free software; you can redistribute it and/or modify it |
6 | * under the terms of version 2 of the GNU General Public License as | 6 | * under the terms of version 2 of the GNU General Public License as |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-sta.c b/drivers/net/wireless/iwlwifi/iwl-agn-sta.c index 35f085ac336b..079275f2c64d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-sta.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | * | 2 | * |
3 | * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. | 3 | * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. |
4 | * | 4 | * |
5 | * Portions of this file are derived from the ipw3945 project, as well | 5 | * Portions of this file are derived from the ipw3945 project, as well |
6 | * as portions of the ieee80211 subsystem header files. | 6 | * as portions of the ieee80211 subsystem header files. |
@@ -474,7 +474,7 @@ int iwl_remove_dynamic_key(struct iwl_priv *priv, | |||
474 | memset(&priv->stations[sta_id].keyinfo, 0, | 474 | memset(&priv->stations[sta_id].keyinfo, 0, |
475 | sizeof(struct iwl_hw_key)); | 475 | sizeof(struct iwl_hw_key)); |
476 | memset(&priv->stations[sta_id].sta.key, 0, | 476 | memset(&priv->stations[sta_id].sta.key, 0, |
477 | sizeof(struct iwl4965_keyinfo)); | 477 | sizeof(struct iwl_keyinfo)); |
478 | priv->stations[sta_id].sta.key.key_flags = | 478 | priv->stations[sta_id].sta.key.key_flags = |
479 | STA_KEY_FLG_NO_ENC | STA_KEY_FLG_INVALID; | 479 | STA_KEY_FLG_NO_ENC | STA_KEY_FLG_INVALID; |
480 | priv->stations[sta_id].sta.key.key_offset = WEP_INVALID_OFFSET; | 480 | priv->stations[sta_id].sta.key.key_offset = WEP_INVALID_OFFSET; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tt.c b/drivers/net/wireless/iwlwifi/iwl-agn-tt.c index e3a8216a033c..348f74f1c8e8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tt.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tt.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | * | 2 | * |
3 | * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved. | 3 | * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved. |
4 | * | 4 | * |
5 | * Portions of this file are derived from the ipw3945 project, as well | 5 | * Portions of this file are derived from the ipw3945 project, as well |
6 | * as portions of the ieee80211 subsystem header files. | 6 | * as portions of the ieee80211 subsystem header files. |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tt.h b/drivers/net/wireless/iwlwifi/iwl-agn-tt.h index d55060427cac..d118ed29bf3f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tt.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tt.h | |||
@@ -1,6 +1,6 @@ | |||
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | * | 2 | * |
3 | * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved. | 3 | * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved. |
4 | * | 4 | * |
5 | * Portions of this file are derived from the ipw3945 project, as well | 5 | * Portions of this file are derived from the ipw3945 project, as well |
6 | * as portions of the ieee80211 subsystem header files. | 6 | * as portions of the ieee80211 subsystem header files. |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c index a709d05c5868..2816b432c62f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * | 2 | * |
3 | * GPL LICENSE SUMMARY | 3 | * GPL LICENSE SUMMARY |
4 | * | 4 | * |
5 | * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. | 5 | * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of version 2 of the GNU General Public License as | 8 | * it under the terms of version 2 of the GNU General Public License as |
@@ -222,13 +222,8 @@ void iwlagn_tx_queue_set_status(struct iwl_priv *priv, | |||
222 | scd_retry ? "BA" : "AC/CMD", txq_id, tx_fifo_id); | 222 | scd_retry ? "BA" : "AC/CMD", txq_id, tx_fifo_id); |
223 | } | 223 | } |
224 | 224 | ||
225 | int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id, | 225 | static int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id, int sta_id, int tid) |
226 | int tx_fifo, int sta_id, int tid, u16 ssn_idx) | ||
227 | { | 226 | { |
228 | unsigned long flags; | ||
229 | u16 ra_tid; | ||
230 | int ret; | ||
231 | |||
232 | if ((IWLAGN_FIRST_AMPDU_QUEUE > txq_id) || | 227 | if ((IWLAGN_FIRST_AMPDU_QUEUE > txq_id) || |
233 | (IWLAGN_FIRST_AMPDU_QUEUE + | 228 | (IWLAGN_FIRST_AMPDU_QUEUE + |
234 | priv->cfg->base_params->num_of_ampdu_queues <= txq_id)) { | 229 | priv->cfg->base_params->num_of_ampdu_queues <= txq_id)) { |
@@ -240,12 +235,33 @@ int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id, | |||
240 | return -EINVAL; | 235 | return -EINVAL; |
241 | } | 236 | } |
242 | 237 | ||
243 | ra_tid = BUILD_RAxTID(sta_id, tid); | ||
244 | |||
245 | /* Modify device's station table to Tx this TID */ | 238 | /* Modify device's station table to Tx this TID */ |
246 | ret = iwl_sta_tx_modify_enable_tid(priv, sta_id, tid); | 239 | return iwl_sta_tx_modify_enable_tid(priv, sta_id, tid); |
247 | if (ret) | 240 | } |
248 | return ret; | 241 | |
242 | void iwlagn_txq_agg_queue_setup(struct iwl_priv *priv, | ||
243 | struct ieee80211_sta *sta, | ||
244 | int tid, int frame_limit) | ||
245 | { | ||
246 | int sta_id, tx_fifo, txq_id, ssn_idx; | ||
247 | u16 ra_tid; | ||
248 | unsigned long flags; | ||
249 | struct iwl_tid_data *tid_data; | ||
250 | |||
251 | sta_id = iwl_sta_id(sta); | ||
252 | if (WARN_ON(sta_id == IWL_INVALID_STATION)) | ||
253 | return; | ||
254 | if (WARN_ON(tid >= MAX_TID_COUNT)) | ||
255 | return; | ||
256 | |||
257 | spin_lock_irqsave(&priv->sta_lock, flags); | ||
258 | tid_data = &priv->stations[sta_id].tid[tid]; | ||
259 | ssn_idx = SEQ_TO_SN(tid_data->seq_number); | ||
260 | txq_id = tid_data->agg.txq_id; | ||
261 | tx_fifo = tid_data->agg.tx_fifo; | ||
262 | spin_unlock_irqrestore(&priv->sta_lock, flags); | ||
263 | |||
264 | ra_tid = BUILD_RAxTID(sta_id, tid); | ||
249 | 265 | ||
250 | spin_lock_irqsave(&priv->lock, flags); | 266 | spin_lock_irqsave(&priv->lock, flags); |
251 | 267 | ||
@@ -271,10 +287,10 @@ int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id, | |||
271 | iwl_write_targ_mem(priv, priv->scd_base_addr + | 287 | iwl_write_targ_mem(priv, priv->scd_base_addr + |
272 | IWLAGN_SCD_CONTEXT_QUEUE_OFFSET(txq_id) + | 288 | IWLAGN_SCD_CONTEXT_QUEUE_OFFSET(txq_id) + |
273 | sizeof(u32), | 289 | sizeof(u32), |
274 | ((SCD_WIN_SIZE << | 290 | ((frame_limit << |
275 | IWLAGN_SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) & | 291 | IWLAGN_SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) & |
276 | IWLAGN_SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) | | 292 | IWLAGN_SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) | |
277 | ((SCD_FRAME_LIMIT << | 293 | ((frame_limit << |
278 | IWLAGN_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) & | 294 | IWLAGN_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) & |
279 | IWLAGN_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK)); | 295 | IWLAGN_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK)); |
280 | 296 | ||
@@ -284,12 +300,10 @@ int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id, | |||
284 | iwlagn_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 1); | 300 | iwlagn_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 1); |
285 | 301 | ||
286 | spin_unlock_irqrestore(&priv->lock, flags); | 302 | spin_unlock_irqrestore(&priv->lock, flags); |
287 | |||
288 | return 0; | ||
289 | } | 303 | } |
290 | 304 | ||
291 | int iwlagn_txq_agg_disable(struct iwl_priv *priv, u16 txq_id, | 305 | static int iwlagn_txq_agg_disable(struct iwl_priv *priv, u16 txq_id, |
292 | u16 ssn_idx, u8 tx_fifo) | 306 | u16 ssn_idx, u8 tx_fifo) |
293 | { | 307 | { |
294 | if ((IWLAGN_FIRST_AMPDU_QUEUE > txq_id) || | 308 | if ((IWLAGN_FIRST_AMPDU_QUEUE > txq_id) || |
295 | (IWLAGN_FIRST_AMPDU_QUEUE + | 309 | (IWLAGN_FIRST_AMPDU_QUEUE + |
@@ -1034,11 +1048,11 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif, | |||
1034 | tid_data = &priv->stations[sta_id].tid[tid]; | 1048 | tid_data = &priv->stations[sta_id].tid[tid]; |
1035 | *ssn = SEQ_TO_SN(tid_data->seq_number); | 1049 | *ssn = SEQ_TO_SN(tid_data->seq_number); |
1036 | tid_data->agg.txq_id = txq_id; | 1050 | tid_data->agg.txq_id = txq_id; |
1051 | tid_data->agg.tx_fifo = tx_fifo; | ||
1037 | iwl_set_swq_id(&priv->txq[txq_id], get_ac_from_tid(tid), txq_id); | 1052 | iwl_set_swq_id(&priv->txq[txq_id], get_ac_from_tid(tid), txq_id); |
1038 | spin_unlock_irqrestore(&priv->sta_lock, flags); | 1053 | spin_unlock_irqrestore(&priv->sta_lock, flags); |
1039 | 1054 | ||
1040 | ret = priv->cfg->ops->lib->txq_agg_enable(priv, txq_id, tx_fifo, | 1055 | ret = iwlagn_txq_agg_enable(priv, txq_id, sta_id, tid); |
1041 | sta_id, tid, *ssn); | ||
1042 | if (ret) | 1056 | if (ret) |
1043 | return ret; | 1057 | return ret; |
1044 | 1058 | ||
@@ -1125,8 +1139,7 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif, | |||
1125 | * to deactivate the uCode queue, just return "success" to allow | 1139 | * to deactivate the uCode queue, just return "success" to allow |
1126 | * mac80211 to clean up it own data. | 1140 | * mac80211 to clean up it own data. |
1127 | */ | 1141 | */ |
1128 | priv->cfg->ops->lib->txq_agg_disable(priv, txq_id, ssn, | 1142 | iwlagn_txq_agg_disable(priv, txq_id, ssn, tx_fifo_id); |
1129 | tx_fifo_id); | ||
1130 | spin_unlock_irqrestore(&priv->lock, flags); | 1143 | spin_unlock_irqrestore(&priv->lock, flags); |
1131 | 1144 | ||
1132 | ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); | 1145 | ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); |
@@ -1155,8 +1168,7 @@ int iwlagn_txq_check_empty(struct iwl_priv *priv, | |||
1155 | u16 ssn = SEQ_TO_SN(tid_data->seq_number); | 1168 | u16 ssn = SEQ_TO_SN(tid_data->seq_number); |
1156 | int tx_fifo = get_fifo_from_tid(ctx, tid); | 1169 | int tx_fifo = get_fifo_from_tid(ctx, tid); |
1157 | IWL_DEBUG_HT(priv, "HW queue empty: continue DELBA flow\n"); | 1170 | IWL_DEBUG_HT(priv, "HW queue empty: continue DELBA flow\n"); |
1158 | priv->cfg->ops->lib->txq_agg_disable(priv, txq_id, | 1171 | iwlagn_txq_agg_disable(priv, txq_id, ssn, tx_fifo); |
1159 | ssn, tx_fifo); | ||
1160 | tid_data->agg.state = IWL_AGG_OFF; | 1172 | tid_data->agg.state = IWL_AGG_OFF; |
1161 | ieee80211_stop_tx_ba_cb_irqsafe(ctx->vif, addr, tid); | 1173 | ieee80211_stop_tx_ba_cb_irqsafe(ctx->vif, addr, tid); |
1162 | } | 1174 | } |
@@ -1251,11 +1263,11 @@ static int iwlagn_tx_status_reply_compressed_ba(struct iwl_priv *priv, | |||
1251 | struct iwl_compressed_ba_resp *ba_resp) | 1263 | struct iwl_compressed_ba_resp *ba_resp) |
1252 | 1264 | ||
1253 | { | 1265 | { |
1254 | int i, sh, ack; | 1266 | int sh; |
1255 | u16 seq_ctl = le16_to_cpu(ba_resp->seq_ctl); | 1267 | u16 seq_ctl = le16_to_cpu(ba_resp->seq_ctl); |
1256 | u16 scd_flow = le16_to_cpu(ba_resp->scd_flow); | 1268 | u16 scd_flow = le16_to_cpu(ba_resp->scd_flow); |
1257 | int successes = 0; | ||
1258 | struct ieee80211_tx_info *info; | 1269 | struct ieee80211_tx_info *info; |
1270 | u64 bitmap, sent_bitmap; | ||
1259 | 1271 | ||
1260 | if (unlikely(!agg->wait_for_ba)) { | 1272 | if (unlikely(!agg->wait_for_ba)) { |
1261 | if (unlikely(ba_resp->bitmap)) | 1273 | if (unlikely(ba_resp->bitmap)) |
@@ -1269,70 +1281,42 @@ static int iwlagn_tx_status_reply_compressed_ba(struct iwl_priv *priv, | |||
1269 | 1281 | ||
1270 | /* Calculate shift to align block-ack bits with our Tx window bits */ | 1282 | /* Calculate shift to align block-ack bits with our Tx window bits */ |
1271 | sh = agg->start_idx - SEQ_TO_INDEX(seq_ctl >> 4); | 1283 | sh = agg->start_idx - SEQ_TO_INDEX(seq_ctl >> 4); |
1272 | if (sh < 0) /* tbw something is wrong with indices */ | 1284 | if (sh < 0) |
1273 | sh += 0x100; | 1285 | sh += 0x100; |
1274 | 1286 | ||
1275 | if (agg->frame_count > (64 - sh)) { | 1287 | /* |
1276 | IWL_DEBUG_TX_REPLY(priv, "more frames than bitmap size"); | 1288 | * Check for success or failure according to the |
1277 | return -1; | 1289 | * transmitted bitmap and block-ack bitmap |
1278 | } | 1290 | */ |
1279 | if (!priv->cfg->base_params->no_agg_framecnt_info && ba_resp->txed) { | 1291 | bitmap = le64_to_cpu(ba_resp->bitmap) >> sh; |
1292 | sent_bitmap = bitmap & agg->bitmap; | ||
1293 | |||
1294 | /* Sanity check values reported by uCode */ | ||
1295 | if (ba_resp->txed_2_done > ba_resp->txed) { | ||
1296 | IWL_DEBUG_TX_REPLY(priv, | ||
1297 | "bogus sent(%d) and ack(%d) count\n", | ||
1298 | ba_resp->txed, ba_resp->txed_2_done); | ||
1280 | /* | 1299 | /* |
1281 | * sent and ack information provided by uCode | 1300 | * set txed_2_done = txed, |
1282 | * use it instead of figure out ourself | 1301 | * so it won't impact rate scale |
1283 | */ | 1302 | */ |
1284 | if (ba_resp->txed_2_done > ba_resp->txed) { | 1303 | ba_resp->txed = ba_resp->txed_2_done; |
1285 | IWL_DEBUG_TX_REPLY(priv, | 1304 | } |
1286 | "bogus sent(%d) and ack(%d) count\n", | 1305 | IWL_DEBUG_HT(priv, "agg frames sent:%d, acked:%d\n", |
1287 | ba_resp->txed, ba_resp->txed_2_done); | 1306 | ba_resp->txed, ba_resp->txed_2_done); |
1288 | /* | ||
1289 | * set txed_2_done = txed, | ||
1290 | * so it won't impact rate scale | ||
1291 | */ | ||
1292 | ba_resp->txed = ba_resp->txed_2_done; | ||
1293 | } | ||
1294 | IWL_DEBUG_HT(priv, "agg frames sent:%d, acked:%d\n", | ||
1295 | ba_resp->txed, ba_resp->txed_2_done); | ||
1296 | } else { | ||
1297 | u64 bitmap, sent_bitmap; | ||
1298 | |||
1299 | /* don't use 64-bit values for now */ | ||
1300 | bitmap = le64_to_cpu(ba_resp->bitmap) >> sh; | ||
1301 | |||
1302 | /* check for success or failure according to the | ||
1303 | * transmitted bitmap and block-ack bitmap */ | ||
1304 | sent_bitmap = bitmap & agg->bitmap; | ||
1305 | |||
1306 | /* For each frame attempted in aggregation, | ||
1307 | * update driver's record of tx frame's status. */ | ||
1308 | i = 0; | ||
1309 | while (sent_bitmap) { | ||
1310 | ack = sent_bitmap & 1ULL; | ||
1311 | successes += ack; | ||
1312 | IWL_DEBUG_TX_REPLY(priv, "%s ON i=%d idx=%d raw=%d\n", | ||
1313 | ack ? "ACK" : "NACK", i, | ||
1314 | (agg->start_idx + i) & 0xff, | ||
1315 | agg->start_idx + i); | ||
1316 | sent_bitmap >>= 1; | ||
1317 | ++i; | ||
1318 | } | ||
1319 | 1307 | ||
1320 | IWL_DEBUG_TX_REPLY(priv, "Bitmap %llx\n", | 1308 | /* Find the first ACKed frame to store the TX status */ |
1321 | (unsigned long long)bitmap); | 1309 | while (sent_bitmap && !(sent_bitmap & 1)) { |
1310 | agg->start_idx = (agg->start_idx + 1) & 0xff; | ||
1311 | sent_bitmap >>= 1; | ||
1322 | } | 1312 | } |
1323 | 1313 | ||
1324 | info = IEEE80211_SKB_CB(priv->txq[scd_flow].txb[agg->start_idx].skb); | 1314 | info = IEEE80211_SKB_CB(priv->txq[scd_flow].txb[agg->start_idx].skb); |
1325 | memset(&info->status, 0, sizeof(info->status)); | 1315 | memset(&info->status, 0, sizeof(info->status)); |
1326 | info->flags |= IEEE80211_TX_STAT_ACK; | 1316 | info->flags |= IEEE80211_TX_STAT_ACK; |
1327 | info->flags |= IEEE80211_TX_STAT_AMPDU; | 1317 | info->flags |= IEEE80211_TX_STAT_AMPDU; |
1328 | if (!priv->cfg->base_params->no_agg_framecnt_info && ba_resp->txed) { | 1318 | info->status.ampdu_ack_len = ba_resp->txed_2_done; |
1329 | info->status.ampdu_ack_len = ba_resp->txed_2_done; | 1319 | info->status.ampdu_len = ba_resp->txed; |
1330 | info->status.ampdu_len = ba_resp->txed; | ||
1331 | |||
1332 | } else { | ||
1333 | info->status.ampdu_ack_len = successes; | ||
1334 | info->status.ampdu_len = agg->frame_count; | ||
1335 | } | ||
1336 | iwlagn_hwrate_to_tx_control(priv, agg->rate_n_flags, info); | 1320 | iwlagn_hwrate_to_tx_control(priv, agg->rate_n_flags, info); |
1337 | 1321 | ||
1338 | return 0; | 1322 | return 0; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c index d807e5e2b718..01a6d2fc795c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * | 2 | * |
3 | * GPL LICENSE SUMMARY | 3 | * GPL LICENSE SUMMARY |
4 | * | 4 | * |
5 | * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. | 5 | * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of version 2 of the GNU General Public License as | 8 | * it under the terms of version 2 of the GNU General Public License as |
@@ -311,14 +311,14 @@ void iwlagn_init_alive_start(struct iwl_priv *priv) | |||
311 | /* initialize uCode was loaded... verify inst image. | 311 | /* initialize uCode was loaded... verify inst image. |
312 | * This is a paranoid check, because we would not have gotten the | 312 | * This is a paranoid check, because we would not have gotten the |
313 | * "initialize" alive if code weren't properly loaded. */ | 313 | * "initialize" alive if code weren't properly loaded. */ |
314 | if (iwl_verify_ucode(priv)) { | 314 | if (iwl_verify_ucode(priv, &priv->ucode_init)) { |
315 | /* Runtime instruction load was bad; | 315 | /* Runtime instruction load was bad; |
316 | * take it all the way back down so we can try again */ | 316 | * take it all the way back down so we can try again */ |
317 | IWL_DEBUG_INFO(priv, "Bad \"initialize\" uCode load.\n"); | 317 | IWL_DEBUG_INFO(priv, "Bad \"initialize\" uCode load.\n"); |
318 | goto restart; | 318 | goto restart; |
319 | } | 319 | } |
320 | 320 | ||
321 | ret = priv->cfg->ops->lib->alive_notify(priv); | 321 | ret = iwlagn_alive_notify(priv); |
322 | if (ret) { | 322 | if (ret) { |
323 | IWL_WARN(priv, | 323 | IWL_WARN(priv, |
324 | "Could not complete ALIVE transition: %d\n", ret); | 324 | "Could not complete ALIVE transition: %d\n", ret); |
@@ -432,6 +432,7 @@ int iwlagn_alive_notify(struct iwl_priv *priv) | |||
432 | unsigned long flags; | 432 | unsigned long flags; |
433 | int i, chan; | 433 | int i, chan; |
434 | u32 reg_val; | 434 | u32 reg_val; |
435 | int ret; | ||
435 | 436 | ||
436 | spin_lock_irqsave(&priv->lock, flags); | 437 | spin_lock_irqsave(&priv->lock, flags); |
437 | 438 | ||
@@ -527,12 +528,15 @@ int iwlagn_alive_notify(struct iwl_priv *priv) | |||
527 | iwl_clear_bits_prph(priv, APMG_PCIDEV_STT_REG, | 528 | iwl_clear_bits_prph(priv, APMG_PCIDEV_STT_REG, |
528 | APMG_PCIDEV_STT_VAL_L1_ACT_DIS); | 529 | APMG_PCIDEV_STT_VAL_L1_ACT_DIS); |
529 | 530 | ||
530 | iwlagn_send_wimax_coex(priv); | 531 | ret = iwlagn_send_wimax_coex(priv); |
532 | if (ret) | ||
533 | return ret; | ||
531 | 534 | ||
532 | iwlagn_set_Xtal_calib(priv); | 535 | ret = iwlagn_set_Xtal_calib(priv); |
533 | iwl_send_calib_results(priv); | 536 | if (ret) |
537 | return ret; | ||
534 | 538 | ||
535 | return 0; | 539 | return iwl_send_calib_results(priv); |
536 | } | 540 | } |
537 | 541 | ||
538 | 542 | ||
@@ -541,11 +545,12 @@ int iwlagn_alive_notify(struct iwl_priv *priv) | |||
541 | * using sample data 100 bytes apart. If these sample points are good, | 545 | * using sample data 100 bytes apart. If these sample points are good, |
542 | * it's a pretty good bet that everything between them is good, too. | 546 | * it's a pretty good bet that everything between them is good, too. |
543 | */ | 547 | */ |
544 | static int iwlcore_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len) | 548 | static int iwlcore_verify_inst_sparse(struct iwl_priv *priv, |
549 | struct fw_desc *fw_desc) | ||
545 | { | 550 | { |
551 | __le32 *image = (__le32 *)fw_desc->v_addr; | ||
552 | u32 len = fw_desc->len; | ||
546 | u32 val; | 553 | u32 val; |
547 | int ret = 0; | ||
548 | u32 errcnt = 0; | ||
549 | u32 i; | 554 | u32 i; |
550 | 555 | ||
551 | IWL_DEBUG_INFO(priv, "ucode inst image size is %u\n", len); | 556 | IWL_DEBUG_INFO(priv, "ucode inst image size is %u\n", len); |
@@ -556,104 +561,55 @@ static int iwlcore_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 | |||
556 | * if IWL_DL_IO is set */ | 561 | * if IWL_DL_IO is set */ |
557 | iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, | 562 | iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, |
558 | i + IWLAGN_RTC_INST_LOWER_BOUND); | 563 | i + IWLAGN_RTC_INST_LOWER_BOUND); |
559 | val = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); | 564 | val = iwl_read32(priv, HBUS_TARG_MEM_RDAT); |
560 | if (val != le32_to_cpu(*image)) { | 565 | if (val != le32_to_cpu(*image)) |
561 | ret = -EIO; | 566 | return -EIO; |
562 | errcnt++; | ||
563 | if (errcnt >= 3) | ||
564 | break; | ||
565 | } | ||
566 | } | 567 | } |
567 | 568 | ||
568 | return ret; | 569 | return 0; |
569 | } | 570 | } |
570 | 571 | ||
571 | /** | 572 | static void iwl_print_mismatch_inst(struct iwl_priv *priv, |
572 | * iwlcore_verify_inst_full - verify runtime uCode image in card vs. host, | 573 | struct fw_desc *fw_desc) |
573 | * looking at all data. | ||
574 | */ | ||
575 | static int iwl_verify_inst_full(struct iwl_priv *priv, __le32 *image, | ||
576 | u32 len) | ||
577 | { | 574 | { |
575 | __le32 *image = (__le32 *)fw_desc->v_addr; | ||
576 | u32 len = fw_desc->len; | ||
578 | u32 val; | 577 | u32 val; |
579 | u32 save_len = len; | 578 | u32 offs; |
580 | int ret = 0; | 579 | int errors = 0; |
581 | u32 errcnt; | ||
582 | 580 | ||
583 | IWL_DEBUG_INFO(priv, "ucode inst image size is %u\n", len); | 581 | IWL_DEBUG_INFO(priv, "ucode inst image size is %u\n", len); |
584 | 582 | ||
585 | iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, | 583 | iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, |
586 | IWLAGN_RTC_INST_LOWER_BOUND); | 584 | IWLAGN_RTC_INST_LOWER_BOUND); |
587 | 585 | ||
588 | errcnt = 0; | 586 | for (offs = 0; |
589 | for (; len > 0; len -= sizeof(u32), image++) { | 587 | offs < len && errors < 20; |
588 | offs += sizeof(u32), image++) { | ||
590 | /* read data comes through single port, auto-incr addr */ | 589 | /* read data comes through single port, auto-incr addr */ |
591 | /* NOTE: Use the debugless read so we don't flood kernel log | 590 | val = iwl_read32(priv, HBUS_TARG_MEM_RDAT); |
592 | * if IWL_DL_IO is set */ | ||
593 | val = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); | ||
594 | if (val != le32_to_cpu(*image)) { | 591 | if (val != le32_to_cpu(*image)) { |
595 | IWL_ERR(priv, "uCode INST section is invalid at " | 592 | IWL_ERR(priv, "uCode INST section at " |
596 | "offset 0x%x, is 0x%x, s/b 0x%x\n", | 593 | "offset 0x%x, is 0x%x, s/b 0x%x\n", |
597 | save_len - len, val, le32_to_cpu(*image)); | 594 | offs, val, le32_to_cpu(*image)); |
598 | ret = -EIO; | 595 | errors++; |
599 | errcnt++; | ||
600 | if (errcnt >= 20) | ||
601 | break; | ||
602 | } | 596 | } |
603 | } | 597 | } |
604 | |||
605 | if (!errcnt) | ||
606 | IWL_DEBUG_INFO(priv, | ||
607 | "ucode image in INSTRUCTION memory is good\n"); | ||
608 | |||
609 | return ret; | ||
610 | } | 598 | } |
611 | 599 | ||
612 | /** | 600 | /** |
613 | * iwl_verify_ucode - determine which instruction image is in SRAM, | 601 | * iwl_verify_ucode - determine which instruction image is in SRAM, |
614 | * and verify its contents | 602 | * and verify its contents |
615 | */ | 603 | */ |
616 | int iwl_verify_ucode(struct iwl_priv *priv) | 604 | int iwl_verify_ucode(struct iwl_priv *priv, struct fw_desc *fw_desc) |
617 | { | 605 | { |
618 | __le32 *image; | 606 | if (!iwlcore_verify_inst_sparse(priv, fw_desc)) { |
619 | u32 len; | 607 | IWL_DEBUG_INFO(priv, "uCode is good in inst SRAM\n"); |
620 | int ret; | ||
621 | |||
622 | /* Try bootstrap */ | ||
623 | image = (__le32 *)priv->ucode_boot.v_addr; | ||
624 | len = priv->ucode_boot.len; | ||
625 | ret = iwlcore_verify_inst_sparse(priv, image, len); | ||
626 | if (!ret) { | ||
627 | IWL_DEBUG_INFO(priv, "Bootstrap uCode is good in inst SRAM\n"); | ||
628 | return 0; | ||
629 | } | ||
630 | |||
631 | /* Try initialize */ | ||
632 | image = (__le32 *)priv->ucode_init.v_addr; | ||
633 | len = priv->ucode_init.len; | ||
634 | ret = iwlcore_verify_inst_sparse(priv, image, len); | ||
635 | if (!ret) { | ||
636 | IWL_DEBUG_INFO(priv, "Initialize uCode is good in inst SRAM\n"); | ||
637 | return 0; | ||
638 | } | ||
639 | |||
640 | /* Try runtime/protocol */ | ||
641 | image = (__le32 *)priv->ucode_code.v_addr; | ||
642 | len = priv->ucode_code.len; | ||
643 | ret = iwlcore_verify_inst_sparse(priv, image, len); | ||
644 | if (!ret) { | ||
645 | IWL_DEBUG_INFO(priv, "Runtime uCode is good in inst SRAM\n"); | ||
646 | return 0; | 608 | return 0; |
647 | } | 609 | } |
648 | 610 | ||
649 | IWL_ERR(priv, "NO VALID UCODE IMAGE IN INSTRUCTION SRAM!!\n"); | 611 | IWL_ERR(priv, "UCODE IMAGE IN INSTRUCTION SRAM NOT VALID!!\n"); |
650 | 612 | ||
651 | /* Since nothing seems to match, show first several data entries in | 613 | iwl_print_mismatch_inst(priv, fw_desc); |
652 | * instruction SRAM, so maybe visual inspection will give a clue. | 614 | return -EIO; |
653 | * Selection of bootstrap image (vs. other images) is arbitrary. */ | ||
654 | image = (__le32 *)priv->ucode_boot.v_addr; | ||
655 | len = priv->ucode_boot.len; | ||
656 | ret = iwl_verify_inst_full(priv, image, len); | ||
657 | |||
658 | return ret; | ||
659 | } | 615 | } |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 321b18b59135..60bfde75ce87 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | * | 2 | * |
3 | * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. | 3 | * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. |
4 | * | 4 | * |
5 | * Portions of this file are derived from the ipw3945 project, as well | 5 | * Portions of this file are derived from the ipw3945 project, as well |
6 | * as portions of the ieee80211 subsystem header files. | 6 | * as portions of the ieee80211 subsystem header files. |
@@ -409,7 +409,7 @@ int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, | |||
409 | * Tell nic where to find circular buffer of Tx Frame Descriptors for | 409 | * Tell nic where to find circular buffer of Tx Frame Descriptors for |
410 | * given Tx queue, and enable the DMA channel used for that queue. | 410 | * given Tx queue, and enable the DMA channel used for that queue. |
411 | * | 411 | * |
412 | * 4965 supports up to 16 Tx queues in DRAM, mapped to up to 8 Tx DMA | 412 | * supports up to 16 Tx queues in DRAM, mapped to up to 8 Tx DMA |
413 | * channels supported in hardware. | 413 | * channels supported in hardware. |
414 | */ | 414 | */ |
415 | int iwl_hw_tx_queue_init(struct iwl_priv *priv, | 415 | int iwl_hw_tx_queue_init(struct iwl_priv *priv, |
@@ -483,12 +483,14 @@ static void iwl_bg_bt_full_concurrency(struct work_struct *work) | |||
483 | container_of(work, struct iwl_priv, bt_full_concurrency); | 483 | container_of(work, struct iwl_priv, bt_full_concurrency); |
484 | struct iwl_rxon_context *ctx; | 484 | struct iwl_rxon_context *ctx; |
485 | 485 | ||
486 | mutex_lock(&priv->mutex); | ||
487 | |||
486 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) | 488 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) |
487 | return; | 489 | goto out; |
488 | 490 | ||
489 | /* dont send host command if rf-kill is on */ | 491 | /* dont send host command if rf-kill is on */ |
490 | if (!iwl_is_ready_rf(priv)) | 492 | if (!iwl_is_ready_rf(priv)) |
491 | return; | 493 | goto out; |
492 | 494 | ||
493 | IWL_DEBUG_INFO(priv, "BT coex in %s mode\n", | 495 | IWL_DEBUG_INFO(priv, "BT coex in %s mode\n", |
494 | priv->bt_full_concurrent ? | 496 | priv->bt_full_concurrent ? |
@@ -498,15 +500,15 @@ static void iwl_bg_bt_full_concurrency(struct work_struct *work) | |||
498 | * LQ & RXON updated cmds must be sent before BT Config cmd | 500 | * LQ & RXON updated cmds must be sent before BT Config cmd |
499 | * to avoid 3-wire collisions | 501 | * to avoid 3-wire collisions |
500 | */ | 502 | */ |
501 | mutex_lock(&priv->mutex); | ||
502 | for_each_context(priv, ctx) { | 503 | for_each_context(priv, ctx) { |
503 | if (priv->cfg->ops->hcmd->set_rxon_chain) | 504 | if (priv->cfg->ops->hcmd->set_rxon_chain) |
504 | priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx); | 505 | priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx); |
505 | iwlcore_commit_rxon(priv, ctx); | 506 | iwlcore_commit_rxon(priv, ctx); |
506 | } | 507 | } |
507 | mutex_unlock(&priv->mutex); | ||
508 | 508 | ||
509 | priv->cfg->ops->hcmd->send_bt_config(priv); | 509 | priv->cfg->ops->hcmd->send_bt_config(priv); |
510 | out: | ||
511 | mutex_unlock(&priv->mutex); | ||
510 | } | 512 | } |
511 | 513 | ||
512 | /** | 514 | /** |
@@ -556,7 +558,7 @@ static void iwl_print_cont_event_trace(struct iwl_priv *priv, u32 base, | |||
556 | } | 558 | } |
557 | 559 | ||
558 | /* Set starting address; reads will auto-increment */ | 560 | /* Set starting address; reads will auto-increment */ |
559 | _iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, ptr); | 561 | iwl_write32(priv, HBUS_TARG_MEM_RADDR, ptr); |
560 | rmb(); | 562 | rmb(); |
561 | 563 | ||
562 | /* | 564 | /* |
@@ -564,13 +566,13 @@ static void iwl_print_cont_event_trace(struct iwl_priv *priv, u32 base, | |||
564 | * place event id # at far right for easier visual parsing. | 566 | * place event id # at far right for easier visual parsing. |
565 | */ | 567 | */ |
566 | for (i = 0; i < num_events; i++) { | 568 | for (i = 0; i < num_events; i++) { |
567 | ev = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); | 569 | ev = iwl_read32(priv, HBUS_TARG_MEM_RDAT); |
568 | time = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); | 570 | time = iwl_read32(priv, HBUS_TARG_MEM_RDAT); |
569 | if (mode == 0) { | 571 | if (mode == 0) { |
570 | trace_iwlwifi_dev_ucode_cont_event(priv, | 572 | trace_iwlwifi_dev_ucode_cont_event(priv, |
571 | 0, time, ev); | 573 | 0, time, ev); |
572 | } else { | 574 | } else { |
573 | data = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); | 575 | data = iwl_read32(priv, HBUS_TARG_MEM_RDAT); |
574 | trace_iwlwifi_dev_ucode_cont_event(priv, | 576 | trace_iwlwifi_dev_ucode_cont_event(priv, |
575 | time, data, ev); | 577 | time, data, ev); |
576 | } | 578 | } |
@@ -588,10 +590,7 @@ static void iwl_continuous_event_trace(struct iwl_priv *priv) | |||
588 | u32 num_wraps; /* # times uCode wrapped to top of log */ | 590 | u32 num_wraps; /* # times uCode wrapped to top of log */ |
589 | u32 next_entry; /* index of next entry to be written by uCode */ | 591 | u32 next_entry; /* index of next entry to be written by uCode */ |
590 | 592 | ||
591 | if (priv->ucode_type == UCODE_INIT) | 593 | base = priv->device_pointers.error_event_table; |
592 | base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr); | ||
593 | else | ||
594 | base = le32_to_cpu(priv->card_alive.log_event_table_ptr); | ||
595 | if (priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) { | 594 | if (priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) { |
596 | capacity = iwl_read_targ_mem(priv, base); | 595 | capacity = iwl_read_targ_mem(priv, base); |
597 | num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32))); | 596 | num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32))); |
@@ -845,191 +844,6 @@ static inline void iwl_synchronize_irq(struct iwl_priv *priv) | |||
845 | tasklet_kill(&priv->irq_tasklet); | 844 | tasklet_kill(&priv->irq_tasklet); |
846 | } | 845 | } |
847 | 846 | ||
848 | static void iwl_irq_tasklet_legacy(struct iwl_priv *priv) | ||
849 | { | ||
850 | u32 inta, handled = 0; | ||
851 | u32 inta_fh; | ||
852 | unsigned long flags; | ||
853 | u32 i; | ||
854 | #ifdef CONFIG_IWLWIFI_DEBUG | ||
855 | u32 inta_mask; | ||
856 | #endif | ||
857 | |||
858 | spin_lock_irqsave(&priv->lock, flags); | ||
859 | |||
860 | /* Ack/clear/reset pending uCode interrupts. | ||
861 | * Note: Some bits in CSR_INT are "OR" of bits in CSR_FH_INT_STATUS, | ||
862 | * and will clear only when CSR_FH_INT_STATUS gets cleared. */ | ||
863 | inta = iwl_read32(priv, CSR_INT); | ||
864 | iwl_write32(priv, CSR_INT, inta); | ||
865 | |||
866 | /* Ack/clear/reset pending flow-handler (DMA) interrupts. | ||
867 | * Any new interrupts that happen after this, either while we're | ||
868 | * in this tasklet, or later, will show up in next ISR/tasklet. */ | ||
869 | inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); | ||
870 | iwl_write32(priv, CSR_FH_INT_STATUS, inta_fh); | ||
871 | |||
872 | #ifdef CONFIG_IWLWIFI_DEBUG | ||
873 | if (iwl_get_debug_level(priv) & IWL_DL_ISR) { | ||
874 | /* just for debug */ | ||
875 | inta_mask = iwl_read32(priv, CSR_INT_MASK); | ||
876 | IWL_DEBUG_ISR(priv, "inta 0x%08x, enabled 0x%08x, fh 0x%08x\n", | ||
877 | inta, inta_mask, inta_fh); | ||
878 | } | ||
879 | #endif | ||
880 | |||
881 | spin_unlock_irqrestore(&priv->lock, flags); | ||
882 | |||
883 | /* Since CSR_INT and CSR_FH_INT_STATUS reads and clears are not | ||
884 | * atomic, make sure that inta covers all the interrupts that | ||
885 | * we've discovered, even if FH interrupt came in just after | ||
886 | * reading CSR_INT. */ | ||
887 | if (inta_fh & CSR49_FH_INT_RX_MASK) | ||
888 | inta |= CSR_INT_BIT_FH_RX; | ||
889 | if (inta_fh & CSR49_FH_INT_TX_MASK) | ||
890 | inta |= CSR_INT_BIT_FH_TX; | ||
891 | |||
892 | /* Now service all interrupt bits discovered above. */ | ||
893 | if (inta & CSR_INT_BIT_HW_ERR) { | ||
894 | IWL_ERR(priv, "Hardware error detected. Restarting.\n"); | ||
895 | |||
896 | /* Tell the device to stop sending interrupts */ | ||
897 | iwl_disable_interrupts(priv); | ||
898 | |||
899 | priv->isr_stats.hw++; | ||
900 | iwl_irq_handle_error(priv); | ||
901 | |||
902 | handled |= CSR_INT_BIT_HW_ERR; | ||
903 | |||
904 | return; | ||
905 | } | ||
906 | |||
907 | #ifdef CONFIG_IWLWIFI_DEBUG | ||
908 | if (iwl_get_debug_level(priv) & (IWL_DL_ISR)) { | ||
909 | /* NIC fires this, but we don't use it, redundant with WAKEUP */ | ||
910 | if (inta & CSR_INT_BIT_SCD) { | ||
911 | IWL_DEBUG_ISR(priv, "Scheduler finished to transmit " | ||
912 | "the frame/frames.\n"); | ||
913 | priv->isr_stats.sch++; | ||
914 | } | ||
915 | |||
916 | /* Alive notification via Rx interrupt will do the real work */ | ||
917 | if (inta & CSR_INT_BIT_ALIVE) { | ||
918 | IWL_DEBUG_ISR(priv, "Alive interrupt\n"); | ||
919 | priv->isr_stats.alive++; | ||
920 | } | ||
921 | } | ||
922 | #endif | ||
923 | /* Safely ignore these bits for debug checks below */ | ||
924 | inta &= ~(CSR_INT_BIT_SCD | CSR_INT_BIT_ALIVE); | ||
925 | |||
926 | /* HW RF KILL switch toggled */ | ||
927 | if (inta & CSR_INT_BIT_RF_KILL) { | ||
928 | int hw_rf_kill = 0; | ||
929 | if (!(iwl_read32(priv, CSR_GP_CNTRL) & | ||
930 | CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)) | ||
931 | hw_rf_kill = 1; | ||
932 | |||
933 | IWL_WARN(priv, "RF_KILL bit toggled to %s.\n", | ||
934 | hw_rf_kill ? "disable radio" : "enable radio"); | ||
935 | |||
936 | priv->isr_stats.rfkill++; | ||
937 | |||
938 | /* driver only loads ucode once setting the interface up. | ||
939 | * the driver allows loading the ucode even if the radio | ||
940 | * is killed. Hence update the killswitch state here. The | ||
941 | * rfkill handler will care about restarting if needed. | ||
942 | */ | ||
943 | if (!test_bit(STATUS_ALIVE, &priv->status)) { | ||
944 | if (hw_rf_kill) | ||
945 | set_bit(STATUS_RF_KILL_HW, &priv->status); | ||
946 | else | ||
947 | clear_bit(STATUS_RF_KILL_HW, &priv->status); | ||
948 | wiphy_rfkill_set_hw_state(priv->hw->wiphy, hw_rf_kill); | ||
949 | } | ||
950 | |||
951 | handled |= CSR_INT_BIT_RF_KILL; | ||
952 | } | ||
953 | |||
954 | /* Chip got too hot and stopped itself */ | ||
955 | if (inta & CSR_INT_BIT_CT_KILL) { | ||
956 | IWL_ERR(priv, "Microcode CT kill error detected.\n"); | ||
957 | priv->isr_stats.ctkill++; | ||
958 | handled |= CSR_INT_BIT_CT_KILL; | ||
959 | } | ||
960 | |||
961 | /* Error detected by uCode */ | ||
962 | if (inta & CSR_INT_BIT_SW_ERR) { | ||
963 | IWL_ERR(priv, "Microcode SW error detected. " | ||
964 | " Restarting 0x%X.\n", inta); | ||
965 | priv->isr_stats.sw++; | ||
966 | iwl_irq_handle_error(priv); | ||
967 | handled |= CSR_INT_BIT_SW_ERR; | ||
968 | } | ||
969 | |||
970 | /* | ||
971 | * uCode wakes up after power-down sleep. | ||
972 | * Tell device about any new tx or host commands enqueued, | ||
973 | * and about any Rx buffers made available while asleep. | ||
974 | */ | ||
975 | if (inta & CSR_INT_BIT_WAKEUP) { | ||
976 | IWL_DEBUG_ISR(priv, "Wakeup interrupt\n"); | ||
977 | iwl_rx_queue_update_write_ptr(priv, &priv->rxq); | ||
978 | for (i = 0; i < priv->hw_params.max_txq_num; i++) | ||
979 | iwl_txq_update_write_ptr(priv, &priv->txq[i]); | ||
980 | priv->isr_stats.wakeup++; | ||
981 | handled |= CSR_INT_BIT_WAKEUP; | ||
982 | } | ||
983 | |||
984 | /* All uCode command responses, including Tx command responses, | ||
985 | * Rx "responses" (frame-received notification), and other | ||
986 | * notifications from uCode come through here*/ | ||
987 | if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) { | ||
988 | iwl_rx_handle(priv); | ||
989 | priv->isr_stats.rx++; | ||
990 | handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX); | ||
991 | } | ||
992 | |||
993 | /* This "Tx" DMA channel is used only for loading uCode */ | ||
994 | if (inta & CSR_INT_BIT_FH_TX) { | ||
995 | IWL_DEBUG_ISR(priv, "uCode load interrupt\n"); | ||
996 | priv->isr_stats.tx++; | ||
997 | handled |= CSR_INT_BIT_FH_TX; | ||
998 | /* Wake up uCode load routine, now that load is complete */ | ||
999 | priv->ucode_write_complete = 1; | ||
1000 | wake_up_interruptible(&priv->wait_command_queue); | ||
1001 | } | ||
1002 | |||
1003 | if (inta & ~handled) { | ||
1004 | IWL_ERR(priv, "Unhandled INTA bits 0x%08x\n", inta & ~handled); | ||
1005 | priv->isr_stats.unhandled++; | ||
1006 | } | ||
1007 | |||
1008 | if (inta & ~(priv->inta_mask)) { | ||
1009 | IWL_WARN(priv, "Disabled INTA bits 0x%08x were pending\n", | ||
1010 | inta & ~priv->inta_mask); | ||
1011 | IWL_WARN(priv, " with FH_INT = 0x%08x\n", inta_fh); | ||
1012 | } | ||
1013 | |||
1014 | /* Re-enable all interrupts */ | ||
1015 | /* only Re-enable if disabled by irq */ | ||
1016 | if (test_bit(STATUS_INT_ENABLED, &priv->status)) | ||
1017 | iwl_enable_interrupts(priv); | ||
1018 | /* Re-enable RF_KILL if it occurred */ | ||
1019 | else if (handled & CSR_INT_BIT_RF_KILL) | ||
1020 | iwl_enable_rfkill_int(priv); | ||
1021 | |||
1022 | #ifdef CONFIG_IWLWIFI_DEBUG | ||
1023 | if (iwl_get_debug_level(priv) & (IWL_DL_ISR)) { | ||
1024 | inta = iwl_read32(priv, CSR_INT); | ||
1025 | inta_mask = iwl_read32(priv, CSR_INT_MASK); | ||
1026 | inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); | ||
1027 | IWL_DEBUG_ISR(priv, "End inta 0x%08x, enabled 0x%08x, fh 0x%08x, " | ||
1028 | "flags 0x%08lx\n", inta, inta_mask, inta_fh, flags); | ||
1029 | } | ||
1030 | #endif | ||
1031 | } | ||
1032 | |||
1033 | /* tasklet for iwlagn interrupt */ | 847 | /* tasklet for iwlagn interrupt */ |
1034 | static void iwl_irq_tasklet(struct iwl_priv *priv) | 848 | static void iwl_irq_tasklet(struct iwl_priv *priv) |
1035 | { | 849 | { |
@@ -1171,7 +985,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) | |||
1171 | if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) { | 985 | if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) { |
1172 | handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX); | 986 | handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX); |
1173 | iwl_write32(priv, CSR_FH_INT_STATUS, | 987 | iwl_write32(priv, CSR_FH_INT_STATUS, |
1174 | CSR49_FH_INT_RX_MASK); | 988 | CSR_FH_INT_RX_MASK); |
1175 | } | 989 | } |
1176 | if (inta & CSR_INT_BIT_RX_PERIODIC) { | 990 | if (inta & CSR_INT_BIT_RX_PERIODIC) { |
1177 | handled |= CSR_INT_BIT_RX_PERIODIC; | 991 | handled |= CSR_INT_BIT_RX_PERIODIC; |
@@ -1209,7 +1023,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) | |||
1209 | 1023 | ||
1210 | /* This "Tx" DMA channel is used only for loading uCode */ | 1024 | /* This "Tx" DMA channel is used only for loading uCode */ |
1211 | if (inta & CSR_INT_BIT_FH_TX) { | 1025 | if (inta & CSR_INT_BIT_FH_TX) { |
1212 | iwl_write32(priv, CSR_FH_INT_STATUS, CSR49_FH_INT_TX_MASK); | 1026 | iwl_write32(priv, CSR_FH_INT_STATUS, CSR_FH_INT_TX_MASK); |
1213 | IWL_DEBUG_ISR(priv, "uCode load interrupt\n"); | 1027 | IWL_DEBUG_ISR(priv, "uCode load interrupt\n"); |
1214 | priv->isr_stats.tx++; | 1028 | priv->isr_stats.tx++; |
1215 | handled |= CSR_INT_BIT_FH_TX; | 1029 | handled |= CSR_INT_BIT_FH_TX; |
@@ -1361,10 +1175,8 @@ static void iwl_dealloc_ucode_pci(struct iwl_priv *priv) | |||
1361 | { | 1175 | { |
1362 | iwl_free_fw_desc(priv->pci_dev, &priv->ucode_code); | 1176 | iwl_free_fw_desc(priv->pci_dev, &priv->ucode_code); |
1363 | iwl_free_fw_desc(priv->pci_dev, &priv->ucode_data); | 1177 | iwl_free_fw_desc(priv->pci_dev, &priv->ucode_data); |
1364 | iwl_free_fw_desc(priv->pci_dev, &priv->ucode_data_backup); | ||
1365 | iwl_free_fw_desc(priv->pci_dev, &priv->ucode_init); | 1178 | iwl_free_fw_desc(priv->pci_dev, &priv->ucode_init); |
1366 | iwl_free_fw_desc(priv->pci_dev, &priv->ucode_init_data); | 1179 | iwl_free_fw_desc(priv->pci_dev, &priv->ucode_init_data); |
1367 | iwl_free_fw_desc(priv->pci_dev, &priv->ucode_boot); | ||
1368 | } | 1180 | } |
1369 | 1181 | ||
1370 | static void iwl_nic_start(struct iwl_priv *priv) | 1182 | static void iwl_nic_start(struct iwl_priv *priv) |
@@ -1376,7 +1188,7 @@ static void iwl_nic_start(struct iwl_priv *priv) | |||
1376 | struct iwlagn_ucode_capabilities { | 1188 | struct iwlagn_ucode_capabilities { |
1377 | u32 max_probe_length; | 1189 | u32 max_probe_length; |
1378 | u32 standard_phy_calibration_size; | 1190 | u32 standard_phy_calibration_size; |
1379 | bool pan; | 1191 | u32 flags; |
1380 | }; | 1192 | }; |
1381 | 1193 | ||
1382 | static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context); | 1194 | static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context); |
@@ -1422,8 +1234,8 @@ static int __must_check iwl_request_firmware(struct iwl_priv *priv, bool first) | |||
1422 | } | 1234 | } |
1423 | 1235 | ||
1424 | struct iwlagn_firmware_pieces { | 1236 | struct iwlagn_firmware_pieces { |
1425 | const void *inst, *data, *init, *init_data, *boot; | 1237 | const void *inst, *data, *init, *init_data; |
1426 | size_t inst_size, data_size, init_size, init_data_size, boot_size; | 1238 | size_t inst_size, data_size, init_size, init_data_size; |
1427 | 1239 | ||
1428 | u32 build; | 1240 | u32 build; |
1429 | 1241 | ||
@@ -1444,28 +1256,18 @@ static int iwlagn_load_legacy_firmware(struct iwl_priv *priv, | |||
1444 | 1256 | ||
1445 | switch (api_ver) { | 1257 | switch (api_ver) { |
1446 | default: | 1258 | default: |
1447 | /* | 1259 | hdr_size = 28; |
1448 | * 4965 doesn't revision the firmware file format | 1260 | if (ucode_raw->size < hdr_size) { |
1449 | * along with the API version, it always uses v1 | 1261 | IWL_ERR(priv, "File size too small!\n"); |
1450 | * file format. | 1262 | return -EINVAL; |
1451 | */ | ||
1452 | if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != | ||
1453 | CSR_HW_REV_TYPE_4965) { | ||
1454 | hdr_size = 28; | ||
1455 | if (ucode_raw->size < hdr_size) { | ||
1456 | IWL_ERR(priv, "File size too small!\n"); | ||
1457 | return -EINVAL; | ||
1458 | } | ||
1459 | pieces->build = le32_to_cpu(ucode->u.v2.build); | ||
1460 | pieces->inst_size = le32_to_cpu(ucode->u.v2.inst_size); | ||
1461 | pieces->data_size = le32_to_cpu(ucode->u.v2.data_size); | ||
1462 | pieces->init_size = le32_to_cpu(ucode->u.v2.init_size); | ||
1463 | pieces->init_data_size = le32_to_cpu(ucode->u.v2.init_data_size); | ||
1464 | pieces->boot_size = le32_to_cpu(ucode->u.v2.boot_size); | ||
1465 | src = ucode->u.v2.data; | ||
1466 | break; | ||
1467 | } | 1263 | } |
1468 | /* fall through for 4965 */ | 1264 | pieces->build = le32_to_cpu(ucode->u.v2.build); |
1265 | pieces->inst_size = le32_to_cpu(ucode->u.v2.inst_size); | ||
1266 | pieces->data_size = le32_to_cpu(ucode->u.v2.data_size); | ||
1267 | pieces->init_size = le32_to_cpu(ucode->u.v2.init_size); | ||
1268 | pieces->init_data_size = le32_to_cpu(ucode->u.v2.init_data_size); | ||
1269 | src = ucode->u.v2.data; | ||
1270 | break; | ||
1469 | case 0: | 1271 | case 0: |
1470 | case 1: | 1272 | case 1: |
1471 | case 2: | 1273 | case 2: |
@@ -1479,7 +1281,6 @@ static int iwlagn_load_legacy_firmware(struct iwl_priv *priv, | |||
1479 | pieces->data_size = le32_to_cpu(ucode->u.v1.data_size); | 1281 | pieces->data_size = le32_to_cpu(ucode->u.v1.data_size); |
1480 | pieces->init_size = le32_to_cpu(ucode->u.v1.init_size); | 1282 | pieces->init_size = le32_to_cpu(ucode->u.v1.init_size); |
1481 | pieces->init_data_size = le32_to_cpu(ucode->u.v1.init_data_size); | 1283 | pieces->init_data_size = le32_to_cpu(ucode->u.v1.init_data_size); |
1482 | pieces->boot_size = le32_to_cpu(ucode->u.v1.boot_size); | ||
1483 | src = ucode->u.v1.data; | 1284 | src = ucode->u.v1.data; |
1484 | break; | 1285 | break; |
1485 | } | 1286 | } |
@@ -1487,7 +1288,7 @@ static int iwlagn_load_legacy_firmware(struct iwl_priv *priv, | |||
1487 | /* Verify size of file vs. image size info in file's header */ | 1288 | /* Verify size of file vs. image size info in file's header */ |
1488 | if (ucode_raw->size != hdr_size + pieces->inst_size + | 1289 | if (ucode_raw->size != hdr_size + pieces->inst_size + |
1489 | pieces->data_size + pieces->init_size + | 1290 | pieces->data_size + pieces->init_size + |
1490 | pieces->init_data_size + pieces->boot_size) { | 1291 | pieces->init_data_size) { |
1491 | 1292 | ||
1492 | IWL_ERR(priv, | 1293 | IWL_ERR(priv, |
1493 | "uCode file size %d does not match expected size\n", | 1294 | "uCode file size %d does not match expected size\n", |
@@ -1503,8 +1304,6 @@ static int iwlagn_load_legacy_firmware(struct iwl_priv *priv, | |||
1503 | src += pieces->init_size; | 1304 | src += pieces->init_size; |
1504 | pieces->init_data = src; | 1305 | pieces->init_data = src; |
1505 | src += pieces->init_data_size; | 1306 | src += pieces->init_data_size; |
1506 | pieces->boot = src; | ||
1507 | src += pieces->boot_size; | ||
1508 | 1307 | ||
1509 | return 0; | 1308 | return 0; |
1510 | } | 1309 | } |
@@ -1605,8 +1404,7 @@ static int iwlagn_load_firmware(struct iwl_priv *priv, | |||
1605 | pieces->init_data_size = tlv_len; | 1404 | pieces->init_data_size = tlv_len; |
1606 | break; | 1405 | break; |
1607 | case IWL_UCODE_TLV_BOOT: | 1406 | case IWL_UCODE_TLV_BOOT: |
1608 | pieces->boot = tlv_data; | 1407 | IWL_ERR(priv, "Found unexpected BOOT ucode\n"); |
1609 | pieces->boot_size = tlv_len; | ||
1610 | break; | 1408 | break; |
1611 | case IWL_UCODE_TLV_PROBE_MAX_LEN: | 1409 | case IWL_UCODE_TLV_PROBE_MAX_LEN: |
1612 | if (tlv_len != sizeof(u32)) | 1410 | if (tlv_len != sizeof(u32)) |
@@ -1617,7 +1415,23 @@ static int iwlagn_load_firmware(struct iwl_priv *priv, | |||
1617 | case IWL_UCODE_TLV_PAN: | 1415 | case IWL_UCODE_TLV_PAN: |
1618 | if (tlv_len) | 1416 | if (tlv_len) |
1619 | goto invalid_tlv_len; | 1417 | goto invalid_tlv_len; |
1620 | capa->pan = true; | 1418 | capa->flags |= IWL_UCODE_TLV_FLAGS_PAN; |
1419 | break; | ||
1420 | case IWL_UCODE_TLV_FLAGS: | ||
1421 | /* must be at least one u32 */ | ||
1422 | if (tlv_len < sizeof(u32)) | ||
1423 | goto invalid_tlv_len; | ||
1424 | /* and a proper number of u32s */ | ||
1425 | if (tlv_len % sizeof(u32)) | ||
1426 | goto invalid_tlv_len; | ||
1427 | /* | ||
1428 | * This driver only reads the first u32 as | ||
1429 | * right now no more features are defined, | ||
1430 | * if that changes then either the driver | ||
1431 | * will not work with the new firmware, or | ||
1432 | * it'll not take advantage of new features. | ||
1433 | */ | ||
1434 | capa->flags = le32_to_cpup((__le32 *)tlv_data); | ||
1621 | break; | 1435 | break; |
1622 | case IWL_UCODE_TLV_INIT_EVTLOG_PTR: | 1436 | case IWL_UCODE_TLV_INIT_EVTLOG_PTR: |
1623 | if (tlv_len != sizeof(u32)) | 1437 | if (tlv_len != sizeof(u32)) |
@@ -1806,8 +1620,6 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) | |||
1806 | pieces.init_size); | 1620 | pieces.init_size); |
1807 | IWL_DEBUG_INFO(priv, "f/w package hdr init data size = %Zd\n", | 1621 | IWL_DEBUG_INFO(priv, "f/w package hdr init data size = %Zd\n", |
1808 | pieces.init_data_size); | 1622 | pieces.init_data_size); |
1809 | IWL_DEBUG_INFO(priv, "f/w package hdr boot inst size = %Zd\n", | ||
1810 | pieces.boot_size); | ||
1811 | 1623 | ||
1812 | /* Verify that uCode images will fit in card's SRAM */ | 1624 | /* Verify that uCode images will fit in card's SRAM */ |
1813 | if (pieces.inst_size > priv->hw_params.max_inst_size) { | 1625 | if (pieces.inst_size > priv->hw_params.max_inst_size) { |
@@ -1834,12 +1646,6 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) | |||
1834 | goto try_again; | 1646 | goto try_again; |
1835 | } | 1647 | } |
1836 | 1648 | ||
1837 | if (pieces.boot_size > priv->hw_params.max_bsm_size) { | ||
1838 | IWL_ERR(priv, "uCode boot instr len %Zd too large to fit in\n", | ||
1839 | pieces.boot_size); | ||
1840 | goto try_again; | ||
1841 | } | ||
1842 | |||
1843 | /* Allocate ucode buffers for card's bus-master loading ... */ | 1649 | /* Allocate ucode buffers for card's bus-master loading ... */ |
1844 | 1650 | ||
1845 | /* Runtime instructions and 2 copies of data: | 1651 | /* Runtime instructions and 2 copies of data: |
@@ -1851,11 +1657,7 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) | |||
1851 | priv->ucode_data.len = pieces.data_size; | 1657 | priv->ucode_data.len = pieces.data_size; |
1852 | iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_data); | 1658 | iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_data); |
1853 | 1659 | ||
1854 | priv->ucode_data_backup.len = pieces.data_size; | 1660 | if (!priv->ucode_code.v_addr || !priv->ucode_data.v_addr) |
1855 | iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_data_backup); | ||
1856 | |||
1857 | if (!priv->ucode_code.v_addr || !priv->ucode_data.v_addr || | ||
1858 | !priv->ucode_data_backup.v_addr) | ||
1859 | goto err_pci_alloc; | 1661 | goto err_pci_alloc; |
1860 | 1662 | ||
1861 | /* Initialization instructions and data */ | 1663 | /* Initialization instructions and data */ |
@@ -1870,15 +1672,6 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) | |||
1870 | goto err_pci_alloc; | 1672 | goto err_pci_alloc; |
1871 | } | 1673 | } |
1872 | 1674 | ||
1873 | /* Bootstrap (instructions only, no data) */ | ||
1874 | if (pieces.boot_size) { | ||
1875 | priv->ucode_boot.len = pieces.boot_size; | ||
1876 | iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_boot); | ||
1877 | |||
1878 | if (!priv->ucode_boot.v_addr) | ||
1879 | goto err_pci_alloc; | ||
1880 | } | ||
1881 | |||
1882 | /* Now that we can no longer fail, copy information */ | 1675 | /* Now that we can no longer fail, copy information */ |
1883 | 1676 | ||
1884 | /* | 1677 | /* |
@@ -1901,12 +1694,21 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) | |||
1901 | priv->cfg->base_params->max_event_log_size; | 1694 | priv->cfg->base_params->max_event_log_size; |
1902 | priv->_agn.inst_errlog_ptr = pieces.inst_errlog_ptr; | 1695 | priv->_agn.inst_errlog_ptr = pieces.inst_errlog_ptr; |
1903 | 1696 | ||
1904 | if (ucode_capa.pan) { | 1697 | if (ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PAN) { |
1905 | priv->valid_contexts |= BIT(IWL_RXON_CTX_PAN); | 1698 | priv->valid_contexts |= BIT(IWL_RXON_CTX_PAN); |
1906 | priv->sta_key_max_num = STA_KEY_MAX_NUM_PAN; | 1699 | priv->sta_key_max_num = STA_KEY_MAX_NUM_PAN; |
1907 | } else | 1700 | } else |
1908 | priv->sta_key_max_num = STA_KEY_MAX_NUM; | 1701 | priv->sta_key_max_num = STA_KEY_MAX_NUM; |
1909 | 1702 | ||
1703 | if (priv->valid_contexts != BIT(IWL_RXON_CTX_BSS)) | ||
1704 | priv->cmd_queue = IWL_IPAN_CMD_QUEUE_NUM; | ||
1705 | else | ||
1706 | priv->cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM; | ||
1707 | |||
1708 | if (ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BTSTATS || | ||
1709 | (priv->cfg->bt_params && priv->cfg->bt_params->bt_statistics)) | ||
1710 | priv->bt_statistics = true; | ||
1711 | |||
1910 | /* Copy images into buffers for card's bus-master reads ... */ | 1712 | /* Copy images into buffers for card's bus-master reads ... */ |
1911 | 1713 | ||
1912 | /* Runtime instructions (first block of data in file) */ | 1714 | /* Runtime instructions (first block of data in file) */ |
@@ -1924,7 +1726,6 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) | |||
1924 | IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode data len %Zd\n", | 1726 | IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode data len %Zd\n", |
1925 | pieces.data_size); | 1727 | pieces.data_size); |
1926 | memcpy(priv->ucode_data.v_addr, pieces.data, pieces.data_size); | 1728 | memcpy(priv->ucode_data.v_addr, pieces.data, pieces.data_size); |
1927 | memcpy(priv->ucode_data_backup.v_addr, pieces.data, pieces.data_size); | ||
1928 | 1729 | ||
1929 | /* Initialization instructions */ | 1730 | /* Initialization instructions */ |
1930 | if (pieces.init_size) { | 1731 | if (pieces.init_size) { |
@@ -1941,11 +1742,6 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) | |||
1941 | pieces.init_data_size); | 1742 | pieces.init_data_size); |
1942 | } | 1743 | } |
1943 | 1744 | ||
1944 | /* Bootstrap instructions */ | ||
1945 | IWL_DEBUG_INFO(priv, "Copying (but not loading) boot instr len %Zd\n", | ||
1946 | pieces.boot_size); | ||
1947 | memcpy(priv->ucode_boot.v_addr, pieces.boot, pieces.boot_size); | ||
1948 | |||
1949 | /* | 1745 | /* |
1950 | * figure out the offset of chain noise reset and gain commands | 1746 | * figure out the offset of chain noise reset and gain commands |
1951 | * base on the size of standard phy calibration commands table size | 1747 | * base on the size of standard phy calibration commands table size |
@@ -2077,12 +1873,11 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv) | |||
2077 | u32 blink1, blink2, ilink1, ilink2; | 1873 | u32 blink1, blink2, ilink1, ilink2; |
2078 | u32 pc, hcmd; | 1874 | u32 pc, hcmd; |
2079 | 1875 | ||
1876 | base = priv->device_pointers.error_event_table; | ||
2080 | if (priv->ucode_type == UCODE_INIT) { | 1877 | if (priv->ucode_type == UCODE_INIT) { |
2081 | base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr); | ||
2082 | if (!base) | 1878 | if (!base) |
2083 | base = priv->_agn.init_errlog_ptr; | 1879 | base = priv->_agn.init_errlog_ptr; |
2084 | } else { | 1880 | } else { |
2085 | base = le32_to_cpu(priv->card_alive.error_event_table_ptr); | ||
2086 | if (!base) | 1881 | if (!base) |
2087 | base = priv->_agn.inst_errlog_ptr; | 1882 | base = priv->_agn.inst_errlog_ptr; |
2088 | } | 1883 | } |
@@ -2147,12 +1942,11 @@ static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, | |||
2147 | if (num_events == 0) | 1942 | if (num_events == 0) |
2148 | return pos; | 1943 | return pos; |
2149 | 1944 | ||
1945 | base = priv->device_pointers.log_event_table; | ||
2150 | if (priv->ucode_type == UCODE_INIT) { | 1946 | if (priv->ucode_type == UCODE_INIT) { |
2151 | base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr); | ||
2152 | if (!base) | 1947 | if (!base) |
2153 | base = priv->_agn.init_evtlog_ptr; | 1948 | base = priv->_agn.init_evtlog_ptr; |
2154 | } else { | 1949 | } else { |
2155 | base = le32_to_cpu(priv->card_alive.log_event_table_ptr); | ||
2156 | if (!base) | 1950 | if (!base) |
2157 | base = priv->_agn.inst_evtlog_ptr; | 1951 | base = priv->_agn.inst_evtlog_ptr; |
2158 | } | 1952 | } |
@@ -2169,14 +1963,14 @@ static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, | |||
2169 | iwl_grab_nic_access(priv); | 1963 | iwl_grab_nic_access(priv); |
2170 | 1964 | ||
2171 | /* Set starting address; reads will auto-increment */ | 1965 | /* Set starting address; reads will auto-increment */ |
2172 | _iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, ptr); | 1966 | iwl_write32(priv, HBUS_TARG_MEM_RADDR, ptr); |
2173 | rmb(); | 1967 | rmb(); |
2174 | 1968 | ||
2175 | /* "time" is actually "data" for mode 0 (no timestamp). | 1969 | /* "time" is actually "data" for mode 0 (no timestamp). |
2176 | * place event id # at far right for easier visual parsing. */ | 1970 | * place event id # at far right for easier visual parsing. */ |
2177 | for (i = 0; i < num_events; i++) { | 1971 | for (i = 0; i < num_events; i++) { |
2178 | ev = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); | 1972 | ev = iwl_read32(priv, HBUS_TARG_MEM_RDAT); |
2179 | time = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); | 1973 | time = iwl_read32(priv, HBUS_TARG_MEM_RDAT); |
2180 | if (mode == 0) { | 1974 | if (mode == 0) { |
2181 | /* data, ev */ | 1975 | /* data, ev */ |
2182 | if (bufsz) { | 1976 | if (bufsz) { |
@@ -2190,7 +1984,7 @@ static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, | |||
2190 | time, ev); | 1984 | time, ev); |
2191 | } | 1985 | } |
2192 | } else { | 1986 | } else { |
2193 | data = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); | 1987 | data = iwl_read32(priv, HBUS_TARG_MEM_RDAT); |
2194 | if (bufsz) { | 1988 | if (bufsz) { |
2195 | pos += scnprintf(*buf + pos, bufsz - pos, | 1989 | pos += scnprintf(*buf + pos, bufsz - pos, |
2196 | "EVT_LOGT:%010u:0x%08x:%04u\n", | 1990 | "EVT_LOGT:%010u:0x%08x:%04u\n", |
@@ -2261,13 +2055,12 @@ int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log, | |||
2261 | int pos = 0; | 2055 | int pos = 0; |
2262 | size_t bufsz = 0; | 2056 | size_t bufsz = 0; |
2263 | 2057 | ||
2058 | base = priv->device_pointers.log_event_table; | ||
2264 | if (priv->ucode_type == UCODE_INIT) { | 2059 | if (priv->ucode_type == UCODE_INIT) { |
2265 | base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr); | ||
2266 | logsize = priv->_agn.init_evtlog_size; | 2060 | logsize = priv->_agn.init_evtlog_size; |
2267 | if (!base) | 2061 | if (!base) |
2268 | base = priv->_agn.init_evtlog_ptr; | 2062 | base = priv->_agn.init_evtlog_ptr; |
2269 | } else { | 2063 | } else { |
2270 | base = le32_to_cpu(priv->card_alive.log_event_table_ptr); | ||
2271 | logsize = priv->_agn.inst_evtlog_size; | 2064 | logsize = priv->_agn.inst_evtlog_size; |
2272 | if (!base) | 2065 | if (!base) |
2273 | base = priv->_agn.inst_evtlog_ptr; | 2066 | base = priv->_agn.inst_evtlog_ptr; |
@@ -2433,14 +2226,14 @@ static void iwl_alive_start(struct iwl_priv *priv) | |||
2433 | /* Initialize uCode has loaded Runtime uCode ... verify inst image. | 2226 | /* Initialize uCode has loaded Runtime uCode ... verify inst image. |
2434 | * This is a paranoid check, because we would not have gotten the | 2227 | * This is a paranoid check, because we would not have gotten the |
2435 | * "runtime" alive if code weren't properly loaded. */ | 2228 | * "runtime" alive if code weren't properly loaded. */ |
2436 | if (iwl_verify_ucode(priv)) { | 2229 | if (iwl_verify_ucode(priv, &priv->ucode_code)) { |
2437 | /* Runtime instruction load was bad; | 2230 | /* Runtime instruction load was bad; |
2438 | * take it all the way back down so we can try again */ | 2231 | * take it all the way back down so we can try again */ |
2439 | IWL_DEBUG_INFO(priv, "Bad runtime uCode load.\n"); | 2232 | IWL_DEBUG_INFO(priv, "Bad runtime uCode load.\n"); |
2440 | goto restart; | 2233 | goto restart; |
2441 | } | 2234 | } |
2442 | 2235 | ||
2443 | ret = priv->cfg->ops->lib->alive_notify(priv); | 2236 | ret = iwlagn_alive_notify(priv); |
2444 | if (ret) { | 2237 | if (ret) { |
2445 | IWL_WARN(priv, | 2238 | IWL_WARN(priv, |
2446 | "Could not complete ALIVE transition [ntf]: %d\n", ret); | 2239 | "Could not complete ALIVE transition [ntf]: %d\n", ret); |
@@ -2537,7 +2330,7 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv); | |||
2537 | static void __iwl_down(struct iwl_priv *priv) | 2330 | static void __iwl_down(struct iwl_priv *priv) |
2538 | { | 2331 | { |
2539 | unsigned long flags; | 2332 | unsigned long flags; |
2540 | int exit_pending = test_bit(STATUS_EXIT_PENDING, &priv->status); | 2333 | int exit_pending; |
2541 | 2334 | ||
2542 | IWL_DEBUG_INFO(priv, DRV_NAME " is going down\n"); | 2335 | IWL_DEBUG_INFO(priv, DRV_NAME " is going down\n"); |
2543 | 2336 | ||
@@ -2563,9 +2356,6 @@ static void __iwl_down(struct iwl_priv *priv) | |||
2563 | priv->bt_full_concurrent = false; | 2356 | priv->bt_full_concurrent = false; |
2564 | priv->bt_ci_compliance = 0; | 2357 | priv->bt_ci_compliance = 0; |
2565 | 2358 | ||
2566 | /* Unblock any waiting calls */ | ||
2567 | wake_up_interruptible_all(&priv->wait_command_queue); | ||
2568 | |||
2569 | /* Wipe out the EXIT_PENDING status bit if we are not actually | 2359 | /* Wipe out the EXIT_PENDING status bit if we are not actually |
2570 | * exiting the module */ | 2360 | * exiting the module */ |
2571 | if (!exit_pending) | 2361 | if (!exit_pending) |
@@ -2607,8 +2397,7 @@ static void __iwl_down(struct iwl_priv *priv) | |||
2607 | STATUS_EXIT_PENDING; | 2397 | STATUS_EXIT_PENDING; |
2608 | 2398 | ||
2609 | /* device going down, Stop using ICT table */ | 2399 | /* device going down, Stop using ICT table */ |
2610 | if (priv->cfg->ops->lib->isr_ops.disable) | 2400 | iwl_disable_ict(priv); |
2611 | priv->cfg->ops->lib->isr_ops.disable(priv); | ||
2612 | 2401 | ||
2613 | iwlagn_txq_ctx_stop(priv); | 2402 | iwlagn_txq_ctx_stop(priv); |
2614 | iwlagn_rxq_stop(priv); | 2403 | iwlagn_rxq_stop(priv); |
@@ -2624,8 +2413,6 @@ static void __iwl_down(struct iwl_priv *priv) | |||
2624 | iwl_apm_stop(priv); | 2413 | iwl_apm_stop(priv); |
2625 | 2414 | ||
2626 | exit: | 2415 | exit: |
2627 | memset(&priv->card_alive, 0, sizeof(struct iwl_alive_resp)); | ||
2628 | |||
2629 | dev_kfree_skb(priv->beacon_skb); | 2416 | dev_kfree_skb(priv->beacon_skb); |
2630 | priv->beacon_skb = NULL; | 2417 | priv->beacon_skb = NULL; |
2631 | 2418 | ||
@@ -2704,11 +2491,6 @@ static int __iwl_up(struct iwl_priv *priv) | |||
2704 | return -EIO; | 2491 | return -EIO; |
2705 | } | 2492 | } |
2706 | 2493 | ||
2707 | if (!priv->ucode_data_backup.v_addr || !priv->ucode_data.v_addr) { | ||
2708 | IWL_ERR(priv, "ucode not available for device bringup\n"); | ||
2709 | return -EIO; | ||
2710 | } | ||
2711 | |||
2712 | for_each_context(priv, ctx) { | 2494 | for_each_context(priv, ctx) { |
2713 | ret = iwlagn_alloc_bcast_station(priv, ctx); | 2495 | ret = iwlagn_alloc_bcast_station(priv, ctx); |
2714 | if (ret) { | 2496 | if (ret) { |
@@ -2740,12 +2522,6 @@ static int __iwl_up(struct iwl_priv *priv) | |||
2740 | 2522 | ||
2741 | iwl_write32(priv, CSR_INT, 0xFFFFFFFF); | 2523 | iwl_write32(priv, CSR_INT, 0xFFFFFFFF); |
2742 | 2524 | ||
2743 | /* must be initialised before iwl_hw_nic_init */ | ||
2744 | if (priv->valid_contexts != BIT(IWL_RXON_CTX_BSS)) | ||
2745 | priv->cmd_queue = IWL_IPAN_CMD_QUEUE_NUM; | ||
2746 | else | ||
2747 | priv->cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM; | ||
2748 | |||
2749 | ret = iwlagn_hw_nic_init(priv); | 2525 | ret = iwlagn_hw_nic_init(priv); |
2750 | if (ret) { | 2526 | if (ret) { |
2751 | IWL_ERR(priv, "Unable to init nic\n"); | 2527 | IWL_ERR(priv, "Unable to init nic\n"); |
@@ -2765,18 +2541,12 @@ static int __iwl_up(struct iwl_priv *priv) | |||
2765 | iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); | 2541 | iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); |
2766 | iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); | 2542 | iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); |
2767 | 2543 | ||
2768 | /* Copy original ucode data image from disk into backup cache. | ||
2769 | * This will be used to initialize the on-board processor's | ||
2770 | * data SRAM for a clean start when the runtime program first loads. */ | ||
2771 | memcpy(priv->ucode_data_backup.v_addr, priv->ucode_data.v_addr, | ||
2772 | priv->ucode_data.len); | ||
2773 | |||
2774 | for (i = 0; i < MAX_HW_RESTARTS; i++) { | 2544 | for (i = 0; i < MAX_HW_RESTARTS; i++) { |
2775 | 2545 | ||
2776 | /* load bootstrap state machine, | 2546 | /* load bootstrap state machine, |
2777 | * load bootstrap program into processor's memory, | 2547 | * load bootstrap program into processor's memory, |
2778 | * prepare to load the "initialize" uCode */ | 2548 | * prepare to load the "initialize" uCode */ |
2779 | ret = priv->cfg->ops->lib->load_ucode(priv); | 2549 | ret = iwlagn_load_ucode(priv); |
2780 | 2550 | ||
2781 | if (ret) { | 2551 | if (ret) { |
2782 | IWL_ERR(priv, "Unable to set up bootstrap uCode: %d\n", | 2552 | IWL_ERR(priv, "Unable to set up bootstrap uCode: %d\n", |
@@ -2814,11 +2584,14 @@ static void iwl_bg_init_alive_start(struct work_struct *data) | |||
2814 | struct iwl_priv *priv = | 2584 | struct iwl_priv *priv = |
2815 | container_of(data, struct iwl_priv, init_alive_start.work); | 2585 | container_of(data, struct iwl_priv, init_alive_start.work); |
2816 | 2586 | ||
2817 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) | 2587 | mutex_lock(&priv->mutex); |
2588 | |||
2589 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { | ||
2590 | mutex_unlock(&priv->mutex); | ||
2818 | return; | 2591 | return; |
2592 | } | ||
2819 | 2593 | ||
2820 | mutex_lock(&priv->mutex); | 2594 | iwlagn_init_alive_start(priv); |
2821 | priv->cfg->ops->lib->init_alive_start(priv); | ||
2822 | mutex_unlock(&priv->mutex); | 2595 | mutex_unlock(&priv->mutex); |
2823 | } | 2596 | } |
2824 | 2597 | ||
@@ -2827,15 +2600,15 @@ static void iwl_bg_alive_start(struct work_struct *data) | |||
2827 | struct iwl_priv *priv = | 2600 | struct iwl_priv *priv = |
2828 | container_of(data, struct iwl_priv, alive_start.work); | 2601 | container_of(data, struct iwl_priv, alive_start.work); |
2829 | 2602 | ||
2603 | mutex_lock(&priv->mutex); | ||
2830 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) | 2604 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) |
2831 | return; | 2605 | goto unlock; |
2832 | 2606 | ||
2833 | /* enable dram interrupt */ | 2607 | /* enable dram interrupt */ |
2834 | if (priv->cfg->ops->lib->isr_ops.reset) | 2608 | iwl_reset_ict(priv); |
2835 | priv->cfg->ops->lib->isr_ops.reset(priv); | ||
2836 | 2609 | ||
2837 | mutex_lock(&priv->mutex); | ||
2838 | iwl_alive_start(priv); | 2610 | iwl_alive_start(priv); |
2611 | unlock: | ||
2839 | mutex_unlock(&priv->mutex); | 2612 | mutex_unlock(&priv->mutex); |
2840 | } | 2613 | } |
2841 | 2614 | ||
@@ -3063,6 +2836,9 @@ static int iwl_mac_setup_register(struct iwl_priv *priv, | |||
3063 | hw->flags |= IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS | | 2836 | hw->flags |= IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS | |
3064 | IEEE80211_HW_SUPPORTS_STATIC_SMPS; | 2837 | IEEE80211_HW_SUPPORTS_STATIC_SMPS; |
3065 | 2838 | ||
2839 | if (capa->flags & IWL_UCODE_TLV_FLAGS_MFP) | ||
2840 | hw->flags |= IEEE80211_HW_MFP_CAPABLE; | ||
2841 | |||
3066 | hw->sta_data_size = sizeof(struct iwl_station_priv); | 2842 | hw->sta_data_size = sizeof(struct iwl_station_priv); |
3067 | hw->vif_data_size = sizeof(struct iwl_vif_priv); | 2843 | hw->vif_data_size = sizeof(struct iwl_vif_priv); |
3068 | 2844 | ||
@@ -3112,7 +2888,7 @@ static int iwl_mac_setup_register(struct iwl_priv *priv, | |||
3112 | } | 2888 | } |
3113 | 2889 | ||
3114 | 2890 | ||
3115 | int iwlagn_mac_start(struct ieee80211_hw *hw) | 2891 | static int iwlagn_mac_start(struct ieee80211_hw *hw) |
3116 | { | 2892 | { |
3117 | struct iwl_priv *priv = hw->priv; | 2893 | struct iwl_priv *priv = hw->priv; |
3118 | int ret; | 2894 | int ret; |
@@ -3153,7 +2929,7 @@ out: | |||
3153 | return 0; | 2929 | return 0; |
3154 | } | 2930 | } |
3155 | 2931 | ||
3156 | void iwlagn_mac_stop(struct ieee80211_hw *hw) | 2932 | static void iwlagn_mac_stop(struct ieee80211_hw *hw) |
3157 | { | 2933 | { |
3158 | struct iwl_priv *priv = hw->priv; | 2934 | struct iwl_priv *priv = hw->priv; |
3159 | 2935 | ||
@@ -3176,7 +2952,7 @@ void iwlagn_mac_stop(struct ieee80211_hw *hw) | |||
3176 | IWL_DEBUG_MAC80211(priv, "leave\n"); | 2952 | IWL_DEBUG_MAC80211(priv, "leave\n"); |
3177 | } | 2953 | } |
3178 | 2954 | ||
3179 | void iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | 2955 | static void iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) |
3180 | { | 2956 | { |
3181 | struct iwl_priv *priv = hw->priv; | 2957 | struct iwl_priv *priv = hw->priv; |
3182 | 2958 | ||
@@ -3191,11 +2967,11 @@ void iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
3191 | IWL_DEBUG_MACDUMP(priv, "leave\n"); | 2967 | IWL_DEBUG_MACDUMP(priv, "leave\n"); |
3192 | } | 2968 | } |
3193 | 2969 | ||
3194 | void iwlagn_mac_update_tkip_key(struct ieee80211_hw *hw, | 2970 | static void iwlagn_mac_update_tkip_key(struct ieee80211_hw *hw, |
3195 | struct ieee80211_vif *vif, | 2971 | struct ieee80211_vif *vif, |
3196 | struct ieee80211_key_conf *keyconf, | 2972 | struct ieee80211_key_conf *keyconf, |
3197 | struct ieee80211_sta *sta, | 2973 | struct ieee80211_sta *sta, |
3198 | u32 iv32, u16 *phase1key) | 2974 | u32 iv32, u16 *phase1key) |
3199 | { | 2975 | { |
3200 | struct iwl_priv *priv = hw->priv; | 2976 | struct iwl_priv *priv = hw->priv; |
3201 | struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; | 2977 | struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; |
@@ -3208,9 +2984,10 @@ void iwlagn_mac_update_tkip_key(struct ieee80211_hw *hw, | |||
3208 | IWL_DEBUG_MAC80211(priv, "leave\n"); | 2984 | IWL_DEBUG_MAC80211(priv, "leave\n"); |
3209 | } | 2985 | } |
3210 | 2986 | ||
3211 | int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, | 2987 | static int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, |
3212 | struct ieee80211_vif *vif, struct ieee80211_sta *sta, | 2988 | struct ieee80211_vif *vif, |
3213 | struct ieee80211_key_conf *key) | 2989 | struct ieee80211_sta *sta, |
2990 | struct ieee80211_key_conf *key) | ||
3214 | { | 2991 | { |
3215 | struct iwl_priv *priv = hw->priv; | 2992 | struct iwl_priv *priv = hw->priv; |
3216 | struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; | 2993 | struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; |
@@ -3285,11 +3062,11 @@ int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, | |||
3285 | return ret; | 3062 | return ret; |
3286 | } | 3063 | } |
3287 | 3064 | ||
3288 | int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, | 3065 | static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, |
3289 | struct ieee80211_vif *vif, | 3066 | struct ieee80211_vif *vif, |
3290 | enum ieee80211_ampdu_mlme_action action, | 3067 | enum ieee80211_ampdu_mlme_action action, |
3291 | struct ieee80211_sta *sta, u16 tid, u16 *ssn, | 3068 | struct ieee80211_sta *sta, u16 tid, u16 *ssn, |
3292 | u8 buf_size) | 3069 | u8 buf_size) |
3293 | { | 3070 | { |
3294 | struct iwl_priv *priv = hw->priv; | 3071 | struct iwl_priv *priv = hw->priv; |
3295 | int ret = -EINVAL; | 3072 | int ret = -EINVAL; |
@@ -3348,6 +3125,10 @@ int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, | |||
3348 | } | 3125 | } |
3349 | break; | 3126 | break; |
3350 | case IEEE80211_AMPDU_TX_OPERATIONAL: | 3127 | case IEEE80211_AMPDU_TX_OPERATIONAL: |
3128 | buf_size = min_t(int, buf_size, LINK_QUAL_AGG_FRAME_LIMIT_DEF); | ||
3129 | |||
3130 | iwlagn_txq_agg_queue_setup(priv, sta, tid, buf_size); | ||
3131 | |||
3351 | /* | 3132 | /* |
3352 | * If the limit is 0, then it wasn't initialised yet, | 3133 | * If the limit is 0, then it wasn't initialised yet, |
3353 | * use the default. We can do that since we take the | 3134 | * use the default. We can do that since we take the |
@@ -3392,9 +3173,9 @@ int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, | |||
3392 | return ret; | 3173 | return ret; |
3393 | } | 3174 | } |
3394 | 3175 | ||
3395 | int iwlagn_mac_sta_add(struct ieee80211_hw *hw, | 3176 | static int iwlagn_mac_sta_add(struct ieee80211_hw *hw, |
3396 | struct ieee80211_vif *vif, | 3177 | struct ieee80211_vif *vif, |
3397 | struct ieee80211_sta *sta) | 3178 | struct ieee80211_sta *sta) |
3398 | { | 3179 | { |
3399 | struct iwl_priv *priv = hw->priv; | 3180 | struct iwl_priv *priv = hw->priv; |
3400 | struct iwl_station_priv *sta_priv = (void *)sta->drv_priv; | 3181 | struct iwl_station_priv *sta_priv = (void *)sta->drv_priv; |
@@ -3435,8 +3216,8 @@ int iwlagn_mac_sta_add(struct ieee80211_hw *hw, | |||
3435 | return 0; | 3216 | return 0; |
3436 | } | 3217 | } |
3437 | 3218 | ||
3438 | void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, | 3219 | static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, |
3439 | struct ieee80211_channel_switch *ch_switch) | 3220 | struct ieee80211_channel_switch *ch_switch) |
3440 | { | 3221 | { |
3441 | struct iwl_priv *priv = hw->priv; | 3222 | struct iwl_priv *priv = hw->priv; |
3442 | const struct iwl_channel_info *ch_info; | 3223 | const struct iwl_channel_info *ch_info; |
@@ -3457,21 +3238,22 @@ void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, | |||
3457 | 3238 | ||
3458 | IWL_DEBUG_MAC80211(priv, "enter\n"); | 3239 | IWL_DEBUG_MAC80211(priv, "enter\n"); |
3459 | 3240 | ||
3241 | mutex_lock(&priv->mutex); | ||
3242 | |||
3460 | if (iwl_is_rfkill(priv)) | 3243 | if (iwl_is_rfkill(priv)) |
3461 | goto out_exit; | 3244 | goto out; |
3462 | 3245 | ||
3463 | if (test_bit(STATUS_EXIT_PENDING, &priv->status) || | 3246 | if (test_bit(STATUS_EXIT_PENDING, &priv->status) || |
3464 | test_bit(STATUS_SCANNING, &priv->status)) | 3247 | test_bit(STATUS_SCANNING, &priv->status)) |
3465 | goto out_exit; | 3248 | goto out; |
3466 | 3249 | ||
3467 | if (!iwl_is_associated_ctx(ctx)) | 3250 | if (!iwl_is_associated_ctx(ctx)) |
3468 | goto out_exit; | 3251 | goto out; |
3469 | 3252 | ||
3470 | /* channel switch in progress */ | 3253 | /* channel switch in progress */ |
3471 | if (priv->switch_rxon.switch_in_progress == true) | 3254 | if (priv->switch_rxon.switch_in_progress == true) |
3472 | goto out_exit; | 3255 | goto out; |
3473 | 3256 | ||
3474 | mutex_lock(&priv->mutex); | ||
3475 | if (priv->cfg->ops->lib->set_channel_switch) { | 3257 | if (priv->cfg->ops->lib->set_channel_switch) { |
3476 | 3258 | ||
3477 | ch = channel->hw_value; | 3259 | ch = channel->hw_value; |
@@ -3527,16 +3309,15 @@ void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, | |||
3527 | } | 3309 | } |
3528 | out: | 3310 | out: |
3529 | mutex_unlock(&priv->mutex); | 3311 | mutex_unlock(&priv->mutex); |
3530 | out_exit: | ||
3531 | if (!priv->switch_rxon.switch_in_progress) | 3312 | if (!priv->switch_rxon.switch_in_progress) |
3532 | ieee80211_chswitch_done(ctx->vif, false); | 3313 | ieee80211_chswitch_done(ctx->vif, false); |
3533 | IWL_DEBUG_MAC80211(priv, "leave\n"); | 3314 | IWL_DEBUG_MAC80211(priv, "leave\n"); |
3534 | } | 3315 | } |
3535 | 3316 | ||
3536 | void iwlagn_configure_filter(struct ieee80211_hw *hw, | 3317 | static void iwlagn_configure_filter(struct ieee80211_hw *hw, |
3537 | unsigned int changed_flags, | 3318 | unsigned int changed_flags, |
3538 | unsigned int *total_flags, | 3319 | unsigned int *total_flags, |
3539 | u64 multicast) | 3320 | u64 multicast) |
3540 | { | 3321 | { |
3541 | struct iwl_priv *priv = hw->priv; | 3322 | struct iwl_priv *priv = hw->priv; |
3542 | __le32 filter_or = 0, filter_nand = 0; | 3323 | __le32 filter_or = 0, filter_nand = 0; |
@@ -3583,7 +3364,7 @@ void iwlagn_configure_filter(struct ieee80211_hw *hw, | |||
3583 | FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL; | 3364 | FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL; |
3584 | } | 3365 | } |
3585 | 3366 | ||
3586 | void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop) | 3367 | static void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop) |
3587 | { | 3368 | { |
3588 | struct iwl_priv *priv = hw->priv; | 3369 | struct iwl_priv *priv = hw->priv; |
3589 | 3370 | ||
@@ -3750,12 +3531,8 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv) | |||
3750 | priv->watchdog.data = (unsigned long)priv; | 3531 | priv->watchdog.data = (unsigned long)priv; |
3751 | priv->watchdog.function = iwl_bg_watchdog; | 3532 | priv->watchdog.function = iwl_bg_watchdog; |
3752 | 3533 | ||
3753 | if (!priv->cfg->base_params->use_isr_legacy) | 3534 | tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) |
3754 | tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) | 3535 | iwl_irq_tasklet, (unsigned long)priv); |
3755 | iwl_irq_tasklet, (unsigned long)priv); | ||
3756 | else | ||
3757 | tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) | ||
3758 | iwl_irq_tasklet_legacy, (unsigned long)priv); | ||
3759 | } | 3536 | } |
3760 | 3537 | ||
3761 | static void iwl_cancel_deferred_work(struct iwl_priv *priv) | 3538 | static void iwl_cancel_deferred_work(struct iwl_priv *priv) |
@@ -3808,7 +3585,6 @@ static int iwl_init_drv(struct iwl_priv *priv) | |||
3808 | INIT_LIST_HEAD(&priv->free_frames); | 3585 | INIT_LIST_HEAD(&priv->free_frames); |
3809 | 3586 | ||
3810 | mutex_init(&priv->mutex); | 3587 | mutex_init(&priv->mutex); |
3811 | mutex_init(&priv->sync_cmd_mutex); | ||
3812 | 3588 | ||
3813 | priv->ieee_channels = NULL; | 3589 | priv->ieee_channels = NULL; |
3814 | priv->ieee_rates = NULL; | 3590 | priv->ieee_rates = NULL; |
@@ -3907,12 +3683,13 @@ struct ieee80211_ops iwlagn_hw_ops = { | |||
3907 | .offchannel_tx_cancel_wait = iwl_mac_offchannel_tx_cancel_wait, | 3683 | .offchannel_tx_cancel_wait = iwl_mac_offchannel_tx_cancel_wait, |
3908 | }; | 3684 | }; |
3909 | 3685 | ||
3910 | static void iwl_hw_detect(struct iwl_priv *priv) | 3686 | static u32 iwl_hw_detect(struct iwl_priv *priv) |
3911 | { | 3687 | { |
3912 | priv->hw_rev = _iwl_read32(priv, CSR_HW_REV); | 3688 | u8 rev_id; |
3913 | priv->hw_wa_rev = _iwl_read32(priv, CSR_HW_REV_WA_REG); | 3689 | |
3914 | priv->rev_id = priv->pci_dev->revision; | 3690 | pci_read_config_byte(priv->pci_dev, PCI_REVISION_ID, &rev_id); |
3915 | IWL_DEBUG_INFO(priv, "HW Revision ID = 0x%X\n", priv->rev_id); | 3691 | IWL_DEBUG_INFO(priv, "HW Revision ID = 0x%X\n", rev_id); |
3692 | return iwl_read32(priv, CSR_HW_REV); | ||
3916 | } | 3693 | } |
3917 | 3694 | ||
3918 | static int iwl_set_hw_params(struct iwl_priv *priv) | 3695 | static int iwl_set_hw_params(struct iwl_priv *priv) |
@@ -3963,19 +3740,12 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
3963 | struct iwl_cfg *cfg = (struct iwl_cfg *)(ent->driver_data); | 3740 | struct iwl_cfg *cfg = (struct iwl_cfg *)(ent->driver_data); |
3964 | unsigned long flags; | 3741 | unsigned long flags; |
3965 | u16 pci_cmd, num_mac; | 3742 | u16 pci_cmd, num_mac; |
3743 | u32 hw_rev; | ||
3966 | 3744 | ||
3967 | /************************ | 3745 | /************************ |
3968 | * 1. Allocating HW data | 3746 | * 1. Allocating HW data |
3969 | ************************/ | 3747 | ************************/ |
3970 | 3748 | ||
3971 | /* Disabling hardware scan means that mac80211 will perform scans | ||
3972 | * "the hard way", rather than using device's scan. */ | ||
3973 | if (cfg->mod_params->disable_hw_scan) { | ||
3974 | dev_printk(KERN_DEBUG, &(pdev->dev), | ||
3975 | "sw scan support is deprecated\n"); | ||
3976 | iwlagn_hw_ops.hw_scan = NULL; | ||
3977 | } | ||
3978 | |||
3979 | hw = iwl_alloc_all(cfg); | 3749 | hw = iwl_alloc_all(cfg); |
3980 | if (!hw) { | 3750 | if (!hw) { |
3981 | err = -ENOMEM; | 3751 | err = -ENOMEM; |
@@ -4116,9 +3886,9 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
4116 | */ | 3886 | */ |
4117 | iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET); | 3887 | iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET); |
4118 | 3888 | ||
4119 | iwl_hw_detect(priv); | 3889 | hw_rev = iwl_hw_detect(priv); |
4120 | IWL_INFO(priv, "Detected %s, REV=0x%X\n", | 3890 | IWL_INFO(priv, "Detected %s, REV=0x%X\n", |
4121 | priv->cfg->name, priv->hw_rev); | 3891 | priv->cfg->name, hw_rev); |
4122 | 3892 | ||
4123 | /* We disable the RETRY_TIMEOUT register (0x41) to keep | 3893 | /* We disable the RETRY_TIMEOUT register (0x41) to keep |
4124 | * PCI Tx retries from interfering with C3 CPU state */ | 3894 | * PCI Tx retries from interfering with C3 CPU state */ |
@@ -4134,7 +3904,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
4134 | * 4. Read EEPROM | 3904 | * 4. Read EEPROM |
4135 | *****************/ | 3905 | *****************/ |
4136 | /* Read the EEPROM */ | 3906 | /* Read the EEPROM */ |
4137 | err = iwl_eeprom_init(priv); | 3907 | err = iwl_eeprom_init(priv, hw_rev); |
4138 | if (err) { | 3908 | if (err) { |
4139 | IWL_ERR(priv, "Unable to init EEPROM\n"); | 3909 | IWL_ERR(priv, "Unable to init EEPROM\n"); |
4140 | goto out_iounmap; | 3910 | goto out_iounmap; |
@@ -4186,10 +3956,9 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
4186 | 3956 | ||
4187 | pci_enable_msi(priv->pci_dev); | 3957 | pci_enable_msi(priv->pci_dev); |
4188 | 3958 | ||
4189 | if (priv->cfg->ops->lib->isr_ops.alloc) | 3959 | iwl_alloc_isr_ict(priv); |
4190 | priv->cfg->ops->lib->isr_ops.alloc(priv); | ||
4191 | 3960 | ||
4192 | err = request_irq(priv->pci_dev->irq, priv->cfg->ops->lib->isr_ops.isr, | 3961 | err = request_irq(priv->pci_dev->irq, iwl_isr_ict, |
4193 | IRQF_SHARED, DRV_NAME, priv); | 3962 | IRQF_SHARED, DRV_NAME, priv); |
4194 | if (err) { | 3963 | if (err) { |
4195 | IWL_ERR(priv, "Error allocating IRQ %d\n", priv->pci_dev->irq); | 3964 | IWL_ERR(priv, "Error allocating IRQ %d\n", priv->pci_dev->irq); |
@@ -4236,8 +4005,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
4236 | destroy_workqueue(priv->workqueue); | 4005 | destroy_workqueue(priv->workqueue); |
4237 | priv->workqueue = NULL; | 4006 | priv->workqueue = NULL; |
4238 | free_irq(priv->pci_dev->irq, priv); | 4007 | free_irq(priv->pci_dev->irq, priv); |
4239 | if (priv->cfg->ops->lib->isr_ops.free) | 4008 | iwl_free_isr_ict(priv); |
4240 | priv->cfg->ops->lib->isr_ops.free(priv); | ||
4241 | out_disable_msi: | 4009 | out_disable_msi: |
4242 | pci_disable_msi(priv->pci_dev); | 4010 | pci_disable_msi(priv->pci_dev); |
4243 | iwl_uninit_drv(priv); | 4011 | iwl_uninit_drv(priv); |
@@ -4335,8 +4103,7 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev) | |||
4335 | 4103 | ||
4336 | iwl_uninit_drv(priv); | 4104 | iwl_uninit_drv(priv); |
4337 | 4105 | ||
4338 | if (priv->cfg->ops->lib->isr_ops.free) | 4106 | iwl_free_isr_ict(priv); |
4339 | priv->cfg->ops->lib->isr_ops.free(priv); | ||
4340 | 4107 | ||
4341 | dev_kfree_skb(priv->beacon_skb); | 4108 | dev_kfree_skb(priv->beacon_skb); |
4342 | 4109 | ||
@@ -4585,43 +4352,21 @@ module_exit(iwl_exit); | |||
4585 | module_init(iwl_init); | 4352 | module_init(iwl_init); |
4586 | 4353 | ||
4587 | #ifdef CONFIG_IWLWIFI_DEBUG | 4354 | #ifdef CONFIG_IWLWIFI_DEBUG |
4588 | module_param_named(debug50, iwl_debug_level, uint, S_IRUGO); | ||
4589 | MODULE_PARM_DESC(debug50, "50XX debug output mask (deprecated)"); | ||
4590 | module_param_named(debug, iwl_debug_level, uint, S_IRUGO | S_IWUSR); | 4355 | module_param_named(debug, iwl_debug_level, uint, S_IRUGO | S_IWUSR); |
4591 | MODULE_PARM_DESC(debug, "debug output mask"); | 4356 | MODULE_PARM_DESC(debug, "debug output mask"); |
4592 | #endif | 4357 | #endif |
4593 | 4358 | ||
4594 | module_param_named(swcrypto50, iwlagn_mod_params.sw_crypto, bool, S_IRUGO); | ||
4595 | MODULE_PARM_DESC(swcrypto50, | ||
4596 | "using crypto in software (default 0 [hardware]) (deprecated)"); | ||
4597 | module_param_named(swcrypto, iwlagn_mod_params.sw_crypto, int, S_IRUGO); | 4359 | module_param_named(swcrypto, iwlagn_mod_params.sw_crypto, int, S_IRUGO); |
4598 | MODULE_PARM_DESC(swcrypto, "using crypto in software (default 0 [hardware])"); | 4360 | MODULE_PARM_DESC(swcrypto, "using crypto in software (default 0 [hardware])"); |
4599 | module_param_named(queues_num50, | ||
4600 | iwlagn_mod_params.num_of_queues, int, S_IRUGO); | ||
4601 | MODULE_PARM_DESC(queues_num50, | ||
4602 | "number of hw queues in 50xx series (deprecated)"); | ||
4603 | module_param_named(queues_num, iwlagn_mod_params.num_of_queues, int, S_IRUGO); | 4361 | module_param_named(queues_num, iwlagn_mod_params.num_of_queues, int, S_IRUGO); |
4604 | MODULE_PARM_DESC(queues_num, "number of hw queues."); | 4362 | MODULE_PARM_DESC(queues_num, "number of hw queues."); |
4605 | module_param_named(11n_disable50, iwlagn_mod_params.disable_11n, int, S_IRUGO); | ||
4606 | MODULE_PARM_DESC(11n_disable50, "disable 50XX 11n functionality (deprecated)"); | ||
4607 | module_param_named(11n_disable, iwlagn_mod_params.disable_11n, int, S_IRUGO); | 4363 | module_param_named(11n_disable, iwlagn_mod_params.disable_11n, int, S_IRUGO); |
4608 | MODULE_PARM_DESC(11n_disable, "disable 11n functionality"); | 4364 | MODULE_PARM_DESC(11n_disable, "disable 11n functionality"); |
4609 | module_param_named(amsdu_size_8K50, iwlagn_mod_params.amsdu_size_8K, | ||
4610 | int, S_IRUGO); | ||
4611 | MODULE_PARM_DESC(amsdu_size_8K50, | ||
4612 | "enable 8K amsdu size in 50XX series (deprecated)"); | ||
4613 | module_param_named(amsdu_size_8K, iwlagn_mod_params.amsdu_size_8K, | 4365 | module_param_named(amsdu_size_8K, iwlagn_mod_params.amsdu_size_8K, |
4614 | int, S_IRUGO); | 4366 | int, S_IRUGO); |
4615 | MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size"); | 4367 | MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size"); |
4616 | module_param_named(fw_restart50, iwlagn_mod_params.restart_fw, int, S_IRUGO); | ||
4617 | MODULE_PARM_DESC(fw_restart50, | ||
4618 | "restart firmware in case of error (deprecated)"); | ||
4619 | module_param_named(fw_restart, iwlagn_mod_params.restart_fw, int, S_IRUGO); | 4368 | module_param_named(fw_restart, iwlagn_mod_params.restart_fw, int, S_IRUGO); |
4620 | MODULE_PARM_DESC(fw_restart, "restart firmware in case of error"); | 4369 | MODULE_PARM_DESC(fw_restart, "restart firmware in case of error"); |
4621 | module_param_named( | ||
4622 | disable_hw_scan, iwlagn_mod_params.disable_hw_scan, int, S_IRUGO); | ||
4623 | MODULE_PARM_DESC(disable_hw_scan, | ||
4624 | "disable hardware scanning (default 0) (deprecated)"); | ||
4625 | 4370 | ||
4626 | module_param_named(ucode_alternative, iwlagn_wanted_ucode_alternative, int, | 4371 | module_param_named(ucode_alternative, iwlagn_wanted_ucode_alternative, int, |
4627 | S_IRUGO); | 4372 | S_IRUGO); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h index 20f8e4188994..016b79e4421e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn.h | |||
@@ -5,7 +5,7 @@ | |||
5 | * | 5 | * |
6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
7 | * | 7 | * |
8 | * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of version 2 of the GNU General Public License as | 11 | * it under the terms of version 2 of the GNU General Public License as |
@@ -30,7 +30,7 @@ | |||
30 | * | 30 | * |
31 | * BSD LICENSE | 31 | * BSD LICENSE |
32 | * | 32 | * |
33 | * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. | 33 | * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. |
34 | * All rights reserved. | 34 | * All rights reserved. |
35 | * | 35 | * |
36 | * Redistribution and use in source and binary forms, with or without | 36 | * Redistribution and use in source and binary forms, with or without |
@@ -66,7 +66,6 @@ | |||
66 | #include "iwl-dev.h" | 66 | #include "iwl-dev.h" |
67 | 67 | ||
68 | /* configuration for the _agn devices */ | 68 | /* configuration for the _agn devices */ |
69 | extern struct iwl_cfg iwl4965_agn_cfg; | ||
70 | extern struct iwl_cfg iwl5300_agn_cfg; | 69 | extern struct iwl_cfg iwl5300_agn_cfg; |
71 | extern struct iwl_cfg iwl5100_agn_cfg; | 70 | extern struct iwl_cfg iwl5100_agn_cfg; |
72 | extern struct iwl_cfg iwl5350_agn_cfg; | 71 | extern struct iwl_cfg iwl5350_agn_cfg; |
@@ -114,7 +113,6 @@ extern struct iwl_hcmd_ops iwlagn_bt_hcmd; | |||
114 | extern struct iwl_hcmd_utils_ops iwlagn_hcmd_utils; | 113 | extern struct iwl_hcmd_utils_ops iwlagn_hcmd_utils; |
115 | 114 | ||
116 | extern struct ieee80211_ops iwlagn_hw_ops; | 115 | extern struct ieee80211_ops iwlagn_hw_ops; |
117 | extern struct ieee80211_ops iwl4965_hw_ops; | ||
118 | 116 | ||
119 | int iwl_reset_ict(struct iwl_priv *priv); | 117 | int iwl_reset_ict(struct iwl_priv *priv); |
120 | void iwl_disable_ict(struct iwl_priv *priv); | 118 | void iwl_disable_ict(struct iwl_priv *priv); |
@@ -133,10 +131,6 @@ void iwlagn_txq_update_byte_cnt_tbl(struct iwl_priv *priv, | |||
133 | u16 byte_cnt); | 131 | u16 byte_cnt); |
134 | void iwlagn_txq_inval_byte_cnt_tbl(struct iwl_priv *priv, | 132 | void iwlagn_txq_inval_byte_cnt_tbl(struct iwl_priv *priv, |
135 | struct iwl_tx_queue *txq); | 133 | struct iwl_tx_queue *txq); |
136 | int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id, | ||
137 | int tx_fifo, int sta_id, int tid, u16 ssn_idx); | ||
138 | int iwlagn_txq_agg_disable(struct iwl_priv *priv, u16 txq_id, | ||
139 | u16 ssn_idx, u8 tx_fifo); | ||
140 | void iwlagn_txq_set_sched(struct iwl_priv *priv, u32 mask); | 134 | void iwlagn_txq_set_sched(struct iwl_priv *priv, u32 mask); |
141 | void iwl_free_tfds_in_queue(struct iwl_priv *priv, | 135 | void iwl_free_tfds_in_queue(struct iwl_priv *priv, |
142 | int sta_id, int tid, int freed); | 136 | int sta_id, int tid, int freed); |
@@ -158,7 +152,7 @@ void iwlagn_rx_calib_complete(struct iwl_priv *priv, | |||
158 | struct iwl_rx_mem_buffer *rxb); | 152 | struct iwl_rx_mem_buffer *rxb); |
159 | void iwlagn_init_alive_start(struct iwl_priv *priv); | 153 | void iwlagn_init_alive_start(struct iwl_priv *priv); |
160 | int iwlagn_alive_notify(struct iwl_priv *priv); | 154 | int iwlagn_alive_notify(struct iwl_priv *priv); |
161 | int iwl_verify_ucode(struct iwl_priv *priv); | 155 | int iwl_verify_ucode(struct iwl_priv *priv, struct fw_desc *fw_desc); |
162 | void iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type); | 156 | void iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type); |
163 | void iwlagn_send_prio_tbl(struct iwl_priv *priv); | 157 | void iwlagn_send_prio_tbl(struct iwl_priv *priv); |
164 | 158 | ||
@@ -206,6 +200,9 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif, | |||
206 | struct ieee80211_sta *sta, u16 tid, u16 *ssn); | 200 | struct ieee80211_sta *sta, u16 tid, u16 *ssn); |
207 | int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif, | 201 | int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif, |
208 | struct ieee80211_sta *sta, u16 tid); | 202 | struct ieee80211_sta *sta, u16 tid); |
203 | void iwlagn_txq_agg_queue_setup(struct iwl_priv *priv, | ||
204 | struct ieee80211_sta *sta, | ||
205 | int tid, int frame_limit); | ||
209 | int iwlagn_txq_check_empty(struct iwl_priv *priv, | 206 | int iwlagn_txq_check_empty(struct iwl_priv *priv, |
210 | int sta_id, u8 tid, int txq_id); | 207 | int sta_id, u8 tid, int txq_id); |
211 | void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, | 208 | void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, |
@@ -311,7 +308,7 @@ static inline u32 iwl_ant_idx_to_flags(u8 ant_idx) | |||
311 | 308 | ||
312 | static inline u8 iwl_hw_get_rate(__le32 rate_n_flags) | 309 | static inline u8 iwl_hw_get_rate(__le32 rate_n_flags) |
313 | { | 310 | { |
314 | return le32_to_cpu(rate_n_flags) & 0xFF; | 311 | return le32_to_cpu(rate_n_flags) & RATE_MCS_RATE_MSK; |
315 | } | 312 | } |
316 | 313 | ||
317 | static inline __le32 iwl_hw_set_rate_n_flags(u8 rate, u32 flags) | 314 | static inline __le32 iwl_hw_set_rate_n_flags(u8 rate, u32 flags) |
@@ -340,32 +337,4 @@ void __releases(wait_entry) | |||
340 | iwlagn_remove_notification(struct iwl_priv *priv, | 337 | iwlagn_remove_notification(struct iwl_priv *priv, |
341 | struct iwl_notification_wait *wait_entry); | 338 | struct iwl_notification_wait *wait_entry); |
342 | 339 | ||
343 | /* mac80211 handlers (for 4965) */ | ||
344 | void iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb); | ||
345 | int iwlagn_mac_start(struct ieee80211_hw *hw); | ||
346 | void iwlagn_mac_stop(struct ieee80211_hw *hw); | ||
347 | void iwlagn_configure_filter(struct ieee80211_hw *hw, | ||
348 | unsigned int changed_flags, | ||
349 | unsigned int *total_flags, | ||
350 | u64 multicast); | ||
351 | int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, | ||
352 | struct ieee80211_vif *vif, struct ieee80211_sta *sta, | ||
353 | struct ieee80211_key_conf *key); | ||
354 | void iwlagn_mac_update_tkip_key(struct ieee80211_hw *hw, | ||
355 | struct ieee80211_vif *vif, | ||
356 | struct ieee80211_key_conf *keyconf, | ||
357 | struct ieee80211_sta *sta, | ||
358 | u32 iv32, u16 *phase1key); | ||
359 | int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, | ||
360 | struct ieee80211_vif *vif, | ||
361 | enum ieee80211_ampdu_mlme_action action, | ||
362 | struct ieee80211_sta *sta, u16 tid, u16 *ssn, | ||
363 | u8 buf_size); | ||
364 | int iwlagn_mac_sta_add(struct ieee80211_hw *hw, | ||
365 | struct ieee80211_vif *vif, | ||
366 | struct ieee80211_sta *sta); | ||
367 | void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, | ||
368 | struct ieee80211_channel_switch *ch_switch); | ||
369 | void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop); | ||
370 | |||
371 | #endif /* __iwl_agn_h__ */ | 340 | #endif /* __iwl_agn_h__ */ |
diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index ca42ffa63ed7..a1a5c1b23096 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h | |||
@@ -5,7 +5,7 @@ | |||
5 | * | 5 | * |
6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
7 | * | 7 | * |
8 | * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of version 2 of the GNU General Public License as | 11 | * it under the terms of version 2 of the GNU General Public License as |
@@ -30,7 +30,7 @@ | |||
30 | * | 30 | * |
31 | * BSD LICENSE | 31 | * BSD LICENSE |
32 | * | 32 | * |
33 | * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. | 33 | * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. |
34 | * All rights reserved. | 34 | * All rights reserved. |
35 | * | 35 | * |
36 | * Redistribution and use in source and binary forms, with or without | 36 | * Redistribution and use in source and binary forms, with or without |
@@ -103,9 +103,7 @@ enum { | |||
103 | REPLY_WEPKEY = 0x20, | 103 | REPLY_WEPKEY = 0x20, |
104 | 104 | ||
105 | /* RX, TX, LEDs */ | 105 | /* RX, TX, LEDs */ |
106 | REPLY_3945_RX = 0x1b, /* 3945 only */ | ||
107 | REPLY_TX = 0x1c, | 106 | REPLY_TX = 0x1c, |
108 | REPLY_RATE_SCALE = 0x47, /* 3945 only */ | ||
109 | REPLY_LEDS_CMD = 0x48, | 107 | REPLY_LEDS_CMD = 0x48, |
110 | REPLY_TX_LINK_QUALITY_CMD = 0x4e, /* for 4965 and up */ | 108 | REPLY_TX_LINK_QUALITY_CMD = 0x4e, /* for 4965 and up */ |
111 | 109 | ||
@@ -229,7 +227,7 @@ struct iwl_cmd_header { | |||
229 | * There is one exception: uCode sets bit 15 when it originates | 227 | * There is one exception: uCode sets bit 15 when it originates |
230 | * the response/notification, i.e. when the response/notification | 228 | * the response/notification, i.e. when the response/notification |
231 | * is not a direct response to a command sent by the driver. For | 229 | * is not a direct response to a command sent by the driver. For |
232 | * example, uCode issues REPLY_3945_RX when it sends a received frame | 230 | * example, uCode issues REPLY_RX when it sends a received frame |
233 | * to the driver; it is not a direct response to any driver command. | 231 | * to the driver; it is not a direct response to any driver command. |
234 | * | 232 | * |
235 | * The Linux driver uses the following format: | 233 | * The Linux driver uses the following format: |
@@ -249,36 +247,6 @@ struct iwl_cmd_header { | |||
249 | 247 | ||
250 | 248 | ||
251 | /** | 249 | /** |
252 | * struct iwl3945_tx_power | ||
253 | * | ||
254 | * Used in REPLY_TX_PWR_TABLE_CMD, REPLY_SCAN_CMD, REPLY_CHANNEL_SWITCH | ||
255 | * | ||
256 | * Each entry contains two values: | ||
257 | * 1) DSP gain (or sometimes called DSP attenuation). This is a fine-grained | ||
258 | * linear value that multiplies the output of the digital signal processor, | ||
259 | * before being sent to the analog radio. | ||
260 | * 2) Radio gain. This sets the analog gain of the radio Tx path. | ||
261 | * It is a coarser setting, and behaves in a logarithmic (dB) fashion. | ||
262 | * | ||
263 | * Driver obtains values from struct iwl3945_tx_power power_gain_table[][]. | ||
264 | */ | ||
265 | struct iwl3945_tx_power { | ||
266 | u8 tx_gain; /* gain for analog radio */ | ||
267 | u8 dsp_atten; /* gain for DSP */ | ||
268 | } __packed; | ||
269 | |||
270 | /** | ||
271 | * struct iwl3945_power_per_rate | ||
272 | * | ||
273 | * Used in REPLY_TX_PWR_TABLE_CMD, REPLY_CHANNEL_SWITCH | ||
274 | */ | ||
275 | struct iwl3945_power_per_rate { | ||
276 | u8 rate; /* plcp */ | ||
277 | struct iwl3945_tx_power tpc; | ||
278 | u8 reserved; | ||
279 | } __packed; | ||
280 | |||
281 | /** | ||
282 | * iwlagn rate_n_flags bit fields | 250 | * iwlagn rate_n_flags bit fields |
283 | * | 251 | * |
284 | * rate_n_flags format is used in following iwlagn commands: | 252 | * rate_n_flags format is used in following iwlagn commands: |
@@ -324,6 +292,8 @@ struct iwl3945_power_per_rate { | |||
324 | #define RATE_MCS_SPATIAL_MSK 0x18 | 292 | #define RATE_MCS_SPATIAL_MSK 0x18 |
325 | #define RATE_MCS_HT_DUP_POS 5 | 293 | #define RATE_MCS_HT_DUP_POS 5 |
326 | #define RATE_MCS_HT_DUP_MSK 0x20 | 294 | #define RATE_MCS_HT_DUP_MSK 0x20 |
295 | /* Both legacy and HT use bits 7:0 as the CCK/OFDM rate or HT MCS */ | ||
296 | #define RATE_MCS_RATE_MSK 0xff | ||
327 | 297 | ||
328 | /* Bit 8: (1) HT format, (0) legacy format in bits 7:0 */ | 298 | /* Bit 8: (1) HT format, (0) legacy format in bits 7:0 */ |
329 | #define RATE_MCS_FLAGS_POS 8 | 299 | #define RATE_MCS_FLAGS_POS 8 |
@@ -375,30 +345,6 @@ struct iwl3945_power_per_rate { | |||
375 | #define IWL_PWR_CCK_ENTRIES 2 | 345 | #define IWL_PWR_CCK_ENTRIES 2 |
376 | 346 | ||
377 | /** | 347 | /** |
378 | * union iwl4965_tx_power_dual_stream | ||
379 | * | ||
380 | * Host format used for REPLY_TX_PWR_TABLE_CMD, REPLY_CHANNEL_SWITCH | ||
381 | * Use __le32 version (struct tx_power_dual_stream) when building command. | ||
382 | * | ||
383 | * Driver provides radio gain and DSP attenuation settings to device in pairs, | ||
384 | * one value for each transmitter chain. The first value is for transmitter A, | ||
385 | * second for transmitter B. | ||
386 | * | ||
387 | * For SISO bit rates, both values in a pair should be identical. | ||
388 | * For MIMO rates, one value may be different from the other, | ||
389 | * in order to balance the Tx output between the two transmitters. | ||
390 | * | ||
391 | * See more details in doc for TXPOWER in iwl-4965-hw.h. | ||
392 | */ | ||
393 | union iwl4965_tx_power_dual_stream { | ||
394 | struct { | ||
395 | u8 radio_tx_gain[2]; | ||
396 | u8 dsp_predis_atten[2]; | ||
397 | } s; | ||
398 | u32 dw; | ||
399 | }; | ||
400 | |||
401 | /** | ||
402 | * struct tx_power_dual_stream | 348 | * struct tx_power_dual_stream |
403 | * | 349 | * |
404 | * Table entries in REPLY_TX_PWR_TABLE_CMD, REPLY_CHANNEL_SWITCH | 350 | * Table entries in REPLY_TX_PWR_TABLE_CMD, REPLY_CHANNEL_SWITCH |
@@ -410,15 +356,6 @@ struct tx_power_dual_stream { | |||
410 | } __packed; | 356 | } __packed; |
411 | 357 | ||
412 | /** | 358 | /** |
413 | * struct iwl4965_tx_power_db | ||
414 | * | ||
415 | * Entire table within REPLY_TX_PWR_TABLE_CMD, REPLY_CHANNEL_SWITCH | ||
416 | */ | ||
417 | struct iwl4965_tx_power_db { | ||
418 | struct tx_power_dual_stream power_tbl[POWER_TABLE_NUM_ENTRIES]; | ||
419 | } __packed; | ||
420 | |||
421 | /** | ||
422 | * Command REPLY_TX_POWER_DBM_CMD = 0x98 | 359 | * Command REPLY_TX_POWER_DBM_CMD = 0x98 |
423 | * struct iwlagn_tx_power_dbm_cmd | 360 | * struct iwlagn_tx_power_dbm_cmd |
424 | */ | 361 | */ |
@@ -451,54 +388,6 @@ struct iwl_tx_ant_config_cmd { | |||
451 | #define UCODE_VALID_OK cpu_to_le32(0x1) | 388 | #define UCODE_VALID_OK cpu_to_le32(0x1) |
452 | #define INITIALIZE_SUBTYPE (9) | 389 | #define INITIALIZE_SUBTYPE (9) |
453 | 390 | ||
454 | /* | ||
455 | * ("Initialize") REPLY_ALIVE = 0x1 (response only, not a command) | ||
456 | * | ||
457 | * uCode issues this "initialize alive" notification once the initialization | ||
458 | * uCode image has completed its work, and is ready to load the runtime image. | ||
459 | * This is the *first* "alive" notification that the driver will receive after | ||
460 | * rebooting uCode; the "initialize" alive is indicated by subtype field == 9. | ||
461 | * | ||
462 | * See comments documenting "BSM" (bootstrap state machine). | ||
463 | * | ||
464 | * For 4965, this notification contains important calibration data for | ||
465 | * calculating txpower settings: | ||
466 | * | ||
467 | * 1) Power supply voltage indication. The voltage sensor outputs higher | ||
468 | * values for lower voltage, and vice verse. | ||
469 | * | ||
470 | * 2) Temperature measurement parameters, for each of two channel widths | ||
471 | * (20 MHz and 40 MHz) supported by the radios. Temperature sensing | ||
472 | * is done via one of the receiver chains, and channel width influences | ||
473 | * the results. | ||
474 | * | ||
475 | * 3) Tx gain compensation to balance 4965's 2 Tx chains for MIMO operation, | ||
476 | * for each of 5 frequency ranges. | ||
477 | */ | ||
478 | struct iwl_init_alive_resp { | ||
479 | u8 ucode_minor; | ||
480 | u8 ucode_major; | ||
481 | __le16 reserved1; | ||
482 | u8 sw_rev[8]; | ||
483 | u8 ver_type; | ||
484 | u8 ver_subtype; /* "9" for initialize alive */ | ||
485 | __le16 reserved2; | ||
486 | __le32 log_event_table_ptr; | ||
487 | __le32 error_event_table_ptr; | ||
488 | __le32 timestamp; | ||
489 | __le32 is_valid; | ||
490 | |||
491 | /* calibration values from "initialize" uCode */ | ||
492 | __le32 voltage; /* signed, higher value is lower voltage */ | ||
493 | __le32 therm_r1[2]; /* signed, 1st for normal, 2nd for HT40 */ | ||
494 | __le32 therm_r2[2]; /* signed */ | ||
495 | __le32 therm_r3[2]; /* signed */ | ||
496 | __le32 therm_r4[2]; /* signed */ | ||
497 | __le32 tx_atten[5][2]; /* signed MIMO gain comp, 5 freq groups, | ||
498 | * 2 Tx chains */ | ||
499 | } __packed; | ||
500 | |||
501 | |||
502 | /** | 391 | /** |
503 | * REPLY_ALIVE = 0x1 (response only, not a command) | 392 | * REPLY_ALIVE = 0x1 (response only, not a command) |
504 | * | 393 | * |
@@ -722,46 +611,6 @@ enum { | |||
722 | * regardless of whether RXON_FILTER_ASSOC_MSK is set. | 611 | * regardless of whether RXON_FILTER_ASSOC_MSK is set. |
723 | */ | 612 | */ |
724 | 613 | ||
725 | struct iwl3945_rxon_cmd { | ||
726 | u8 node_addr[6]; | ||
727 | __le16 reserved1; | ||
728 | u8 bssid_addr[6]; | ||
729 | __le16 reserved2; | ||
730 | u8 wlap_bssid_addr[6]; | ||
731 | __le16 reserved3; | ||
732 | u8 dev_type; | ||
733 | u8 air_propagation; | ||
734 | __le16 reserved4; | ||
735 | u8 ofdm_basic_rates; | ||
736 | u8 cck_basic_rates; | ||
737 | __le16 assoc_id; | ||
738 | __le32 flags; | ||
739 | __le32 filter_flags; | ||
740 | __le16 channel; | ||
741 | __le16 reserved5; | ||
742 | } __packed; | ||
743 | |||
744 | struct iwl4965_rxon_cmd { | ||
745 | u8 node_addr[6]; | ||
746 | __le16 reserved1; | ||
747 | u8 bssid_addr[6]; | ||
748 | __le16 reserved2; | ||
749 | u8 wlap_bssid_addr[6]; | ||
750 | __le16 reserved3; | ||
751 | u8 dev_type; | ||
752 | u8 air_propagation; | ||
753 | __le16 rx_chain; | ||
754 | u8 ofdm_basic_rates; | ||
755 | u8 cck_basic_rates; | ||
756 | __le16 assoc_id; | ||
757 | __le32 flags; | ||
758 | __le32 filter_flags; | ||
759 | __le16 channel; | ||
760 | u8 ofdm_ht_single_stream_basic_rates; | ||
761 | u8 ofdm_ht_dual_stream_basic_rates; | ||
762 | } __packed; | ||
763 | |||
764 | /* 5000 HW just extend this command */ | ||
765 | struct iwl_rxon_cmd { | 614 | struct iwl_rxon_cmd { |
766 | u8 node_addr[6]; | 615 | u8 node_addr[6]; |
767 | __le16 reserved1; | 616 | __le16 reserved1; |
@@ -789,25 +638,6 @@ struct iwl_rxon_cmd { | |||
789 | /* | 638 | /* |
790 | * REPLY_RXON_ASSOC = 0x11 (command, has simple generic response) | 639 | * REPLY_RXON_ASSOC = 0x11 (command, has simple generic response) |
791 | */ | 640 | */ |
792 | struct iwl3945_rxon_assoc_cmd { | ||
793 | __le32 flags; | ||
794 | __le32 filter_flags; | ||
795 | u8 ofdm_basic_rates; | ||
796 | u8 cck_basic_rates; | ||
797 | __le16 reserved; | ||
798 | } __packed; | ||
799 | |||
800 | struct iwl4965_rxon_assoc_cmd { | ||
801 | __le32 flags; | ||
802 | __le32 filter_flags; | ||
803 | u8 ofdm_basic_rates; | ||
804 | u8 cck_basic_rates; | ||
805 | u8 ofdm_ht_single_stream_basic_rates; | ||
806 | u8 ofdm_ht_dual_stream_basic_rates; | ||
807 | __le16 rx_chain_select_flags; | ||
808 | __le16 reserved; | ||
809 | } __packed; | ||
810 | |||
811 | struct iwl5000_rxon_assoc_cmd { | 641 | struct iwl5000_rxon_assoc_cmd { |
812 | __le32 flags; | 642 | __le32 flags; |
813 | __le32 filter_flags; | 643 | __le32 filter_flags; |
@@ -843,26 +673,6 @@ struct iwl_rxon_time_cmd { | |||
843 | /* | 673 | /* |
844 | * REPLY_CHANNEL_SWITCH = 0x72 (command, has simple generic response) | 674 | * REPLY_CHANNEL_SWITCH = 0x72 (command, has simple generic response) |
845 | */ | 675 | */ |
846 | struct iwl3945_channel_switch_cmd { | ||
847 | u8 band; | ||
848 | u8 expect_beacon; | ||
849 | __le16 channel; | ||
850 | __le32 rxon_flags; | ||
851 | __le32 rxon_filter_flags; | ||
852 | __le32 switch_time; | ||
853 | struct iwl3945_power_per_rate power[IWL_MAX_RATES]; | ||
854 | } __packed; | ||
855 | |||
856 | struct iwl4965_channel_switch_cmd { | ||
857 | u8 band; | ||
858 | u8 expect_beacon; | ||
859 | __le16 channel; | ||
860 | __le32 rxon_flags; | ||
861 | __le32 rxon_filter_flags; | ||
862 | __le32 switch_time; | ||
863 | struct iwl4965_tx_power_db tx_power; | ||
864 | } __packed; | ||
865 | |||
866 | /** | 676 | /** |
867 | * struct iwl5000_channel_switch_cmd | 677 | * struct iwl5000_channel_switch_cmd |
868 | * @band: 0- 5.2GHz, 1- 2.4GHz | 678 | * @band: 0- 5.2GHz, 1- 2.4GHz |
@@ -976,15 +786,10 @@ struct iwl_qosparam_cmd { | |||
976 | #define IWL_AP_ID 0 | 786 | #define IWL_AP_ID 0 |
977 | #define IWL_AP_ID_PAN 1 | 787 | #define IWL_AP_ID_PAN 1 |
978 | #define IWL_STA_ID 2 | 788 | #define IWL_STA_ID 2 |
979 | #define IWL3945_BROADCAST_ID 24 | ||
980 | #define IWL3945_STATION_COUNT 25 | ||
981 | #define IWL4965_BROADCAST_ID 31 | ||
982 | #define IWL4965_STATION_COUNT 32 | ||
983 | #define IWLAGN_PAN_BCAST_ID 14 | 789 | #define IWLAGN_PAN_BCAST_ID 14 |
984 | #define IWLAGN_BROADCAST_ID 15 | 790 | #define IWLAGN_BROADCAST_ID 15 |
985 | #define IWLAGN_STATION_COUNT 16 | 791 | #define IWLAGN_STATION_COUNT 16 |
986 | 792 | ||
987 | #define IWL_STATION_COUNT 32 /* MAX(3945,4965)*/ | ||
988 | #define IWL_INVALID_STATION 255 | 793 | #define IWL_INVALID_STATION 255 |
989 | 794 | ||
990 | #define STA_FLG_TX_RATE_MSK cpu_to_le32(1 << 2) | 795 | #define STA_FLG_TX_RATE_MSK cpu_to_le32(1 << 2) |
@@ -1032,16 +837,6 @@ struct iwl_qosparam_cmd { | |||
1032 | * combined with Traffic ID (QOS priority), in format used by Tx Scheduler */ | 837 | * combined with Traffic ID (QOS priority), in format used by Tx Scheduler */ |
1033 | #define BUILD_RAxTID(sta_id, tid) (((sta_id) << 4) + (tid)) | 838 | #define BUILD_RAxTID(sta_id, tid) (((sta_id) << 4) + (tid)) |
1034 | 839 | ||
1035 | struct iwl4965_keyinfo { | ||
1036 | __le16 key_flags; | ||
1037 | u8 tkip_rx_tsc_byte2; /* TSC[2] for key mix ph1 detection */ | ||
1038 | u8 reserved1; | ||
1039 | __le16 tkip_rx_ttak[5]; /* 10-byte unicast TKIP TTAK */ | ||
1040 | u8 key_offset; | ||
1041 | u8 reserved2; | ||
1042 | u8 key[16]; /* 16-byte unicast decryption key */ | ||
1043 | } __packed; | ||
1044 | |||
1045 | /* agn */ | 840 | /* agn */ |
1046 | struct iwl_keyinfo { | 841 | struct iwl_keyinfo { |
1047 | __le16 key_flags; | 842 | __le16 key_flags; |
@@ -1083,7 +878,6 @@ struct sta_id_modify { | |||
1083 | * with info on security keys, aggregation parameters, and Tx rates for | 878 | * with info on security keys, aggregation parameters, and Tx rates for |
1084 | * initial Tx attempt and any retries (agn devices uses | 879 | * initial Tx attempt and any retries (agn devices uses |
1085 | * REPLY_TX_LINK_QUALITY_CMD, | 880 | * REPLY_TX_LINK_QUALITY_CMD, |
1086 | * 3945 uses REPLY_RATE_SCALE to set up rate tables). | ||
1087 | * | 881 | * |
1088 | * REPLY_ADD_STA sets up the table entry for one station, either creating | 882 | * REPLY_ADD_STA sets up the table entry for one station, either creating |
1089 | * a new entry, or modifying a pre-existing one. | 883 | * a new entry, or modifying a pre-existing one. |
@@ -1103,72 +897,6 @@ struct sta_id_modify { | |||
1103 | * entries for all STAs in network, starting with index IWL_STA_ID. | 897 | * entries for all STAs in network, starting with index IWL_STA_ID. |
1104 | */ | 898 | */ |
1105 | 899 | ||
1106 | struct iwl3945_addsta_cmd { | ||
1107 | u8 mode; /* 1: modify existing, 0: add new station */ | ||
1108 | u8 reserved[3]; | ||
1109 | struct sta_id_modify sta; | ||
1110 | struct iwl4965_keyinfo key; | ||
1111 | __le32 station_flags; /* STA_FLG_* */ | ||
1112 | __le32 station_flags_msk; /* STA_FLG_* */ | ||
1113 | |||
1114 | /* bit field to disable (1) or enable (0) Tx for Traffic ID (TID) | ||
1115 | * corresponding to bit (e.g. bit 5 controls TID 5). | ||
1116 | * Set modify_mask bit STA_MODIFY_TID_DISABLE_TX to use this field. */ | ||
1117 | __le16 tid_disable_tx; | ||
1118 | |||
1119 | __le16 rate_n_flags; | ||
1120 | |||
1121 | /* TID for which to add block-ack support. | ||
1122 | * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */ | ||
1123 | u8 add_immediate_ba_tid; | ||
1124 | |||
1125 | /* TID for which to remove block-ack support. | ||
1126 | * Set modify_mask bit STA_MODIFY_DELBA_TID_MSK to use this field. */ | ||
1127 | u8 remove_immediate_ba_tid; | ||
1128 | |||
1129 | /* Starting Sequence Number for added block-ack support. | ||
1130 | * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */ | ||
1131 | __le16 add_immediate_ba_ssn; | ||
1132 | } __packed; | ||
1133 | |||
1134 | struct iwl4965_addsta_cmd { | ||
1135 | u8 mode; /* 1: modify existing, 0: add new station */ | ||
1136 | u8 reserved[3]; | ||
1137 | struct sta_id_modify sta; | ||
1138 | struct iwl4965_keyinfo key; | ||
1139 | __le32 station_flags; /* STA_FLG_* */ | ||
1140 | __le32 station_flags_msk; /* STA_FLG_* */ | ||
1141 | |||
1142 | /* bit field to disable (1) or enable (0) Tx for Traffic ID (TID) | ||
1143 | * corresponding to bit (e.g. bit 5 controls TID 5). | ||
1144 | * Set modify_mask bit STA_MODIFY_TID_DISABLE_TX to use this field. */ | ||
1145 | __le16 tid_disable_tx; | ||
1146 | |||
1147 | __le16 reserved1; | ||
1148 | |||
1149 | /* TID for which to add block-ack support. | ||
1150 | * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */ | ||
1151 | u8 add_immediate_ba_tid; | ||
1152 | |||
1153 | /* TID for which to remove block-ack support. | ||
1154 | * Set modify_mask bit STA_MODIFY_DELBA_TID_MSK to use this field. */ | ||
1155 | u8 remove_immediate_ba_tid; | ||
1156 | |||
1157 | /* Starting Sequence Number for added block-ack support. | ||
1158 | * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */ | ||
1159 | __le16 add_immediate_ba_ssn; | ||
1160 | |||
1161 | /* | ||
1162 | * Number of packets OK to transmit to station even though | ||
1163 | * it is asleep -- used to synchronise PS-poll and u-APSD | ||
1164 | * responses while ucode keeps track of STA sleep state. | ||
1165 | */ | ||
1166 | __le16 sleep_tx_count; | ||
1167 | |||
1168 | __le16 reserved2; | ||
1169 | } __packed; | ||
1170 | |||
1171 | /* agn */ | ||
1172 | struct iwl_addsta_cmd { | 900 | struct iwl_addsta_cmd { |
1173 | u8 mode; /* 1: modify existing, 0: add new station */ | 901 | u8 mode; /* 1: modify existing, 0: add new station */ |
1174 | u8 reserved[3]; | 902 | u8 reserved[3]; |
@@ -1337,62 +1065,6 @@ struct iwl_wep_cmd { | |||
1337 | #define RX_MPDU_RES_STATUS_DEC_DONE_MSK (0x800) | 1065 | #define RX_MPDU_RES_STATUS_DEC_DONE_MSK (0x800) |
1338 | 1066 | ||
1339 | 1067 | ||
1340 | struct iwl3945_rx_frame_stats { | ||
1341 | u8 phy_count; | ||
1342 | u8 id; | ||
1343 | u8 rssi; | ||
1344 | u8 agc; | ||
1345 | __le16 sig_avg; | ||
1346 | __le16 noise_diff; | ||
1347 | u8 payload[0]; | ||
1348 | } __packed; | ||
1349 | |||
1350 | struct iwl3945_rx_frame_hdr { | ||
1351 | __le16 channel; | ||
1352 | __le16 phy_flags; | ||
1353 | u8 reserved1; | ||
1354 | u8 rate; | ||
1355 | __le16 len; | ||
1356 | u8 payload[0]; | ||
1357 | } __packed; | ||
1358 | |||
1359 | struct iwl3945_rx_frame_end { | ||
1360 | __le32 status; | ||
1361 | __le64 timestamp; | ||
1362 | __le32 beacon_timestamp; | ||
1363 | } __packed; | ||
1364 | |||
1365 | /* | ||
1366 | * REPLY_3945_RX = 0x1b (response only, not a command) | ||
1367 | * | ||
1368 | * NOTE: DO NOT dereference from casts to this structure | ||
1369 | * It is provided only for calculating minimum data set size. | ||
1370 | * The actual offsets of the hdr and end are dynamic based on | ||
1371 | * stats.phy_count | ||
1372 | */ | ||
1373 | struct iwl3945_rx_frame { | ||
1374 | struct iwl3945_rx_frame_stats stats; | ||
1375 | struct iwl3945_rx_frame_hdr hdr; | ||
1376 | struct iwl3945_rx_frame_end end; | ||
1377 | } __packed; | ||
1378 | |||
1379 | #define IWL39_RX_FRAME_SIZE (4 + sizeof(struct iwl3945_rx_frame)) | ||
1380 | |||
1381 | /* Fixed (non-configurable) rx data from phy */ | ||
1382 | |||
1383 | #define IWL49_RX_RES_PHY_CNT 14 | ||
1384 | #define IWL49_RX_PHY_FLAGS_ANTENNAE_OFFSET (4) | ||
1385 | #define IWL49_RX_PHY_FLAGS_ANTENNAE_MASK (0x70) | ||
1386 | #define IWL49_AGC_DB_MASK (0x3f80) /* MASK(7,13) */ | ||
1387 | #define IWL49_AGC_DB_POS (7) | ||
1388 | struct iwl4965_rx_non_cfg_phy { | ||
1389 | __le16 ant_selection; /* ant A bit 4, ant B bit 5, ant C bit 6 */ | ||
1390 | __le16 agc_info; /* agc code 0:6, agc dB 7:13, reserved 14:15 */ | ||
1391 | u8 rssi_info[6]; /* we use even entries, 0/2/4 for A/B/C rssi */ | ||
1392 | u8 pad[0]; | ||
1393 | } __packed; | ||
1394 | |||
1395 | |||
1396 | #define IWLAGN_RX_RES_PHY_CNT 8 | 1068 | #define IWLAGN_RX_RES_PHY_CNT 8 |
1397 | #define IWLAGN_RX_RES_AGC_IDX 1 | 1069 | #define IWLAGN_RX_RES_AGC_IDX 1 |
1398 | #define IWLAGN_RX_RES_RSSI_AB_IDX 2 | 1070 | #define IWLAGN_RX_RES_RSSI_AB_IDX 2 |
@@ -1576,80 +1248,6 @@ struct iwl_rx_mpdu_res_start { | |||
1576 | * REPLY_TX = 0x1c (command) | 1248 | * REPLY_TX = 0x1c (command) |
1577 | */ | 1249 | */ |
1578 | 1250 | ||
1579 | struct iwl3945_tx_cmd { | ||
1580 | /* | ||
1581 | * MPDU byte count: | ||
1582 | * MAC header (24/26/30/32 bytes) + 2 bytes pad if 26/30 header size, | ||
1583 | * + 8 byte IV for CCM or TKIP (not used for WEP) | ||
1584 | * + Data payload | ||
1585 | * + 8-byte MIC (not used for CCM/WEP) | ||
1586 | * NOTE: Does not include Tx command bytes, post-MAC pad bytes, | ||
1587 | * MIC (CCM) 8 bytes, ICV (WEP/TKIP/CKIP) 4 bytes, CRC 4 bytes.i | ||
1588 | * Range: 14-2342 bytes. | ||
1589 | */ | ||
1590 | __le16 len; | ||
1591 | |||
1592 | /* | ||
1593 | * MPDU or MSDU byte count for next frame. | ||
1594 | * Used for fragmentation and bursting, but not 11n aggregation. | ||
1595 | * Same as "len", but for next frame. Set to 0 if not applicable. | ||
1596 | */ | ||
1597 | __le16 next_frame_len; | ||
1598 | |||
1599 | __le32 tx_flags; /* TX_CMD_FLG_* */ | ||
1600 | |||
1601 | u8 rate; | ||
1602 | |||
1603 | /* Index of recipient station in uCode's station table */ | ||
1604 | u8 sta_id; | ||
1605 | u8 tid_tspec; | ||
1606 | u8 sec_ctl; | ||
1607 | u8 key[16]; | ||
1608 | union { | ||
1609 | u8 byte[8]; | ||
1610 | __le16 word[4]; | ||
1611 | __le32 dw[2]; | ||
1612 | } tkip_mic; | ||
1613 | __le32 next_frame_info; | ||
1614 | union { | ||
1615 | __le32 life_time; | ||
1616 | __le32 attempt; | ||
1617 | } stop_time; | ||
1618 | u8 supp_rates[2]; | ||
1619 | u8 rts_retry_limit; /*byte 50 */ | ||
1620 | u8 data_retry_limit; /*byte 51 */ | ||
1621 | union { | ||
1622 | __le16 pm_frame_timeout; | ||
1623 | __le16 attempt_duration; | ||
1624 | } timeout; | ||
1625 | |||
1626 | /* | ||
1627 | * Duration of EDCA burst Tx Opportunity, in 32-usec units. | ||
1628 | * Set this if txop time is not specified by HCCA protocol (e.g. by AP). | ||
1629 | */ | ||
1630 | __le16 driver_txop; | ||
1631 | |||
1632 | /* | ||
1633 | * MAC header goes here, followed by 2 bytes padding if MAC header | ||
1634 | * length is 26 or 30 bytes, followed by payload data | ||
1635 | */ | ||
1636 | u8 payload[0]; | ||
1637 | struct ieee80211_hdr hdr[0]; | ||
1638 | } __packed; | ||
1639 | |||
1640 | /* | ||
1641 | * REPLY_TX = 0x1c (response) | ||
1642 | */ | ||
1643 | struct iwl3945_tx_resp { | ||
1644 | u8 failure_rts; | ||
1645 | u8 failure_frame; | ||
1646 | u8 bt_kill_count; | ||
1647 | u8 rate; | ||
1648 | __le32 wireless_media_time; | ||
1649 | __le32 status; /* TX status */ | ||
1650 | } __packed; | ||
1651 | |||
1652 | |||
1653 | /* | 1251 | /* |
1654 | * 4965 uCode updates these Tx attempt count values in host DRAM. | 1252 | * 4965 uCode updates these Tx attempt count values in host DRAM. |
1655 | * Used for managing Tx retries when expecting block-acks. | 1253 | * Used for managing Tx retries when expecting block-acks. |
@@ -1740,54 +1338,6 @@ struct iwl_tx_cmd { | |||
1740 | struct ieee80211_hdr hdr[0]; | 1338 | struct ieee80211_hdr hdr[0]; |
1741 | } __packed; | 1339 | } __packed; |
1742 | 1340 | ||
1743 | /* TX command response is sent after *3945* transmission attempts. | ||
1744 | * | ||
1745 | * NOTES: | ||
1746 | * | ||
1747 | * TX_STATUS_FAIL_NEXT_FRAG | ||
1748 | * | ||
1749 | * If the fragment flag in the MAC header for the frame being transmitted | ||
1750 | * is set and there is insufficient time to transmit the next frame, the | ||
1751 | * TX status will be returned with 'TX_STATUS_FAIL_NEXT_FRAG'. | ||
1752 | * | ||
1753 | * TX_STATUS_FIFO_UNDERRUN | ||
1754 | * | ||
1755 | * Indicates the host did not provide bytes to the FIFO fast enough while | ||
1756 | * a TX was in progress. | ||
1757 | * | ||
1758 | * TX_STATUS_FAIL_MGMNT_ABORT | ||
1759 | * | ||
1760 | * This status is only possible if the ABORT ON MGMT RX parameter was | ||
1761 | * set to true with the TX command. | ||
1762 | * | ||
1763 | * If the MSB of the status parameter is set then an abort sequence is | ||
1764 | * required. This sequence consists of the host activating the TX Abort | ||
1765 | * control line, and then waiting for the TX Abort command response. This | ||
1766 | * indicates that a the device is no longer in a transmit state, and that the | ||
1767 | * command FIFO has been cleared. The host must then deactivate the TX Abort | ||
1768 | * control line. Receiving is still allowed in this case. | ||
1769 | */ | ||
1770 | enum { | ||
1771 | TX_3945_STATUS_SUCCESS = 0x01, | ||
1772 | TX_3945_STATUS_DIRECT_DONE = 0x02, | ||
1773 | TX_3945_STATUS_FAIL_SHORT_LIMIT = 0x82, | ||
1774 | TX_3945_STATUS_FAIL_LONG_LIMIT = 0x83, | ||
1775 | TX_3945_STATUS_FAIL_FIFO_UNDERRUN = 0x84, | ||
1776 | TX_3945_STATUS_FAIL_MGMNT_ABORT = 0x85, | ||
1777 | TX_3945_STATUS_FAIL_NEXT_FRAG = 0x86, | ||
1778 | TX_3945_STATUS_FAIL_LIFE_EXPIRE = 0x87, | ||
1779 | TX_3945_STATUS_FAIL_DEST_PS = 0x88, | ||
1780 | TX_3945_STATUS_FAIL_ABORTED = 0x89, | ||
1781 | TX_3945_STATUS_FAIL_BT_RETRY = 0x8a, | ||
1782 | TX_3945_STATUS_FAIL_STA_INVALID = 0x8b, | ||
1783 | TX_3945_STATUS_FAIL_FRAG_DROPPED = 0x8c, | ||
1784 | TX_3945_STATUS_FAIL_TID_DISABLE = 0x8d, | ||
1785 | TX_3945_STATUS_FAIL_FRAME_FLUSHED = 0x8e, | ||
1786 | TX_3945_STATUS_FAIL_INSUFFICIENT_CF_POLL = 0x8f, | ||
1787 | TX_3945_STATUS_FAIL_TX_LOCKED = 0x90, | ||
1788 | TX_3945_STATUS_FAIL_NO_BEACON_ON_RADAR = 0x91, | ||
1789 | }; | ||
1790 | |||
1791 | /* | 1341 | /* |
1792 | * TX command response is sent after *agn* transmission attempts. | 1342 | * TX command response is sent after *agn* transmission attempts. |
1793 | * | 1343 | * |
@@ -1905,43 +1455,6 @@ struct agg_tx_status { | |||
1905 | __le16 sequence; | 1455 | __le16 sequence; |
1906 | } __packed; | 1456 | } __packed; |
1907 | 1457 | ||
1908 | struct iwl4965_tx_resp { | ||
1909 | u8 frame_count; /* 1 no aggregation, >1 aggregation */ | ||
1910 | u8 bt_kill_count; /* # blocked by bluetooth (unused for agg) */ | ||
1911 | u8 failure_rts; /* # failures due to unsuccessful RTS */ | ||
1912 | u8 failure_frame; /* # failures due to no ACK (unused for agg) */ | ||
1913 | |||
1914 | /* For non-agg: Rate at which frame was successful. | ||
1915 | * For agg: Rate at which all frames were transmitted. */ | ||
1916 | __le32 rate_n_flags; /* RATE_MCS_* */ | ||
1917 | |||
1918 | /* For non-agg: RTS + CTS + frame tx attempts time + ACK. | ||
1919 | * For agg: RTS + CTS + aggregation tx time + block-ack time. */ | ||
1920 | __le16 wireless_media_time; /* uSecs */ | ||
1921 | |||
1922 | __le16 reserved; | ||
1923 | __le32 pa_power1; /* RF power amplifier measurement (not used) */ | ||
1924 | __le32 pa_power2; | ||
1925 | |||
1926 | /* | ||
1927 | * For non-agg: frame status TX_STATUS_* | ||
1928 | * For agg: status of 1st frame, AGG_TX_STATE_*; other frame status | ||
1929 | * fields follow this one, up to frame_count. | ||
1930 | * Bit fields: | ||
1931 | * 11- 0: AGG_TX_STATE_* status code | ||
1932 | * 15-12: Retry count for 1st frame in aggregation (retries | ||
1933 | * occur if tx failed for this frame when it was a | ||
1934 | * member of a previous aggregation block). If rate | ||
1935 | * scaling is used, retry count indicates the rate | ||
1936 | * table entry used for all frames in the new agg. | ||
1937 | * 31-16: Sequence # for this frame's Tx cmd (not SSN!) | ||
1938 | */ | ||
1939 | union { | ||
1940 | __le32 status; | ||
1941 | struct agg_tx_status agg_status[0]; /* for each agg frame */ | ||
1942 | } u; | ||
1943 | } __packed; | ||
1944 | |||
1945 | /* | 1458 | /* |
1946 | * definitions for initial rate index field | 1459 | * definitions for initial rate index field |
1947 | * bits [3:0] initial rate index | 1460 | * bits [3:0] initial rate index |
@@ -2030,51 +1543,7 @@ struct iwl_compressed_ba_resp { | |||
2030 | /* | 1543 | /* |
2031 | * REPLY_TX_PWR_TABLE_CMD = 0x97 (command, has simple generic response) | 1544 | * REPLY_TX_PWR_TABLE_CMD = 0x97 (command, has simple generic response) |
2032 | * | 1545 | * |
2033 | * See details under "TXPOWER" in iwl-4965-hw.h. | ||
2034 | */ | ||
2035 | |||
2036 | struct iwl3945_txpowertable_cmd { | ||
2037 | u8 band; /* 0: 5 GHz, 1: 2.4 GHz */ | ||
2038 | u8 reserved; | ||
2039 | __le16 channel; | ||
2040 | struct iwl3945_power_per_rate power[IWL_MAX_RATES]; | ||
2041 | } __packed; | ||
2042 | |||
2043 | struct iwl4965_txpowertable_cmd { | ||
2044 | u8 band; /* 0: 5 GHz, 1: 2.4 GHz */ | ||
2045 | u8 reserved; | ||
2046 | __le16 channel; | ||
2047 | struct iwl4965_tx_power_db tx_power; | ||
2048 | } __packed; | ||
2049 | |||
2050 | |||
2051 | /** | ||
2052 | * struct iwl3945_rate_scaling_cmd - Rate Scaling Command & Response | ||
2053 | * | ||
2054 | * REPLY_RATE_SCALE = 0x47 (command, has simple generic response) | ||
2055 | * | ||
2056 | * NOTE: The table of rates passed to the uCode via the | ||
2057 | * RATE_SCALE command sets up the corresponding order of | ||
2058 | * rates used for all related commands, including rate | ||
2059 | * masks, etc. | ||
2060 | * | ||
2061 | * For example, if you set 9MB (PLCP 0x0f) as the first | ||
2062 | * rate in the rate table, the bit mask for that rate | ||
2063 | * when passed through ofdm_basic_rates on the REPLY_RXON | ||
2064 | * command would be bit 0 (1 << 0) | ||
2065 | */ | 1546 | */ |
2066 | struct iwl3945_rate_scaling_info { | ||
2067 | __le16 rate_n_flags; | ||
2068 | u8 try_cnt; | ||
2069 | u8 next_rate_index; | ||
2070 | } __packed; | ||
2071 | |||
2072 | struct iwl3945_rate_scaling_cmd { | ||
2073 | u8 table_id; | ||
2074 | u8 reserved[3]; | ||
2075 | struct iwl3945_rate_scaling_info table[IWL_MAX_RATES]; | ||
2076 | } __packed; | ||
2077 | |||
2078 | 1547 | ||
2079 | /*RS_NEW_API: only TLC_RTS remains and moved to bit 0 */ | 1548 | /*RS_NEW_API: only TLC_RTS remains and moved to bit 0 */ |
2080 | #define LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK (1 << 0) | 1549 | #define LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK (1 << 0) |
@@ -2130,7 +1599,7 @@ struct iwl_link_qual_general_params { | |||
2130 | #define LINK_QUAL_AGG_DISABLE_START_MAX (255) | 1599 | #define LINK_QUAL_AGG_DISABLE_START_MAX (255) |
2131 | #define LINK_QUAL_AGG_DISABLE_START_MIN (0) | 1600 | #define LINK_QUAL_AGG_DISABLE_START_MIN (0) |
2132 | 1601 | ||
2133 | #define LINK_QUAL_AGG_FRAME_LIMIT_DEF (31) | 1602 | #define LINK_QUAL_AGG_FRAME_LIMIT_DEF (63) |
2134 | #define LINK_QUAL_AGG_FRAME_LIMIT_MAX (63) | 1603 | #define LINK_QUAL_AGG_FRAME_LIMIT_MAX (63) |
2135 | #define LINK_QUAL_AGG_FRAME_LIMIT_MIN (0) | 1604 | #define LINK_QUAL_AGG_FRAME_LIMIT_MIN (0) |
2136 | 1605 | ||
@@ -2696,14 +2165,6 @@ struct iwl_spectrum_notification { | |||
2696 | #define IWL_POWER_BT_SCO_ENA cpu_to_le16(BIT(8)) | 2165 | #define IWL_POWER_BT_SCO_ENA cpu_to_le16(BIT(8)) |
2697 | #define IWL_POWER_ADVANCE_PM_ENA_MSK cpu_to_le16(BIT(9)) | 2166 | #define IWL_POWER_ADVANCE_PM_ENA_MSK cpu_to_le16(BIT(9)) |
2698 | 2167 | ||
2699 | struct iwl3945_powertable_cmd { | ||
2700 | __le16 flags; | ||
2701 | u8 reserved[2]; | ||
2702 | __le32 rx_data_timeout; | ||
2703 | __le32 tx_data_timeout; | ||
2704 | __le32 sleep_interval[IWL_POWER_VEC_SIZE]; | ||
2705 | } __packed; | ||
2706 | |||
2707 | struct iwl_powertable_cmd { | 2168 | struct iwl_powertable_cmd { |
2708 | __le16 flags; | 2169 | __le16 flags; |
2709 | u8 keep_alive_seconds; /* 3945 reserved */ | 2170 | u8 keep_alive_seconds; /* 3945 reserved */ |
@@ -2806,25 +2267,6 @@ struct iwl_ct_kill_throttling_config { | |||
2806 | * active_dwell < max_out_time | 2267 | * active_dwell < max_out_time |
2807 | */ | 2268 | */ |
2808 | 2269 | ||
2809 | /* FIXME: rename to AP1, remove tpc */ | ||
2810 | struct iwl3945_scan_channel { | ||
2811 | /* | ||
2812 | * type is defined as: | ||
2813 | * 0:0 1 = active, 0 = passive | ||
2814 | * 1:4 SSID direct bit map; if a bit is set, then corresponding | ||
2815 | * SSID IE is transmitted in probe request. | ||
2816 | * 5:7 reserved | ||
2817 | */ | ||
2818 | u8 type; | ||
2819 | u8 channel; /* band is selected by iwl3945_scan_cmd "flags" field */ | ||
2820 | struct iwl3945_tx_power tpc; | ||
2821 | __le16 active_dwell; /* in 1024-uSec TU (time units), typ 5-50 */ | ||
2822 | __le16 passive_dwell; /* in 1024-uSec TU (time units), typ 20-500 */ | ||
2823 | } __packed; | ||
2824 | |||
2825 | /* set number of direct probes u8 type */ | ||
2826 | #define IWL39_SCAN_PROBE_MASK(n) ((BIT(n) | (BIT(n) - BIT(1)))) | ||
2827 | |||
2828 | struct iwl_scan_channel { | 2270 | struct iwl_scan_channel { |
2829 | /* | 2271 | /* |
2830 | * type is defined as: | 2272 | * type is defined as: |
@@ -2920,50 +2362,6 @@ struct iwl_ssid_ie { | |||
2920 | * struct iwl_scan_channel. | 2362 | * struct iwl_scan_channel. |
2921 | */ | 2363 | */ |
2922 | 2364 | ||
2923 | struct iwl3945_scan_cmd { | ||
2924 | __le16 len; | ||
2925 | u8 reserved0; | ||
2926 | u8 channel_count; /* # channels in channel list */ | ||
2927 | __le16 quiet_time; /* dwell only this # millisecs on quiet channel | ||
2928 | * (only for active scan) */ | ||
2929 | __le16 quiet_plcp_th; /* quiet chnl is < this # pkts (typ. 1) */ | ||
2930 | __le16 good_CRC_th; /* passive -> active promotion threshold */ | ||
2931 | __le16 reserved1; | ||
2932 | __le32 max_out_time; /* max usec to be away from associated (service) | ||
2933 | * channel */ | ||
2934 | __le32 suspend_time; /* pause scan this long (in "extended beacon | ||
2935 | * format") when returning to service channel: | ||
2936 | * 3945; 31:24 # beacons, 19:0 additional usec, | ||
2937 | * 4965; 31:22 # beacons, 21:0 additional usec. | ||
2938 | */ | ||
2939 | __le32 flags; /* RXON_FLG_* */ | ||
2940 | __le32 filter_flags; /* RXON_FILTER_* */ | ||
2941 | |||
2942 | /* For active scans (set to all-0s for passive scans). | ||
2943 | * Does not include payload. Must specify Tx rate; no rate scaling. */ | ||
2944 | struct iwl3945_tx_cmd tx_cmd; | ||
2945 | |||
2946 | /* For directed active scans (set to all-0s otherwise) */ | ||
2947 | struct iwl_ssid_ie direct_scan[PROBE_OPTION_MAX_3945]; | ||
2948 | |||
2949 | /* | ||
2950 | * Probe request frame, followed by channel list. | ||
2951 | * | ||
2952 | * Size of probe request frame is specified by byte count in tx_cmd. | ||
2953 | * Channel list follows immediately after probe request frame. | ||
2954 | * Number of channels in list is specified by channel_count. | ||
2955 | * Each channel in list is of type: | ||
2956 | * | ||
2957 | * struct iwl3945_scan_channel channels[0]; | ||
2958 | * | ||
2959 | * NOTE: Only one band of channels can be scanned per pass. You | ||
2960 | * must not mix 2.4GHz channels and 5.2GHz channels, and you must wait | ||
2961 | * for one scan to complete (i.e. receive SCAN_COMPLETE_NOTIFICATION) | ||
2962 | * before requesting another scan. | ||
2963 | */ | ||
2964 | u8 data[0]; | ||
2965 | } __packed; | ||
2966 | |||
2967 | enum iwl_scan_flags { | 2365 | enum iwl_scan_flags { |
2968 | /* BIT(0) currently unused */ | 2366 | /* BIT(0) currently unused */ |
2969 | IWL_SCAN_FLAGS_ACTION_FRAME_TX = BIT(1), | 2367 | IWL_SCAN_FLAGS_ACTION_FRAME_TX = BIT(1), |
@@ -3090,20 +2488,6 @@ enum iwl_ibss_manager { | |||
3090 | * BEACON_NOTIFICATION = 0x90 (notification only, not a command) | 2488 | * BEACON_NOTIFICATION = 0x90 (notification only, not a command) |
3091 | */ | 2489 | */ |
3092 | 2490 | ||
3093 | struct iwl3945_beacon_notif { | ||
3094 | struct iwl3945_tx_resp beacon_notify_hdr; | ||
3095 | __le32 low_tsf; | ||
3096 | __le32 high_tsf; | ||
3097 | __le32 ibss_mgr_status; | ||
3098 | } __packed; | ||
3099 | |||
3100 | struct iwl4965_beacon_notif { | ||
3101 | struct iwl4965_tx_resp beacon_notify_hdr; | ||
3102 | __le32 low_tsf; | ||
3103 | __le32 high_tsf; | ||
3104 | __le32 ibss_mgr_status; | ||
3105 | } __packed; | ||
3106 | |||
3107 | struct iwlagn_beacon_notif { | 2491 | struct iwlagn_beacon_notif { |
3108 | struct iwlagn_tx_resp beacon_notify_hdr; | 2492 | struct iwlagn_tx_resp beacon_notify_hdr; |
3109 | __le32 low_tsf; | 2493 | __le32 low_tsf; |
@@ -3115,14 +2499,6 @@ struct iwlagn_beacon_notif { | |||
3115 | * REPLY_TX_BEACON = 0x91 (command, has simple generic response) | 2499 | * REPLY_TX_BEACON = 0x91 (command, has simple generic response) |
3116 | */ | 2500 | */ |
3117 | 2501 | ||
3118 | struct iwl3945_tx_beacon_cmd { | ||
3119 | struct iwl3945_tx_cmd tx; | ||
3120 | __le16 tim_idx; | ||
3121 | u8 tim_size; | ||
3122 | u8 reserved1; | ||
3123 | struct ieee80211_hdr frame[0]; /* beacon frame */ | ||
3124 | } __packed; | ||
3125 | |||
3126 | struct iwl_tx_beacon_cmd { | 2502 | struct iwl_tx_beacon_cmd { |
3127 | struct iwl_tx_cmd tx; | 2503 | struct iwl_tx_cmd tx; |
3128 | __le16 tim_idx; | 2504 | __le16 tim_idx; |
@@ -3471,13 +2847,6 @@ struct iwl_statistics_cmd { | |||
3471 | #define STATISTICS_REPLY_FLG_BAND_24G_MSK cpu_to_le32(0x2) | 2847 | #define STATISTICS_REPLY_FLG_BAND_24G_MSK cpu_to_le32(0x2) |
3472 | #define STATISTICS_REPLY_FLG_HT40_MODE_MSK cpu_to_le32(0x8) | 2848 | #define STATISTICS_REPLY_FLG_HT40_MODE_MSK cpu_to_le32(0x8) |
3473 | 2849 | ||
3474 | struct iwl3945_notif_statistics { | ||
3475 | __le32 flag; | ||
3476 | struct iwl39_statistics_rx rx; | ||
3477 | struct iwl39_statistics_tx tx; | ||
3478 | struct iwl39_statistics_general general; | ||
3479 | } __packed; | ||
3480 | |||
3481 | struct iwl_notif_statistics { | 2850 | struct iwl_notif_statistics { |
3482 | __le32 flag; | 2851 | __le32 flag; |
3483 | struct statistics_rx rx; | 2852 | struct statistics_rx rx; |
@@ -4451,10 +3820,6 @@ struct iwl_rx_packet { | |||
4451 | __le32 len_n_flags; | 3820 | __le32 len_n_flags; |
4452 | struct iwl_cmd_header hdr; | 3821 | struct iwl_cmd_header hdr; |
4453 | union { | 3822 | union { |
4454 | struct iwl3945_rx_frame rx_frame; | ||
4455 | struct iwl3945_tx_resp tx_resp; | ||
4456 | struct iwl3945_beacon_notif beacon_status; | ||
4457 | |||
4458 | struct iwl_alive_resp alive_frame; | 3823 | struct iwl_alive_resp alive_frame; |
4459 | struct iwl_spectrum_notification spectrum_notif; | 3824 | struct iwl_spectrum_notification spectrum_notif; |
4460 | struct iwl_csa_notification csa_notif; | 3825 | struct iwl_csa_notification csa_notif; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index bafbe57c9602..45ec5cfe3fcf 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * | 2 | * |
3 | * GPL LICENSE SUMMARY | 3 | * GPL LICENSE SUMMARY |
4 | * | 4 | * |
5 | * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. | 5 | * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of version 2 of the GNU General Public License as | 8 | * it under the terms of version 2 of the GNU General Public License as |
@@ -890,10 +890,8 @@ void iwl_print_rx_config_cmd(struct iwl_priv *priv, | |||
890 | IWL_DEBUG_RADIO(priv, "u16 assoc_id: 0x%x\n", le16_to_cpu(rxon->assoc_id)); | 890 | IWL_DEBUG_RADIO(priv, "u16 assoc_id: 0x%x\n", le16_to_cpu(rxon->assoc_id)); |
891 | } | 891 | } |
892 | #endif | 892 | #endif |
893 | /** | 893 | |
894 | * iwl_irq_handle_error - called for HW or SW error interrupt from card | 894 | void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand) |
895 | */ | ||
896 | void iwl_irq_handle_error(struct iwl_priv *priv) | ||
897 | { | 895 | { |
898 | unsigned int reload_msec; | 896 | unsigned int reload_msec; |
899 | unsigned long reload_jiffies; | 897 | unsigned long reload_jiffies; |
@@ -904,18 +902,62 @@ void iwl_irq_handle_error(struct iwl_priv *priv) | |||
904 | /* Cancel currently queued command. */ | 902 | /* Cancel currently queued command. */ |
905 | clear_bit(STATUS_HCMD_ACTIVE, &priv->status); | 903 | clear_bit(STATUS_HCMD_ACTIVE, &priv->status); |
906 | 904 | ||
905 | /* Keep the restart process from trying to send host | ||
906 | * commands by clearing the ready bit */ | ||
907 | clear_bit(STATUS_READY, &priv->status); | ||
908 | |||
909 | wake_up_interruptible(&priv->wait_command_queue); | ||
910 | |||
911 | if (!ondemand) { | ||
912 | /* | ||
913 | * If firmware keep reloading, then it indicate something | ||
914 | * serious wrong and firmware having problem to recover | ||
915 | * from it. Instead of keep trying which will fill the syslog | ||
916 | * and hang the system, let's just stop it | ||
917 | */ | ||
918 | reload_jiffies = jiffies; | ||
919 | reload_msec = jiffies_to_msecs((long) reload_jiffies - | ||
920 | (long) priv->reload_jiffies); | ||
921 | priv->reload_jiffies = reload_jiffies; | ||
922 | if (reload_msec <= IWL_MIN_RELOAD_DURATION) { | ||
923 | priv->reload_count++; | ||
924 | if (priv->reload_count >= IWL_MAX_CONTINUE_RELOAD_CNT) { | ||
925 | IWL_ERR(priv, "BUG_ON, Stop restarting\n"); | ||
926 | return; | ||
927 | } | ||
928 | } else | ||
929 | priv->reload_count = 0; | ||
930 | } | ||
931 | |||
932 | if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) { | ||
933 | if (priv->cfg->mod_params->restart_fw) { | ||
934 | IWL_DEBUG(priv, IWL_DL_FW_ERRORS, | ||
935 | "Restarting adapter due to uCode error.\n"); | ||
936 | queue_work(priv->workqueue, &priv->restart); | ||
937 | } else | ||
938 | IWL_DEBUG(priv, IWL_DL_FW_ERRORS, | ||
939 | "Detected FW error, but not restarting\n"); | ||
940 | } | ||
941 | } | ||
942 | |||
943 | /** | ||
944 | * iwl_irq_handle_error - called for HW or SW error interrupt from card | ||
945 | */ | ||
946 | void iwl_irq_handle_error(struct iwl_priv *priv) | ||
947 | { | ||
907 | /* W/A for WiFi/WiMAX coex and WiMAX own the RF */ | 948 | /* W/A for WiFi/WiMAX coex and WiMAX own the RF */ |
908 | if (priv->cfg->internal_wimax_coex && | 949 | if (priv->cfg->internal_wimax_coex && |
909 | (!(iwl_read_prph(priv, APMG_CLK_CTRL_REG) & | 950 | (!(iwl_read_prph(priv, APMG_CLK_CTRL_REG) & |
910 | APMS_CLK_VAL_MRB_FUNC_MODE) || | 951 | APMS_CLK_VAL_MRB_FUNC_MODE) || |
911 | (iwl_read_prph(priv, APMG_PS_CTRL_REG) & | 952 | (iwl_read_prph(priv, APMG_PS_CTRL_REG) & |
912 | APMG_PS_CTRL_VAL_RESET_REQ))) { | 953 | APMG_PS_CTRL_VAL_RESET_REQ))) { |
913 | wake_up_interruptible(&priv->wait_command_queue); | ||
914 | /* | 954 | /* |
915 | *Keep the restart process from trying to send host | 955 | * Keep the restart process from trying to send host |
916 | * commands by clearing the INIT status bit | 956 | * commands by clearing the ready bit. |
917 | */ | 957 | */ |
918 | clear_bit(STATUS_READY, &priv->status); | 958 | clear_bit(STATUS_READY, &priv->status); |
959 | clear_bit(STATUS_HCMD_ACTIVE, &priv->status); | ||
960 | wake_up_interruptible(&priv->wait_command_queue); | ||
919 | IWL_ERR(priv, "RF is used by WiMAX\n"); | 961 | IWL_ERR(priv, "RF is used by WiMAX\n"); |
920 | return; | 962 | return; |
921 | } | 963 | } |
@@ -935,38 +977,7 @@ void iwl_irq_handle_error(struct iwl_priv *priv) | |||
935 | &priv->contexts[IWL_RXON_CTX_BSS]); | 977 | &priv->contexts[IWL_RXON_CTX_BSS]); |
936 | #endif | 978 | #endif |
937 | 979 | ||
938 | wake_up_interruptible(&priv->wait_command_queue); | 980 | iwlagn_fw_error(priv, false); |
939 | |||
940 | /* Keep the restart process from trying to send host | ||
941 | * commands by clearing the INIT status bit */ | ||
942 | clear_bit(STATUS_READY, &priv->status); | ||
943 | |||
944 | /* | ||
945 | * If firmware keep reloading, then it indicate something | ||
946 | * serious wrong and firmware having problem to recover | ||
947 | * from it. Instead of keep trying which will fill the syslog | ||
948 | * and hang the system, let's just stop it | ||
949 | */ | ||
950 | reload_jiffies = jiffies; | ||
951 | reload_msec = jiffies_to_msecs((long) reload_jiffies - | ||
952 | (long) priv->reload_jiffies); | ||
953 | priv->reload_jiffies = reload_jiffies; | ||
954 | if (reload_msec <= IWL_MIN_RELOAD_DURATION) { | ||
955 | priv->reload_count++; | ||
956 | if (priv->reload_count >= IWL_MAX_CONTINUE_RELOAD_CNT) { | ||
957 | IWL_ERR(priv, "BUG_ON, Stop restarting\n"); | ||
958 | return; | ||
959 | } | ||
960 | } else | ||
961 | priv->reload_count = 0; | ||
962 | |||
963 | if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) { | ||
964 | IWL_DEBUG(priv, IWL_DL_FW_ERRORS, | ||
965 | "Restarting adapter due to uCode error.\n"); | ||
966 | |||
967 | if (priv->cfg->mod_params->restart_fw) | ||
968 | queue_work(priv->workqueue, &priv->restart); | ||
969 | } | ||
970 | } | 981 | } |
971 | 982 | ||
972 | static int iwl_apm_stop_master(struct iwl_priv *priv) | 983 | static int iwl_apm_stop_master(struct iwl_priv *priv) |
@@ -1094,21 +1105,13 @@ int iwl_apm_init(struct iwl_priv *priv) | |||
1094 | } | 1105 | } |
1095 | 1106 | ||
1096 | /* | 1107 | /* |
1097 | * Enable DMA and BSM (if used) clocks, wait for them to stabilize. | 1108 | * Enable DMA clock and wait for it to stabilize. |
1098 | * BSM (Boostrap State Machine) is only in 3945 and 4965; | ||
1099 | * later devices (i.e. 5000 and later) have non-volatile SRAM, | ||
1100 | * and don't need BSM to restore data after power-saving sleep. | ||
1101 | * | 1109 | * |
1102 | * Write to "CLK_EN_REG"; "1" bits enable clocks, while "0" bits | 1110 | * Write to "CLK_EN_REG"; "1" bits enable clocks, while "0" bits |
1103 | * do not disable clocks. This preserves any hardware bits already | 1111 | * do not disable clocks. This preserves any hardware bits already |
1104 | * set by default in "CLK_CTRL_REG" after reset. | 1112 | * set by default in "CLK_CTRL_REG" after reset. |
1105 | */ | 1113 | */ |
1106 | if (priv->cfg->base_params->use_bsm) | 1114 | iwl_write_prph(priv, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT); |
1107 | iwl_write_prph(priv, APMG_CLK_EN_REG, | ||
1108 | APMG_CLK_VAL_DMA_CLK_RQT | APMG_CLK_VAL_BSM_CLK_RQT); | ||
1109 | else | ||
1110 | iwl_write_prph(priv, APMG_CLK_EN_REG, | ||
1111 | APMG_CLK_VAL_DMA_CLK_RQT); | ||
1112 | udelay(20); | 1115 | udelay(20); |
1113 | 1116 | ||
1114 | /* Disable L1-Active */ | 1117 | /* Disable L1-Active */ |
@@ -1430,7 +1433,6 @@ void iwl_mac_remove_interface(struct ieee80211_hw *hw, | |||
1430 | 1433 | ||
1431 | iwl_teardown_interface(priv, vif, false); | 1434 | iwl_teardown_interface(priv, vif, false); |
1432 | 1435 | ||
1433 | memset(priv->bssid, 0, ETH_ALEN); | ||
1434 | mutex_unlock(&priv->mutex); | 1436 | mutex_unlock(&priv->mutex); |
1435 | 1437 | ||
1436 | IWL_DEBUG_MAC80211(priv, "leave\n"); | 1438 | IWL_DEBUG_MAC80211(priv, "leave\n"); |
@@ -1756,15 +1758,7 @@ int iwl_force_reset(struct iwl_priv *priv, int mode, bool external) | |||
1756 | break; | 1758 | break; |
1757 | } | 1759 | } |
1758 | IWL_ERR(priv, "On demand firmware reload\n"); | 1760 | IWL_ERR(priv, "On demand firmware reload\n"); |
1759 | /* Set the FW error flag -- cleared on iwl_down */ | 1761 | iwlagn_fw_error(priv, true); |
1760 | set_bit(STATUS_FW_ERROR, &priv->status); | ||
1761 | wake_up_interruptible(&priv->wait_command_queue); | ||
1762 | /* | ||
1763 | * Keep the restart process from trying to send host | ||
1764 | * commands by clearing the INIT status bit | ||
1765 | */ | ||
1766 | clear_bit(STATUS_READY, &priv->status); | ||
1767 | queue_work(priv->workqueue, &priv->restart); | ||
1768 | break; | 1762 | break; |
1769 | } | 1763 | } |
1770 | return 0; | 1764 | return 0; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index b316d833d9a2..82939f851eb9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h | |||
@@ -5,7 +5,7 @@ | |||
5 | * | 5 | * |
6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
7 | * | 7 | * |
8 | * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of version 2 of the GNU General Public License as | 11 | * it under the terms of version 2 of the GNU General Public License as |
@@ -30,7 +30,7 @@ | |||
30 | * | 30 | * |
31 | * BSD LICENSE | 31 | * BSD LICENSE |
32 | * | 32 | * |
33 | * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. | 33 | * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. |
34 | * All rights reserved. | 34 | * All rights reserved. |
35 | * | 35 | * |
36 | * Redistribution and use in source and binary forms, with or without | 36 | * Redistribution and use in source and binary forms, with or without |
@@ -73,7 +73,7 @@ struct iwl_cmd; | |||
73 | 73 | ||
74 | 74 | ||
75 | #define IWLWIFI_VERSION "in-tree:" | 75 | #define IWLWIFI_VERSION "in-tree:" |
76 | #define DRV_COPYRIGHT "Copyright(c) 2003-2010 Intel Corporation" | 76 | #define DRV_COPYRIGHT "Copyright(c) 2003-2011 Intel Corporation" |
77 | #define DRV_AUTHOR "<ilw@linux.intel.com>" | 77 | #define DRV_AUTHOR "<ilw@linux.intel.com>" |
78 | 78 | ||
79 | #define IWL_PCI_DEVICE(dev, subdev, cfg) \ | 79 | #define IWL_PCI_DEVICE(dev, subdev, cfg) \ |
@@ -122,14 +122,6 @@ struct iwl_apm_ops { | |||
122 | void (*config)(struct iwl_priv *priv); | 122 | void (*config)(struct iwl_priv *priv); |
123 | }; | 123 | }; |
124 | 124 | ||
125 | struct iwl_isr_ops { | ||
126 | irqreturn_t (*isr) (int irq, void *data); | ||
127 | void (*free)(struct iwl_priv *priv); | ||
128 | int (*alloc)(struct iwl_priv *priv); | ||
129 | int (*reset)(struct iwl_priv *priv); | ||
130 | void (*disable)(struct iwl_priv *priv); | ||
131 | }; | ||
132 | |||
133 | struct iwl_debugfs_ops { | 125 | struct iwl_debugfs_ops { |
134 | ssize_t (*rx_stats_read)(struct file *file, char __user *user_buf, | 126 | ssize_t (*rx_stats_read)(struct file *file, char __user *user_buf, |
135 | size_t count, loff_t *ppos); | 127 | size_t count, loff_t *ppos); |
@@ -171,25 +163,15 @@ struct iwl_lib_ops { | |||
171 | struct iwl_tx_queue *txq); | 163 | struct iwl_tx_queue *txq); |
172 | int (*txq_init)(struct iwl_priv *priv, | 164 | int (*txq_init)(struct iwl_priv *priv, |
173 | struct iwl_tx_queue *txq); | 165 | struct iwl_tx_queue *txq); |
174 | /* aggregations */ | ||
175 | int (*txq_agg_enable)(struct iwl_priv *priv, int txq_id, int tx_fifo, | ||
176 | int sta_id, int tid, u16 ssn_idx); | ||
177 | int (*txq_agg_disable)(struct iwl_priv *priv, u16 txq_id, u16 ssn_idx, | ||
178 | u8 tx_fifo); | ||
179 | /* setup Rx handler */ | 166 | /* setup Rx handler */ |
180 | void (*rx_handler_setup)(struct iwl_priv *priv); | 167 | void (*rx_handler_setup)(struct iwl_priv *priv); |
181 | /* setup deferred work */ | 168 | /* setup deferred work */ |
182 | void (*setup_deferred_work)(struct iwl_priv *priv); | 169 | void (*setup_deferred_work)(struct iwl_priv *priv); |
183 | /* cancel deferred work */ | 170 | /* cancel deferred work */ |
184 | void (*cancel_deferred_work)(struct iwl_priv *priv); | 171 | void (*cancel_deferred_work)(struct iwl_priv *priv); |
185 | /* alive notification after init uCode load */ | ||
186 | void (*init_alive_start)(struct iwl_priv *priv); | ||
187 | /* alive notification */ | ||
188 | int (*alive_notify)(struct iwl_priv *priv); | ||
189 | /* check validity of rtc data address */ | 172 | /* check validity of rtc data address */ |
190 | int (*is_valid_rtc_data_addr)(u32 addr); | 173 | int (*is_valid_rtc_data_addr)(u32 addr); |
191 | /* 1st ucode load */ | 174 | |
192 | int (*load_ucode)(struct iwl_priv *priv); | ||
193 | int (*dump_nic_event_log)(struct iwl_priv *priv, | 175 | int (*dump_nic_event_log)(struct iwl_priv *priv, |
194 | bool full_log, char **buf, bool display); | 176 | bool full_log, char **buf, bool display); |
195 | void (*dump_nic_error_log)(struct iwl_priv *priv); | 177 | void (*dump_nic_error_log)(struct iwl_priv *priv); |
@@ -204,9 +186,6 @@ struct iwl_lib_ops { | |||
204 | int (*send_tx_power) (struct iwl_priv *priv); | 186 | int (*send_tx_power) (struct iwl_priv *priv); |
205 | void (*update_chain_flags)(struct iwl_priv *priv); | 187 | void (*update_chain_flags)(struct iwl_priv *priv); |
206 | 188 | ||
207 | /* isr */ | ||
208 | struct iwl_isr_ops isr_ops; | ||
209 | |||
210 | /* eeprom operations (as defined in iwl-eeprom.h) */ | 189 | /* eeprom operations (as defined in iwl-eeprom.h) */ |
211 | struct iwl_eeprom_ops eeprom_ops; | 190 | struct iwl_eeprom_ops eeprom_ops; |
212 | 191 | ||
@@ -252,7 +231,6 @@ struct iwl_ops { | |||
252 | 231 | ||
253 | struct iwl_mod_params { | 232 | struct iwl_mod_params { |
254 | int sw_crypto; /* def: 0 = using hardware encryption */ | 233 | int sw_crypto; /* def: 0 = using hardware encryption */ |
255 | int disable_hw_scan; /* def: 0 = use h/w scan */ | ||
256 | int num_of_queues; /* def: HW dependent */ | 234 | int num_of_queues; /* def: HW dependent */ |
257 | int disable_11n; /* def: 0 = 11n capabilities enabled */ | 235 | int disable_11n; /* def: 0 = 11n capabilities enabled */ |
258 | int amsdu_size_8K; /* def: 1 = enable 8K amsdu size */ | 236 | int amsdu_size_8K; /* def: 1 = enable 8K amsdu size */ |
@@ -286,8 +264,6 @@ struct iwl_mod_params { | |||
286 | * @chain_noise_calib_by_driver: driver has the capability to perform | 264 | * @chain_noise_calib_by_driver: driver has the capability to perform |
287 | * chain noise calibration operation | 265 | * chain noise calibration operation |
288 | * @shadow_reg_enable: HW shadhow register bit | 266 | * @shadow_reg_enable: HW shadhow register bit |
289 | * @no_agg_framecnt_info: uCode do not provide aggregation frame count | ||
290 | * information | ||
291 | */ | 267 | */ |
292 | struct iwl_base_params { | 268 | struct iwl_base_params { |
293 | int eeprom_size; | 269 | int eeprom_size; |
@@ -296,9 +272,7 @@ struct iwl_base_params { | |||
296 | /* for iwl_apm_init() */ | 272 | /* for iwl_apm_init() */ |
297 | u32 pll_cfg_val; | 273 | u32 pll_cfg_val; |
298 | bool set_l0s; | 274 | bool set_l0s; |
299 | bool use_bsm; | ||
300 | 275 | ||
301 | bool use_isr_legacy; | ||
302 | const u16 max_ll_items; | 276 | const u16 max_ll_items; |
303 | const bool shadow_ram_support; | 277 | const bool shadow_ram_support; |
304 | u16 led_compensation; | 278 | u16 led_compensation; |
@@ -317,7 +291,6 @@ struct iwl_base_params { | |||
317 | const bool sensitivity_calib_by_driver; | 291 | const bool sensitivity_calib_by_driver; |
318 | const bool chain_noise_calib_by_driver; | 292 | const bool chain_noise_calib_by_driver; |
319 | const bool shadow_reg_enable; | 293 | const bool shadow_reg_enable; |
320 | const bool no_agg_framecnt_info; | ||
321 | }; | 294 | }; |
322 | /* | 295 | /* |
323 | * @advanced_bt_coexist: support advanced bt coexist | 296 | * @advanced_bt_coexist: support advanced bt coexist |
@@ -738,10 +711,13 @@ static inline bool iwl_advanced_bt_coexist(struct iwl_priv *priv) | |||
738 | 711 | ||
739 | static inline bool iwl_bt_statistics(struct iwl_priv *priv) | 712 | static inline bool iwl_bt_statistics(struct iwl_priv *priv) |
740 | { | 713 | { |
741 | return priv->cfg->bt_params && priv->cfg->bt_params->bt_statistics; | 714 | return priv->bt_statistics; |
742 | } | 715 | } |
743 | 716 | ||
744 | extern bool bt_coex_active; | 717 | extern bool bt_coex_active; |
745 | extern bool bt_siso_mode; | 718 | extern bool bt_siso_mode; |
746 | 719 | ||
720 | |||
721 | void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand); | ||
722 | |||
747 | #endif /* __iwl_core_h__ */ | 723 | #endif /* __iwl_core_h__ */ |
diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index f52bc040bcbf..5ab90ba7a024 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h | |||
@@ -5,7 +5,7 @@ | |||
5 | * | 5 | * |
6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
7 | * | 7 | * |
8 | * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of version 2 of the GNU General Public License as | 11 | * it under the terms of version 2 of the GNU General Public License as |
@@ -30,7 +30,7 @@ | |||
30 | * | 30 | * |
31 | * BSD LICENSE | 31 | * BSD LICENSE |
32 | * | 32 | * |
33 | * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. | 33 | * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. |
34 | * All rights reserved. | 34 | * All rights reserved. |
35 | * | 35 | * |
36 | * Redistribution and use in source and binary forms, with or without | 36 | * Redistribution and use in source and binary forms, with or without |
@@ -155,18 +155,10 @@ | |||
155 | #define CSR_DBG_LINK_PWR_MGMT_REG (CSR_BASE+0x250) | 155 | #define CSR_DBG_LINK_PWR_MGMT_REG (CSR_BASE+0x250) |
156 | 156 | ||
157 | /* Bits for CSR_HW_IF_CONFIG_REG */ | 157 | /* Bits for CSR_HW_IF_CONFIG_REG */ |
158 | #define CSR49_HW_IF_CONFIG_REG_BIT_4965_R (0x00000010) | ||
159 | #define CSR_HW_IF_CONFIG_REG_MSK_BOARD_VER (0x00000C00) | 158 | #define CSR_HW_IF_CONFIG_REG_MSK_BOARD_VER (0x00000C00) |
160 | #define CSR_HW_IF_CONFIG_REG_BIT_MAC_SI (0x00000100) | 159 | #define CSR_HW_IF_CONFIG_REG_BIT_MAC_SI (0x00000100) |
161 | #define CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI (0x00000200) | 160 | #define CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI (0x00000200) |
162 | 161 | ||
163 | #define CSR39_HW_IF_CONFIG_REG_BIT_3945_MB (0x00000100) | ||
164 | #define CSR39_HW_IF_CONFIG_REG_BIT_3945_MM (0x00000200) | ||
165 | #define CSR39_HW_IF_CONFIG_REG_BIT_SKU_MRC (0x00000400) | ||
166 | #define CSR39_HW_IF_CONFIG_REG_BIT_BOARD_TYPE (0x00000800) | ||
167 | #define CSR39_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_A (0x00000000) | ||
168 | #define CSR39_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_B (0x00001000) | ||
169 | |||
170 | #define CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A (0x00080000) | 162 | #define CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A (0x00080000) |
171 | #define CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM (0x00200000) | 163 | #define CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM (0x00200000) |
172 | #define CSR_HW_IF_CONFIG_REG_BIT_NIC_READY (0x00400000) /* PCI_OWN_SEM */ | 164 | #define CSR_HW_IF_CONFIG_REG_BIT_NIC_READY (0x00400000) /* PCI_OWN_SEM */ |
@@ -186,7 +178,7 @@ | |||
186 | #define CSR_INT_BIT_SW_ERR (1 << 25) /* uCode error */ | 178 | #define CSR_INT_BIT_SW_ERR (1 << 25) /* uCode error */ |
187 | #define CSR_INT_BIT_RF_KILL (1 << 7) /* HW RFKILL switch GP_CNTRL[27] toggled */ | 179 | #define CSR_INT_BIT_RF_KILL (1 << 7) /* HW RFKILL switch GP_CNTRL[27] toggled */ |
188 | #define CSR_INT_BIT_CT_KILL (1 << 6) /* Critical temp (chip too hot) rfkill */ | 180 | #define CSR_INT_BIT_CT_KILL (1 << 6) /* Critical temp (chip too hot) rfkill */ |
189 | #define CSR_INT_BIT_SW_RX (1 << 3) /* Rx, command responses, 3945 */ | 181 | #define CSR_INT_BIT_SW_RX (1 << 3) /* Rx, command responses */ |
190 | #define CSR_INT_BIT_WAKEUP (1 << 1) /* NIC controller waking up (pwr mgmt) */ | 182 | #define CSR_INT_BIT_WAKEUP (1 << 1) /* NIC controller waking up (pwr mgmt) */ |
191 | #define CSR_INT_BIT_ALIVE (1 << 0) /* uCode interrupts once it initializes */ | 183 | #define CSR_INT_BIT_ALIVE (1 << 0) /* uCode interrupts once it initializes */ |
192 | 184 | ||
@@ -202,29 +194,17 @@ | |||
202 | /* interrupt flags in FH (flow handler) (PCI busmaster DMA) */ | 194 | /* interrupt flags in FH (flow handler) (PCI busmaster DMA) */ |
203 | #define CSR_FH_INT_BIT_ERR (1 << 31) /* Error */ | 195 | #define CSR_FH_INT_BIT_ERR (1 << 31) /* Error */ |
204 | #define CSR_FH_INT_BIT_HI_PRIOR (1 << 30) /* High priority Rx, bypass coalescing */ | 196 | #define CSR_FH_INT_BIT_HI_PRIOR (1 << 30) /* High priority Rx, bypass coalescing */ |
205 | #define CSR39_FH_INT_BIT_RX_CHNL2 (1 << 18) /* Rx channel 2 (3945 only) */ | ||
206 | #define CSR_FH_INT_BIT_RX_CHNL1 (1 << 17) /* Rx channel 1 */ | 197 | #define CSR_FH_INT_BIT_RX_CHNL1 (1 << 17) /* Rx channel 1 */ |
207 | #define CSR_FH_INT_BIT_RX_CHNL0 (1 << 16) /* Rx channel 0 */ | 198 | #define CSR_FH_INT_BIT_RX_CHNL0 (1 << 16) /* Rx channel 0 */ |
208 | #define CSR39_FH_INT_BIT_TX_CHNL6 (1 << 6) /* Tx channel 6 (3945 only) */ | ||
209 | #define CSR_FH_INT_BIT_TX_CHNL1 (1 << 1) /* Tx channel 1 */ | 199 | #define CSR_FH_INT_BIT_TX_CHNL1 (1 << 1) /* Tx channel 1 */ |
210 | #define CSR_FH_INT_BIT_TX_CHNL0 (1 << 0) /* Tx channel 0 */ | 200 | #define CSR_FH_INT_BIT_TX_CHNL0 (1 << 0) /* Tx channel 0 */ |
211 | 201 | ||
212 | #define CSR39_FH_INT_RX_MASK (CSR_FH_INT_BIT_HI_PRIOR | \ | 202 | #define CSR_FH_INT_RX_MASK (CSR_FH_INT_BIT_HI_PRIOR | \ |
213 | CSR39_FH_INT_BIT_RX_CHNL2 | \ | 203 | CSR_FH_INT_BIT_RX_CHNL1 | \ |
214 | CSR_FH_INT_BIT_RX_CHNL1 | \ | 204 | CSR_FH_INT_BIT_RX_CHNL0) |
215 | CSR_FH_INT_BIT_RX_CHNL0) | ||
216 | |||
217 | |||
218 | #define CSR39_FH_INT_TX_MASK (CSR39_FH_INT_BIT_TX_CHNL6 | \ | ||
219 | CSR_FH_INT_BIT_TX_CHNL1 | \ | ||
220 | CSR_FH_INT_BIT_TX_CHNL0) | ||
221 | |||
222 | #define CSR49_FH_INT_RX_MASK (CSR_FH_INT_BIT_HI_PRIOR | \ | ||
223 | CSR_FH_INT_BIT_RX_CHNL1 | \ | ||
224 | CSR_FH_INT_BIT_RX_CHNL0) | ||
225 | 205 | ||
226 | #define CSR49_FH_INT_TX_MASK (CSR_FH_INT_BIT_TX_CHNL1 | \ | 206 | #define CSR_FH_INT_TX_MASK (CSR_FH_INT_BIT_TX_CHNL1 | \ |
227 | CSR_FH_INT_BIT_TX_CHNL0) | 207 | CSR_FH_INT_BIT_TX_CHNL0) |
228 | 208 | ||
229 | /* GPIO */ | 209 | /* GPIO */ |
230 | #define CSR_GPIO_IN_BIT_AUX_POWER (0x00000200) | 210 | #define CSR_GPIO_IN_BIT_AUX_POWER (0x00000200) |
@@ -268,7 +248,7 @@ | |||
268 | * Indicates MAC (ucode processor, etc.) is powered up and can run. | 248 | * Indicates MAC (ucode processor, etc.) is powered up and can run. |
269 | * Internal resources are accessible. | 249 | * Internal resources are accessible. |
270 | * NOTE: This does not indicate that the processor is actually running. | 250 | * NOTE: This does not indicate that the processor is actually running. |
271 | * NOTE: This does not indicate that 4965 or 3945 has completed | 251 | * NOTE: This does not indicate that device has completed |
272 | * init or post-power-down restore of internal SRAM memory. | 252 | * init or post-power-down restore of internal SRAM memory. |
273 | * Use CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP as indication that | 253 | * Use CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP as indication that |
274 | * SRAM is restored and uCode is in normal operation mode. | 254 | * SRAM is restored and uCode is in normal operation mode. |
@@ -291,8 +271,6 @@ | |||
291 | 271 | ||
292 | /* HW REV */ | 272 | /* HW REV */ |
293 | #define CSR_HW_REV_TYPE_MSK (0x00001F0) | 273 | #define CSR_HW_REV_TYPE_MSK (0x00001F0) |
294 | #define CSR_HW_REV_TYPE_3945 (0x00000D0) | ||
295 | #define CSR_HW_REV_TYPE_4965 (0x0000000) | ||
296 | #define CSR_HW_REV_TYPE_5300 (0x0000020) | 274 | #define CSR_HW_REV_TYPE_5300 (0x0000020) |
297 | #define CSR_HW_REV_TYPE_5350 (0x0000030) | 275 | #define CSR_HW_REV_TYPE_5350 (0x0000030) |
298 | #define CSR_HW_REV_TYPE_5100 (0x0000050) | 276 | #define CSR_HW_REV_TYPE_5100 (0x0000050) |
@@ -363,7 +341,7 @@ | |||
363 | * 0: MAC_SLEEP | 341 | * 0: MAC_SLEEP |
364 | * uCode sets this when preparing a power-saving power-down. | 342 | * uCode sets this when preparing a power-saving power-down. |
365 | * uCode resets this when power-up is complete and SRAM is sane. | 343 | * uCode resets this when power-up is complete and SRAM is sane. |
366 | * NOTE: 3945/4965 saves internal SRAM data to host when powering down, | 344 | * NOTE: device saves internal SRAM data to host when powering down, |
367 | * and must restore this data after powering back up. | 345 | * and must restore this data after powering back up. |
368 | * MAC_SLEEP is the best indication that restore is complete. | 346 | * MAC_SLEEP is the best indication that restore is complete. |
369 | * Later devices (5xxx/6xxx/1xxx) use non-volatile SRAM, and | 347 | * Later devices (5xxx/6xxx/1xxx) use non-volatile SRAM, and |
@@ -394,7 +372,6 @@ | |||
394 | #define CSR_LED_REG_TRUN_OFF (0x38) | 372 | #define CSR_LED_REG_TRUN_OFF (0x38) |
395 | 373 | ||
396 | /* ANA_PLL */ | 374 | /* ANA_PLL */ |
397 | #define CSR39_ANA_PLL_CFG_VAL (0x01000000) | ||
398 | #define CSR50_ANA_PLL_CFG_VAL (0x00880300) | 375 | #define CSR50_ANA_PLL_CFG_VAL (0x00880300) |
399 | 376 | ||
400 | /* HPET MEM debug */ | 377 | /* HPET MEM debug */ |
diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index ebdea3be3ef9..2824ccbcc1fc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h | |||
@@ -1,6 +1,6 @@ | |||
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | * | 2 | * |
3 | * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. | 3 | * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. |
4 | * | 4 | * |
5 | * Portions of this file are derived from the ipw3945 project. | 5 | * Portions of this file are derived from the ipw3945 project. |
6 | * | 6 | * |
@@ -146,7 +146,6 @@ static inline void iwl_dbgfs_unregister(struct iwl_priv *priv) | |||
146 | #define IWL_DL_RX (1 << 24) | 146 | #define IWL_DL_RX (1 << 24) |
147 | #define IWL_DL_ISR (1 << 25) | 147 | #define IWL_DL_ISR (1 << 25) |
148 | #define IWL_DL_HT (1 << 26) | 148 | #define IWL_DL_HT (1 << 26) |
149 | #define IWL_DL_IO (1 << 27) | ||
150 | /* 0xF0000000 - 0x10000000 */ | 149 | /* 0xF0000000 - 0x10000000 */ |
151 | #define IWL_DL_11H (1 << 28) | 150 | #define IWL_DL_11H (1 << 28) |
152 | #define IWL_DL_STATS (1 << 29) | 151 | #define IWL_DL_STATS (1 << 29) |
@@ -174,7 +173,6 @@ static inline void iwl_dbgfs_unregister(struct iwl_priv *priv) | |||
174 | IWL_DEBUG_LIMIT(p, IWL_DL_DROP, f, ## a) | 173 | IWL_DEBUG_LIMIT(p, IWL_DL_DROP, f, ## a) |
175 | #define IWL_DEBUG_AP(p, f, a...) IWL_DEBUG(p, IWL_DL_AP, f, ## a) | 174 | #define IWL_DEBUG_AP(p, f, a...) IWL_DEBUG(p, IWL_DL_AP, f, ## a) |
176 | #define IWL_DEBUG_TXPOWER(p, f, a...) IWL_DEBUG(p, IWL_DL_TXPOWER, f, ## a) | 175 | #define IWL_DEBUG_TXPOWER(p, f, a...) IWL_DEBUG(p, IWL_DL_TXPOWER, f, ## a) |
177 | #define IWL_DEBUG_IO(p, f, a...) IWL_DEBUG(p, IWL_DL_IO, f, ## a) | ||
178 | #define IWL_DEBUG_RATE(p, f, a...) IWL_DEBUG(p, IWL_DL_RATE, f, ## a) | 176 | #define IWL_DEBUG_RATE(p, f, a...) IWL_DEBUG(p, IWL_DL_RATE, f, ## a) |
179 | #define IWL_DEBUG_RATE_LIMIT(p, f, a...) \ | 177 | #define IWL_DEBUG_RATE_LIMIT(p, f, a...) \ |
180 | IWL_DEBUG_LIMIT(p, IWL_DL_RATE, f, ## a) | 178 | IWL_DEBUG_LIMIT(p, IWL_DL_RATE, f, ## a) |
diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 8842411f1cf3..92f6efd2c73f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * | 2 | * |
3 | * GPL LICENSE SUMMARY | 3 | * GPL LICENSE SUMMARY |
4 | * | 4 | * |
5 | * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. | 5 | * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of version 2 of the GNU General Public License as | 8 | * it under the terms of version 2 of the GNU General Public License as |
@@ -1572,12 +1572,10 @@ static ssize_t iwl_dbgfs_bt_traffic_read(struct file *file, | |||
1572 | int pos = 0; | 1572 | int pos = 0; |
1573 | char buf[200]; | 1573 | char buf[200]; |
1574 | const size_t bufsz = sizeof(buf); | 1574 | const size_t bufsz = sizeof(buf); |
1575 | ssize_t ret; | ||
1576 | 1575 | ||
1577 | if (!priv->bt_enable_flag) { | 1576 | if (!priv->bt_enable_flag) { |
1578 | pos += scnprintf(buf + pos, bufsz - pos, "BT coex disabled\n"); | 1577 | pos += scnprintf(buf + pos, bufsz - pos, "BT coex disabled\n"); |
1579 | ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); | 1578 | return simple_read_from_buffer(user_buf, count, ppos, buf, pos); |
1580 | return ret; | ||
1581 | } | 1579 | } |
1582 | pos += scnprintf(buf + pos, bufsz - pos, "BT enable flag: 0x%x\n", | 1580 | pos += scnprintf(buf + pos, bufsz - pos, "BT enable flag: 0x%x\n", |
1583 | priv->bt_enable_flag); | 1581 | priv->bt_enable_flag); |
@@ -1608,8 +1606,7 @@ static ssize_t iwl_dbgfs_bt_traffic_read(struct file *file, | |||
1608 | break; | 1606 | break; |
1609 | } | 1607 | } |
1610 | 1608 | ||
1611 | ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); | 1609 | return simple_read_from_buffer(user_buf, count, ppos, buf, pos); |
1612 | return ret; | ||
1613 | } | 1610 | } |
1614 | 1611 | ||
1615 | static ssize_t iwl_dbgfs_protection_mode_read(struct file *file, | 1612 | static ssize_t iwl_dbgfs_protection_mode_read(struct file *file, |
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 68b953f2bdc7..72133368c1f5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h | |||
@@ -1,6 +1,6 @@ | |||
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | * | 2 | * |
3 | * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. | 3 | * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify it | 5 | * This program is free software; you can redistribute it and/or modify it |
6 | * under the terms of version 2 of the GNU General Public License as | 6 | * under the terms of version 2 of the GNU General Public License as |
@@ -26,7 +26,6 @@ | |||
26 | /* | 26 | /* |
27 | * Please use this file (iwl-dev.h) for driver implementation definitions. | 27 | * Please use this file (iwl-dev.h) for driver implementation definitions. |
28 | * Please use iwl-commands.h for uCode API definitions. | 28 | * Please use iwl-commands.h for uCode API definitions. |
29 | * Please use iwl-4965-hw.h for hardware-related definitions. | ||
30 | */ | 29 | */ |
31 | 30 | ||
32 | #ifndef __iwl_dev_h__ | 31 | #ifndef __iwl_dev_h__ |
@@ -179,53 +178,12 @@ struct iwl_tx_queue { | |||
179 | 178 | ||
180 | #define IWL_NUM_SCAN_RATES (2) | 179 | #define IWL_NUM_SCAN_RATES (2) |
181 | 180 | ||
182 | struct iwl4965_channel_tgd_info { | ||
183 | u8 type; | ||
184 | s8 max_power; | ||
185 | }; | ||
186 | |||
187 | struct iwl4965_channel_tgh_info { | ||
188 | s64 last_radar_time; | ||
189 | }; | ||
190 | |||
191 | #define IWL4965_MAX_RATE (33) | ||
192 | |||
193 | struct iwl3945_clip_group { | ||
194 | /* maximum power level to prevent clipping for each rate, derived by | ||
195 | * us from this band's saturation power in EEPROM */ | ||
196 | const s8 clip_powers[IWL_MAX_RATES]; | ||
197 | }; | ||
198 | |||
199 | /* current Tx power values to use, one for each rate for each channel. | ||
200 | * requested power is limited by: | ||
201 | * -- regulatory EEPROM limits for this channel | ||
202 | * -- hardware capabilities (clip-powers) | ||
203 | * -- spectrum management | ||
204 | * -- user preference (e.g. iwconfig) | ||
205 | * when requested power is set, base power index must also be set. */ | ||
206 | struct iwl3945_channel_power_info { | ||
207 | struct iwl3945_tx_power tpc; /* actual radio and DSP gain settings */ | ||
208 | s8 power_table_index; /* actual (compenst'd) index into gain table */ | ||
209 | s8 base_power_index; /* gain index for power at factory temp. */ | ||
210 | s8 requested_power; /* power (dBm) requested for this chnl/rate */ | ||
211 | }; | ||
212 | |||
213 | /* current scan Tx power values to use, one for each scan rate for each | ||
214 | * channel. */ | ||
215 | struct iwl3945_scan_power_info { | ||
216 | struct iwl3945_tx_power tpc; /* actual radio and DSP gain settings */ | ||
217 | s8 power_table_index; /* actual (compenst'd) index into gain table */ | ||
218 | s8 requested_power; /* scan pwr (dBm) requested for chnl/rate */ | ||
219 | }; | ||
220 | |||
221 | /* | 181 | /* |
222 | * One for each channel, holds all channel setup data | 182 | * One for each channel, holds all channel setup data |
223 | * Some of the fields (e.g. eeprom and flags/max_power_avg) are redundant | 183 | * Some of the fields (e.g. eeprom and flags/max_power_avg) are redundant |
224 | * with one another! | 184 | * with one another! |
225 | */ | 185 | */ |
226 | struct iwl_channel_info { | 186 | struct iwl_channel_info { |
227 | struct iwl4965_channel_tgd_info tgd; | ||
228 | struct iwl4965_channel_tgh_info tgh; | ||
229 | struct iwl_eeprom_channel eeprom; /* EEPROM regulatory limit */ | 187 | struct iwl_eeprom_channel eeprom; /* EEPROM regulatory limit */ |
230 | struct iwl_eeprom_channel ht40_eeprom; /* EEPROM regulatory limit for | 188 | struct iwl_eeprom_channel ht40_eeprom; /* EEPROM regulatory limit for |
231 | * HT40 channel */ | 189 | * HT40 channel */ |
@@ -245,14 +203,6 @@ struct iwl_channel_info { | |||
245 | s8 ht40_max_power_avg; /* (dBm) regul. eeprom, normal Tx, any rate */ | 203 | s8 ht40_max_power_avg; /* (dBm) regul. eeprom, normal Tx, any rate */ |
246 | u8 ht40_flags; /* flags copied from EEPROM */ | 204 | u8 ht40_flags; /* flags copied from EEPROM */ |
247 | u8 ht40_extension_channel; /* HT_IE_EXT_CHANNEL_* */ | 205 | u8 ht40_extension_channel; /* HT_IE_EXT_CHANNEL_* */ |
248 | |||
249 | /* Radio/DSP gain settings for each "normal" data Tx rate. | ||
250 | * These include, in addition to RF and DSP gain, a few fields for | ||
251 | * remembering/modifying gain settings (indexes). */ | ||
252 | struct iwl3945_channel_power_info power_info[IWL4965_MAX_RATE]; | ||
253 | |||
254 | /* Radio/DSP gain settings for each scan rate, for directed scans. */ | ||
255 | struct iwl3945_scan_power_info scan_pwr_info[IWL_NUM_SCAN_RATES]; | ||
256 | }; | 206 | }; |
257 | 207 | ||
258 | #define IWL_TX_FIFO_BK 0 /* shared */ | 208 | #define IWL_TX_FIFO_BK 0 /* shared */ |
@@ -309,6 +259,7 @@ enum { | |||
309 | CMD_SIZE_HUGE = (1 << 0), | 259 | CMD_SIZE_HUGE = (1 << 0), |
310 | CMD_ASYNC = (1 << 1), | 260 | CMD_ASYNC = (1 << 1), |
311 | CMD_WANT_SKB = (1 << 2), | 261 | CMD_WANT_SKB = (1 << 2), |
262 | CMD_MAPPED = (1 << 3), | ||
312 | }; | 263 | }; |
313 | 264 | ||
314 | #define DEF_CMD_PAYLOAD_SIZE 320 | 265 | #define DEF_CMD_PAYLOAD_SIZE 320 |
@@ -416,6 +367,7 @@ struct iwl_ht_agg { | |||
416 | #define IWL_EMPTYING_HW_QUEUE_ADDBA 2 | 367 | #define IWL_EMPTYING_HW_QUEUE_ADDBA 2 |
417 | #define IWL_EMPTYING_HW_QUEUE_DELBA 3 | 368 | #define IWL_EMPTYING_HW_QUEUE_DELBA 3 |
418 | u8 state; | 369 | u8 state; |
370 | u8 tx_fifo; | ||
419 | }; | 371 | }; |
420 | 372 | ||
421 | 373 | ||
@@ -499,9 +451,6 @@ struct iwl_station_priv_common { | |||
499 | * When mac80211 creates a station it reserves some space (hw->sta_data_size) | 451 | * When mac80211 creates a station it reserves some space (hw->sta_data_size) |
500 | * in the structure for use by driver. This structure is places in that | 452 | * in the structure for use by driver. This structure is places in that |
501 | * space. | 453 | * space. |
502 | * | ||
503 | * The common struct MUST be first because it is shared between | ||
504 | * 3945 and agn! | ||
505 | */ | 454 | */ |
506 | struct iwl_station_priv { | 455 | struct iwl_station_priv { |
507 | struct iwl_station_priv_common common; | 456 | struct iwl_station_priv_common common; |
@@ -586,6 +535,22 @@ enum iwl_ucode_tlv_type { | |||
586 | IWL_UCODE_TLV_INIT_ERRLOG_PTR = 13, | 535 | IWL_UCODE_TLV_INIT_ERRLOG_PTR = 13, |
587 | IWL_UCODE_TLV_ENHANCE_SENS_TBL = 14, | 536 | IWL_UCODE_TLV_ENHANCE_SENS_TBL = 14, |
588 | IWL_UCODE_TLV_PHY_CALIBRATION_SIZE = 15, | 537 | IWL_UCODE_TLV_PHY_CALIBRATION_SIZE = 15, |
538 | /* 16 and 17 reserved for future use */ | ||
539 | IWL_UCODE_TLV_FLAGS = 18, | ||
540 | }; | ||
541 | |||
542 | /** | ||
543 | * enum iwl_ucode_tlv_flag - ucode API flags | ||
544 | * @IWL_UCODE_TLV_FLAGS_PAN: This is PAN capable microcode; this previously | ||
545 | * was a separate TLV but moved here to save space. | ||
546 | * @IWL_UCODE_TLV_FLAGS_BTSTATS: This uCode image uses BT statistics, which | ||
547 | * may be true even if the device doesn't have BT. | ||
548 | * @IWL_UCODE_TLV_FLAGS_MFP: This uCode image supports MFP (802.11w). | ||
549 | */ | ||
550 | enum iwl_ucode_tlv_flag { | ||
551 | IWL_UCODE_TLV_FLAGS_PAN = BIT(0), | ||
552 | IWL_UCODE_TLV_FLAGS_BTSTATS = BIT(1), | ||
553 | IWL_UCODE_TLV_FLAGS_MFP = BIT(2), | ||
589 | }; | 554 | }; |
590 | 555 | ||
591 | struct iwl_ucode_tlv { | 556 | struct iwl_ucode_tlv { |
@@ -619,14 +584,6 @@ struct iwl_tlv_ucode_header { | |||
619 | u8 data[0]; | 584 | u8 data[0]; |
620 | }; | 585 | }; |
621 | 586 | ||
622 | struct iwl4965_ibss_seq { | ||
623 | u8 mac[ETH_ALEN]; | ||
624 | u16 seq_num; | ||
625 | u16 frag_num; | ||
626 | unsigned long packet_time; | ||
627 | struct list_head list; | ||
628 | }; | ||
629 | |||
630 | struct iwl_sensitivity_ranges { | 587 | struct iwl_sensitivity_ranges { |
631 | u16 min_nrg_cck; | 588 | u16 min_nrg_cck; |
632 | u16 max_nrg_cck; | 589 | u16 max_nrg_cck; |
@@ -700,7 +657,6 @@ struct iwl_hw_params { | |||
700 | u8 max_beacon_itrvl; /* in 1024 ms */ | 657 | u8 max_beacon_itrvl; /* in 1024 ms */ |
701 | u32 max_inst_size; | 658 | u32 max_inst_size; |
702 | u32 max_data_size; | 659 | u32 max_data_size; |
703 | u32 max_bsm_size; | ||
704 | u32 ct_kill_threshold; /* value in hw-dependent units */ | 660 | u32 ct_kill_threshold; /* value in hw-dependent units */ |
705 | u32 ct_kill_exit_threshold; /* value in hw-dependent units */ | 661 | u32 ct_kill_exit_threshold; /* value in hw-dependent units */ |
706 | /* for 1000, 6000 series and up */ | 662 | /* for 1000, 6000 series and up */ |
@@ -722,8 +678,6 @@ struct iwl_hw_params { | |||
722 | * Naming convention -- | 678 | * Naming convention -- |
723 | * iwl_ <-- Is part of iwlwifi | 679 | * iwl_ <-- Is part of iwlwifi |
724 | * iwlXXXX_ <-- Hardware specific (implemented in iwl-XXXX.c for XXXX) | 680 | * iwlXXXX_ <-- Hardware specific (implemented in iwl-XXXX.c for XXXX) |
725 | * iwl4965_bg_ <-- Called from work queue context | ||
726 | * iwl4965_mac_ <-- mac80211 callback | ||
727 | * | 681 | * |
728 | ****************************************************************************/ | 682 | ****************************************************************************/ |
729 | extern void iwl_update_chain_flags(struct iwl_priv *priv); | 683 | extern void iwl_update_chain_flags(struct iwl_priv *priv); |
@@ -772,7 +726,6 @@ struct iwl_dma_ptr { | |||
772 | 726 | ||
773 | /* Sensitivity and chain noise calibration */ | 727 | /* Sensitivity and chain noise calibration */ |
774 | #define INITIALIZATION_VALUE 0xFFFF | 728 | #define INITIALIZATION_VALUE 0xFFFF |
775 | #define IWL4965_CAL_NUM_BEACONS 20 | ||
776 | #define IWL_CAL_NUM_BEACONS 16 | 729 | #define IWL_CAL_NUM_BEACONS 16 |
777 | #define MAXIMUM_ALLOWED_PATHLOSS 15 | 730 | #define MAXIMUM_ALLOWED_PATHLOSS 15 |
778 | 731 | ||
@@ -806,24 +759,19 @@ struct iwl_dma_ptr { | |||
806 | #define NRG_NUM_PREV_STAT_L 20 | 759 | #define NRG_NUM_PREV_STAT_L 20 |
807 | #define NUM_RX_CHAINS 3 | 760 | #define NUM_RX_CHAINS 3 |
808 | 761 | ||
809 | enum iwl4965_false_alarm_state { | 762 | enum iwlagn_false_alarm_state { |
810 | IWL_FA_TOO_MANY = 0, | 763 | IWL_FA_TOO_MANY = 0, |
811 | IWL_FA_TOO_FEW = 1, | 764 | IWL_FA_TOO_FEW = 1, |
812 | IWL_FA_GOOD_RANGE = 2, | 765 | IWL_FA_GOOD_RANGE = 2, |
813 | }; | 766 | }; |
814 | 767 | ||
815 | enum iwl4965_chain_noise_state { | 768 | enum iwlagn_chain_noise_state { |
816 | IWL_CHAIN_NOISE_ALIVE = 0, /* must be 0 */ | 769 | IWL_CHAIN_NOISE_ALIVE = 0, /* must be 0 */ |
817 | IWL_CHAIN_NOISE_ACCUMULATE, | 770 | IWL_CHAIN_NOISE_ACCUMULATE, |
818 | IWL_CHAIN_NOISE_CALIBRATED, | 771 | IWL_CHAIN_NOISE_CALIBRATED, |
819 | IWL_CHAIN_NOISE_DONE, | 772 | IWL_CHAIN_NOISE_DONE, |
820 | }; | 773 | }; |
821 | 774 | ||
822 | enum iwl4965_calib_enabled_state { | ||
823 | IWL_CALIB_DISABLED = 0, /* must be 0 */ | ||
824 | IWL_CALIB_ENABLED = 1, | ||
825 | }; | ||
826 | |||
827 | 775 | ||
828 | /* | 776 | /* |
829 | * enum iwl_calib | 777 | * enum iwl_calib |
@@ -1131,12 +1079,6 @@ struct iwl_force_reset { | |||
1131 | 1079 | ||
1132 | /* extend beacon time format bit shifting */ | 1080 | /* extend beacon time format bit shifting */ |
1133 | /* | 1081 | /* |
1134 | * for _3945 devices | ||
1135 | * bits 31:24 - extended | ||
1136 | * bits 23:0 - interval | ||
1137 | */ | ||
1138 | #define IWL3945_EXT_BEACON_TIME_POS 24 | ||
1139 | /* | ||
1140 | * for _agn devices | 1082 | * for _agn devices |
1141 | * bits 31:22 - extended | 1083 | * bits 31:22 - extended |
1142 | * bits 21:0 - interval | 1084 | * bits 21:0 - interval |
@@ -1249,7 +1191,6 @@ struct iwl_priv { | |||
1249 | int frames_count; | 1191 | int frames_count; |
1250 | 1192 | ||
1251 | enum ieee80211_band band; | 1193 | enum ieee80211_band band; |
1252 | int alloc_rxb_page; | ||
1253 | 1194 | ||
1254 | void (*rx_handlers[REPLY_MAX])(struct iwl_priv *priv, | 1195 | void (*rx_handlers[REPLY_MAX])(struct iwl_priv *priv, |
1255 | struct iwl_rx_mem_buffer *rxb); | 1196 | struct iwl_rx_mem_buffer *rxb); |
@@ -1305,16 +1246,12 @@ struct iwl_priv { | |||
1305 | spinlock_t hcmd_lock; /* protect hcmd */ | 1246 | spinlock_t hcmd_lock; /* protect hcmd */ |
1306 | spinlock_t reg_lock; /* protect hw register access */ | 1247 | spinlock_t reg_lock; /* protect hw register access */ |
1307 | struct mutex mutex; | 1248 | struct mutex mutex; |
1308 | struct mutex sync_cmd_mutex; /* enable serialization of sync commands */ | ||
1309 | 1249 | ||
1310 | /* basic pci-network driver stuff */ | 1250 | /* basic pci-network driver stuff */ |
1311 | struct pci_dev *pci_dev; | 1251 | struct pci_dev *pci_dev; |
1312 | 1252 | ||
1313 | /* pci hardware address support */ | 1253 | /* pci hardware address support */ |
1314 | void __iomem *hw_base; | 1254 | void __iomem *hw_base; |
1315 | u32 hw_rev; | ||
1316 | u32 hw_wa_rev; | ||
1317 | u8 rev_id; | ||
1318 | 1255 | ||
1319 | /* microcode/device supports multiple contexts */ | 1256 | /* microcode/device supports multiple contexts */ |
1320 | u8 valid_contexts; | 1257 | u8 valid_contexts; |
@@ -1334,10 +1271,8 @@ struct iwl_priv { | |||
1334 | iwl_ucode.ver */ | 1271 | iwl_ucode.ver */ |
1335 | struct fw_desc ucode_code; /* runtime inst */ | 1272 | struct fw_desc ucode_code; /* runtime inst */ |
1336 | struct fw_desc ucode_data; /* runtime data original */ | 1273 | struct fw_desc ucode_data; /* runtime data original */ |
1337 | struct fw_desc ucode_data_backup; /* runtime data save/restore */ | ||
1338 | struct fw_desc ucode_init; /* initialization inst */ | 1274 | struct fw_desc ucode_init; /* initialization inst */ |
1339 | struct fw_desc ucode_init_data; /* initialization data */ | 1275 | struct fw_desc ucode_init_data; /* initialization data */ |
1340 | struct fw_desc ucode_boot; /* bootstrap inst */ | ||
1341 | enum ucode_type ucode_type; | 1276 | enum ucode_type ucode_type; |
1342 | u8 ucode_write_complete; /* the image write is complete */ | 1277 | u8 ucode_write_complete; /* the image write is complete */ |
1343 | char firmware_name[25]; | 1278 | char firmware_name[25]; |
@@ -1346,10 +1281,10 @@ struct iwl_priv { | |||
1346 | 1281 | ||
1347 | struct iwl_switch_rxon switch_rxon; | 1282 | struct iwl_switch_rxon switch_rxon; |
1348 | 1283 | ||
1349 | /* 1st responses from initialize and runtime uCode images. | 1284 | struct { |
1350 | * _agn's initialize alive response contains some calibration data. */ | 1285 | u32 error_event_table; |
1351 | struct iwl_init_alive_resp card_alive_init; | 1286 | u32 log_event_table; |
1352 | struct iwl_alive_resp card_alive; | 1287 | } device_pointers; |
1353 | 1288 | ||
1354 | u16 active_rate; | 1289 | u16 active_rate; |
1355 | 1290 | ||
@@ -1390,15 +1325,12 @@ struct iwl_priv { | |||
1390 | struct iwl_power_mgr power_data; | 1325 | struct iwl_power_mgr power_data; |
1391 | struct iwl_tt_mgmt thermal_throttle; | 1326 | struct iwl_tt_mgmt thermal_throttle; |
1392 | 1327 | ||
1393 | /* context information */ | ||
1394 | u8 bssid[ETH_ALEN]; /* used only on 3945 but filled by core */ | ||
1395 | |||
1396 | /* station table variables */ | 1328 | /* station table variables */ |
1397 | 1329 | ||
1398 | /* Note: if lock and sta_lock are needed, lock must be acquired first */ | 1330 | /* Note: if lock and sta_lock are needed, lock must be acquired first */ |
1399 | spinlock_t sta_lock; | 1331 | spinlock_t sta_lock; |
1400 | int num_stations; | 1332 | int num_stations; |
1401 | struct iwl_station_entry stations[IWL_STATION_COUNT]; | 1333 | struct iwl_station_entry stations[IWLAGN_STATION_COUNT]; |
1402 | unsigned long ucode_key_table; | 1334 | unsigned long ucode_key_table; |
1403 | 1335 | ||
1404 | /* queue refcounts */ | 1336 | /* queue refcounts */ |
@@ -1422,101 +1354,66 @@ struct iwl_priv { | |||
1422 | /* Last Rx'd beacon timestamp */ | 1354 | /* Last Rx'd beacon timestamp */ |
1423 | u64 timestamp; | 1355 | u64 timestamp; |
1424 | 1356 | ||
1425 | union { | 1357 | struct { |
1426 | #if defined(CONFIG_IWL3945) || defined(CONFIG_IWL3945_MODULE) | 1358 | /* INT ICT Table */ |
1427 | struct { | 1359 | __le32 *ict_tbl; |
1428 | void *shared_virt; | 1360 | void *ict_tbl_vir; |
1429 | dma_addr_t shared_phys; | 1361 | dma_addr_t ict_tbl_dma; |
1430 | 1362 | dma_addr_t aligned_ict_tbl_dma; | |
1431 | struct delayed_work thermal_periodic; | 1363 | int ict_index; |
1432 | struct delayed_work rfkill_poll; | 1364 | u32 inta; |
1433 | 1365 | bool use_ict; | |
1434 | struct iwl3945_notif_statistics statistics; | 1366 | /* |
1435 | #ifdef CONFIG_IWLWIFI_DEBUGFS | 1367 | * reporting the number of tids has AGG on. 0 means |
1436 | struct iwl3945_notif_statistics accum_statistics; | 1368 | * no AGGREGATION |
1437 | struct iwl3945_notif_statistics delta_statistics; | 1369 | */ |
1438 | struct iwl3945_notif_statistics max_delta; | 1370 | u8 agg_tids_count; |
1439 | #endif | 1371 | |
1440 | 1372 | struct iwl_rx_phy_res last_phy_res; | |
1441 | u32 sta_supp_rates; | 1373 | bool last_phy_res_valid; |
1442 | int last_rx_rssi; /* From Rx packet statistics */ | 1374 | |
1443 | 1375 | struct completion firmware_loading_complete; | |
1444 | /* Rx'd packet timing information */ | 1376 | |
1445 | u32 last_beacon_time; | 1377 | u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr; |
1446 | u64 last_tsf; | 1378 | u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr; |
1447 | 1379 | ||
1448 | /* | 1380 | /* |
1449 | * each calibration channel group in the | 1381 | * chain noise reset and gain commands are the |
1450 | * EEPROM has a derived clip setting for | 1382 | * two extra calibration commands follows the standard |
1451 | * each rate. | 1383 | * phy calibration commands |
1452 | */ | 1384 | */ |
1453 | const struct iwl3945_clip_group clip_groups[5]; | 1385 | u8 phy_calib_chain_noise_reset_cmd; |
1454 | 1386 | u8 phy_calib_chain_noise_gain_cmd; | |
1455 | } _3945; | 1387 | |
1456 | #endif | 1388 | struct iwl_notif_statistics statistics; |
1457 | #if defined(CONFIG_IWLAGN) || defined(CONFIG_IWLAGN_MODULE) | 1389 | struct iwl_bt_notif_statistics statistics_bt; |
1458 | struct { | 1390 | /* counts reply_tx error */ |
1459 | /* INT ICT Table */ | 1391 | struct reply_tx_error_statistics reply_tx_stats; |
1460 | __le32 *ict_tbl; | 1392 | struct reply_agg_tx_error_statistics reply_agg_tx_stats; |
1461 | void *ict_tbl_vir; | ||
1462 | dma_addr_t ict_tbl_dma; | ||
1463 | dma_addr_t aligned_ict_tbl_dma; | ||
1464 | int ict_index; | ||
1465 | u32 inta; | ||
1466 | bool use_ict; | ||
1467 | /* | ||
1468 | * reporting the number of tids has AGG on. 0 means | ||
1469 | * no AGGREGATION | ||
1470 | */ | ||
1471 | u8 agg_tids_count; | ||
1472 | |||
1473 | struct iwl_rx_phy_res last_phy_res; | ||
1474 | bool last_phy_res_valid; | ||
1475 | |||
1476 | struct completion firmware_loading_complete; | ||
1477 | |||
1478 | u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr; | ||
1479 | u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr; | ||
1480 | |||
1481 | /* | ||
1482 | * chain noise reset and gain commands are the | ||
1483 | * two extra calibration commands follows the standard | ||
1484 | * phy calibration commands | ||
1485 | */ | ||
1486 | u8 phy_calib_chain_noise_reset_cmd; | ||
1487 | u8 phy_calib_chain_noise_gain_cmd; | ||
1488 | |||
1489 | struct iwl_notif_statistics statistics; | ||
1490 | struct iwl_bt_notif_statistics statistics_bt; | ||
1491 | /* counts reply_tx error */ | ||
1492 | struct reply_tx_error_statistics reply_tx_stats; | ||
1493 | struct reply_agg_tx_error_statistics reply_agg_tx_stats; | ||
1494 | #ifdef CONFIG_IWLWIFI_DEBUGFS | 1393 | #ifdef CONFIG_IWLWIFI_DEBUGFS |
1495 | struct iwl_notif_statistics accum_statistics; | 1394 | struct iwl_notif_statistics accum_statistics; |
1496 | struct iwl_notif_statistics delta_statistics; | 1395 | struct iwl_notif_statistics delta_statistics; |
1497 | struct iwl_notif_statistics max_delta; | 1396 | struct iwl_notif_statistics max_delta; |
1498 | struct iwl_bt_notif_statistics accum_statistics_bt; | 1397 | struct iwl_bt_notif_statistics accum_statistics_bt; |
1499 | struct iwl_bt_notif_statistics delta_statistics_bt; | 1398 | struct iwl_bt_notif_statistics delta_statistics_bt; |
1500 | struct iwl_bt_notif_statistics max_delta_bt; | 1399 | struct iwl_bt_notif_statistics max_delta_bt; |
1501 | #endif | 1400 | #endif |
1502 | 1401 | /* notification wait support */ | |
1503 | /* notification wait support */ | 1402 | struct list_head notif_waits; |
1504 | struct list_head notif_waits; | 1403 | spinlock_t notif_wait_lock; |
1505 | spinlock_t notif_wait_lock; | 1404 | wait_queue_head_t notif_waitq; |
1506 | wait_queue_head_t notif_waitq; | 1405 | |
1507 | 1406 | /* remain-on-channel offload support */ | |
1508 | /* remain-on-channel offload support */ | 1407 | struct ieee80211_channel *hw_roc_channel; |
1509 | struct ieee80211_channel *hw_roc_channel; | 1408 | struct delayed_work hw_roc_work; |
1510 | struct delayed_work hw_roc_work; | 1409 | enum nl80211_channel_type hw_roc_chantype; |
1511 | enum nl80211_channel_type hw_roc_chantype; | 1410 | int hw_roc_duration; |
1512 | int hw_roc_duration; | 1411 | bool hw_roc_setup; |
1513 | 1412 | ||
1514 | struct sk_buff *offchan_tx_skb; | 1413 | struct sk_buff *offchan_tx_skb; |
1515 | int offchan_tx_timeout; | 1414 | int offchan_tx_timeout; |
1516 | struct ieee80211_channel *offchan_tx_chan; | 1415 | struct ieee80211_channel *offchan_tx_chan; |
1517 | } _agn; | 1416 | } _agn; |
1518 | #endif | ||
1519 | }; | ||
1520 | 1417 | ||
1521 | /* bt coex */ | 1418 | /* bt coex */ |
1522 | u8 bt_enable_flag; | 1419 | u8 bt_enable_flag; |
@@ -1525,6 +1422,7 @@ struct iwl_priv { | |||
1525 | bool bt_ch_announce; | 1422 | bool bt_ch_announce; |
1526 | bool bt_full_concurrent; | 1423 | bool bt_full_concurrent; |
1527 | bool bt_ant_couple_ok; | 1424 | bool bt_ant_couple_ok; |
1425 | bool bt_statistics; | ||
1528 | __le32 kill_ack_mask; | 1426 | __le32 kill_ack_mask; |
1529 | __le32 kill_cts_mask; | 1427 | __le32 kill_cts_mask; |
1530 | __le16 bt_valid; | 1428 | __le16 bt_valid; |
@@ -1710,12 +1608,10 @@ static inline int is_channel_ibss(const struct iwl_channel_info *ch) | |||
1710 | static inline void __iwl_free_pages(struct iwl_priv *priv, struct page *page) | 1608 | static inline void __iwl_free_pages(struct iwl_priv *priv, struct page *page) |
1711 | { | 1609 | { |
1712 | __free_pages(page, priv->hw_params.rx_page_order); | 1610 | __free_pages(page, priv->hw_params.rx_page_order); |
1713 | priv->alloc_rxb_page--; | ||
1714 | } | 1611 | } |
1715 | 1612 | ||
1716 | static inline void iwl_free_pages(struct iwl_priv *priv, unsigned long page) | 1613 | static inline void iwl_free_pages(struct iwl_priv *priv, unsigned long page) |
1717 | { | 1614 | { |
1718 | free_pages(page, priv->hw_params.rx_page_order); | 1615 | free_pages(page, priv->hw_params.rx_page_order); |
1719 | priv->alloc_rxb_page--; | ||
1720 | } | 1616 | } |
1721 | #endif /* __iwl_dev_h__ */ | 1617 | #endif /* __iwl_dev_h__ */ |
diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.c b/drivers/net/wireless/iwlwifi/iwl-devtrace.c index 4a487639d932..a635a7e75447 100644 --- a/drivers/net/wireless/iwlwifi/iwl-devtrace.c +++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | * | 2 | * |
3 | * Copyright(c) 2009 - 2010 Intel Corporation. All rights reserved. | 3 | * Copyright(c) 2009 - 2011 Intel Corporation. All rights reserved. |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify it | 5 | * This program is free software; you can redistribute it and/or modify it |
6 | * under the terms of version 2 of the GNU General Public License as | 6 | * under the terms of version 2 of the GNU General Public License as |
diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.h b/drivers/net/wireless/iwlwifi/iwl-devtrace.h index 4cf864c664ee..f00172cb8a6d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-devtrace.h +++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.h | |||
@@ -1,6 +1,6 @@ | |||
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | * | 2 | * |
3 | * Copyright(c) 2009 - 2010 Intel Corporation. All rights reserved. | 3 | * Copyright(c) 2009 - 2011 Intel Corporation. All rights reserved. |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify it | 5 | * This program is free software; you can redistribute it and/or modify it |
6 | * under the terms of version 2 of the GNU General Public License as | 6 | * under the terms of version 2 of the GNU General Public License as |
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index 833194a2c639..859b94a12297 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c | |||
@@ -5,7 +5,7 @@ | |||
5 | * | 5 | * |
6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
7 | * | 7 | * |
8 | * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of version 2 of the GNU General Public License as | 11 | * it under the terms of version 2 of the GNU General Public License as |
@@ -30,7 +30,7 @@ | |||
30 | * | 30 | * |
31 | * BSD LICENSE | 31 | * BSD LICENSE |
32 | * | 32 | * |
33 | * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. | 33 | * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. |
34 | * All rights reserved. | 34 | * All rights reserved. |
35 | * | 35 | * |
36 | * Redistribution and use in source and binary forms, with or without | 36 | * Redistribution and use in source and binary forms, with or without |
@@ -188,18 +188,16 @@ static void iwl_set_otp_access(struct iwl_priv *priv, enum iwl_access_mode mode) | |||
188 | CSR_OTP_GP_REG_OTP_ACCESS_MODE); | 188 | CSR_OTP_GP_REG_OTP_ACCESS_MODE); |
189 | } | 189 | } |
190 | 190 | ||
191 | static int iwlcore_get_nvm_type(struct iwl_priv *priv) | 191 | static int iwlcore_get_nvm_type(struct iwl_priv *priv, u32 hw_rev) |
192 | { | 192 | { |
193 | u32 otpgp; | 193 | u32 otpgp; |
194 | int nvm_type; | 194 | int nvm_type; |
195 | 195 | ||
196 | /* OTP only valid for CP/PP and after */ | 196 | /* OTP only valid for CP/PP and after */ |
197 | switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { | 197 | switch (hw_rev & CSR_HW_REV_TYPE_MSK) { |
198 | case CSR_HW_REV_TYPE_NONE: | 198 | case CSR_HW_REV_TYPE_NONE: |
199 | IWL_ERR(priv, "Unknown hardware type\n"); | 199 | IWL_ERR(priv, "Unknown hardware type\n"); |
200 | return -ENOENT; | 200 | return -ENOENT; |
201 | case CSR_HW_REV_TYPE_3945: | ||
202 | case CSR_HW_REV_TYPE_4965: | ||
203 | case CSR_HW_REV_TYPE_5300: | 201 | case CSR_HW_REV_TYPE_5300: |
204 | case CSR_HW_REV_TYPE_5350: | 202 | case CSR_HW_REV_TYPE_5350: |
205 | case CSR_HW_REV_TYPE_5100: | 203 | case CSR_HW_REV_TYPE_5100: |
@@ -228,15 +226,15 @@ static int iwl_init_otp_access(struct iwl_priv *priv) | |||
228 | int ret; | 226 | int ret; |
229 | 227 | ||
230 | /* Enable 40MHz radio clock */ | 228 | /* Enable 40MHz radio clock */ |
231 | _iwl_write32(priv, CSR_GP_CNTRL, | 229 | iwl_write32(priv, CSR_GP_CNTRL, |
232 | _iwl_read32(priv, CSR_GP_CNTRL) | | 230 | iwl_read32(priv, CSR_GP_CNTRL) | |
233 | CSR_GP_CNTRL_REG_FLAG_INIT_DONE); | 231 | CSR_GP_CNTRL_REG_FLAG_INIT_DONE); |
234 | 232 | ||
235 | /* wait for clock to be ready */ | 233 | /* wait for clock to be ready */ |
236 | ret = iwl_poll_bit(priv, CSR_GP_CNTRL, | 234 | ret = iwl_poll_bit(priv, CSR_GP_CNTRL, |
237 | CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, | 235 | CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, |
238 | CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, | 236 | CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, |
239 | 25000); | 237 | 25000); |
240 | if (ret < 0) | 238 | if (ret < 0) |
241 | IWL_ERR(priv, "Time out access OTP\n"); | 239 | IWL_ERR(priv, "Time out access OTP\n"); |
242 | else { | 240 | else { |
@@ -263,17 +261,17 @@ static int iwl_read_otp_word(struct iwl_priv *priv, u16 addr, __le16 *eeprom_dat | |||
263 | u32 r; | 261 | u32 r; |
264 | u32 otpgp; | 262 | u32 otpgp; |
265 | 263 | ||
266 | _iwl_write32(priv, CSR_EEPROM_REG, | 264 | iwl_write32(priv, CSR_EEPROM_REG, |
267 | CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); | 265 | CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); |
268 | ret = iwl_poll_bit(priv, CSR_EEPROM_REG, | 266 | ret = iwl_poll_bit(priv, CSR_EEPROM_REG, |
269 | CSR_EEPROM_REG_READ_VALID_MSK, | 267 | CSR_EEPROM_REG_READ_VALID_MSK, |
270 | CSR_EEPROM_REG_READ_VALID_MSK, | 268 | CSR_EEPROM_REG_READ_VALID_MSK, |
271 | IWL_EEPROM_ACCESS_TIMEOUT); | 269 | IWL_EEPROM_ACCESS_TIMEOUT); |
272 | if (ret < 0) { | 270 | if (ret < 0) { |
273 | IWL_ERR(priv, "Time out reading OTP[%d]\n", addr); | 271 | IWL_ERR(priv, "Time out reading OTP[%d]\n", addr); |
274 | return ret; | 272 | return ret; |
275 | } | 273 | } |
276 | r = _iwl_read_direct32(priv, CSR_EEPROM_REG); | 274 | r = iwl_read32(priv, CSR_EEPROM_REG); |
277 | /* check for ECC errors: */ | 275 | /* check for ECC errors: */ |
278 | otpgp = iwl_read32(priv, CSR_OTP_GP_REG); | 276 | otpgp = iwl_read32(priv, CSR_OTP_GP_REG); |
279 | if (otpgp & CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK) { | 277 | if (otpgp & CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK) { |
@@ -396,7 +394,7 @@ u16 iwl_eeprom_query16(const struct iwl_priv *priv, size_t offset) | |||
396 | * | 394 | * |
397 | * NOTE: This routine uses the non-debug IO access functions. | 395 | * NOTE: This routine uses the non-debug IO access functions. |
398 | */ | 396 | */ |
399 | int iwl_eeprom_init(struct iwl_priv *priv) | 397 | int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev) |
400 | { | 398 | { |
401 | __le16 *e; | 399 | __le16 *e; |
402 | u32 gp = iwl_read32(priv, CSR_EEPROM_GP); | 400 | u32 gp = iwl_read32(priv, CSR_EEPROM_GP); |
@@ -406,7 +404,7 @@ int iwl_eeprom_init(struct iwl_priv *priv) | |||
406 | u16 validblockaddr = 0; | 404 | u16 validblockaddr = 0; |
407 | u16 cache_addr = 0; | 405 | u16 cache_addr = 0; |
408 | 406 | ||
409 | priv->nvm_device_type = iwlcore_get_nvm_type(priv); | 407 | priv->nvm_device_type = iwlcore_get_nvm_type(priv, hw_rev); |
410 | if (priv->nvm_device_type == -ENOENT) | 408 | if (priv->nvm_device_type == -ENOENT) |
411 | return -ENOENT; | 409 | return -ENOENT; |
412 | /* allocate eeprom */ | 410 | /* allocate eeprom */ |
@@ -444,9 +442,9 @@ int iwl_eeprom_init(struct iwl_priv *priv) | |||
444 | ret = -ENOENT; | 442 | ret = -ENOENT; |
445 | goto done; | 443 | goto done; |
446 | } | 444 | } |
447 | _iwl_write32(priv, CSR_EEPROM_GP, | 445 | iwl_write32(priv, CSR_EEPROM_GP, |
448 | iwl_read32(priv, CSR_EEPROM_GP) & | 446 | iwl_read32(priv, CSR_EEPROM_GP) & |
449 | ~CSR_EEPROM_GP_IF_OWNER_MSK); | 447 | ~CSR_EEPROM_GP_IF_OWNER_MSK); |
450 | 448 | ||
451 | iwl_set_bit(priv, CSR_OTP_GP_REG, | 449 | iwl_set_bit(priv, CSR_OTP_GP_REG, |
452 | CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK | | 450 | CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK | |
@@ -473,8 +471,8 @@ int iwl_eeprom_init(struct iwl_priv *priv) | |||
473 | for (addr = 0; addr < sz; addr += sizeof(u16)) { | 471 | for (addr = 0; addr < sz; addr += sizeof(u16)) { |
474 | u32 r; | 472 | u32 r; |
475 | 473 | ||
476 | _iwl_write32(priv, CSR_EEPROM_REG, | 474 | iwl_write32(priv, CSR_EEPROM_REG, |
477 | CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); | 475 | CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); |
478 | 476 | ||
479 | ret = iwl_poll_bit(priv, CSR_EEPROM_REG, | 477 | ret = iwl_poll_bit(priv, CSR_EEPROM_REG, |
480 | CSR_EEPROM_REG_READ_VALID_MSK, | 478 | CSR_EEPROM_REG_READ_VALID_MSK, |
@@ -484,7 +482,7 @@ int iwl_eeprom_init(struct iwl_priv *priv) | |||
484 | IWL_ERR(priv, "Time out reading EEPROM[%d]\n", addr); | 482 | IWL_ERR(priv, "Time out reading EEPROM[%d]\n", addr); |
485 | goto done; | 483 | goto done; |
486 | } | 484 | } |
487 | r = _iwl_read_direct32(priv, CSR_EEPROM_REG); | 485 | r = iwl_read32(priv, CSR_EEPROM_REG); |
488 | e[addr / 2] = cpu_to_le16(r >> 16); | 486 | e[addr / 2] = cpu_to_le16(r >> 16); |
489 | } | 487 | } |
490 | } | 488 | } |
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index 20b66469d68f..0e9d9703636a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h | |||
@@ -5,7 +5,7 @@ | |||
5 | * | 5 | * |
6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
7 | * | 7 | * |
8 | * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of version 2 of the GNU General Public License as | 11 | * it under the terms of version 2 of the GNU General Public License as |
@@ -30,7 +30,7 @@ | |||
30 | * | 30 | * |
31 | * BSD LICENSE | 31 | * BSD LICENSE |
32 | * | 32 | * |
33 | * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. | 33 | * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. |
34 | * All rights reserved. | 34 | * All rights reserved. |
35 | * | 35 | * |
36 | * Redistribution and use in source and binary forms, with or without | 36 | * Redistribution and use in source and binary forms, with or without |
@@ -110,10 +110,6 @@ enum { | |||
110 | }; | 110 | }; |
111 | 111 | ||
112 | /* SKU Capabilities */ | 112 | /* SKU Capabilities */ |
113 | /* 3945 only */ | ||
114 | #define EEPROM_SKU_CAP_SW_RF_KILL_ENABLE (1 << 0) | ||
115 | #define EEPROM_SKU_CAP_HW_RF_KILL_ENABLE (1 << 1) | ||
116 | |||
117 | /* 5000 and up */ | 113 | /* 5000 and up */ |
118 | #define EEPROM_SKU_CAP_BAND_POS (4) | 114 | #define EEPROM_SKU_CAP_BAND_POS (4) |
119 | #define EEPROM_SKU_CAP_BAND_SELECTION \ | 115 | #define EEPROM_SKU_CAP_BAND_SELECTION \ |
@@ -168,28 +164,6 @@ struct iwl_eeprom_enhanced_txpwr { | |||
168 | s8 mimo3_max; | 164 | s8 mimo3_max; |
169 | } __packed; | 165 | } __packed; |
170 | 166 | ||
171 | /* 3945 Specific */ | ||
172 | #define EEPROM_3945_EEPROM_VERSION (0x2f) | ||
173 | |||
174 | /* 4965 has two radio transmitters (and 3 radio receivers) */ | ||
175 | #define EEPROM_TX_POWER_TX_CHAINS (2) | ||
176 | |||
177 | /* 4965 has room for up to 8 sets of txpower calibration data */ | ||
178 | #define EEPROM_TX_POWER_BANDS (8) | ||
179 | |||
180 | /* 4965 factory calibration measures txpower gain settings for | ||
181 | * each of 3 target output levels */ | ||
182 | #define EEPROM_TX_POWER_MEASUREMENTS (3) | ||
183 | |||
184 | /* 4965 Specific */ | ||
185 | /* 4965 driver does not work with txpower calibration version < 5 */ | ||
186 | #define EEPROM_4965_TX_POWER_VERSION (5) | ||
187 | #define EEPROM_4965_EEPROM_VERSION (0x2f) | ||
188 | #define EEPROM_4965_CALIB_VERSION_OFFSET (2*0xB6) /* 2 bytes */ | ||
189 | #define EEPROM_4965_CALIB_TXPOWER_OFFSET (2*0xE8) /* 48 bytes */ | ||
190 | #define EEPROM_4965_BOARD_REVISION (2*0x4F) /* 2 bytes */ | ||
191 | #define EEPROM_4965_BOARD_PBA (2*0x56+1) /* 9 bytes */ | ||
192 | |||
193 | /* 5000 Specific */ | 167 | /* 5000 Specific */ |
194 | #define EEPROM_5000_TX_POWER_VERSION (4) | 168 | #define EEPROM_5000_TX_POWER_VERSION (4) |
195 | #define EEPROM_5000_EEPROM_VERSION (0x11A) | 169 | #define EEPROM_5000_EEPROM_VERSION (0x11A) |
@@ -282,90 +256,6 @@ struct iwl_eeprom_enhanced_txpwr { | |||
282 | /* 2.4 GHz */ | 256 | /* 2.4 GHz */ |
283 | extern const u8 iwl_eeprom_band_1[14]; | 257 | extern const u8 iwl_eeprom_band_1[14]; |
284 | 258 | ||
285 | /* | ||
286 | * factory calibration data for one txpower level, on one channel, | ||
287 | * measured on one of the 2 tx chains (radio transmitter and associated | ||
288 | * antenna). EEPROM contains: | ||
289 | * | ||
290 | * 1) Temperature (degrees Celsius) of device when measurement was made. | ||
291 | * | ||
292 | * 2) Gain table index used to achieve the target measurement power. | ||
293 | * This refers to the "well-known" gain tables (see iwl-4965-hw.h). | ||
294 | * | ||
295 | * 3) Actual measured output power, in half-dBm ("34" = 17 dBm). | ||
296 | * | ||
297 | * 4) RF power amplifier detector level measurement (not used). | ||
298 | */ | ||
299 | struct iwl_eeprom_calib_measure { | ||
300 | u8 temperature; /* Device temperature (Celsius) */ | ||
301 | u8 gain_idx; /* Index into gain table */ | ||
302 | u8 actual_pow; /* Measured RF output power, half-dBm */ | ||
303 | s8 pa_det; /* Power amp detector level (not used) */ | ||
304 | } __packed; | ||
305 | |||
306 | |||
307 | /* | ||
308 | * measurement set for one channel. EEPROM contains: | ||
309 | * | ||
310 | * 1) Channel number measured | ||
311 | * | ||
312 | * 2) Measurements for each of 3 power levels for each of 2 radio transmitters | ||
313 | * (a.k.a. "tx chains") (6 measurements altogether) | ||
314 | */ | ||
315 | struct iwl_eeprom_calib_ch_info { | ||
316 | u8 ch_num; | ||
317 | struct iwl_eeprom_calib_measure | ||
318 | measurements[EEPROM_TX_POWER_TX_CHAINS] | ||
319 | [EEPROM_TX_POWER_MEASUREMENTS]; | ||
320 | } __packed; | ||
321 | |||
322 | /* | ||
323 | * txpower subband info. | ||
324 | * | ||
325 | * For each frequency subband, EEPROM contains the following: | ||
326 | * | ||
327 | * 1) First and last channels within range of the subband. "0" values | ||
328 | * indicate that this sample set is not being used. | ||
329 | * | ||
330 | * 2) Sample measurement sets for 2 channels close to the range endpoints. | ||
331 | */ | ||
332 | struct iwl_eeprom_calib_subband_info { | ||
333 | u8 ch_from; /* channel number of lowest channel in subband */ | ||
334 | u8 ch_to; /* channel number of highest channel in subband */ | ||
335 | struct iwl_eeprom_calib_ch_info ch1; | ||
336 | struct iwl_eeprom_calib_ch_info ch2; | ||
337 | } __packed; | ||
338 | |||
339 | |||
340 | /* | ||
341 | * txpower calibration info. EEPROM contains: | ||
342 | * | ||
343 | * 1) Factory-measured saturation power levels (maximum levels at which | ||
344 | * tx power amplifier can output a signal without too much distortion). | ||
345 | * There is one level for 2.4 GHz band and one for 5 GHz band. These | ||
346 | * values apply to all channels within each of the bands. | ||
347 | * | ||
348 | * 2) Factory-measured power supply voltage level. This is assumed to be | ||
349 | * constant (i.e. same value applies to all channels/bands) while the | ||
350 | * factory measurements are being made. | ||
351 | * | ||
352 | * 3) Up to 8 sets of factory-measured txpower calibration values. | ||
353 | * These are for different frequency ranges, since txpower gain | ||
354 | * characteristics of the analog radio circuitry vary with frequency. | ||
355 | * | ||
356 | * Not all sets need to be filled with data; | ||
357 | * struct iwl_eeprom_calib_subband_info contains range of channels | ||
358 | * (0 if unused) for each set of data. | ||
359 | */ | ||
360 | struct iwl_eeprom_calib_info { | ||
361 | u8 saturation_power24; /* half-dBm (e.g. "34" = 17 dBm) */ | ||
362 | u8 saturation_power52; /* half-dBm */ | ||
363 | __le16 voltage; /* signed */ | ||
364 | struct iwl_eeprom_calib_subband_info | ||
365 | band_info[EEPROM_TX_POWER_BANDS]; | ||
366 | } __packed; | ||
367 | |||
368 | |||
369 | #define ADDRESS_MSK 0x0000FFFF | 259 | #define ADDRESS_MSK 0x0000FFFF |
370 | #define INDIRECT_TYPE_MSK 0x000F0000 | 260 | #define INDIRECT_TYPE_MSK 0x000F0000 |
371 | #define INDIRECT_HOST 0x00010000 | 261 | #define INDIRECT_HOST 0x00010000 |
@@ -398,83 +288,8 @@ struct iwl_eeprom_calib_info { | |||
398 | #define EEPROM_RF_CFG_TX_ANT_MSK(x) ((x >> 8) & 0xF) /* bits 8-11 */ | 288 | #define EEPROM_RF_CFG_TX_ANT_MSK(x) ((x >> 8) & 0xF) /* bits 8-11 */ |
399 | #define EEPROM_RF_CFG_RX_ANT_MSK(x) ((x >> 12) & 0xF) /* bits 12-15 */ | 289 | #define EEPROM_RF_CFG_RX_ANT_MSK(x) ((x >> 12) & 0xF) /* bits 12-15 */ |
400 | 290 | ||
401 | #define EEPROM_3945_RF_CFG_TYPE_MAX 0x0 | ||
402 | #define EEPROM_4965_RF_CFG_TYPE_MAX 0x1 | ||
403 | |||
404 | /* Radio Config for 5000 and up */ | ||
405 | #define EEPROM_RF_CONFIG_TYPE_R3x3 0x0 | ||
406 | #define EEPROM_RF_CONFIG_TYPE_R2x2 0x1 | ||
407 | #define EEPROM_RF_CONFIG_TYPE_R1x2 0x2 | ||
408 | #define EEPROM_RF_CONFIG_TYPE_MAX 0x3 | 291 | #define EEPROM_RF_CONFIG_TYPE_MAX 0x3 |
409 | 292 | ||
410 | /* | ||
411 | * Per-channel regulatory data. | ||
412 | * | ||
413 | * Each channel that *might* be supported by iwl has a fixed location | ||
414 | * in EEPROM containing EEPROM_CHANNEL_* usage flags (LSB) and max regulatory | ||
415 | * txpower (MSB). | ||
416 | * | ||
417 | * Entries immediately below are for 20 MHz channel width. HT40 (40 MHz) | ||
418 | * channels (only for 4965, not supported by 3945) appear later in the EEPROM. | ||
419 | * | ||
420 | * 2.4 GHz channels 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 | ||
421 | */ | ||
422 | #define EEPROM_REGULATORY_SKU_ID (2*0x60) /* 4 bytes */ | ||
423 | #define EEPROM_REGULATORY_BAND_1 (2*0x62) /* 2 bytes */ | ||
424 | #define EEPROM_REGULATORY_BAND_1_CHANNELS (2*0x63) /* 28 bytes */ | ||
425 | |||
426 | /* | ||
427 | * 4.9 GHz channels 183, 184, 185, 187, 188, 189, 192, 196, | ||
428 | * 5.0 GHz channels 7, 8, 11, 12, 16 | ||
429 | * (4915-5080MHz) (none of these is ever supported) | ||
430 | */ | ||
431 | #define EEPROM_REGULATORY_BAND_2 (2*0x71) /* 2 bytes */ | ||
432 | #define EEPROM_REGULATORY_BAND_2_CHANNELS (2*0x72) /* 26 bytes */ | ||
433 | |||
434 | /* | ||
435 | * 5.2 GHz channels 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64 | ||
436 | * (5170-5320MHz) | ||
437 | */ | ||
438 | #define EEPROM_REGULATORY_BAND_3 (2*0x7F) /* 2 bytes */ | ||
439 | #define EEPROM_REGULATORY_BAND_3_CHANNELS (2*0x80) /* 24 bytes */ | ||
440 | |||
441 | /* | ||
442 | * 5.5 GHz channels 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140 | ||
443 | * (5500-5700MHz) | ||
444 | */ | ||
445 | #define EEPROM_REGULATORY_BAND_4 (2*0x8C) /* 2 bytes */ | ||
446 | #define EEPROM_REGULATORY_BAND_4_CHANNELS (2*0x8D) /* 22 bytes */ | ||
447 | |||
448 | /* | ||
449 | * 5.7 GHz channels 145, 149, 153, 157, 161, 165 | ||
450 | * (5725-5825MHz) | ||
451 | */ | ||
452 | #define EEPROM_REGULATORY_BAND_5 (2*0x98) /* 2 bytes */ | ||
453 | #define EEPROM_REGULATORY_BAND_5_CHANNELS (2*0x99) /* 12 bytes */ | ||
454 | |||
455 | /* | ||
456 | * 2.4 GHz HT40 channels 1 (5), 2 (6), 3 (7), 4 (8), 5 (9), 6 (10), 7 (11) | ||
457 | * | ||
458 | * The channel listed is the center of the lower 20 MHz half of the channel. | ||
459 | * The overall center frequency is actually 2 channels (10 MHz) above that, | ||
460 | * and the upper half of each HT40 channel is centered 4 channels (20 MHz) away | ||
461 | * from the lower half; e.g. the upper half of HT40 channel 1 is channel 5, | ||
462 | * and the overall HT40 channel width centers on channel 3. | ||
463 | * | ||
464 | * NOTE: The RXON command uses 20 MHz channel numbers to specify the | ||
465 | * control channel to which to tune. RXON also specifies whether the | ||
466 | * control channel is the upper or lower half of a HT40 channel. | ||
467 | * | ||
468 | * NOTE: 4965 does not support HT40 channels on 2.4 GHz. | ||
469 | */ | ||
470 | #define EEPROM_4965_REGULATORY_BAND_24_HT40_CHANNELS (2*0xA0) /* 14 bytes */ | ||
471 | |||
472 | /* | ||
473 | * 5.2 GHz HT40 channels 36 (40), 44 (48), 52 (56), 60 (64), | ||
474 | * 100 (104), 108 (112), 116 (120), 124 (128), 132 (136), 149 (153), 157 (161) | ||
475 | */ | ||
476 | #define EEPROM_4965_REGULATORY_BAND_52_HT40_CHANNELS (2*0xA8) /* 22 bytes */ | ||
477 | |||
478 | #define EEPROM_REGULATORY_BAND_NO_HT40 (0) | 293 | #define EEPROM_REGULATORY_BAND_NO_HT40 (0) |
479 | 294 | ||
480 | struct iwl_eeprom_ops { | 295 | struct iwl_eeprom_ops { |
@@ -487,7 +302,7 @@ struct iwl_eeprom_ops { | |||
487 | }; | 302 | }; |
488 | 303 | ||
489 | 304 | ||
490 | int iwl_eeprom_init(struct iwl_priv *priv); | 305 | int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev); |
491 | void iwl_eeprom_free(struct iwl_priv *priv); | 306 | void iwl_eeprom_free(struct iwl_priv *priv); |
492 | int iwl_eeprom_check_version(struct iwl_priv *priv); | 307 | int iwl_eeprom_check_version(struct iwl_priv *priv); |
493 | int iwl_eeprom_check_sku(struct iwl_priv *priv); | 308 | int iwl_eeprom_check_sku(struct iwl_priv *priv); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-fh.h b/drivers/net/wireless/iwlwifi/iwl-fh.h index 474009a244d4..e7a1bc6b76fd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fh.h +++ b/drivers/net/wireless/iwlwifi/iwl-fh.h | |||
@@ -5,7 +5,7 @@ | |||
5 | * | 5 | * |
6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
7 | * | 7 | * |
8 | * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of version 2 of the GNU General Public License as | 11 | * it under the terms of version 2 of the GNU General Public License as |
@@ -30,7 +30,7 @@ | |||
30 | * | 30 | * |
31 | * BSD LICENSE | 31 | * BSD LICENSE |
32 | * | 32 | * |
33 | * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. | 33 | * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. |
34 | * All rights reserved. | 34 | * All rights reserved. |
35 | * | 35 | * |
36 | * Redistribution and use in source and binary forms, with or without | 36 | * Redistribution and use in source and binary forms, with or without |
diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c index 02499f684683..9177b553fe57 100644 --- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c +++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * | 2 | * |
3 | * GPL LICENSE SUMMARY | 3 | * GPL LICENSE SUMMARY |
4 | * | 4 | * |
5 | * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. | 5 | * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of version 2 of the GNU General Public License as | 8 | * it under the terms of version 2 of the GNU General Public License as |
@@ -51,9 +51,7 @@ const char *get_cmd_string(u8 cmd) | |||
51 | IWL_CMD(REPLY_REMOVE_ALL_STA); | 51 | IWL_CMD(REPLY_REMOVE_ALL_STA); |
52 | IWL_CMD(REPLY_TXFIFO_FLUSH); | 52 | IWL_CMD(REPLY_TXFIFO_FLUSH); |
53 | IWL_CMD(REPLY_WEPKEY); | 53 | IWL_CMD(REPLY_WEPKEY); |
54 | IWL_CMD(REPLY_3945_RX); | ||
55 | IWL_CMD(REPLY_TX); | 54 | IWL_CMD(REPLY_TX); |
56 | IWL_CMD(REPLY_RATE_SCALE); | ||
57 | IWL_CMD(REPLY_LEDS_CMD); | 55 | IWL_CMD(REPLY_LEDS_CMD); |
58 | IWL_CMD(REPLY_TX_LINK_QUALITY_CMD); | 56 | IWL_CMD(REPLY_TX_LINK_QUALITY_CMD); |
59 | IWL_CMD(COEX_PRIORITY_TABLE_CMD); | 57 | IWL_CMD(COEX_PRIORITY_TABLE_CMD); |
@@ -171,14 +169,13 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) | |||
171 | int cmd_idx; | 169 | int cmd_idx; |
172 | int ret; | 170 | int ret; |
173 | 171 | ||
174 | BUG_ON(cmd->flags & CMD_ASYNC); | 172 | lockdep_assert_held(&priv->mutex); |
175 | 173 | ||
176 | /* A synchronous command can not have a callback set. */ | 174 | /* A synchronous command can not have a callback set. */ |
177 | BUG_ON(cmd->callback); | 175 | BUG_ON((cmd->flags & CMD_ASYNC) || cmd->callback); |
178 | 176 | ||
179 | IWL_DEBUG_INFO(priv, "Attempting to send sync command %s\n", | 177 | IWL_DEBUG_INFO(priv, "Attempting to send sync command %s\n", |
180 | get_cmd_string(cmd->id)); | 178 | get_cmd_string(cmd->id)); |
181 | mutex_lock(&priv->sync_cmd_mutex); | ||
182 | 179 | ||
183 | set_bit(STATUS_HCMD_ACTIVE, &priv->status); | 180 | set_bit(STATUS_HCMD_ACTIVE, &priv->status); |
184 | IWL_DEBUG_INFO(priv, "Setting HCMD_ACTIVE for command %s\n", | 181 | IWL_DEBUG_INFO(priv, "Setting HCMD_ACTIVE for command %s\n", |
@@ -189,7 +186,7 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) | |||
189 | ret = cmd_idx; | 186 | ret = cmd_idx; |
190 | IWL_ERR(priv, "Error sending %s: enqueue_hcmd failed: %d\n", | 187 | IWL_ERR(priv, "Error sending %s: enqueue_hcmd failed: %d\n", |
191 | get_cmd_string(cmd->id), ret); | 188 | get_cmd_string(cmd->id), ret); |
192 | goto out; | 189 | return ret; |
193 | } | 190 | } |
194 | 191 | ||
195 | ret = wait_event_interruptible_timeout(priv->wait_command_queue, | 192 | ret = wait_event_interruptible_timeout(priv->wait_command_queue, |
@@ -229,8 +226,7 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) | |||
229 | goto cancel; | 226 | goto cancel; |
230 | } | 227 | } |
231 | 228 | ||
232 | ret = 0; | 229 | return 0; |
233 | goto out; | ||
234 | 230 | ||
235 | cancel: | 231 | cancel: |
236 | if (cmd->flags & CMD_WANT_SKB) { | 232 | if (cmd->flags & CMD_WANT_SKB) { |
@@ -248,8 +244,7 @@ fail: | |||
248 | iwl_free_pages(priv, cmd->reply_page); | 244 | iwl_free_pages(priv, cmd->reply_page); |
249 | cmd->reply_page = 0; | 245 | cmd->reply_page = 0; |
250 | } | 246 | } |
251 | out: | 247 | |
252 | mutex_unlock(&priv->sync_cmd_mutex); | ||
253 | return ret; | 248 | return ret; |
254 | } | 249 | } |
255 | 250 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-helpers.h b/drivers/net/wireless/iwlwifi/iwl-helpers.h index 8821f088ba7f..5da5761c74b1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-helpers.h +++ b/drivers/net/wireless/iwlwifi/iwl-helpers.h | |||
@@ -1,6 +1,6 @@ | |||
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | * | 2 | * |
3 | * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. | 3 | * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. |
4 | * | 4 | * |
5 | * Portions of this file are derived from the ipw3945 project, as well | 5 | * Portions of this file are derived from the ipw3945 project, as well |
6 | * as portions of the ieee80211 subsystem header files. | 6 | * as portions of the ieee80211 subsystem header files. |
diff --git a/drivers/net/wireless/iwlwifi/iwl-io.c b/drivers/net/wireless/iwlwifi/iwl-io.c new file mode 100644 index 000000000000..51337416e4ca --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-io.c | |||
@@ -0,0 +1,274 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. | ||
4 | * | ||
5 | * Portions of this file are derived from the ipw3945 project. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of version 2 of the GNU General Public License as | ||
9 | * published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
14 | * more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along with | ||
17 | * this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA | ||
19 | * | ||
20 | * The full GNU General Public License is included in this distribution in the | ||
21 | * file called LICENSE. | ||
22 | * | ||
23 | * Contact Information: | ||
24 | * Intel Linux Wireless <ilw@linux.intel.com> | ||
25 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
26 | * | ||
27 | *****************************************************************************/ | ||
28 | |||
29 | #include "iwl-io.h" | ||
30 | |||
31 | #define IWL_POLL_INTERVAL 10 /* microseconds */ | ||
32 | |||
33 | static inline void __iwl_set_bit(struct iwl_priv *priv, u32 reg, u32 mask) | ||
34 | { | ||
35 | iwl_write32(priv, reg, iwl_read32(priv, reg) | mask); | ||
36 | } | ||
37 | |||
38 | static inline void __iwl_clear_bit(struct iwl_priv *priv, u32 reg, u32 mask) | ||
39 | { | ||
40 | iwl_write32(priv, reg, iwl_read32(priv, reg) & ~mask); | ||
41 | } | ||
42 | |||
43 | void iwl_set_bit(struct iwl_priv *priv, u32 reg, u32 mask) | ||
44 | { | ||
45 | unsigned long flags; | ||
46 | |||
47 | spin_lock_irqsave(&priv->reg_lock, flags); | ||
48 | __iwl_set_bit(priv, reg, mask); | ||
49 | spin_unlock_irqrestore(&priv->reg_lock, flags); | ||
50 | } | ||
51 | |||
52 | void iwl_clear_bit(struct iwl_priv *priv, u32 reg, u32 mask) | ||
53 | { | ||
54 | unsigned long flags; | ||
55 | |||
56 | spin_lock_irqsave(&priv->reg_lock, flags); | ||
57 | __iwl_clear_bit(priv, reg, mask); | ||
58 | spin_unlock_irqrestore(&priv->reg_lock, flags); | ||
59 | } | ||
60 | |||
61 | int iwl_poll_bit(struct iwl_priv *priv, u32 addr, | ||
62 | u32 bits, u32 mask, int timeout) | ||
63 | { | ||
64 | int t = 0; | ||
65 | |||
66 | do { | ||
67 | if ((iwl_read32(priv, addr) & mask) == (bits & mask)) | ||
68 | return t; | ||
69 | udelay(IWL_POLL_INTERVAL); | ||
70 | t += IWL_POLL_INTERVAL; | ||
71 | } while (t < timeout); | ||
72 | |||
73 | return -ETIMEDOUT; | ||
74 | } | ||
75 | |||
76 | int iwl_grab_nic_access(struct iwl_priv *priv) | ||
77 | { | ||
78 | int ret; | ||
79 | u32 val; | ||
80 | |||
81 | lockdep_assert_held(&priv->reg_lock); | ||
82 | |||
83 | /* this bit wakes up the NIC */ | ||
84 | __iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); | ||
85 | |||
86 | /* | ||
87 | * These bits say the device is running, and should keep running for | ||
88 | * at least a short while (at least as long as MAC_ACCESS_REQ stays 1), | ||
89 | * but they do not indicate that embedded SRAM is restored yet; | ||
90 | * 3945 and 4965 have volatile SRAM, and must save/restore contents | ||
91 | * to/from host DRAM when sleeping/waking for power-saving. | ||
92 | * Each direction takes approximately 1/4 millisecond; with this | ||
93 | * overhead, it's a good idea to grab and hold MAC_ACCESS_REQUEST if a | ||
94 | * series of register accesses are expected (e.g. reading Event Log), | ||
95 | * to keep device from sleeping. | ||
96 | * | ||
97 | * CSR_UCODE_DRV_GP1 register bit MAC_SLEEP == 0 indicates that | ||
98 | * SRAM is okay/restored. We don't check that here because this call | ||
99 | * is just for hardware register access; but GP1 MAC_SLEEP check is a | ||
100 | * good idea before accessing 3945/4965 SRAM (e.g. reading Event Log). | ||
101 | * | ||
102 | * 5000 series and later (including 1000 series) have non-volatile SRAM, | ||
103 | * and do not save/restore SRAM when power cycling. | ||
104 | */ | ||
105 | ret = iwl_poll_bit(priv, CSR_GP_CNTRL, | ||
106 | CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN, | ||
107 | (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY | | ||
108 | CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 15000); | ||
109 | if (ret < 0) { | ||
110 | val = iwl_read32(priv, CSR_GP_CNTRL); | ||
111 | IWL_ERR(priv, | ||
112 | "MAC is in deep sleep!. CSR_GP_CNTRL = 0x%08X\n", val); | ||
113 | iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_FORCE_NMI); | ||
114 | return -EIO; | ||
115 | } | ||
116 | |||
117 | return 0; | ||
118 | } | ||
119 | |||
120 | void iwl_release_nic_access(struct iwl_priv *priv) | ||
121 | { | ||
122 | lockdep_assert_held(&priv->reg_lock); | ||
123 | __iwl_clear_bit(priv, CSR_GP_CNTRL, | ||
124 | CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); | ||
125 | } | ||
126 | |||
127 | u32 iwl_read_direct32(struct iwl_priv *priv, u32 reg) | ||
128 | { | ||
129 | u32 value; | ||
130 | unsigned long flags; | ||
131 | |||
132 | spin_lock_irqsave(&priv->reg_lock, flags); | ||
133 | iwl_grab_nic_access(priv); | ||
134 | value = iwl_read32(priv, reg); | ||
135 | iwl_release_nic_access(priv); | ||
136 | spin_unlock_irqrestore(&priv->reg_lock, flags); | ||
137 | |||
138 | return value; | ||
139 | } | ||
140 | |||
141 | void iwl_write_direct32(struct iwl_priv *priv, u32 reg, u32 value) | ||
142 | { | ||
143 | unsigned long flags; | ||
144 | |||
145 | spin_lock_irqsave(&priv->reg_lock, flags); | ||
146 | if (!iwl_grab_nic_access(priv)) { | ||
147 | iwl_write32(priv, reg, value); | ||
148 | iwl_release_nic_access(priv); | ||
149 | } | ||
150 | spin_unlock_irqrestore(&priv->reg_lock, flags); | ||
151 | } | ||
152 | |||
153 | int iwl_poll_direct_bit(struct iwl_priv *priv, u32 addr, u32 mask, | ||
154 | int timeout) | ||
155 | { | ||
156 | int t = 0; | ||
157 | |||
158 | do { | ||
159 | if ((iwl_read_direct32(priv, addr) & mask) == mask) | ||
160 | return t; | ||
161 | udelay(IWL_POLL_INTERVAL); | ||
162 | t += IWL_POLL_INTERVAL; | ||
163 | } while (t < timeout); | ||
164 | |||
165 | return -ETIMEDOUT; | ||
166 | } | ||
167 | |||
168 | static inline u32 __iwl_read_prph(struct iwl_priv *priv, u32 reg) | ||
169 | { | ||
170 | iwl_write32(priv, HBUS_TARG_PRPH_RADDR, reg | (3 << 24)); | ||
171 | rmb(); | ||
172 | return iwl_read32(priv, HBUS_TARG_PRPH_RDAT); | ||
173 | } | ||
174 | |||
175 | static inline void __iwl_write_prph(struct iwl_priv *priv, u32 addr, u32 val) | ||
176 | { | ||
177 | iwl_write32(priv, HBUS_TARG_PRPH_WADDR, | ||
178 | ((addr & 0x0000FFFF) | (3 << 24))); | ||
179 | wmb(); | ||
180 | iwl_write32(priv, HBUS_TARG_PRPH_WDAT, val); | ||
181 | } | ||
182 | |||
183 | u32 iwl_read_prph(struct iwl_priv *priv, u32 reg) | ||
184 | { | ||
185 | unsigned long flags; | ||
186 | u32 val; | ||
187 | |||
188 | spin_lock_irqsave(&priv->reg_lock, flags); | ||
189 | iwl_grab_nic_access(priv); | ||
190 | val = __iwl_read_prph(priv, reg); | ||
191 | iwl_release_nic_access(priv); | ||
192 | spin_unlock_irqrestore(&priv->reg_lock, flags); | ||
193 | return val; | ||
194 | } | ||
195 | |||
196 | void iwl_write_prph(struct iwl_priv *priv, u32 addr, u32 val) | ||
197 | { | ||
198 | unsigned long flags; | ||
199 | |||
200 | spin_lock_irqsave(&priv->reg_lock, flags); | ||
201 | if (!iwl_grab_nic_access(priv)) { | ||
202 | __iwl_write_prph(priv, addr, val); | ||
203 | iwl_release_nic_access(priv); | ||
204 | } | ||
205 | spin_unlock_irqrestore(&priv->reg_lock, flags); | ||
206 | } | ||
207 | |||
208 | void iwl_set_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask) | ||
209 | { | ||
210 | unsigned long flags; | ||
211 | |||
212 | spin_lock_irqsave(&priv->reg_lock, flags); | ||
213 | iwl_grab_nic_access(priv); | ||
214 | __iwl_write_prph(priv, reg, __iwl_read_prph(priv, reg) | mask); | ||
215 | iwl_release_nic_access(priv); | ||
216 | spin_unlock_irqrestore(&priv->reg_lock, flags); | ||
217 | } | ||
218 | |||
219 | void iwl_set_bits_mask_prph(struct iwl_priv *priv, u32 reg, | ||
220 | u32 bits, u32 mask) | ||
221 | { | ||
222 | unsigned long flags; | ||
223 | |||
224 | spin_lock_irqsave(&priv->reg_lock, flags); | ||
225 | iwl_grab_nic_access(priv); | ||
226 | __iwl_write_prph(priv, reg, | ||
227 | (__iwl_read_prph(priv, reg) & mask) | bits); | ||
228 | iwl_release_nic_access(priv); | ||
229 | spin_unlock_irqrestore(&priv->reg_lock, flags); | ||
230 | } | ||
231 | |||
232 | void iwl_clear_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask) | ||
233 | { | ||
234 | unsigned long flags; | ||
235 | u32 val; | ||
236 | |||
237 | spin_lock_irqsave(&priv->reg_lock, flags); | ||
238 | iwl_grab_nic_access(priv); | ||
239 | val = __iwl_read_prph(priv, reg); | ||
240 | __iwl_write_prph(priv, reg, (val & ~mask)); | ||
241 | iwl_release_nic_access(priv); | ||
242 | spin_unlock_irqrestore(&priv->reg_lock, flags); | ||
243 | } | ||
244 | |||
245 | u32 iwl_read_targ_mem(struct iwl_priv *priv, u32 addr) | ||
246 | { | ||
247 | unsigned long flags; | ||
248 | u32 value; | ||
249 | |||
250 | spin_lock_irqsave(&priv->reg_lock, flags); | ||
251 | iwl_grab_nic_access(priv); | ||
252 | |||
253 | iwl_write32(priv, HBUS_TARG_MEM_RADDR, addr); | ||
254 | rmb(); | ||
255 | value = iwl_read32(priv, HBUS_TARG_MEM_RDAT); | ||
256 | |||
257 | iwl_release_nic_access(priv); | ||
258 | spin_unlock_irqrestore(&priv->reg_lock, flags); | ||
259 | return value; | ||
260 | } | ||
261 | |||
262 | void iwl_write_targ_mem(struct iwl_priv *priv, u32 addr, u32 val) | ||
263 | { | ||
264 | unsigned long flags; | ||
265 | |||
266 | spin_lock_irqsave(&priv->reg_lock, flags); | ||
267 | if (!iwl_grab_nic_access(priv)) { | ||
268 | iwl_write32(priv, HBUS_TARG_MEM_WADDR, addr); | ||
269 | wmb(); | ||
270 | iwl_write32(priv, HBUS_TARG_MEM_WDAT, val); | ||
271 | iwl_release_nic_access(priv); | ||
272 | } | ||
273 | spin_unlock_irqrestore(&priv->reg_lock, flags); | ||
274 | } | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h index 0203a3bbf872..ab632baf49d5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.h +++ b/drivers/net/wireless/iwlwifi/iwl-io.h | |||
@@ -1,6 +1,6 @@ | |||
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | * | 2 | * |
3 | * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. | 3 | * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. |
4 | * | 4 | * |
5 | * Portions of this file are derived from the ipw3945 project. | 5 | * Portions of this file are derived from the ipw3945 project. |
6 | * | 6 | * |
@@ -35,494 +35,47 @@ | |||
35 | #include "iwl-debug.h" | 35 | #include "iwl-debug.h" |
36 | #include "iwl-devtrace.h" | 36 | #include "iwl-devtrace.h" |
37 | 37 | ||
38 | /* | 38 | static inline void iwl_write8(struct iwl_priv *priv, u32 ofs, u8 val) |
39 | * IO, register, and NIC memory access functions | ||
40 | * | ||
41 | * NOTE on naming convention and macro usage for these | ||
42 | * | ||
43 | * A single _ prefix before a an access function means that no state | ||
44 | * check or debug information is printed when that function is called. | ||
45 | * | ||
46 | * A double __ prefix before an access function means that state is checked | ||
47 | * and the current line number and caller function name are printed in addition | ||
48 | * to any other debug output. | ||
49 | * | ||
50 | * The non-prefixed name is the #define that maps the caller into a | ||
51 | * #define that provides the caller's name and __LINE__ to the double | ||
52 | * prefix version. | ||
53 | * | ||
54 | * If you wish to call the function without any debug or state checking, | ||
55 | * you should use the single _ prefix version (as is used by dependent IO | ||
56 | * routines, for example _iwl_read_direct32 calls the non-check version of | ||
57 | * _iwl_read32.) | ||
58 | * | ||
59 | * These declarations are *extremely* useful in quickly isolating code deltas | ||
60 | * which result in misconfiguration of the hardware I/O. In combination with | ||
61 | * git-bisect and the IO debug level you can quickly determine the specific | ||
62 | * commit which breaks the IO sequence to the hardware. | ||
63 | * | ||
64 | */ | ||
65 | |||
66 | static inline void _iwl_write8(struct iwl_priv *priv, u32 ofs, u8 val) | ||
67 | { | 39 | { |
68 | trace_iwlwifi_dev_iowrite8(priv, ofs, val); | 40 | trace_iwlwifi_dev_iowrite8(priv, ofs, val); |
69 | iowrite8(val, priv->hw_base + ofs); | 41 | iowrite8(val, priv->hw_base + ofs); |
70 | } | 42 | } |
71 | 43 | ||
72 | #ifdef CONFIG_IWLWIFI_DEBUG | 44 | static inline void iwl_write32(struct iwl_priv *priv, u32 ofs, u32 val) |
73 | static inline void __iwl_write8(const char *f, u32 l, struct iwl_priv *priv, | ||
74 | u32 ofs, u8 val) | ||
75 | { | ||
76 | IWL_DEBUG_IO(priv, "write8(0x%08X, 0x%02X) - %s %d\n", ofs, val, f, l); | ||
77 | _iwl_write8(priv, ofs, val); | ||
78 | } | ||
79 | #define iwl_write8(priv, ofs, val) \ | ||
80 | __iwl_write8(__FILE__, __LINE__, priv, ofs, val) | ||
81 | #else | ||
82 | #define iwl_write8(priv, ofs, val) _iwl_write8(priv, ofs, val) | ||
83 | #endif | ||
84 | |||
85 | |||
86 | static inline void _iwl_write32(struct iwl_priv *priv, u32 ofs, u32 val) | ||
87 | { | 45 | { |
88 | trace_iwlwifi_dev_iowrite32(priv, ofs, val); | 46 | trace_iwlwifi_dev_iowrite32(priv, ofs, val); |
89 | iowrite32(val, priv->hw_base + ofs); | 47 | iowrite32(val, priv->hw_base + ofs); |
90 | } | 48 | } |
91 | 49 | ||
92 | #ifdef CONFIG_IWLWIFI_DEBUG | 50 | static inline u32 iwl_read32(struct iwl_priv *priv, u32 ofs) |
93 | static inline void __iwl_write32(const char *f, u32 l, struct iwl_priv *priv, | ||
94 | u32 ofs, u32 val) | ||
95 | { | ||
96 | IWL_DEBUG_IO(priv, "write32(0x%08X, 0x%08X) - %s %d\n", ofs, val, f, l); | ||
97 | _iwl_write32(priv, ofs, val); | ||
98 | } | ||
99 | #define iwl_write32(priv, ofs, val) \ | ||
100 | __iwl_write32(__FILE__, __LINE__, priv, ofs, val) | ||
101 | #else | ||
102 | #define iwl_write32(priv, ofs, val) _iwl_write32(priv, ofs, val) | ||
103 | #endif | ||
104 | |||
105 | static inline u32 _iwl_read32(struct iwl_priv *priv, u32 ofs) | ||
106 | { | 51 | { |
107 | u32 val = ioread32(priv->hw_base + ofs); | 52 | u32 val = ioread32(priv->hw_base + ofs); |
108 | trace_iwlwifi_dev_ioread32(priv, ofs, val); | 53 | trace_iwlwifi_dev_ioread32(priv, ofs, val); |
109 | return val; | 54 | return val; |
110 | } | 55 | } |
111 | 56 | ||
112 | #ifdef CONFIG_IWLWIFI_DEBUG | 57 | void iwl_set_bit(struct iwl_priv *priv, u32 reg, u32 mask); |
113 | static inline u32 __iwl_read32(char *f, u32 l, struct iwl_priv *priv, u32 ofs) | 58 | void iwl_clear_bit(struct iwl_priv *priv, u32 reg, u32 mask); |
114 | { | ||
115 | IWL_DEBUG_IO(priv, "read_direct32(0x%08X) - %s %d\n", ofs, f, l); | ||
116 | return _iwl_read32(priv, ofs); | ||
117 | } | ||
118 | #define iwl_read32(priv, ofs) __iwl_read32(__FILE__, __LINE__, priv, ofs) | ||
119 | #else | ||
120 | #define iwl_read32(p, o) _iwl_read32(p, o) | ||
121 | #endif | ||
122 | |||
123 | #define IWL_POLL_INTERVAL 10 /* microseconds */ | ||
124 | static inline int _iwl_poll_bit(struct iwl_priv *priv, u32 addr, | ||
125 | u32 bits, u32 mask, int timeout) | ||
126 | { | ||
127 | int t = 0; | ||
128 | |||
129 | do { | ||
130 | if ((_iwl_read32(priv, addr) & mask) == (bits & mask)) | ||
131 | return t; | ||
132 | udelay(IWL_POLL_INTERVAL); | ||
133 | t += IWL_POLL_INTERVAL; | ||
134 | } while (t < timeout); | ||
135 | |||
136 | return -ETIMEDOUT; | ||
137 | } | ||
138 | #ifdef CONFIG_IWLWIFI_DEBUG | ||
139 | static inline int __iwl_poll_bit(const char *f, u32 l, | ||
140 | struct iwl_priv *priv, u32 addr, | ||
141 | u32 bits, u32 mask, int timeout) | ||
142 | { | ||
143 | int ret = _iwl_poll_bit(priv, addr, bits, mask, timeout); | ||
144 | IWL_DEBUG_IO(priv, "poll_bit(0x%08X, 0x%08X, 0x%08X) - %s- %s %d\n", | ||
145 | addr, bits, mask, | ||
146 | unlikely(ret == -ETIMEDOUT) ? "timeout" : "", f, l); | ||
147 | return ret; | ||
148 | } | ||
149 | #define iwl_poll_bit(priv, addr, bits, mask, timeout) \ | ||
150 | __iwl_poll_bit(__FILE__, __LINE__, priv, addr, bits, mask, timeout) | ||
151 | #else | ||
152 | #define iwl_poll_bit(p, a, b, m, t) _iwl_poll_bit(p, a, b, m, t) | ||
153 | #endif | ||
154 | |||
155 | static inline void _iwl_set_bit(struct iwl_priv *priv, u32 reg, u32 mask) | ||
156 | { | ||
157 | _iwl_write32(priv, reg, _iwl_read32(priv, reg) | mask); | ||
158 | } | ||
159 | #ifdef CONFIG_IWLWIFI_DEBUG | ||
160 | static inline void __iwl_set_bit(const char *f, u32 l, | ||
161 | struct iwl_priv *priv, u32 reg, u32 mask) | ||
162 | { | ||
163 | u32 val = _iwl_read32(priv, reg) | mask; | ||
164 | IWL_DEBUG_IO(priv, "set_bit(0x%08X, 0x%08X) = 0x%08X\n", reg, mask, val); | ||
165 | _iwl_write32(priv, reg, val); | ||
166 | } | ||
167 | static inline void iwl_set_bit(struct iwl_priv *p, u32 r, u32 m) | ||
168 | { | ||
169 | unsigned long reg_flags; | ||
170 | |||
171 | spin_lock_irqsave(&p->reg_lock, reg_flags); | ||
172 | __iwl_set_bit(__FILE__, __LINE__, p, r, m); | ||
173 | spin_unlock_irqrestore(&p->reg_lock, reg_flags); | ||
174 | } | ||
175 | #else | ||
176 | static inline void iwl_set_bit(struct iwl_priv *p, u32 r, u32 m) | ||
177 | { | ||
178 | unsigned long reg_flags; | ||
179 | |||
180 | spin_lock_irqsave(&p->reg_lock, reg_flags); | ||
181 | _iwl_set_bit(p, r, m); | ||
182 | spin_unlock_irqrestore(&p->reg_lock, reg_flags); | ||
183 | } | ||
184 | #endif | ||
185 | |||
186 | static inline void _iwl_clear_bit(struct iwl_priv *priv, u32 reg, u32 mask) | ||
187 | { | ||
188 | _iwl_write32(priv, reg, _iwl_read32(priv, reg) & ~mask); | ||
189 | } | ||
190 | #ifdef CONFIG_IWLWIFI_DEBUG | ||
191 | static inline void __iwl_clear_bit(const char *f, u32 l, | ||
192 | struct iwl_priv *priv, u32 reg, u32 mask) | ||
193 | { | ||
194 | u32 val = _iwl_read32(priv, reg) & ~mask; | ||
195 | IWL_DEBUG_IO(priv, "clear_bit(0x%08X, 0x%08X) = 0x%08X\n", reg, mask, val); | ||
196 | _iwl_write32(priv, reg, val); | ||
197 | } | ||
198 | static inline void iwl_clear_bit(struct iwl_priv *p, u32 r, u32 m) | ||
199 | { | ||
200 | unsigned long reg_flags; | ||
201 | |||
202 | spin_lock_irqsave(&p->reg_lock, reg_flags); | ||
203 | __iwl_clear_bit(__FILE__, __LINE__, p, r, m); | ||
204 | spin_unlock_irqrestore(&p->reg_lock, reg_flags); | ||
205 | } | ||
206 | #else | ||
207 | static inline void iwl_clear_bit(struct iwl_priv *p, u32 r, u32 m) | ||
208 | { | ||
209 | unsigned long reg_flags; | ||
210 | |||
211 | spin_lock_irqsave(&p->reg_lock, reg_flags); | ||
212 | _iwl_clear_bit(p, r, m); | ||
213 | spin_unlock_irqrestore(&p->reg_lock, reg_flags); | ||
214 | } | ||
215 | #endif | ||
216 | |||
217 | static inline int _iwl_grab_nic_access(struct iwl_priv *priv) | ||
218 | { | ||
219 | int ret; | ||
220 | u32 val; | ||
221 | |||
222 | /* this bit wakes up the NIC */ | ||
223 | _iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); | ||
224 | |||
225 | /* | ||
226 | * These bits say the device is running, and should keep running for | ||
227 | * at least a short while (at least as long as MAC_ACCESS_REQ stays 1), | ||
228 | * but they do not indicate that embedded SRAM is restored yet; | ||
229 | * 3945 and 4965 have volatile SRAM, and must save/restore contents | ||
230 | * to/from host DRAM when sleeping/waking for power-saving. | ||
231 | * Each direction takes approximately 1/4 millisecond; with this | ||
232 | * overhead, it's a good idea to grab and hold MAC_ACCESS_REQUEST if a | ||
233 | * series of register accesses are expected (e.g. reading Event Log), | ||
234 | * to keep device from sleeping. | ||
235 | * | ||
236 | * CSR_UCODE_DRV_GP1 register bit MAC_SLEEP == 0 indicates that | ||
237 | * SRAM is okay/restored. We don't check that here because this call | ||
238 | * is just for hardware register access; but GP1 MAC_SLEEP check is a | ||
239 | * good idea before accessing 3945/4965 SRAM (e.g. reading Event Log). | ||
240 | * | ||
241 | * 5000 series and later (including 1000 series) have non-volatile SRAM, | ||
242 | * and do not save/restore SRAM when power cycling. | ||
243 | */ | ||
244 | ret = _iwl_poll_bit(priv, CSR_GP_CNTRL, | ||
245 | CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN, | ||
246 | (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY | | ||
247 | CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 15000); | ||
248 | if (ret < 0) { | ||
249 | val = _iwl_read32(priv, CSR_GP_CNTRL); | ||
250 | IWL_ERR(priv, "MAC is in deep sleep!. CSR_GP_CNTRL = 0x%08X\n", val); | ||
251 | _iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_FORCE_NMI); | ||
252 | return -EIO; | ||
253 | } | ||
254 | |||
255 | return 0; | ||
256 | } | ||
257 | |||
258 | #ifdef CONFIG_IWLWIFI_DEBUG | ||
259 | static inline int __iwl_grab_nic_access(const char *f, u32 l, | ||
260 | struct iwl_priv *priv) | ||
261 | { | ||
262 | IWL_DEBUG_IO(priv, "grabbing nic access - %s %d\n", f, l); | ||
263 | return _iwl_grab_nic_access(priv); | ||
264 | } | ||
265 | #define iwl_grab_nic_access(priv) \ | ||
266 | __iwl_grab_nic_access(__FILE__, __LINE__, priv) | ||
267 | #else | ||
268 | #define iwl_grab_nic_access(priv) \ | ||
269 | _iwl_grab_nic_access(priv) | ||
270 | #endif | ||
271 | |||
272 | static inline void _iwl_release_nic_access(struct iwl_priv *priv) | ||
273 | { | ||
274 | _iwl_clear_bit(priv, CSR_GP_CNTRL, | ||
275 | CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); | ||
276 | } | ||
277 | #ifdef CONFIG_IWLWIFI_DEBUG | ||
278 | static inline void __iwl_release_nic_access(const char *f, u32 l, | ||
279 | struct iwl_priv *priv) | ||
280 | { | ||
281 | |||
282 | IWL_DEBUG_IO(priv, "releasing nic access - %s %d\n", f, l); | ||
283 | _iwl_release_nic_access(priv); | ||
284 | } | ||
285 | #define iwl_release_nic_access(priv) \ | ||
286 | __iwl_release_nic_access(__FILE__, __LINE__, priv) | ||
287 | #else | ||
288 | #define iwl_release_nic_access(priv) \ | ||
289 | _iwl_release_nic_access(priv) | ||
290 | #endif | ||
291 | |||
292 | static inline u32 _iwl_read_direct32(struct iwl_priv *priv, u32 reg) | ||
293 | { | ||
294 | return _iwl_read32(priv, reg); | ||
295 | } | ||
296 | #ifdef CONFIG_IWLWIFI_DEBUG | ||
297 | static inline u32 __iwl_read_direct32(const char *f, u32 l, | ||
298 | struct iwl_priv *priv, u32 reg) | ||
299 | { | ||
300 | u32 value = _iwl_read_direct32(priv, reg); | ||
301 | IWL_DEBUG_IO(priv, "read_direct32(0x%4X) = 0x%08x - %s %d\n", reg, value, | ||
302 | f, l); | ||
303 | return value; | ||
304 | } | ||
305 | static inline u32 iwl_read_direct32(struct iwl_priv *priv, u32 reg) | ||
306 | { | ||
307 | u32 value; | ||
308 | unsigned long reg_flags; | ||
309 | |||
310 | spin_lock_irqsave(&priv->reg_lock, reg_flags); | ||
311 | iwl_grab_nic_access(priv); | ||
312 | value = __iwl_read_direct32(__FILE__, __LINE__, priv, reg); | ||
313 | iwl_release_nic_access(priv); | ||
314 | spin_unlock_irqrestore(&priv->reg_lock, reg_flags); | ||
315 | return value; | ||
316 | } | ||
317 | |||
318 | #else | ||
319 | static inline u32 iwl_read_direct32(struct iwl_priv *priv, u32 reg) | ||
320 | { | ||
321 | u32 value; | ||
322 | unsigned long reg_flags; | ||
323 | |||
324 | spin_lock_irqsave(&priv->reg_lock, reg_flags); | ||
325 | iwl_grab_nic_access(priv); | ||
326 | value = _iwl_read_direct32(priv, reg); | ||
327 | iwl_release_nic_access(priv); | ||
328 | spin_unlock_irqrestore(&priv->reg_lock, reg_flags); | ||
329 | return value; | ||
330 | |||
331 | } | ||
332 | #endif | ||
333 | |||
334 | static inline void _iwl_write_direct32(struct iwl_priv *priv, | ||
335 | u32 reg, u32 value) | ||
336 | { | ||
337 | _iwl_write32(priv, reg, value); | ||
338 | } | ||
339 | static inline void iwl_write_direct32(struct iwl_priv *priv, u32 reg, u32 value) | ||
340 | { | ||
341 | unsigned long reg_flags; | ||
342 | |||
343 | spin_lock_irqsave(&priv->reg_lock, reg_flags); | ||
344 | if (!iwl_grab_nic_access(priv)) { | ||
345 | _iwl_write_direct32(priv, reg, value); | ||
346 | iwl_release_nic_access(priv); | ||
347 | } | ||
348 | spin_unlock_irqrestore(&priv->reg_lock, reg_flags); | ||
349 | } | ||
350 | |||
351 | static inline void iwl_write_reg_buf(struct iwl_priv *priv, | ||
352 | u32 reg, u32 len, u32 *values) | ||
353 | { | ||
354 | u32 count = sizeof(u32); | ||
355 | |||
356 | if ((priv != NULL) && (values != NULL)) { | ||
357 | for (; 0 < len; len -= count, reg += count, values++) | ||
358 | iwl_write_direct32(priv, reg, *values); | ||
359 | } | ||
360 | } | ||
361 | |||
362 | static inline int _iwl_poll_direct_bit(struct iwl_priv *priv, u32 addr, | ||
363 | u32 mask, int timeout) | ||
364 | { | ||
365 | int t = 0; | ||
366 | |||
367 | do { | ||
368 | if ((iwl_read_direct32(priv, addr) & mask) == mask) | ||
369 | return t; | ||
370 | udelay(IWL_POLL_INTERVAL); | ||
371 | t += IWL_POLL_INTERVAL; | ||
372 | } while (t < timeout); | ||
373 | |||
374 | return -ETIMEDOUT; | ||
375 | } | ||
376 | |||
377 | #ifdef CONFIG_IWLWIFI_DEBUG | ||
378 | static inline int __iwl_poll_direct_bit(const char *f, u32 l, | ||
379 | struct iwl_priv *priv, | ||
380 | u32 addr, u32 mask, int timeout) | ||
381 | { | ||
382 | int ret = _iwl_poll_direct_bit(priv, addr, mask, timeout); | ||
383 | |||
384 | if (unlikely(ret == -ETIMEDOUT)) | ||
385 | IWL_DEBUG_IO(priv, "poll_direct_bit(0x%08X, 0x%08X) - " | ||
386 | "timedout - %s %d\n", addr, mask, f, l); | ||
387 | else | ||
388 | IWL_DEBUG_IO(priv, "poll_direct_bit(0x%08X, 0x%08X) = 0x%08X " | ||
389 | "- %s %d\n", addr, mask, ret, f, l); | ||
390 | return ret; | ||
391 | } | ||
392 | #define iwl_poll_direct_bit(priv, addr, mask, timeout) \ | ||
393 | __iwl_poll_direct_bit(__FILE__, __LINE__, priv, addr, mask, timeout) | ||
394 | #else | ||
395 | #define iwl_poll_direct_bit _iwl_poll_direct_bit | ||
396 | #endif | ||
397 | |||
398 | static inline u32 _iwl_read_prph(struct iwl_priv *priv, u32 reg) | ||
399 | { | ||
400 | _iwl_write_direct32(priv, HBUS_TARG_PRPH_RADDR, reg | (3 << 24)); | ||
401 | rmb(); | ||
402 | return _iwl_read_direct32(priv, HBUS_TARG_PRPH_RDAT); | ||
403 | } | ||
404 | static inline u32 iwl_read_prph(struct iwl_priv *priv, u32 reg) | ||
405 | { | ||
406 | unsigned long reg_flags; | ||
407 | u32 val; | ||
408 | |||
409 | spin_lock_irqsave(&priv->reg_lock, reg_flags); | ||
410 | iwl_grab_nic_access(priv); | ||
411 | val = _iwl_read_prph(priv, reg); | ||
412 | iwl_release_nic_access(priv); | ||
413 | spin_unlock_irqrestore(&priv->reg_lock, reg_flags); | ||
414 | return val; | ||
415 | } | ||
416 | |||
417 | static inline void _iwl_write_prph(struct iwl_priv *priv, | ||
418 | u32 addr, u32 val) | ||
419 | { | ||
420 | _iwl_write_direct32(priv, HBUS_TARG_PRPH_WADDR, | ||
421 | ((addr & 0x0000FFFF) | (3 << 24))); | ||
422 | wmb(); | ||
423 | _iwl_write_direct32(priv, HBUS_TARG_PRPH_WDAT, val); | ||
424 | } | ||
425 | |||
426 | static inline void iwl_write_prph(struct iwl_priv *priv, u32 addr, u32 val) | ||
427 | { | ||
428 | unsigned long reg_flags; | ||
429 | 59 | ||
430 | spin_lock_irqsave(&priv->reg_lock, reg_flags); | 60 | int iwl_poll_bit(struct iwl_priv *priv, u32 addr, |
431 | if (!iwl_grab_nic_access(priv)) { | 61 | u32 bits, u32 mask, int timeout); |
432 | _iwl_write_prph(priv, addr, val); | 62 | int iwl_poll_direct_bit(struct iwl_priv *priv, u32 addr, u32 mask, |
433 | iwl_release_nic_access(priv); | 63 | int timeout); |
434 | } | ||
435 | spin_unlock_irqrestore(&priv->reg_lock, reg_flags); | ||
436 | } | ||
437 | 64 | ||
438 | #define _iwl_set_bits_prph(priv, reg, mask) \ | 65 | int iwl_grab_nic_access(struct iwl_priv *priv); |
439 | _iwl_write_prph(priv, reg, (_iwl_read_prph(priv, reg) | mask)) | 66 | void iwl_release_nic_access(struct iwl_priv *priv); |
440 | 67 | ||
441 | static inline void iwl_set_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask) | 68 | u32 iwl_read_direct32(struct iwl_priv *priv, u32 reg); |
442 | { | 69 | void iwl_write_direct32(struct iwl_priv *priv, u32 reg, u32 value); |
443 | unsigned long reg_flags; | ||
444 | 70 | ||
445 | spin_lock_irqsave(&priv->reg_lock, reg_flags); | ||
446 | iwl_grab_nic_access(priv); | ||
447 | _iwl_set_bits_prph(priv, reg, mask); | ||
448 | iwl_release_nic_access(priv); | ||
449 | spin_unlock_irqrestore(&priv->reg_lock, reg_flags); | ||
450 | } | ||
451 | 71 | ||
452 | #define _iwl_set_bits_mask_prph(priv, reg, bits, mask) \ | 72 | u32 iwl_read_prph(struct iwl_priv *priv, u32 reg); |
453 | _iwl_write_prph(priv, reg, ((_iwl_read_prph(priv, reg) & mask) | bits)) | 73 | void iwl_write_prph(struct iwl_priv *priv, u32 addr, u32 val); |
74 | void iwl_set_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask); | ||
75 | void iwl_set_bits_mask_prph(struct iwl_priv *priv, u32 reg, | ||
76 | u32 bits, u32 mask); | ||
77 | void iwl_clear_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask); | ||
454 | 78 | ||
455 | static inline void iwl_set_bits_mask_prph(struct iwl_priv *priv, u32 reg, | 79 | u32 iwl_read_targ_mem(struct iwl_priv *priv, u32 addr); |
456 | u32 bits, u32 mask) | 80 | void iwl_write_targ_mem(struct iwl_priv *priv, u32 addr, u32 val); |
457 | { | ||
458 | unsigned long reg_flags; | ||
459 | |||
460 | spin_lock_irqsave(&priv->reg_lock, reg_flags); | ||
461 | iwl_grab_nic_access(priv); | ||
462 | _iwl_set_bits_mask_prph(priv, reg, bits, mask); | ||
463 | iwl_release_nic_access(priv); | ||
464 | spin_unlock_irqrestore(&priv->reg_lock, reg_flags); | ||
465 | } | ||
466 | |||
467 | static inline void iwl_clear_bits_prph(struct iwl_priv | ||
468 | *priv, u32 reg, u32 mask) | ||
469 | { | ||
470 | unsigned long reg_flags; | ||
471 | u32 val; | ||
472 | |||
473 | spin_lock_irqsave(&priv->reg_lock, reg_flags); | ||
474 | iwl_grab_nic_access(priv); | ||
475 | val = _iwl_read_prph(priv, reg); | ||
476 | _iwl_write_prph(priv, reg, (val & ~mask)); | ||
477 | iwl_release_nic_access(priv); | ||
478 | spin_unlock_irqrestore(&priv->reg_lock, reg_flags); | ||
479 | } | ||
480 | |||
481 | static inline u32 iwl_read_targ_mem(struct iwl_priv *priv, u32 addr) | ||
482 | { | ||
483 | unsigned long reg_flags; | ||
484 | u32 value; | ||
485 | |||
486 | spin_lock_irqsave(&priv->reg_lock, reg_flags); | ||
487 | iwl_grab_nic_access(priv); | ||
488 | |||
489 | _iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, addr); | ||
490 | rmb(); | ||
491 | value = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); | ||
492 | |||
493 | iwl_release_nic_access(priv); | ||
494 | spin_unlock_irqrestore(&priv->reg_lock, reg_flags); | ||
495 | return value; | ||
496 | } | ||
497 | |||
498 | static inline void iwl_write_targ_mem(struct iwl_priv *priv, u32 addr, u32 val) | ||
499 | { | ||
500 | unsigned long reg_flags; | ||
501 | |||
502 | spin_lock_irqsave(&priv->reg_lock, reg_flags); | ||
503 | if (!iwl_grab_nic_access(priv)) { | ||
504 | _iwl_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr); | ||
505 | wmb(); | ||
506 | _iwl_write_direct32(priv, HBUS_TARG_MEM_WDAT, val); | ||
507 | iwl_release_nic_access(priv); | ||
508 | } | ||
509 | spin_unlock_irqrestore(&priv->reg_lock, reg_flags); | ||
510 | } | ||
511 | |||
512 | static inline void iwl_write_targ_mem_buf(struct iwl_priv *priv, u32 addr, | ||
513 | u32 len, u32 *values) | ||
514 | { | ||
515 | unsigned long reg_flags; | ||
516 | |||
517 | spin_lock_irqsave(&priv->reg_lock, reg_flags); | ||
518 | if (!iwl_grab_nic_access(priv)) { | ||
519 | _iwl_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr); | ||
520 | wmb(); | ||
521 | for (; 0 < len; len -= sizeof(u32), values++) | ||
522 | _iwl_write_direct32(priv, HBUS_TARG_MEM_WDAT, *values); | ||
523 | |||
524 | iwl_release_nic_access(priv); | ||
525 | } | ||
526 | spin_unlock_irqrestore(&priv->reg_lock, reg_flags); | ||
527 | } | ||
528 | #endif | 81 | #endif |
diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c index d7f2a0bb32c9..c2862d4e00e3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-led.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | * | 2 | * |
3 | * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. | 3 | * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify it | 5 | * This program is free software; you can redistribute it and/or modify it |
6 | * under the terms of version 2 of the GNU General Public License as | 6 | * under the terms of version 2 of the GNU General Public License as |
diff --git a/drivers/net/wireless/iwlwifi/iwl-led.h b/drivers/net/wireless/iwlwifi/iwl-led.h index 101eef12b3bb..05b8e8f7dd4a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.h +++ b/drivers/net/wireless/iwlwifi/iwl-led.h | |||
@@ -1,6 +1,6 @@ | |||
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | * | 2 | * |
3 | * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. | 3 | * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify it | 5 | * This program is free software; you can redistribute it and/or modify it |
6 | * under the terms of version 2 of the GNU General Public License as | 6 | * under the terms of version 2 of the GNU General Public License as |
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index 576795e2c75b..c43c8e66de73 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | * | 2 | * |
3 | * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved. | 3 | * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved. |
4 | * | 4 | * |
5 | * Portions of this file are derived from the ipw3945 project, as well | 5 | * Portions of this file are derived from the ipw3945 project, as well |
6 | * as portions of the ieee80211 subsystem header files. | 6 | * as portions of the ieee80211 subsystem header files. |
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.h b/drivers/net/wireless/iwlwifi/iwl-power.h index fe012032c28c..59635d784e27 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.h +++ b/drivers/net/wireless/iwlwifi/iwl-power.h | |||
@@ -1,6 +1,6 @@ | |||
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | * | 2 | * |
3 | * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved. | 3 | * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved. |
4 | * | 4 | * |
5 | * Portions of this file are derived from the ipw3945 project, as well | 5 | * Portions of this file are derived from the ipw3945 project, as well |
6 | * as portions of the ieee80211 subsystem header files. | 6 | * as portions of the ieee80211 subsystem header files. |
diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index 86f5123bccda..c960195df989 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h | |||
@@ -5,7 +5,7 @@ | |||
5 | * | 5 | * |
6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
7 | * | 7 | * |
8 | * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of version 2 of the GNU General Public License as | 11 | * it under the terms of version 2 of the GNU General Public License as |
@@ -30,7 +30,7 @@ | |||
30 | * | 30 | * |
31 | * BSD LICENSE | 31 | * BSD LICENSE |
32 | * | 32 | * |
33 | * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. | 33 | * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. |
34 | * All rights reserved. | 34 | * All rights reserved. |
35 | * | 35 | * |
36 | * Redistribution and use in source and binary forms, with or without | 36 | * Redistribution and use in source and binary forms, with or without |
@@ -91,7 +91,6 @@ | |||
91 | #define APMG_PS_CTRL_VAL_RESET_REQ (0x04000000) | 91 | #define APMG_PS_CTRL_VAL_RESET_REQ (0x04000000) |
92 | #define APMG_PS_CTRL_MSK_PWR_SRC (0x03000000) | 92 | #define APMG_PS_CTRL_MSK_PWR_SRC (0x03000000) |
93 | #define APMG_PS_CTRL_VAL_PWR_SRC_VMAIN (0x00000000) | 93 | #define APMG_PS_CTRL_VAL_PWR_SRC_VMAIN (0x00000000) |
94 | #define APMG_PS_CTRL_VAL_PWR_SRC_MAX (0x01000000) /* 3945 only */ | ||
95 | #define APMG_PS_CTRL_VAL_PWR_SRC_VAUX (0x02000000) | 94 | #define APMG_PS_CTRL_VAL_PWR_SRC_VAUX (0x02000000) |
96 | #define APMG_SVR_VOLTAGE_CONFIG_BIT_MSK (0x000001E0) /* bit 8:5 */ | 95 | #define APMG_SVR_VOLTAGE_CONFIG_BIT_MSK (0x000001E0) /* bit 8:5 */ |
97 | #define APMG_SVR_DIGITAL_VOLTAGE_1_32 (0x00000060) | 96 | #define APMG_SVR_DIGITAL_VOLTAGE_1_32 (0x00000060) |
@@ -99,152 +98,6 @@ | |||
99 | #define APMG_PCIDEV_STT_VAL_L1_ACT_DIS (0x00000800) | 98 | #define APMG_PCIDEV_STT_VAL_L1_ACT_DIS (0x00000800) |
100 | 99 | ||
101 | /** | 100 | /** |
102 | * BSM (Bootstrap State Machine) | ||
103 | * | ||
104 | * The Bootstrap State Machine (BSM) stores a short bootstrap uCode program | ||
105 | * in special SRAM that does not power down when the embedded control | ||
106 | * processor is sleeping (e.g. for periodic power-saving shutdowns of radio). | ||
107 | * | ||
108 | * When powering back up after sleeps (or during initial uCode load), the BSM | ||
109 | * internally loads the short bootstrap program from the special SRAM into the | ||
110 | * embedded processor's instruction SRAM, and starts the processor so it runs | ||
111 | * the bootstrap program. | ||
112 | * | ||
113 | * This bootstrap program loads (via PCI busmaster DMA) instructions and data | ||
114 | * images for a uCode program from host DRAM locations. The host driver | ||
115 | * indicates DRAM locations and sizes for instruction and data images via the | ||
116 | * four BSM_DRAM_* registers. Once the bootstrap program loads the new program, | ||
117 | * the new program starts automatically. | ||
118 | * | ||
119 | * The uCode used for open-source drivers includes two programs: | ||
120 | * | ||
121 | * 1) Initialization -- performs hardware calibration and sets up some | ||
122 | * internal data, then notifies host via "initialize alive" notification | ||
123 | * (struct iwl_init_alive_resp) that it has completed all of its work. | ||
124 | * After signal from host, it then loads and starts the runtime program. | ||
125 | * The initialization program must be used when initially setting up the | ||
126 | * NIC after loading the driver. | ||
127 | * | ||
128 | * 2) Runtime/Protocol -- performs all normal runtime operations. This | ||
129 | * notifies host via "alive" notification (struct iwl_alive_resp) that it | ||
130 | * is ready to be used. | ||
131 | * | ||
132 | * When initializing the NIC, the host driver does the following procedure: | ||
133 | * | ||
134 | * 1) Load bootstrap program (instructions only, no data image for bootstrap) | ||
135 | * into bootstrap memory. Use dword writes starting at BSM_SRAM_LOWER_BOUND | ||
136 | * | ||
137 | * 2) Point (via BSM_DRAM_*) to the "initialize" uCode data and instruction | ||
138 | * images in host DRAM. | ||
139 | * | ||
140 | * 3) Set up BSM to copy from BSM SRAM into uCode instruction SRAM when asked: | ||
141 | * BSM_WR_MEM_SRC_REG = 0 | ||
142 | * BSM_WR_MEM_DST_REG = RTC_INST_LOWER_BOUND | ||
143 | * BSM_WR_MEM_DWCOUNT_REG = # dwords in bootstrap instruction image | ||
144 | * | ||
145 | * 4) Load bootstrap into instruction SRAM: | ||
146 | * BSM_WR_CTRL_REG = BSM_WR_CTRL_REG_BIT_START | ||
147 | * | ||
148 | * 5) Wait for load completion: | ||
149 | * Poll BSM_WR_CTRL_REG for BSM_WR_CTRL_REG_BIT_START = 0 | ||
150 | * | ||
151 | * 6) Enable future boot loads whenever NIC's power management triggers it: | ||
152 | * BSM_WR_CTRL_REG = BSM_WR_CTRL_REG_BIT_START_EN | ||
153 | * | ||
154 | * 7) Start the NIC by removing all reset bits: | ||
155 | * CSR_RESET = 0 | ||
156 | * | ||
157 | * The bootstrap uCode (already in instruction SRAM) loads initialization | ||
158 | * uCode. Initialization uCode performs data initialization, sends | ||
159 | * "initialize alive" notification to host, and waits for a signal from | ||
160 | * host to load runtime code. | ||
161 | * | ||
162 | * 4) Point (via BSM_DRAM_*) to the "runtime" uCode data and instruction | ||
163 | * images in host DRAM. The last register loaded must be the instruction | ||
164 | * byte count register ("1" in MSbit tells initialization uCode to load | ||
165 | * the runtime uCode): | ||
166 | * BSM_DRAM_INST_BYTECOUNT_REG = byte count | BSM_DRAM_INST_LOAD | ||
167 | * | ||
168 | * 5) Wait for "alive" notification, then issue normal runtime commands. | ||
169 | * | ||
170 | * Data caching during power-downs: | ||
171 | * | ||
172 | * Just before the embedded controller powers down (e.g for automatic | ||
173 | * power-saving modes, or for RFKILL), uCode stores (via PCI busmaster DMA) | ||
174 | * a current snapshot of the embedded processor's data SRAM into host DRAM. | ||
175 | * This caches the data while the embedded processor's memory is powered down. | ||
176 | * Location and size are controlled by BSM_DRAM_DATA_* registers. | ||
177 | * | ||
178 | * NOTE: Instruction SRAM does not need to be saved, since that doesn't | ||
179 | * change during operation; the original image (from uCode distribution | ||
180 | * file) can be used for reload. | ||
181 | * | ||
182 | * When powering back up, the BSM loads the bootstrap program. Bootstrap looks | ||
183 | * at the BSM_DRAM_* registers, which now point to the runtime instruction | ||
184 | * image and the cached (modified) runtime data (*not* the initialization | ||
185 | * uCode). Bootstrap reloads these runtime images into SRAM, and restarts the | ||
186 | * uCode from where it left off before the power-down. | ||
187 | * | ||
188 | * NOTE: Initialization uCode does *not* run as part of the save/restore | ||
189 | * procedure. | ||
190 | * | ||
191 | * This save/restore method is mostly for autonomous power management during | ||
192 | * normal operation (result of POWER_TABLE_CMD). Platform suspend/resume and | ||
193 | * RFKILL should use complete restarts (with total re-initialization) of uCode, | ||
194 | * allowing total shutdown (including BSM memory). | ||
195 | * | ||
196 | * Note that, during normal operation, the host DRAM that held the initial | ||
197 | * startup data for the runtime code is now being used as a backup data cache | ||
198 | * for modified data! If you need to completely re-initialize the NIC, make | ||
199 | * sure that you use the runtime data image from the uCode distribution file, | ||
200 | * not the modified/saved runtime data. You may want to store a separate | ||
201 | * "clean" runtime data image in DRAM to avoid disk reads of distribution file. | ||
202 | */ | ||
203 | |||
204 | /* BSM bit fields */ | ||
205 | #define BSM_WR_CTRL_REG_BIT_START (0x80000000) /* start boot load now */ | ||
206 | #define BSM_WR_CTRL_REG_BIT_START_EN (0x40000000) /* enable boot after pwrup*/ | ||
207 | #define BSM_DRAM_INST_LOAD (0x80000000) /* start program load now */ | ||
208 | |||
209 | /* BSM addresses */ | ||
210 | #define BSM_BASE (PRPH_BASE + 0x3400) | ||
211 | #define BSM_END (PRPH_BASE + 0x3800) | ||
212 | |||
213 | #define BSM_WR_CTRL_REG (BSM_BASE + 0x000) /* ctl and status */ | ||
214 | #define BSM_WR_MEM_SRC_REG (BSM_BASE + 0x004) /* source in BSM mem */ | ||
215 | #define BSM_WR_MEM_DST_REG (BSM_BASE + 0x008) /* dest in SRAM mem */ | ||
216 | #define BSM_WR_DWCOUNT_REG (BSM_BASE + 0x00C) /* bytes */ | ||
217 | #define BSM_WR_STATUS_REG (BSM_BASE + 0x010) /* bit 0: 1 == done */ | ||
218 | |||
219 | /* | ||
220 | * Pointers and size regs for bootstrap load and data SRAM save/restore. | ||
221 | * NOTE: 3945 pointers use bits 31:0 of DRAM address. | ||
222 | * 4965 pointers use bits 35:4 of DRAM address. | ||
223 | */ | ||
224 | #define BSM_DRAM_INST_PTR_REG (BSM_BASE + 0x090) | ||
225 | #define BSM_DRAM_INST_BYTECOUNT_REG (BSM_BASE + 0x094) | ||
226 | #define BSM_DRAM_DATA_PTR_REG (BSM_BASE + 0x098) | ||
227 | #define BSM_DRAM_DATA_BYTECOUNT_REG (BSM_BASE + 0x09C) | ||
228 | |||
229 | /* | ||
230 | * BSM special memory, stays powered on during power-save sleeps. | ||
231 | * Read/write, address range from LOWER_BOUND to (LOWER_BOUND + SIZE -1) | ||
232 | */ | ||
233 | #define BSM_SRAM_LOWER_BOUND (PRPH_BASE + 0x3800) | ||
234 | #define BSM_SRAM_SIZE (1024) /* bytes */ | ||
235 | |||
236 | |||
237 | /* 3945 Tx scheduler registers */ | ||
238 | #define ALM_SCD_BASE (PRPH_BASE + 0x2E00) | ||
239 | #define ALM_SCD_MODE_REG (ALM_SCD_BASE + 0x000) | ||
240 | #define ALM_SCD_ARASTAT_REG (ALM_SCD_BASE + 0x004) | ||
241 | #define ALM_SCD_TXFACT_REG (ALM_SCD_BASE + 0x010) | ||
242 | #define ALM_SCD_TXF4MF_REG (ALM_SCD_BASE + 0x014) | ||
243 | #define ALM_SCD_TXF5MF_REG (ALM_SCD_BASE + 0x020) | ||
244 | #define ALM_SCD_SBYP_MODE_1_REG (ALM_SCD_BASE + 0x02C) | ||
245 | #define ALM_SCD_SBYP_MODE_2_REG (ALM_SCD_BASE + 0x030) | ||
246 | |||
247 | /** | ||
248 | * Tx Scheduler | 101 | * Tx Scheduler |
249 | * | 102 | * |
250 | * The Tx Scheduler selects the next frame to be transmitted, choosing TFDs | 103 | * The Tx Scheduler selects the next frame to be transmitted, choosing TFDs |
@@ -330,201 +183,10 @@ | |||
330 | * Max Tx window size is the max number of contiguous TFDs that the scheduler | 183 | * Max Tx window size is the max number of contiguous TFDs that the scheduler |
331 | * can keep track of at one time when creating block-ack chains of frames. | 184 | * can keep track of at one time when creating block-ack chains of frames. |
332 | * Note that "64" matches the number of ack bits in a block-ack packet. | 185 | * Note that "64" matches the number of ack bits in a block-ack packet. |
333 | * Driver should use SCD_WIN_SIZE and SCD_FRAME_LIMIT values to initialize | ||
334 | * IWL49_SCD_CONTEXT_QUEUE_OFFSET(x) values. | ||
335 | */ | 186 | */ |
336 | #define SCD_WIN_SIZE 64 | 187 | #define SCD_WIN_SIZE 64 |
337 | #define SCD_FRAME_LIMIT 64 | 188 | #define SCD_FRAME_LIMIT 64 |
338 | 189 | ||
339 | /* SCD registers are internal, must be accessed via HBUS_TARG_PRPH regs */ | ||
340 | #define IWL49_SCD_START_OFFSET 0xa02c00 | ||
341 | |||
342 | /* | ||
343 | * 4965 tells driver SRAM address for internal scheduler structs via this reg. | ||
344 | * Value is valid only after "Alive" response from uCode. | ||
345 | */ | ||
346 | #define IWL49_SCD_SRAM_BASE_ADDR (IWL49_SCD_START_OFFSET + 0x0) | ||
347 | |||
348 | /* | ||
349 | * Driver may need to update queue-empty bits after changing queue's | ||
350 | * write and read pointers (indexes) during (re-)initialization (i.e. when | ||
351 | * scheduler is not tracking what's happening). | ||
352 | * Bit fields: | ||
353 | * 31-16: Write mask -- 1: update empty bit, 0: don't change empty bit | ||
354 | * 15-00: Empty state, one for each queue -- 1: empty, 0: non-empty | ||
355 | * NOTE: This register is not used by Linux driver. | ||
356 | */ | ||
357 | #define IWL49_SCD_EMPTY_BITS (IWL49_SCD_START_OFFSET + 0x4) | ||
358 | |||
359 | /* | ||
360 | * Physical base address of array of byte count (BC) circular buffers (CBs). | ||
361 | * Each Tx queue has a BC CB in host DRAM to support Scheduler-ACK mode. | ||
362 | * This register points to BC CB for queue 0, must be on 1024-byte boundary. | ||
363 | * Others are spaced by 1024 bytes. | ||
364 | * Each BC CB is 2 bytes * (256 + 64) = 740 bytes, followed by 384 bytes pad. | ||
365 | * (Index into a queue's BC CB) = (index into queue's TFD CB) = (SSN & 0xff). | ||
366 | * Bit fields: | ||
367 | * 25-00: Byte Count CB physical address [35:10], must be 1024-byte aligned. | ||
368 | */ | ||
369 | #define IWL49_SCD_DRAM_BASE_ADDR (IWL49_SCD_START_OFFSET + 0x10) | ||
370 | |||
371 | /* | ||
372 | * Enables any/all Tx DMA/FIFO channels. | ||
373 | * Scheduler generates requests for only the active channels. | ||
374 | * Set this to 0xff to enable all 8 channels (normal usage). | ||
375 | * Bit fields: | ||
376 | * 7- 0: Enable (1), disable (0), one bit for each channel 0-7 | ||
377 | */ | ||
378 | #define IWL49_SCD_TXFACT (IWL49_SCD_START_OFFSET + 0x1c) | ||
379 | /* | ||
380 | * Queue (x) Write Pointers (indexes, really!), one for each Tx queue. | ||
381 | * Initialized and updated by driver as new TFDs are added to queue. | ||
382 | * NOTE: If using Block Ack, index must correspond to frame's | ||
383 | * Start Sequence Number; index = (SSN & 0xff) | ||
384 | * NOTE: Alternative to HBUS_TARG_WRPTR, which is what Linux driver uses? | ||
385 | */ | ||
386 | #define IWL49_SCD_QUEUE_WRPTR(x) (IWL49_SCD_START_OFFSET + 0x24 + (x) * 4) | ||
387 | |||
388 | /* | ||
389 | * Queue (x) Read Pointers (indexes, really!), one for each Tx queue. | ||
390 | * For FIFO mode, index indicates next frame to transmit. | ||
391 | * For Scheduler-ACK mode, index indicates first frame in Tx window. | ||
392 | * Initialized by driver, updated by scheduler. | ||
393 | */ | ||
394 | #define IWL49_SCD_QUEUE_RDPTR(x) (IWL49_SCD_START_OFFSET + 0x64 + (x) * 4) | ||
395 | |||
396 | /* | ||
397 | * Select which queues work in chain mode (1) vs. not (0). | ||
398 | * Use chain mode to build chains of aggregated frames. | ||
399 | * Bit fields: | ||
400 | * 31-16: Reserved | ||
401 | * 15-00: Mode, one bit for each queue -- 1: Chain mode, 0: one-at-a-time | ||
402 | * NOTE: If driver sets up queue for chain mode, it should be also set up | ||
403 | * Scheduler-ACK mode as well, via SCD_QUEUE_STATUS_BITS(x). | ||
404 | */ | ||
405 | #define IWL49_SCD_QUEUECHAIN_SEL (IWL49_SCD_START_OFFSET + 0xd0) | ||
406 | |||
407 | /* | ||
408 | * Select which queues interrupt driver when scheduler increments | ||
409 | * a queue's read pointer (index). | ||
410 | * Bit fields: | ||
411 | * 31-16: Reserved | ||
412 | * 15-00: Interrupt enable, one bit for each queue -- 1: enabled, 0: disabled | ||
413 | * NOTE: This functionality is apparently a no-op; driver relies on interrupts | ||
414 | * from Rx queue to read Tx command responses and update Tx queues. | ||
415 | */ | ||
416 | #define IWL49_SCD_INTERRUPT_MASK (IWL49_SCD_START_OFFSET + 0xe4) | ||
417 | |||
418 | /* | ||
419 | * Queue search status registers. One for each queue. | ||
420 | * Sets up queue mode and assigns queue to Tx DMA channel. | ||
421 | * Bit fields: | ||
422 | * 19-10: Write mask/enable bits for bits 0-9 | ||
423 | * 9: Driver should init to "0" | ||
424 | * 8: Scheduler-ACK mode (1), non-Scheduler-ACK (i.e. FIFO) mode (0). | ||
425 | * Driver should init to "1" for aggregation mode, or "0" otherwise. | ||
426 | * 7-6: Driver should init to "0" | ||
427 | * 5: Window Size Left; indicates whether scheduler can request | ||
428 | * another TFD, based on window size, etc. Driver should init | ||
429 | * this bit to "1" for aggregation mode, or "0" for non-agg. | ||
430 | * 4-1: Tx FIFO to use (range 0-7). | ||
431 | * 0: Queue is active (1), not active (0). | ||
432 | * Other bits should be written as "0" | ||
433 | * | ||
434 | * NOTE: If enabling Scheduler-ACK mode, chain mode should also be enabled | ||
435 | * via SCD_QUEUECHAIN_SEL. | ||
436 | */ | ||
437 | #define IWL49_SCD_QUEUE_STATUS_BITS(x)\ | ||
438 | (IWL49_SCD_START_OFFSET + 0x104 + (x) * 4) | ||
439 | |||
440 | /* Bit field positions */ | ||
441 | #define IWL49_SCD_QUEUE_STTS_REG_POS_ACTIVE (0) | ||
442 | #define IWL49_SCD_QUEUE_STTS_REG_POS_TXF (1) | ||
443 | #define IWL49_SCD_QUEUE_STTS_REG_POS_WSL (5) | ||
444 | #define IWL49_SCD_QUEUE_STTS_REG_POS_SCD_ACK (8) | ||
445 | |||
446 | /* Write masks */ | ||
447 | #define IWL49_SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN (10) | ||
448 | #define IWL49_SCD_QUEUE_STTS_REG_MSK (0x0007FC00) | ||
449 | |||
450 | /** | ||
451 | * 4965 internal SRAM structures for scheduler, shared with driver ... | ||
452 | * | ||
453 | * Driver should clear and initialize the following areas after receiving | ||
454 | * "Alive" response from 4965 uCode, i.e. after initial | ||
455 | * uCode load, or after a uCode load done for error recovery: | ||
456 | * | ||
457 | * SCD_CONTEXT_DATA_OFFSET (size 128 bytes) | ||
458 | * SCD_TX_STTS_BITMAP_OFFSET (size 256 bytes) | ||
459 | * SCD_TRANSLATE_TBL_OFFSET (size 32 bytes) | ||
460 | * | ||
461 | * Driver accesses SRAM via HBUS_TARG_MEM_* registers. | ||
462 | * Driver reads base address of this scheduler area from SCD_SRAM_BASE_ADDR. | ||
463 | * All OFFSET values must be added to this base address. | ||
464 | */ | ||
465 | |||
466 | /* | ||
467 | * Queue context. One 8-byte entry for each of 16 queues. | ||
468 | * | ||
469 | * Driver should clear this entire area (size 0x80) to 0 after receiving | ||
470 | * "Alive" notification from uCode. Additionally, driver should init | ||
471 | * each queue's entry as follows: | ||
472 | * | ||
473 | * LS Dword bit fields: | ||
474 | * 0-06: Max Tx window size for Scheduler-ACK. Driver should init to 64. | ||
475 | * | ||
476 | * MS Dword bit fields: | ||
477 | * 16-22: Frame limit. Driver should init to 10 (0xa). | ||
478 | * | ||
479 | * Driver should init all other bits to 0. | ||
480 | * | ||
481 | * Init must be done after driver receives "Alive" response from 4965 uCode, | ||
482 | * and when setting up queue for aggregation. | ||
483 | */ | ||
484 | #define IWL49_SCD_CONTEXT_DATA_OFFSET 0x380 | ||
485 | #define IWL49_SCD_CONTEXT_QUEUE_OFFSET(x) \ | ||
486 | (IWL49_SCD_CONTEXT_DATA_OFFSET + ((x) * 8)) | ||
487 | |||
488 | #define IWL49_SCD_QUEUE_CTX_REG1_WIN_SIZE_POS (0) | ||
489 | #define IWL49_SCD_QUEUE_CTX_REG1_WIN_SIZE_MSK (0x0000007F) | ||
490 | #define IWL49_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS (16) | ||
491 | #define IWL49_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK (0x007F0000) | ||
492 | |||
493 | /* | ||
494 | * Tx Status Bitmap | ||
495 | * | ||
496 | * Driver should clear this entire area (size 0x100) to 0 after receiving | ||
497 | * "Alive" notification from uCode. Area is used only by device itself; | ||
498 | * no other support (besides clearing) is required from driver. | ||
499 | */ | ||
500 | #define IWL49_SCD_TX_STTS_BITMAP_OFFSET 0x400 | ||
501 | |||
502 | /* | ||
503 | * RAxTID to queue translation mapping. | ||
504 | * | ||
505 | * When queue is in Scheduler-ACK mode, frames placed in a that queue must be | ||
506 | * for only one combination of receiver address (RA) and traffic ID (TID), i.e. | ||
507 | * one QOS priority level destined for one station (for this wireless link, | ||
508 | * not final destination). The SCD_TRANSLATE_TABLE area provides 16 16-bit | ||
509 | * mappings, one for each of the 16 queues. If queue is not in Scheduler-ACK | ||
510 | * mode, the device ignores the mapping value. | ||
511 | * | ||
512 | * Bit fields, for each 16-bit map: | ||
513 | * 15-9: Reserved, set to 0 | ||
514 | * 8-4: Index into device's station table for recipient station | ||
515 | * 3-0: Traffic ID (tid), range 0-15 | ||
516 | * | ||
517 | * Driver should clear this entire area (size 32 bytes) to 0 after receiving | ||
518 | * "Alive" notification from uCode. To update a 16-bit map value, driver | ||
519 | * must read a dword-aligned value from device SRAM, replace the 16-bit map | ||
520 | * value of interest, and write the dword value back into device SRAM. | ||
521 | */ | ||
522 | #define IWL49_SCD_TRANSLATE_TBL_OFFSET 0x500 | ||
523 | |||
524 | /* Find translation table dword to read/write for given queue */ | ||
525 | #define IWL49_SCD_TRANSLATE_TBL_OFFSET_QUEUE(x) \ | ||
526 | ((IWL49_SCD_TRANSLATE_TBL_OFFSET + ((x) * 2)) & 0xfffffffc) | ||
527 | |||
528 | #define IWL_SCD_TXFIFO_POS_TID (0) | 190 | #define IWL_SCD_TXFIFO_POS_TID (0) |
529 | #define IWL_SCD_TXFIFO_POS_RA (4) | 191 | #define IWL_SCD_TXFIFO_POS_RA (4) |
530 | #define IWL_SCD_QUEUE_RA_TID_MAP_RATID_MSK (0x01FF) | 192 | #define IWL_SCD_QUEUE_RA_TID_MAP_RATID_MSK (0x01FF) |
diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 6f9a2fa04763..c421f566982f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | * | 2 | * |
3 | * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. | 3 | * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. |
4 | * | 4 | * |
5 | * Portions of this file are derived from the ipw3945 project, as well | 5 | * Portions of this file are derived from the ipw3945 project, as well |
6 | * as portions of the ieee80211 subsystem header files. | 6 | * as portions of the ieee80211 subsystem header files. |
@@ -239,16 +239,16 @@ static void iwl_rx_reply_alive(struct iwl_priv *priv, | |||
239 | palive->is_valid, palive->ver_type, | 239 | palive->is_valid, palive->ver_type, |
240 | palive->ver_subtype); | 240 | palive->ver_subtype); |
241 | 241 | ||
242 | priv->device_pointers.log_event_table = | ||
243 | le32_to_cpu(palive->log_event_table_ptr); | ||
244 | priv->device_pointers.error_event_table = | ||
245 | le32_to_cpu(palive->error_event_table_ptr); | ||
246 | |||
242 | if (palive->ver_subtype == INITIALIZE_SUBTYPE) { | 247 | if (palive->ver_subtype == INITIALIZE_SUBTYPE) { |
243 | IWL_DEBUG_INFO(priv, "Initialization Alive received.\n"); | 248 | IWL_DEBUG_INFO(priv, "Initialization Alive received.\n"); |
244 | memcpy(&priv->card_alive_init, | ||
245 | &pkt->u.alive_frame, | ||
246 | sizeof(struct iwl_init_alive_resp)); | ||
247 | pwork = &priv->init_alive_start; | 249 | pwork = &priv->init_alive_start; |
248 | } else { | 250 | } else { |
249 | IWL_DEBUG_INFO(priv, "Runtime Alive received.\n"); | 251 | IWL_DEBUG_INFO(priv, "Runtime Alive received.\n"); |
250 | memcpy(&priv->card_alive, &pkt->u.alive_frame, | ||
251 | sizeof(struct iwl_alive_resp)); | ||
252 | pwork = &priv->alive_start; | 252 | pwork = &priv->alive_start; |
253 | } | 253 | } |
254 | 254 | ||
@@ -898,7 +898,6 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, | |||
898 | memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats)); | 898 | memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats)); |
899 | 899 | ||
900 | ieee80211_rx(priv->hw, skb); | 900 | ieee80211_rx(priv->hw, skb); |
901 | priv->alloc_rxb_page--; | ||
902 | rxb->page = NULL; | 901 | rxb->page = NULL; |
903 | } | 902 | } |
904 | 903 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index 914c77e44588..d60d630cb93a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * | 2 | * |
3 | * GPL LICENSE SUMMARY | 3 | * GPL LICENSE SUMMARY |
4 | * | 4 | * |
5 | * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. | 5 | * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of version 2 of the GNU General Public License as | 8 | * it under the terms of version 2 of the GNU General Public License as |
diff --git a/drivers/net/wireless/iwlwifi/iwl-spectrum.h b/drivers/net/wireless/iwlwifi/iwl-spectrum.h index c4ca0b5d77da..cb80bb4ce45e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-spectrum.h +++ b/drivers/net/wireless/iwlwifi/iwl-spectrum.h | |||
@@ -1,6 +1,6 @@ | |||
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | * | 2 | * |
3 | * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. | 3 | * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. |
4 | * | 4 | * |
5 | * Portions of this file are derived from the ieee80211 subsystem header files. | 5 | * Portions of this file are derived from the ieee80211 subsystem header files. |
6 | * | 6 | * |
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index bc90a12408a3..c21515640077 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | * | 2 | * |
3 | * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. | 3 | * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. |
4 | * | 4 | * |
5 | * Portions of this file are derived from the ipw3945 project, as well | 5 | * Portions of this file are derived from the ipw3945 project, as well |
6 | * as portions of the ieee80211 subsystem header files. | 6 | * as portions of the ieee80211 subsystem header files. |
@@ -233,7 +233,6 @@ u8 iwl_prep_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx, | |||
233 | struct iwl_station_entry *station; | 233 | struct iwl_station_entry *station; |
234 | int i; | 234 | int i; |
235 | u8 sta_id = IWL_INVALID_STATION; | 235 | u8 sta_id = IWL_INVALID_STATION; |
236 | u16 rate; | ||
237 | 236 | ||
238 | if (is_ap) | 237 | if (is_ap) |
239 | sta_id = ctx->ap_sta_id; | 238 | sta_id = ctx->ap_sta_id; |
@@ -306,12 +305,6 @@ u8 iwl_prep_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx, | |||
306 | */ | 305 | */ |
307 | iwl_set_ht_add_station(priv, sta_id, sta, ctx); | 306 | iwl_set_ht_add_station(priv, sta_id, sta, ctx); |
308 | 307 | ||
309 | /* 3945 only */ | ||
310 | rate = (priv->band == IEEE80211_BAND_5GHZ) ? | ||
311 | IWL_RATE_6M_PLCP : IWL_RATE_1M_PLCP; | ||
312 | /* Turn on both antennas for the station... */ | ||
313 | station->sta.rate_n_flags = cpu_to_le16(rate | RATE_MCS_ANT_AB_MSK); | ||
314 | |||
315 | return sta_id; | 308 | return sta_id; |
316 | 309 | ||
317 | } | 310 | } |
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.h b/drivers/net/wireless/iwlwifi/iwl-sta.h index 206f1e1a0caf..ff64027ff4cb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.h +++ b/drivers/net/wireless/iwlwifi/iwl-sta.h | |||
@@ -1,6 +1,6 @@ | |||
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | * | 2 | * |
3 | * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. | 3 | * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. |
4 | * | 4 | * |
5 | * Portions of this file are derived from the ipw3945 project, as well | 5 | * Portions of this file are derived from the ipw3945 project, as well |
6 | * as portions of the ieee80211 subsystem header files. | 6 | * as portions of the ieee80211 subsystem header files. |
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 277c9175dcf6..565980fbb591 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | * | 2 | * |
3 | * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. | 3 | * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. |
4 | * | 4 | * |
5 | * Portions of this file are derived from the ipw3945 project, as well | 5 | * Portions of this file are derived from the ipw3945 project, as well |
6 | * as portions of the ieee80211 subsystem header files. | 6 | * as portions of the ieee80211 subsystem header files. |
@@ -149,32 +149,31 @@ void iwl_cmd_queue_unmap(struct iwl_priv *priv) | |||
149 | struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue]; | 149 | struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue]; |
150 | struct iwl_queue *q = &txq->q; | 150 | struct iwl_queue *q = &txq->q; |
151 | int i; | 151 | int i; |
152 | bool huge = false; | ||
153 | 152 | ||
154 | if (q->n_bd == 0) | 153 | if (q->n_bd == 0) |
155 | return; | 154 | return; |
156 | 155 | ||
157 | while (q->read_ptr != q->write_ptr) { | 156 | while (q->read_ptr != q->write_ptr) { |
158 | /* we have no way to tell if it is a huge cmd ATM */ | ||
159 | i = get_cmd_index(q, q->read_ptr, 0); | 157 | i = get_cmd_index(q, q->read_ptr, 0); |
160 | 158 | ||
161 | if (txq->meta[i].flags & CMD_SIZE_HUGE) | 159 | if (txq->meta[i].flags & CMD_MAPPED) { |
162 | huge = true; | ||
163 | else | ||
164 | pci_unmap_single(priv->pci_dev, | 160 | pci_unmap_single(priv->pci_dev, |
165 | dma_unmap_addr(&txq->meta[i], mapping), | 161 | dma_unmap_addr(&txq->meta[i], mapping), |
166 | dma_unmap_len(&txq->meta[i], len), | 162 | dma_unmap_len(&txq->meta[i], len), |
167 | PCI_DMA_BIDIRECTIONAL); | 163 | PCI_DMA_BIDIRECTIONAL); |
164 | txq->meta[i].flags = 0; | ||
165 | } | ||
168 | 166 | ||
169 | q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd); | 167 | q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd); |
170 | } | 168 | } |
171 | 169 | ||
172 | if (huge) { | 170 | i = q->n_window; |
173 | i = q->n_window; | 171 | if (txq->meta[i].flags & CMD_MAPPED) { |
174 | pci_unmap_single(priv->pci_dev, | 172 | pci_unmap_single(priv->pci_dev, |
175 | dma_unmap_addr(&txq->meta[i], mapping), | 173 | dma_unmap_addr(&txq->meta[i], mapping), |
176 | dma_unmap_len(&txq->meta[i], len), | 174 | dma_unmap_len(&txq->meta[i], len), |
177 | PCI_DMA_BIDIRECTIONAL); | 175 | PCI_DMA_BIDIRECTIONAL); |
176 | txq->meta[i].flags = 0; | ||
178 | } | 177 | } |
179 | } | 178 | } |
180 | 179 | ||
@@ -463,7 +462,11 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) | |||
463 | return -EIO; | 462 | return -EIO; |
464 | } | 463 | } |
465 | 464 | ||
465 | spin_lock_irqsave(&priv->hcmd_lock, flags); | ||
466 | |||
466 | if (iwl_queue_space(q) < ((cmd->flags & CMD_ASYNC) ? 2 : 1)) { | 467 | if (iwl_queue_space(q) < ((cmd->flags & CMD_ASYNC) ? 2 : 1)) { |
468 | spin_unlock_irqrestore(&priv->hcmd_lock, flags); | ||
469 | |||
467 | IWL_ERR(priv, "No space in command queue\n"); | 470 | IWL_ERR(priv, "No space in command queue\n"); |
468 | if (priv->cfg->ops->lib->tt_ops.ct_kill_check) { | 471 | if (priv->cfg->ops->lib->tt_ops.ct_kill_check) { |
469 | is_ct_kill = | 472 | is_ct_kill = |
@@ -471,27 +474,22 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) | |||
471 | } | 474 | } |
472 | if (!is_ct_kill) { | 475 | if (!is_ct_kill) { |
473 | IWL_ERR(priv, "Restarting adapter due to queue full\n"); | 476 | IWL_ERR(priv, "Restarting adapter due to queue full\n"); |
474 | queue_work(priv->workqueue, &priv->restart); | 477 | iwlagn_fw_error(priv, false); |
475 | } | 478 | } |
476 | return -ENOSPC; | 479 | return -ENOSPC; |
477 | } | 480 | } |
478 | 481 | ||
479 | spin_lock_irqsave(&priv->hcmd_lock, flags); | ||
480 | |||
481 | /* If this is a huge cmd, mark the huge flag also on the meta.flags | ||
482 | * of the _original_ cmd. This is used for DMA mapping clean up. | ||
483 | */ | ||
484 | if (cmd->flags & CMD_SIZE_HUGE) { | ||
485 | idx = get_cmd_index(q, q->write_ptr, 0); | ||
486 | txq->meta[idx].flags = CMD_SIZE_HUGE; | ||
487 | } | ||
488 | |||
489 | idx = get_cmd_index(q, q->write_ptr, cmd->flags & CMD_SIZE_HUGE); | 482 | idx = get_cmd_index(q, q->write_ptr, cmd->flags & CMD_SIZE_HUGE); |
490 | out_cmd = txq->cmd[idx]; | 483 | out_cmd = txq->cmd[idx]; |
491 | out_meta = &txq->meta[idx]; | 484 | out_meta = &txq->meta[idx]; |
492 | 485 | ||
486 | if (WARN_ON(out_meta->flags & CMD_MAPPED)) { | ||
487 | spin_unlock_irqrestore(&priv->hcmd_lock, flags); | ||
488 | return -ENOSPC; | ||
489 | } | ||
490 | |||
493 | memset(out_meta, 0, sizeof(*out_meta)); /* re-initialize to NULL */ | 491 | memset(out_meta, 0, sizeof(*out_meta)); /* re-initialize to NULL */ |
494 | out_meta->flags = cmd->flags; | 492 | out_meta->flags = cmd->flags | CMD_MAPPED; |
495 | if (cmd->flags & CMD_WANT_SKB) | 493 | if (cmd->flags & CMD_WANT_SKB) |
496 | out_meta->source = cmd; | 494 | out_meta->source = cmd; |
497 | if (cmd->flags & CMD_ASYNC) | 495 | if (cmd->flags & CMD_ASYNC) |
@@ -584,7 +582,7 @@ static void iwl_hcmd_queue_reclaim(struct iwl_priv *priv, int txq_id, | |||
584 | if (nfreed++ > 0) { | 582 | if (nfreed++ > 0) { |
585 | IWL_ERR(priv, "HCMD skipped: index (%d) %d %d\n", idx, | 583 | IWL_ERR(priv, "HCMD skipped: index (%d) %d %d\n", idx, |
586 | q->write_ptr, q->read_ptr); | 584 | q->write_ptr, q->read_ptr); |
587 | queue_work(priv->workqueue, &priv->restart); | 585 | iwlagn_fw_error(priv, false); |
588 | } | 586 | } |
589 | 587 | ||
590 | } | 588 | } |
@@ -609,6 +607,10 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) | |||
609 | struct iwl_device_cmd *cmd; | 607 | struct iwl_device_cmd *cmd; |
610 | struct iwl_cmd_meta *meta; | 608 | struct iwl_cmd_meta *meta; |
611 | struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue]; | 609 | struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue]; |
610 | unsigned long flags; | ||
611 | void (*callback) (struct iwl_priv *priv, struct iwl_device_cmd *cmd, | ||
612 | struct iwl_rx_packet *pkt); | ||
613 | |||
612 | 614 | ||
613 | /* If a Tx command is being handled and it isn't in the actual | 615 | /* If a Tx command is being handled and it isn't in the actual |
614 | * command queue then there a command routing bug has been introduced | 616 | * command queue then there a command routing bug has been introduced |
@@ -622,14 +624,8 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) | |||
622 | return; | 624 | return; |
623 | } | 625 | } |
624 | 626 | ||
625 | /* If this is a huge cmd, clear the huge flag on the meta.flags | 627 | spin_lock_irqsave(&priv->hcmd_lock, flags); |
626 | * of the _original_ cmd. So that iwl_cmd_queue_free won't unmap | 628 | |
627 | * the DMA buffer for the scan (huge) command. | ||
628 | */ | ||
629 | if (huge) { | ||
630 | cmd_index = get_cmd_index(&txq->q, index, 0); | ||
631 | txq->meta[cmd_index].flags = 0; | ||
632 | } | ||
633 | cmd_index = get_cmd_index(&txq->q, index, huge); | 629 | cmd_index = get_cmd_index(&txq->q, index, huge); |
634 | cmd = txq->cmd[cmd_index]; | 630 | cmd = txq->cmd[cmd_index]; |
635 | meta = &txq->meta[cmd_index]; | 631 | meta = &txq->meta[cmd_index]; |
@@ -639,12 +635,13 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) | |||
639 | dma_unmap_len(meta, len), | 635 | dma_unmap_len(meta, len), |
640 | PCI_DMA_BIDIRECTIONAL); | 636 | PCI_DMA_BIDIRECTIONAL); |
641 | 637 | ||
638 | callback = NULL; | ||
642 | /* Input error checking is done when commands are added to queue. */ | 639 | /* Input error checking is done when commands are added to queue. */ |
643 | if (meta->flags & CMD_WANT_SKB) { | 640 | if (meta->flags & CMD_WANT_SKB) { |
644 | meta->source->reply_page = (unsigned long)rxb_addr(rxb); | 641 | meta->source->reply_page = (unsigned long)rxb_addr(rxb); |
645 | rxb->page = NULL; | 642 | rxb->page = NULL; |
646 | } else if (meta->callback) | 643 | } else |
647 | meta->callback(priv, cmd, pkt); | 644 | callback = meta->callback; |
648 | 645 | ||
649 | iwl_hcmd_queue_reclaim(priv, txq_id, index, cmd_index); | 646 | iwl_hcmd_queue_reclaim(priv, txq_id, index, cmd_index); |
650 | 647 | ||
@@ -654,5 +651,12 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) | |||
654 | get_cmd_string(cmd->hdr.cmd)); | 651 | get_cmd_string(cmd->hdr.cmd)); |
655 | wake_up_interruptible(&priv->wait_command_queue); | 652 | wake_up_interruptible(&priv->wait_command_queue); |
656 | } | 653 | } |
654 | |||
655 | /* Mark as unmapped */ | ||
657 | meta->flags = 0; | 656 | meta->flags = 0; |
657 | |||
658 | spin_unlock_irqrestore(&priv->hcmd_lock, flags); | ||
659 | |||
660 | if (callback) | ||
661 | callback(priv, cmd, pkt); | ||
658 | } | 662 | } |
diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c index f6c2cd665f49..078ef43d957d 100644 --- a/drivers/net/wireless/libertas/if_spi.c +++ b/drivers/net/wireless/libertas/if_spi.c | |||
@@ -57,6 +57,7 @@ struct if_spi_card { | |||
57 | /* Handles all SPI communication (except for FW load) */ | 57 | /* Handles all SPI communication (except for FW load) */ |
58 | struct workqueue_struct *workqueue; | 58 | struct workqueue_struct *workqueue; |
59 | struct work_struct packet_work; | 59 | struct work_struct packet_work; |
60 | struct work_struct resume_work; | ||
60 | 61 | ||
61 | u8 cmd_buffer[IF_SPI_CMD_BUF_SIZE]; | 62 | u8 cmd_buffer[IF_SPI_CMD_BUF_SIZE]; |
62 | 63 | ||
@@ -68,6 +69,9 @@ struct if_spi_card { | |||
68 | 69 | ||
69 | /* Protects cmd_packet_list and data_packet_list */ | 70 | /* Protects cmd_packet_list and data_packet_list */ |
70 | spinlock_t buffer_lock; | 71 | spinlock_t buffer_lock; |
72 | |||
73 | /* True is card suspended */ | ||
74 | u8 suspended; | ||
71 | }; | 75 | }; |
72 | 76 | ||
73 | static void free_if_spi_card(struct if_spi_card *card) | 77 | static void free_if_spi_card(struct if_spi_card *card) |
@@ -1057,6 +1061,28 @@ out: | |||
1057 | return err; | 1061 | return err; |
1058 | } | 1062 | } |
1059 | 1063 | ||
1064 | static void if_spi_resume_worker(struct work_struct *work) | ||
1065 | { | ||
1066 | struct if_spi_card *card; | ||
1067 | |||
1068 | card = container_of(work, struct if_spi_card, resume_work); | ||
1069 | |||
1070 | if (card->suspended) { | ||
1071 | if (card->pdata->setup) | ||
1072 | card->pdata->setup(card->spi); | ||
1073 | |||
1074 | /* Init card ... */ | ||
1075 | if_spi_init_card(card); | ||
1076 | |||
1077 | enable_irq(card->spi->irq); | ||
1078 | |||
1079 | /* And resume it ... */ | ||
1080 | lbs_resume(card->priv); | ||
1081 | |||
1082 | card->suspended = 0; | ||
1083 | } | ||
1084 | } | ||
1085 | |||
1060 | static int __devinit if_spi_probe(struct spi_device *spi) | 1086 | static int __devinit if_spi_probe(struct spi_device *spi) |
1061 | { | 1087 | { |
1062 | struct if_spi_card *card; | 1088 | struct if_spi_card *card; |
@@ -1107,6 +1133,7 @@ static int __devinit if_spi_probe(struct spi_device *spi) | |||
1107 | goto free_card; | 1133 | goto free_card; |
1108 | } | 1134 | } |
1109 | card->priv = priv; | 1135 | card->priv = priv; |
1136 | priv->setup_fw_on_resume = 1; | ||
1110 | priv->card = card; | 1137 | priv->card = card; |
1111 | priv->hw_host_to_card = if_spi_host_to_card; | 1138 | priv->hw_host_to_card = if_spi_host_to_card; |
1112 | priv->enter_deep_sleep = NULL; | 1139 | priv->enter_deep_sleep = NULL; |
@@ -1117,6 +1144,7 @@ static int __devinit if_spi_probe(struct spi_device *spi) | |||
1117 | /* Initialize interrupt handling stuff. */ | 1144 | /* Initialize interrupt handling stuff. */ |
1118 | card->workqueue = create_workqueue("libertas_spi"); | 1145 | card->workqueue = create_workqueue("libertas_spi"); |
1119 | INIT_WORK(&card->packet_work, if_spi_host_to_card_worker); | 1146 | INIT_WORK(&card->packet_work, if_spi_host_to_card_worker); |
1147 | INIT_WORK(&card->resume_work, if_spi_resume_worker); | ||
1120 | 1148 | ||
1121 | err = request_irq(spi->irq, if_spi_host_interrupt, | 1149 | err = request_irq(spi->irq, if_spi_host_interrupt, |
1122 | IRQF_TRIGGER_FALLING, "libertas_spi", card); | 1150 | IRQF_TRIGGER_FALLING, "libertas_spi", card); |
@@ -1161,6 +1189,8 @@ static int __devexit libertas_spi_remove(struct spi_device *spi) | |||
1161 | lbs_deb_spi("libertas_spi_remove\n"); | 1189 | lbs_deb_spi("libertas_spi_remove\n"); |
1162 | lbs_deb_enter(LBS_DEB_SPI); | 1190 | lbs_deb_enter(LBS_DEB_SPI); |
1163 | 1191 | ||
1192 | cancel_work_sync(&card->resume_work); | ||
1193 | |||
1164 | lbs_stop_card(priv); | 1194 | lbs_stop_card(priv); |
1165 | lbs_remove_card(priv); /* will call free_netdev */ | 1195 | lbs_remove_card(priv); /* will call free_netdev */ |
1166 | 1196 | ||
@@ -1174,6 +1204,40 @@ static int __devexit libertas_spi_remove(struct spi_device *spi) | |||
1174 | return 0; | 1204 | return 0; |
1175 | } | 1205 | } |
1176 | 1206 | ||
1207 | static int if_spi_suspend(struct device *dev) | ||
1208 | { | ||
1209 | struct spi_device *spi = to_spi_device(dev); | ||
1210 | struct if_spi_card *card = spi_get_drvdata(spi); | ||
1211 | |||
1212 | if (!card->suspended) { | ||
1213 | lbs_suspend(card->priv); | ||
1214 | flush_workqueue(card->workqueue); | ||
1215 | disable_irq(spi->irq); | ||
1216 | |||
1217 | if (card->pdata->teardown) | ||
1218 | card->pdata->teardown(spi); | ||
1219 | card->suspended = 1; | ||
1220 | } | ||
1221 | |||
1222 | return 0; | ||
1223 | } | ||
1224 | |||
1225 | static int if_spi_resume(struct device *dev) | ||
1226 | { | ||
1227 | struct spi_device *spi = to_spi_device(dev); | ||
1228 | struct if_spi_card *card = spi_get_drvdata(spi); | ||
1229 | |||
1230 | /* Schedule delayed work */ | ||
1231 | schedule_work(&card->resume_work); | ||
1232 | |||
1233 | return 0; | ||
1234 | } | ||
1235 | |||
1236 | static const struct dev_pm_ops if_spi_pm_ops = { | ||
1237 | .suspend = if_spi_suspend, | ||
1238 | .resume = if_spi_resume, | ||
1239 | }; | ||
1240 | |||
1177 | static struct spi_driver libertas_spi_driver = { | 1241 | static struct spi_driver libertas_spi_driver = { |
1178 | .probe = if_spi_probe, | 1242 | .probe = if_spi_probe, |
1179 | .remove = __devexit_p(libertas_spi_remove), | 1243 | .remove = __devexit_p(libertas_spi_remove), |
@@ -1181,6 +1245,7 @@ static struct spi_driver libertas_spi_driver = { | |||
1181 | .name = "libertas_spi", | 1245 | .name = "libertas_spi", |
1182 | .bus = &spi_bus_type, | 1246 | .bus = &spi_bus_type, |
1183 | .owner = THIS_MODULE, | 1247 | .owner = THIS_MODULE, |
1248 | .pm = &if_spi_pm_ops, | ||
1184 | }, | 1249 | }, |
1185 | }; | 1250 | }; |
1186 | 1251 | ||
diff --git a/drivers/net/wireless/mwifiex/11n.c b/drivers/net/wireless/mwifiex/11n.c new file mode 100644 index 000000000000..73a6e62f5680 --- /dev/null +++ b/drivers/net/wireless/mwifiex/11n.c | |||
@@ -0,0 +1,809 @@ | |||
1 | /* | ||
2 | * Marvell Wireless LAN device driver: 802.11n | ||
3 | * | ||
4 | * Copyright (C) 2011, Marvell International Ltd. | ||
5 | * | ||
6 | * This software file (the "File") is distributed by Marvell International | ||
7 | * Ltd. under the terms of the GNU General Public License Version 2, June 1991 | ||
8 | * (the "License"). You may use, redistribute and/or modify this File in | ||
9 | * accordance with the terms and conditions of the License, a copy of which | ||
10 | * is available by writing to the Free Software Foundation, Inc., | ||
11 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the | ||
12 | * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. | ||
13 | * | ||
14 | * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE | ||
15 | * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE | ||
16 | * ARE EXPRESSLY DISCLAIMED. The License provides additional details about | ||
17 | * this warranty disclaimer. | ||
18 | */ | ||
19 | |||
20 | #include "decl.h" | ||
21 | #include "ioctl.h" | ||
22 | #include "util.h" | ||
23 | #include "fw.h" | ||
24 | #include "main.h" | ||
25 | #include "wmm.h" | ||
26 | #include "11n.h" | ||
27 | |||
28 | /* | ||
29 | * Fills HT capability information field, AMPDU Parameters field, HT extended | ||
30 | * capability field, and supported MCS set fields. | ||
31 | * | ||
32 | * Only the following HT capability information fields are used, all other | ||
33 | * fields are always turned off. | ||
34 | * | ||
35 | * Bit 1 : Supported channel width (0: 20MHz, 1: Both 20 and 40 MHz) | ||
36 | * Bit 4 : Greenfield support (0: Not supported, 1: Supported) | ||
37 | * Bit 5 : Short GI for 20 MHz support (0: Not supported, 1: Supported) | ||
38 | * Bit 6 : Short GI for 40 MHz support (0: Not supported, 1: Supported) | ||
39 | * Bit 7 : Tx STBC (0: Not supported, 1: Supported) | ||
40 | * Bit 8-9 : Rx STBC (0: Not supported, X: Support for up to X spatial streams) | ||
41 | * Bit 10 : Delayed BA support (0: Not supported, 1: Supported) | ||
42 | * Bit 11 : Maximum AMSDU length (0: 3839 octets, 1: 7935 octets) | ||
43 | * Bit 14 : 40-Mhz intolerant support (0: Not supported, 1: Supported) | ||
44 | * | ||
45 | * In addition, the following AMPDU Parameters are set - | ||
46 | * - Maximum AMPDU length exponent (set to 3) | ||
47 | * - Minimum AMPDU start spacing (set to 0 - No restrictions) | ||
48 | * | ||
49 | * MCS is set for 1x1, with MSC32 for infra mode or ad-hoc mode with 40 MHz | ||
50 | * support. | ||
51 | * | ||
52 | * RD responder bit to set to clear in the extended capability header. | ||
53 | */ | ||
54 | void | ||
55 | mwifiex_fill_cap_info(struct mwifiex_private *priv, | ||
56 | struct mwifiex_ie_types_htcap *ht_cap) | ||
57 | { | ||
58 | struct mwifiex_adapter *adapter = priv->adapter; | ||
59 | u8 *mcs; | ||
60 | int rx_mcs_supp; | ||
61 | uint16_t ht_cap_info = le16_to_cpu(ht_cap->ht_cap.cap_info); | ||
62 | uint16_t ht_ext_cap = le16_to_cpu(ht_cap->ht_cap.extended_ht_cap_info); | ||
63 | |||
64 | /* Convert dev_cap to IEEE80211_HT_CAP */ | ||
65 | if (ISSUPP_CHANWIDTH40(adapter->hw_dot_11n_dev_cap)) | ||
66 | ht_cap_info |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||
67 | else | ||
68 | ht_cap_info &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||
69 | |||
70 | if (ISSUPP_SHORTGI20(adapter->hw_dot_11n_dev_cap)) | ||
71 | ht_cap_info |= IEEE80211_HT_CAP_SGI_20; | ||
72 | else | ||
73 | ht_cap_info &= ~IEEE80211_HT_CAP_SGI_20; | ||
74 | |||
75 | if (ISSUPP_SHORTGI40(adapter->hw_dot_11n_dev_cap)) | ||
76 | ht_cap_info |= IEEE80211_HT_CAP_SGI_40; | ||
77 | else | ||
78 | ht_cap_info &= ~IEEE80211_HT_CAP_SGI_40; | ||
79 | |||
80 | if (ISSUPP_TXSTBC(adapter->hw_dot_11n_dev_cap)) | ||
81 | ht_cap_info |= IEEE80211_HT_CAP_TX_STBC; | ||
82 | else | ||
83 | ht_cap_info &= ~IEEE80211_HT_CAP_TX_STBC; | ||
84 | |||
85 | if (ISSUPP_RXSTBC(adapter->hw_dot_11n_dev_cap)) | ||
86 | ht_cap_info |= 1 << IEEE80211_HT_CAP_RX_STBC_SHIFT; | ||
87 | else | ||
88 | ht_cap_info &= ~(3 << IEEE80211_HT_CAP_RX_STBC_SHIFT); | ||
89 | |||
90 | if (ISSUPP_GREENFIELD(adapter->hw_dot_11n_dev_cap)) | ||
91 | ht_cap_info |= IEEE80211_HT_CAP_GRN_FLD; | ||
92 | else | ||
93 | ht_cap_info &= ~IEEE80211_HT_CAP_GRN_FLD; | ||
94 | |||
95 | ht_cap_info &= ~IEEE80211_HT_CAP_MAX_AMSDU; | ||
96 | ht_cap_info |= IEEE80211_HT_CAP_SM_PS; | ||
97 | |||
98 | ht_cap->ht_cap.ampdu_params_info |= IEEE80211_HT_AMPDU_PARM_FACTOR; | ||
99 | ht_cap->ht_cap.ampdu_params_info &= ~IEEE80211_HT_AMPDU_PARM_DENSITY; | ||
100 | |||
101 | rx_mcs_supp = GET_RXMCSSUPP(adapter->hw_dev_mcs_support); | ||
102 | |||
103 | mcs = (u8 *)&ht_cap->ht_cap.mcs; | ||
104 | |||
105 | /* Set MCS for 1x1 */ | ||
106 | memset(mcs, 0xff, rx_mcs_supp); | ||
107 | |||
108 | /* Clear all the other values */ | ||
109 | memset(&mcs[rx_mcs_supp], 0, | ||
110 | sizeof(struct ieee80211_mcs_info) - rx_mcs_supp); | ||
111 | |||
112 | if (priv->bss_mode == NL80211_IFTYPE_STATION || | ||
113 | (ht_cap_info & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) | ||
114 | /* Set MCS32 for infra mode or ad-hoc mode with 40MHz support */ | ||
115 | SETHT_MCS32(ht_cap->ht_cap.mcs.rx_mask); | ||
116 | |||
117 | /* Clear RD responder bit */ | ||
118 | RESETHT_EXTCAP_RDG(ht_ext_cap); | ||
119 | |||
120 | ht_cap->ht_cap.cap_info = cpu_to_le16(ht_cap_info); | ||
121 | ht_cap->ht_cap.extended_ht_cap_info = cpu_to_le16(ht_ext_cap); | ||
122 | } | ||
123 | |||
124 | /* | ||
125 | * This function returns the pointer to an entry in BA Stream | ||
126 | * table which matches the requested BA status. | ||
127 | */ | ||
128 | static struct mwifiex_tx_ba_stream_tbl * | ||
129 | mwifiex_11n_get_tx_ba_stream_status(struct mwifiex_private *priv, | ||
130 | enum mwifiex_ba_status ba_status) | ||
131 | { | ||
132 | struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl; | ||
133 | unsigned long flags; | ||
134 | |||
135 | spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags); | ||
136 | list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) { | ||
137 | if (tx_ba_tsr_tbl->ba_status == ba_status) { | ||
138 | spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, | ||
139 | flags); | ||
140 | return tx_ba_tsr_tbl; | ||
141 | } | ||
142 | } | ||
143 | spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags); | ||
144 | return NULL; | ||
145 | } | ||
146 | |||
147 | /* | ||
148 | * This function handles the command response of delete a block | ||
149 | * ack request. | ||
150 | * | ||
151 | * The function checks the response success status and takes action | ||
152 | * accordingly (send an add BA request in case of success, or recreate | ||
153 | * the deleted stream in case of failure, if the add BA was also | ||
154 | * initiated by us). | ||
155 | */ | ||
156 | int mwifiex_ret_11n_delba(struct mwifiex_private *priv, | ||
157 | struct host_cmd_ds_command *resp) | ||
158 | { | ||
159 | int tid; | ||
160 | struct mwifiex_tx_ba_stream_tbl *tx_ba_tbl; | ||
161 | struct host_cmd_ds_11n_delba *del_ba = | ||
162 | (struct host_cmd_ds_11n_delba *) &resp->params.del_ba; | ||
163 | uint16_t del_ba_param_set = le16_to_cpu(del_ba->del_ba_param_set); | ||
164 | |||
165 | tid = del_ba_param_set >> DELBA_TID_POS; | ||
166 | if (del_ba->del_result == BA_RESULT_SUCCESS) { | ||
167 | mwifiex_11n_delete_ba_stream_tbl(priv, tid, | ||
168 | del_ba->peer_mac_addr, TYPE_DELBA_SENT, | ||
169 | INITIATOR_BIT(del_ba_param_set)); | ||
170 | |||
171 | tx_ba_tbl = mwifiex_11n_get_tx_ba_stream_status(priv, | ||
172 | BA_STREAM_SETUP_INPROGRESS); | ||
173 | if (tx_ba_tbl) | ||
174 | mwifiex_send_addba(priv, tx_ba_tbl->tid, | ||
175 | tx_ba_tbl->ra); | ||
176 | } else { /* | ||
177 | * In case of failure, recreate the deleted stream in case | ||
178 | * we initiated the ADDBA | ||
179 | */ | ||
180 | if (INITIATOR_BIT(del_ba_param_set)) { | ||
181 | mwifiex_11n_create_tx_ba_stream_tbl(priv, | ||
182 | del_ba->peer_mac_addr, tid, | ||
183 | BA_STREAM_SETUP_INPROGRESS); | ||
184 | |||
185 | tx_ba_tbl = mwifiex_11n_get_tx_ba_stream_status(priv, | ||
186 | BA_STREAM_SETUP_INPROGRESS); | ||
187 | if (tx_ba_tbl) | ||
188 | mwifiex_11n_delete_ba_stream_tbl(priv, | ||
189 | tx_ba_tbl->tid, tx_ba_tbl->ra, | ||
190 | TYPE_DELBA_SENT, true); | ||
191 | } | ||
192 | } | ||
193 | |||
194 | return 0; | ||
195 | } | ||
196 | |||
197 | /* | ||
198 | * This function handles the command response of add a block | ||
199 | * ack request. | ||
200 | * | ||
201 | * Handling includes changing the header fields to CPU formats, checking | ||
202 | * the response success status and taking actions accordingly (delete the | ||
203 | * BA stream table in case of failure). | ||
204 | */ | ||
205 | int mwifiex_ret_11n_addba_req(struct mwifiex_private *priv, | ||
206 | struct host_cmd_ds_command *resp) | ||
207 | { | ||
208 | int tid; | ||
209 | struct host_cmd_ds_11n_addba_rsp *add_ba_rsp = | ||
210 | (struct host_cmd_ds_11n_addba_rsp *) &resp->params.add_ba_rsp; | ||
211 | struct mwifiex_tx_ba_stream_tbl *tx_ba_tbl; | ||
212 | |||
213 | add_ba_rsp->ssn = cpu_to_le16((le16_to_cpu(add_ba_rsp->ssn)) | ||
214 | & SSN_MASK); | ||
215 | |||
216 | tid = (le16_to_cpu(add_ba_rsp->block_ack_param_set) | ||
217 | & IEEE80211_ADDBA_PARAM_TID_MASK) | ||
218 | >> BLOCKACKPARAM_TID_POS; | ||
219 | if (le16_to_cpu(add_ba_rsp->status_code) == BA_RESULT_SUCCESS) { | ||
220 | tx_ba_tbl = mwifiex_11n_get_tx_ba_stream_tbl(priv, tid, | ||
221 | add_ba_rsp->peer_mac_addr); | ||
222 | if (tx_ba_tbl) { | ||
223 | dev_dbg(priv->adapter->dev, "info: BA stream complete\n"); | ||
224 | tx_ba_tbl->ba_status = BA_STREAM_SETUP_COMPLETE; | ||
225 | } else { | ||
226 | dev_err(priv->adapter->dev, "BA stream not created\n"); | ||
227 | } | ||
228 | } else { | ||
229 | mwifiex_11n_delete_ba_stream_tbl(priv, tid, | ||
230 | add_ba_rsp->peer_mac_addr, | ||
231 | TYPE_DELBA_SENT, true); | ||
232 | if (add_ba_rsp->add_rsp_result != BA_RESULT_TIMEOUT) | ||
233 | priv->aggr_prio_tbl[tid].ampdu_ap = | ||
234 | BA_STREAM_NOT_ALLOWED; | ||
235 | } | ||
236 | |||
237 | return 0; | ||
238 | } | ||
239 | |||
240 | /* | ||
241 | * This function handles the command response of 11n configuration request. | ||
242 | * | ||
243 | * Handling includes changing the header fields into CPU format. | ||
244 | */ | ||
245 | int mwifiex_ret_11n_cfg(struct mwifiex_private *priv, | ||
246 | struct host_cmd_ds_command *resp, | ||
247 | void *data_buf) | ||
248 | { | ||
249 | struct mwifiex_ds_11n_tx_cfg *tx_cfg = NULL; | ||
250 | struct host_cmd_ds_11n_cfg *htcfg = &resp->params.htcfg; | ||
251 | |||
252 | if (data_buf) { | ||
253 | tx_cfg = (struct mwifiex_ds_11n_tx_cfg *) data_buf; | ||
254 | tx_cfg->tx_htcap = le16_to_cpu(htcfg->ht_tx_cap); | ||
255 | tx_cfg->tx_htinfo = le16_to_cpu(htcfg->ht_tx_info); | ||
256 | } | ||
257 | return 0; | ||
258 | } | ||
259 | |||
260 | /* | ||
261 | * This function prepares command of reconfigure Tx buffer. | ||
262 | * | ||
263 | * Preparation includes - | ||
264 | * - Setting command ID, action and proper size | ||
265 | * - Setting Tx buffer size (for SET only) | ||
266 | * - Ensuring correct endian-ness | ||
267 | */ | ||
268 | int mwifiex_cmd_recfg_tx_buf(struct mwifiex_private *priv, | ||
269 | struct host_cmd_ds_command *cmd, int cmd_action, | ||
270 | void *data_buf) | ||
271 | { | ||
272 | struct host_cmd_ds_txbuf_cfg *tx_buf = &cmd->params.tx_buf; | ||
273 | u16 action = (u16) cmd_action; | ||
274 | u16 buf_size = *((u16 *) data_buf); | ||
275 | |||
276 | cmd->command = cpu_to_le16(HostCmd_CMD_RECONFIGURE_TX_BUFF); | ||
277 | cmd->size = | ||
278 | cpu_to_le16(sizeof(struct host_cmd_ds_txbuf_cfg) + S_DS_GEN); | ||
279 | tx_buf->action = cpu_to_le16(action); | ||
280 | switch (action) { | ||
281 | case HostCmd_ACT_GEN_SET: | ||
282 | dev_dbg(priv->adapter->dev, "cmd: set tx_buf=%d\n", buf_size); | ||
283 | tx_buf->buff_size = cpu_to_le16(buf_size); | ||
284 | break; | ||
285 | case HostCmd_ACT_GEN_GET: | ||
286 | default: | ||
287 | tx_buf->buff_size = 0; | ||
288 | break; | ||
289 | } | ||
290 | return 0; | ||
291 | } | ||
292 | |||
293 | /* | ||
294 | * This function prepares command of AMSDU aggregation control. | ||
295 | * | ||
296 | * Preparation includes - | ||
297 | * - Setting command ID, action and proper size | ||
298 | * - Setting AMSDU control parameters (for SET only) | ||
299 | * - Ensuring correct endian-ness | ||
300 | */ | ||
301 | int mwifiex_cmd_amsdu_aggr_ctrl(struct mwifiex_private *priv, | ||
302 | struct host_cmd_ds_command *cmd, | ||
303 | int cmd_action, void *data_buf) | ||
304 | { | ||
305 | struct host_cmd_ds_amsdu_aggr_ctrl *amsdu_ctrl = | ||
306 | &cmd->params.amsdu_aggr_ctrl; | ||
307 | u16 action = (u16) cmd_action; | ||
308 | struct mwifiex_ds_11n_amsdu_aggr_ctrl *aa_ctrl = | ||
309 | (struct mwifiex_ds_11n_amsdu_aggr_ctrl *) data_buf; | ||
310 | |||
311 | cmd->command = cpu_to_le16(HostCmd_CMD_AMSDU_AGGR_CTRL); | ||
312 | cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_amsdu_aggr_ctrl) | ||
313 | + S_DS_GEN); | ||
314 | amsdu_ctrl->action = cpu_to_le16(action); | ||
315 | switch (action) { | ||
316 | case HostCmd_ACT_GEN_SET: | ||
317 | amsdu_ctrl->enable = cpu_to_le16(aa_ctrl->enable); | ||
318 | amsdu_ctrl->curr_buf_size = 0; | ||
319 | break; | ||
320 | case HostCmd_ACT_GEN_GET: | ||
321 | default: | ||
322 | amsdu_ctrl->curr_buf_size = 0; | ||
323 | break; | ||
324 | } | ||
325 | return 0; | ||
326 | } | ||
327 | |||
328 | /* | ||
329 | * This function handles the command response of AMSDU aggregation | ||
330 | * control request. | ||
331 | * | ||
332 | * Handling includes changing the header fields into CPU format. | ||
333 | */ | ||
334 | int mwifiex_ret_amsdu_aggr_ctrl(struct mwifiex_private *priv, | ||
335 | struct host_cmd_ds_command *resp, | ||
336 | void *data_buf) | ||
337 | { | ||
338 | struct mwifiex_ds_11n_amsdu_aggr_ctrl *amsdu_aggr_ctrl = NULL; | ||
339 | struct host_cmd_ds_amsdu_aggr_ctrl *amsdu_ctrl = | ||
340 | &resp->params.amsdu_aggr_ctrl; | ||
341 | |||
342 | if (data_buf) { | ||
343 | amsdu_aggr_ctrl = | ||
344 | (struct mwifiex_ds_11n_amsdu_aggr_ctrl *) data_buf; | ||
345 | amsdu_aggr_ctrl->enable = le16_to_cpu(amsdu_ctrl->enable); | ||
346 | amsdu_aggr_ctrl->curr_buf_size = | ||
347 | le16_to_cpu(amsdu_ctrl->curr_buf_size); | ||
348 | } | ||
349 | return 0; | ||
350 | } | ||
351 | |||
352 | /* | ||
353 | * This function prepares 11n configuration command. | ||
354 | * | ||
355 | * Preparation includes - | ||
356 | * - Setting command ID, action and proper size | ||
357 | * - Setting HT Tx capability and HT Tx information fields | ||
358 | * - Ensuring correct endian-ness | ||
359 | */ | ||
360 | int mwifiex_cmd_11n_cfg(struct mwifiex_private *priv, | ||
361 | struct host_cmd_ds_command *cmd, | ||
362 | u16 cmd_action, void *data_buf) | ||
363 | { | ||
364 | struct host_cmd_ds_11n_cfg *htcfg = &cmd->params.htcfg; | ||
365 | struct mwifiex_ds_11n_tx_cfg *txcfg = | ||
366 | (struct mwifiex_ds_11n_tx_cfg *) data_buf; | ||
367 | |||
368 | cmd->command = cpu_to_le16(HostCmd_CMD_11N_CFG); | ||
369 | cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_11n_cfg) + S_DS_GEN); | ||
370 | htcfg->action = cpu_to_le16(cmd_action); | ||
371 | htcfg->ht_tx_cap = cpu_to_le16(txcfg->tx_htcap); | ||
372 | htcfg->ht_tx_info = cpu_to_le16(txcfg->tx_htinfo); | ||
373 | return 0; | ||
374 | } | ||
375 | |||
376 | /* | ||
377 | * This function appends an 11n TLV to a buffer. | ||
378 | * | ||
379 | * Buffer allocation is responsibility of the calling | ||
380 | * function. No size validation is made here. | ||
381 | * | ||
382 | * The function fills up the following sections, if applicable - | ||
383 | * - HT capability IE | ||
384 | * - HT information IE (with channel list) | ||
385 | * - 20/40 BSS Coexistence IE | ||
386 | * - HT Extended Capabilities IE | ||
387 | */ | ||
388 | int | ||
389 | mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv, | ||
390 | struct mwifiex_bssdescriptor *bss_desc, | ||
391 | u8 **buffer) | ||
392 | { | ||
393 | struct mwifiex_ie_types_htcap *ht_cap; | ||
394 | struct mwifiex_ie_types_htinfo *ht_info; | ||
395 | struct mwifiex_ie_types_chan_list_param_set *chan_list; | ||
396 | struct mwifiex_ie_types_2040bssco *bss_co_2040; | ||
397 | struct mwifiex_ie_types_extcap *ext_cap; | ||
398 | int ret_len = 0; | ||
399 | |||
400 | if (!buffer || !*buffer) | ||
401 | return ret_len; | ||
402 | |||
403 | if (bss_desc->bcn_ht_cap) { | ||
404 | ht_cap = (struct mwifiex_ie_types_htcap *) *buffer; | ||
405 | memset(ht_cap, 0, sizeof(struct mwifiex_ie_types_htcap)); | ||
406 | ht_cap->header.type = cpu_to_le16(WLAN_EID_HT_CAPABILITY); | ||
407 | ht_cap->header.len = | ||
408 | cpu_to_le16(sizeof(struct ieee80211_ht_cap)); | ||
409 | memcpy((u8 *) ht_cap + sizeof(struct mwifiex_ie_types_header), | ||
410 | (u8 *) bss_desc->bcn_ht_cap + | ||
411 | sizeof(struct ieee_types_header), | ||
412 | le16_to_cpu(ht_cap->header.len)); | ||
413 | |||
414 | mwifiex_fill_cap_info(priv, ht_cap); | ||
415 | |||
416 | *buffer += sizeof(struct mwifiex_ie_types_htcap); | ||
417 | ret_len += sizeof(struct mwifiex_ie_types_htcap); | ||
418 | } | ||
419 | |||
420 | if (bss_desc->bcn_ht_info) { | ||
421 | if (priv->bss_mode == NL80211_IFTYPE_ADHOC) { | ||
422 | ht_info = (struct mwifiex_ie_types_htinfo *) *buffer; | ||
423 | memset(ht_info, 0, | ||
424 | sizeof(struct mwifiex_ie_types_htinfo)); | ||
425 | ht_info->header.type = | ||
426 | cpu_to_le16(WLAN_EID_HT_INFORMATION); | ||
427 | ht_info->header.len = | ||
428 | cpu_to_le16(sizeof(struct ieee80211_ht_info)); | ||
429 | |||
430 | memcpy((u8 *) ht_info + | ||
431 | sizeof(struct mwifiex_ie_types_header), | ||
432 | (u8 *) bss_desc->bcn_ht_info + | ||
433 | sizeof(struct ieee_types_header), | ||
434 | le16_to_cpu(ht_info->header.len)); | ||
435 | |||
436 | if (!ISSUPP_CHANWIDTH40 | ||
437 | (priv->adapter->hw_dot_11n_dev_cap)) | ||
438 | ht_info->ht_info.ht_param &= | ||
439 | ~(IEEE80211_HT_PARAM_CHAN_WIDTH_ANY | | ||
440 | IEEE80211_HT_PARAM_CHA_SEC_OFFSET); | ||
441 | |||
442 | *buffer += sizeof(struct mwifiex_ie_types_htinfo); | ||
443 | ret_len += sizeof(struct mwifiex_ie_types_htinfo); | ||
444 | } | ||
445 | |||
446 | chan_list = | ||
447 | (struct mwifiex_ie_types_chan_list_param_set *) *buffer; | ||
448 | memset(chan_list, 0, | ||
449 | sizeof(struct mwifiex_ie_types_chan_list_param_set)); | ||
450 | chan_list->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); | ||
451 | chan_list->header.len = cpu_to_le16( | ||
452 | sizeof(struct mwifiex_ie_types_chan_list_param_set) - | ||
453 | sizeof(struct mwifiex_ie_types_header)); | ||
454 | chan_list->chan_scan_param[0].chan_number = | ||
455 | bss_desc->bcn_ht_info->control_chan; | ||
456 | chan_list->chan_scan_param[0].radio_type = | ||
457 | mwifiex_band_to_radio_type((u8) bss_desc->bss_band); | ||
458 | |||
459 | if (ISSUPP_CHANWIDTH40(priv->adapter->hw_dot_11n_dev_cap) | ||
460 | && (bss_desc->bcn_ht_info->ht_param & | ||
461 | IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) | ||
462 | SET_SECONDARYCHAN(chan_list->chan_scan_param[0]. | ||
463 | radio_type, | ||
464 | (bss_desc->bcn_ht_info->ht_param & | ||
465 | IEEE80211_HT_PARAM_CHA_SEC_OFFSET)); | ||
466 | |||
467 | *buffer += sizeof(struct mwifiex_ie_types_chan_list_param_set); | ||
468 | ret_len += sizeof(struct mwifiex_ie_types_chan_list_param_set); | ||
469 | } | ||
470 | |||
471 | if (bss_desc->bcn_bss_co_2040) { | ||
472 | bss_co_2040 = (struct mwifiex_ie_types_2040bssco *) *buffer; | ||
473 | memset(bss_co_2040, 0, | ||
474 | sizeof(struct mwifiex_ie_types_2040bssco)); | ||
475 | bss_co_2040->header.type = cpu_to_le16(WLAN_EID_BSS_COEX_2040); | ||
476 | bss_co_2040->header.len = | ||
477 | cpu_to_le16(sizeof(bss_co_2040->bss_co_2040)); | ||
478 | |||
479 | memcpy((u8 *) bss_co_2040 + | ||
480 | sizeof(struct mwifiex_ie_types_header), | ||
481 | (u8 *) bss_desc->bcn_bss_co_2040 + | ||
482 | sizeof(struct ieee_types_header), | ||
483 | le16_to_cpu(bss_co_2040->header.len)); | ||
484 | |||
485 | *buffer += sizeof(struct mwifiex_ie_types_2040bssco); | ||
486 | ret_len += sizeof(struct mwifiex_ie_types_2040bssco); | ||
487 | } | ||
488 | |||
489 | if (bss_desc->bcn_ext_cap) { | ||
490 | ext_cap = (struct mwifiex_ie_types_extcap *) *buffer; | ||
491 | memset(ext_cap, 0, sizeof(struct mwifiex_ie_types_extcap)); | ||
492 | ext_cap->header.type = cpu_to_le16(WLAN_EID_EXT_CAPABILITY); | ||
493 | ext_cap->header.len = cpu_to_le16(sizeof(ext_cap->ext_cap)); | ||
494 | |||
495 | memcpy((u8 *) ext_cap + | ||
496 | sizeof(struct mwifiex_ie_types_header), | ||
497 | (u8 *) bss_desc->bcn_ext_cap + | ||
498 | sizeof(struct ieee_types_header), | ||
499 | le16_to_cpu(ext_cap->header.len)); | ||
500 | |||
501 | *buffer += sizeof(struct mwifiex_ie_types_extcap); | ||
502 | ret_len += sizeof(struct mwifiex_ie_types_extcap); | ||
503 | } | ||
504 | |||
505 | return ret_len; | ||
506 | } | ||
507 | |||
508 | /* | ||
509 | * This function reconfigures the Tx buffer size in firmware. | ||
510 | * | ||
511 | * This function prepares a firmware command and issues it, if | ||
512 | * the current Tx buffer size is different from the one requested. | ||
513 | * Maximum configurable Tx buffer size is limited by the HT capability | ||
514 | * field value. | ||
515 | */ | ||
516 | void | ||
517 | mwifiex_cfg_tx_buf(struct mwifiex_private *priv, | ||
518 | struct mwifiex_bssdescriptor *bss_desc) | ||
519 | { | ||
520 | u16 max_amsdu = MWIFIEX_TX_DATA_BUF_SIZE_2K; | ||
521 | u16 tx_buf = 0; | ||
522 | u16 curr_tx_buf_size = 0; | ||
523 | |||
524 | if (bss_desc->bcn_ht_cap) { | ||
525 | if (le16_to_cpu(bss_desc->bcn_ht_cap->cap_info) & | ||
526 | IEEE80211_HT_CAP_MAX_AMSDU) | ||
527 | max_amsdu = MWIFIEX_TX_DATA_BUF_SIZE_8K; | ||
528 | else | ||
529 | max_amsdu = MWIFIEX_TX_DATA_BUF_SIZE_4K; | ||
530 | } | ||
531 | |||
532 | tx_buf = min(priv->adapter->max_tx_buf_size, max_amsdu); | ||
533 | |||
534 | dev_dbg(priv->adapter->dev, "info: max_amsdu=%d, max_tx_buf=%d\n", | ||
535 | max_amsdu, priv->adapter->max_tx_buf_size); | ||
536 | |||
537 | if (priv->adapter->curr_tx_buf_size <= MWIFIEX_TX_DATA_BUF_SIZE_2K) | ||
538 | curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K; | ||
539 | else if (priv->adapter->curr_tx_buf_size <= MWIFIEX_TX_DATA_BUF_SIZE_4K) | ||
540 | curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K; | ||
541 | else if (priv->adapter->curr_tx_buf_size <= MWIFIEX_TX_DATA_BUF_SIZE_8K) | ||
542 | curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_8K; | ||
543 | if (curr_tx_buf_size != tx_buf) | ||
544 | mwifiex_prepare_cmd(priv, HostCmd_CMD_RECONFIGURE_TX_BUFF, | ||
545 | HostCmd_ACT_GEN_SET, 0, | ||
546 | NULL, &tx_buf); | ||
547 | |||
548 | return; | ||
549 | } | ||
550 | |||
551 | /* | ||
552 | * This function checks if the given pointer is valid entry of | ||
553 | * Tx BA Stream table. | ||
554 | */ | ||
555 | static int mwifiex_is_tx_ba_stream_ptr_valid(struct mwifiex_private *priv, | ||
556 | struct mwifiex_tx_ba_stream_tbl *tx_tbl_ptr) | ||
557 | { | ||
558 | struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl; | ||
559 | |||
560 | list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) { | ||
561 | if (tx_ba_tsr_tbl == tx_tbl_ptr) | ||
562 | return true; | ||
563 | } | ||
564 | |||
565 | return false; | ||
566 | } | ||
567 | |||
568 | /* | ||
569 | * This function deletes the given entry in Tx BA Stream table. | ||
570 | * | ||
571 | * The function also performs a validity check on the supplied | ||
572 | * pointer before trying to delete. | ||
573 | */ | ||
574 | void mwifiex_11n_delete_tx_ba_stream_tbl_entry(struct mwifiex_private *priv, | ||
575 | struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl) | ||
576 | { | ||
577 | if (!tx_ba_tsr_tbl && | ||
578 | mwifiex_is_tx_ba_stream_ptr_valid(priv, tx_ba_tsr_tbl)) | ||
579 | return; | ||
580 | |||
581 | dev_dbg(priv->adapter->dev, "info: tx_ba_tsr_tbl %p\n", tx_ba_tsr_tbl); | ||
582 | |||
583 | list_del(&tx_ba_tsr_tbl->list); | ||
584 | |||
585 | kfree(tx_ba_tsr_tbl); | ||
586 | |||
587 | return; | ||
588 | } | ||
589 | |||
590 | /* | ||
591 | * This function deletes all the entries in Tx BA Stream table. | ||
592 | */ | ||
593 | void mwifiex_11n_delete_all_tx_ba_stream_tbl(struct mwifiex_private *priv) | ||
594 | { | ||
595 | int i; | ||
596 | struct mwifiex_tx_ba_stream_tbl *del_tbl_ptr, *tmp_node; | ||
597 | unsigned long flags; | ||
598 | |||
599 | spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags); | ||
600 | list_for_each_entry_safe(del_tbl_ptr, tmp_node, | ||
601 | &priv->tx_ba_stream_tbl_ptr, list) | ||
602 | mwifiex_11n_delete_tx_ba_stream_tbl_entry(priv, del_tbl_ptr); | ||
603 | spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags); | ||
604 | |||
605 | INIT_LIST_HEAD(&priv->tx_ba_stream_tbl_ptr); | ||
606 | |||
607 | for (i = 0; i < MAX_NUM_TID; ++i) | ||
608 | priv->aggr_prio_tbl[i].ampdu_ap = | ||
609 | priv->aggr_prio_tbl[i].ampdu_user; | ||
610 | } | ||
611 | |||
612 | /* | ||
613 | * This function returns the pointer to an entry in BA Stream | ||
614 | * table which matches the given RA/TID pair. | ||
615 | */ | ||
616 | struct mwifiex_tx_ba_stream_tbl * | ||
617 | mwifiex_11n_get_tx_ba_stream_tbl(struct mwifiex_private *priv, | ||
618 | int tid, u8 *ra) | ||
619 | { | ||
620 | struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl; | ||
621 | unsigned long flags; | ||
622 | |||
623 | spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags); | ||
624 | list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) { | ||
625 | if ((!memcmp(tx_ba_tsr_tbl->ra, ra, ETH_ALEN)) | ||
626 | && (tx_ba_tsr_tbl->tid == tid)) { | ||
627 | spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, | ||
628 | flags); | ||
629 | return tx_ba_tsr_tbl; | ||
630 | } | ||
631 | } | ||
632 | spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags); | ||
633 | return NULL; | ||
634 | } | ||
635 | |||
636 | /* | ||
637 | * This function creates an entry in Tx BA stream table for the | ||
638 | * given RA/TID pair. | ||
639 | */ | ||
640 | void mwifiex_11n_create_tx_ba_stream_tbl(struct mwifiex_private *priv, | ||
641 | u8 *ra, int tid, | ||
642 | enum mwifiex_ba_status ba_status) | ||
643 | { | ||
644 | struct mwifiex_tx_ba_stream_tbl *new_node; | ||
645 | unsigned long flags; | ||
646 | |||
647 | if (!mwifiex_11n_get_tx_ba_stream_tbl(priv, tid, ra)) { | ||
648 | new_node = kzalloc(sizeof(struct mwifiex_tx_ba_stream_tbl), | ||
649 | GFP_ATOMIC); | ||
650 | if (!new_node) { | ||
651 | dev_err(priv->adapter->dev, | ||
652 | "%s: failed to alloc new_node\n", __func__); | ||
653 | return; | ||
654 | } | ||
655 | |||
656 | INIT_LIST_HEAD(&new_node->list); | ||
657 | |||
658 | new_node->tid = tid; | ||
659 | new_node->ba_status = ba_status; | ||
660 | memcpy(new_node->ra, ra, ETH_ALEN); | ||
661 | |||
662 | spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags); | ||
663 | list_add_tail(&new_node->list, &priv->tx_ba_stream_tbl_ptr); | ||
664 | spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags); | ||
665 | } | ||
666 | |||
667 | return; | ||
668 | } | ||
669 | |||
670 | /* | ||
671 | * This function sends an add BA request to the given TID/RA pair. | ||
672 | */ | ||
673 | int mwifiex_send_addba(struct mwifiex_private *priv, int tid, u8 *peer_mac) | ||
674 | { | ||
675 | struct host_cmd_ds_11n_addba_req add_ba_req; | ||
676 | static u8 dialog_tok; | ||
677 | int ret; | ||
678 | |||
679 | dev_dbg(priv->adapter->dev, "cmd: %s: tid %d\n", __func__, tid); | ||
680 | |||
681 | add_ba_req.block_ack_param_set = cpu_to_le16( | ||
682 | (u16) ((tid << BLOCKACKPARAM_TID_POS) | | ||
683 | (priv->add_ba_param. | ||
684 | tx_win_size << BLOCKACKPARAM_WINSIZE_POS) | | ||
685 | IMMEDIATE_BLOCK_ACK)); | ||
686 | add_ba_req.block_ack_tmo = cpu_to_le16((u16)priv->add_ba_param.timeout); | ||
687 | |||
688 | ++dialog_tok; | ||
689 | |||
690 | if (dialog_tok == 0) | ||
691 | dialog_tok = 1; | ||
692 | |||
693 | add_ba_req.dialog_token = dialog_tok; | ||
694 | memcpy(&add_ba_req.peer_mac_addr, peer_mac, ETH_ALEN); | ||
695 | |||
696 | /* We don't wait for the response of this command */ | ||
697 | ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_11N_ADDBA_REQ, | ||
698 | 0, 0, NULL, &add_ba_req); | ||
699 | |||
700 | return ret; | ||
701 | } | ||
702 | |||
703 | /* | ||
704 | * This function sends a delete BA request to the given TID/RA pair. | ||
705 | */ | ||
706 | int mwifiex_send_delba(struct mwifiex_private *priv, int tid, u8 *peer_mac, | ||
707 | int initiator) | ||
708 | { | ||
709 | struct host_cmd_ds_11n_delba delba; | ||
710 | int ret; | ||
711 | uint16_t del_ba_param_set; | ||
712 | |||
713 | memset(&delba, 0, sizeof(delba)); | ||
714 | delba.del_ba_param_set = cpu_to_le16(tid << DELBA_TID_POS); | ||
715 | |||
716 | del_ba_param_set = le16_to_cpu(delba.del_ba_param_set); | ||
717 | if (initiator) | ||
718 | del_ba_param_set |= IEEE80211_DELBA_PARAM_INITIATOR_MASK; | ||
719 | else | ||
720 | del_ba_param_set &= ~IEEE80211_DELBA_PARAM_INITIATOR_MASK; | ||
721 | |||
722 | memcpy(&delba.peer_mac_addr, peer_mac, ETH_ALEN); | ||
723 | |||
724 | /* We don't wait for the response of this command */ | ||
725 | ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_11N_DELBA, | ||
726 | HostCmd_ACT_GEN_SET, 0, NULL, &delba); | ||
727 | |||
728 | return ret; | ||
729 | } | ||
730 | |||
731 | /* | ||
732 | * This function handles the command response of a delete BA request. | ||
733 | */ | ||
734 | void mwifiex_11n_delete_ba_stream(struct mwifiex_private *priv, u8 *del_ba) | ||
735 | { | ||
736 | struct host_cmd_ds_11n_delba *cmd_del_ba = | ||
737 | (struct host_cmd_ds_11n_delba *) del_ba; | ||
738 | uint16_t del_ba_param_set = le16_to_cpu(cmd_del_ba->del_ba_param_set); | ||
739 | int tid; | ||
740 | |||
741 | tid = del_ba_param_set >> DELBA_TID_POS; | ||
742 | |||
743 | mwifiex_11n_delete_ba_stream_tbl(priv, tid, cmd_del_ba->peer_mac_addr, | ||
744 | TYPE_DELBA_RECEIVE, | ||
745 | INITIATOR_BIT(del_ba_param_set)); | ||
746 | } | ||
747 | |||
748 | /* | ||
749 | * This function retrieves the Rx reordering table. | ||
750 | */ | ||
751 | int mwifiex_get_rx_reorder_tbl(struct mwifiex_private *priv, | ||
752 | struct mwifiex_ds_rx_reorder_tbl *buf) | ||
753 | { | ||
754 | int i; | ||
755 | struct mwifiex_ds_rx_reorder_tbl *rx_reo_tbl = buf; | ||
756 | struct mwifiex_rx_reorder_tbl *rx_reorder_tbl_ptr; | ||
757 | int count = 0; | ||
758 | unsigned long flags; | ||
759 | |||
760 | spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags); | ||
761 | list_for_each_entry(rx_reorder_tbl_ptr, &priv->rx_reorder_tbl_ptr, | ||
762 | list) { | ||
763 | rx_reo_tbl->tid = (u16) rx_reorder_tbl_ptr->tid; | ||
764 | memcpy(rx_reo_tbl->ta, rx_reorder_tbl_ptr->ta, ETH_ALEN); | ||
765 | rx_reo_tbl->start_win = rx_reorder_tbl_ptr->start_win; | ||
766 | rx_reo_tbl->win_size = rx_reorder_tbl_ptr->win_size; | ||
767 | for (i = 0; i < rx_reorder_tbl_ptr->win_size; ++i) { | ||
768 | if (rx_reorder_tbl_ptr->rx_reorder_ptr[i]) | ||
769 | rx_reo_tbl->buffer[i] = true; | ||
770 | else | ||
771 | rx_reo_tbl->buffer[i] = false; | ||
772 | } | ||
773 | rx_reo_tbl++; | ||
774 | count++; | ||
775 | |||
776 | if (count >= MWIFIEX_MAX_RX_BASTREAM_SUPPORTED) | ||
777 | break; | ||
778 | } | ||
779 | spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags); | ||
780 | |||
781 | return count; | ||
782 | } | ||
783 | |||
784 | /* | ||
785 | * This function retrieves the Tx BA stream table. | ||
786 | */ | ||
787 | int mwifiex_get_tx_ba_stream_tbl(struct mwifiex_private *priv, | ||
788 | struct mwifiex_ds_tx_ba_stream_tbl *buf) | ||
789 | { | ||
790 | struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl; | ||
791 | struct mwifiex_ds_tx_ba_stream_tbl *rx_reo_tbl = buf; | ||
792 | int count = 0; | ||
793 | unsigned long flags; | ||
794 | |||
795 | spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags); | ||
796 | list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) { | ||
797 | rx_reo_tbl->tid = (u16) tx_ba_tsr_tbl->tid; | ||
798 | dev_dbg(priv->adapter->dev, "data: %s tid=%d\n", | ||
799 | __func__, rx_reo_tbl->tid); | ||
800 | memcpy(rx_reo_tbl->ra, tx_ba_tsr_tbl->ra, ETH_ALEN); | ||
801 | rx_reo_tbl++; | ||
802 | count++; | ||
803 | if (count >= MWIFIEX_MAX_TX_BASTREAM_SUPPORTED) | ||
804 | break; | ||
805 | } | ||
806 | spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags); | ||
807 | |||
808 | return count; | ||
809 | } | ||
diff --git a/drivers/net/wireless/mwifiex/11n.h b/drivers/net/wireless/mwifiex/11n.h new file mode 100644 index 000000000000..71a853e61b61 --- /dev/null +++ b/drivers/net/wireless/mwifiex/11n.h | |||
@@ -0,0 +1,176 @@ | |||
1 | /* | ||
2 | * Marvell Wireless LAN device driver: 802.11n | ||
3 | * | ||
4 | * Copyright (C) 2011, Marvell International Ltd. | ||
5 | * | ||
6 | * This software file (the "File") is distributed by Marvell International | ||
7 | * Ltd. under the terms of the GNU General Public License Version 2, June 1991 | ||
8 | * (the "License"). You may use, redistribute and/or modify this File in | ||
9 | * accordance with the terms and conditions of the License, a copy of which | ||
10 | * is available by writing to the Free Software Foundation, Inc., | ||
11 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the | ||
12 | * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. | ||
13 | * | ||
14 | * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE | ||
15 | * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE | ||
16 | * ARE EXPRESSLY DISCLAIMED. The License provides additional details about | ||
17 | * this warranty disclaimer. | ||
18 | */ | ||
19 | |||
20 | #ifndef _MWIFIEX_11N_H_ | ||
21 | #define _MWIFIEX_11N_H_ | ||
22 | |||
23 | #include "11n_aggr.h" | ||
24 | #include "11n_rxreorder.h" | ||
25 | #include "wmm.h" | ||
26 | |||
27 | int mwifiex_ret_11n_delba(struct mwifiex_private *priv, | ||
28 | struct host_cmd_ds_command *resp); | ||
29 | int mwifiex_ret_11n_addba_req(struct mwifiex_private *priv, | ||
30 | struct host_cmd_ds_command *resp); | ||
31 | int mwifiex_ret_11n_cfg(struct mwifiex_private *priv, | ||
32 | struct host_cmd_ds_command *resp, | ||
33 | void *data_buf); | ||
34 | int mwifiex_cmd_11n_cfg(struct mwifiex_private *priv, | ||
35 | struct host_cmd_ds_command *cmd, | ||
36 | u16 cmd_action, void *data_buf); | ||
37 | |||
38 | int mwifiex_cmd_11n_cfg(struct mwifiex_private *priv, | ||
39 | struct host_cmd_ds_command *cmd, | ||
40 | u16 cmd_action, void *data_buf); | ||
41 | |||
42 | int mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv, | ||
43 | struct mwifiex_bssdescriptor *bss_desc, | ||
44 | u8 **buffer); | ||
45 | void mwifiex_cfg_tx_buf(struct mwifiex_private *priv, | ||
46 | struct mwifiex_bssdescriptor *bss_desc); | ||
47 | void mwifiex_fill_cap_info(struct mwifiex_private *, | ||
48 | struct mwifiex_ie_types_htcap *); | ||
49 | int mwifiex_set_get_11n_htcap_cfg(struct mwifiex_private *priv, | ||
50 | u16 action, int *htcap_cfg); | ||
51 | void mwifiex_11n_delete_tx_ba_stream_tbl_entry(struct mwifiex_private *priv, | ||
52 | struct mwifiex_tx_ba_stream_tbl | ||
53 | *tx_tbl); | ||
54 | void mwifiex_11n_delete_all_tx_ba_stream_tbl(struct mwifiex_private *priv); | ||
55 | struct mwifiex_tx_ba_stream_tbl *mwifiex_11n_get_tx_ba_stream_tbl(struct | ||
56 | mwifiex_private | ||
57 | *priv, int tid, | ||
58 | u8 *ra); | ||
59 | void mwifiex_11n_create_tx_ba_stream_tbl(struct mwifiex_private *priv, u8 *ra, | ||
60 | int tid, | ||
61 | enum mwifiex_ba_status ba_status); | ||
62 | int mwifiex_send_addba(struct mwifiex_private *priv, int tid, u8 *peer_mac); | ||
63 | int mwifiex_send_delba(struct mwifiex_private *priv, int tid, u8 *peer_mac, | ||
64 | int initiator); | ||
65 | void mwifiex_11n_delete_ba_stream(struct mwifiex_private *priv, u8 *del_ba); | ||
66 | int mwifiex_get_rx_reorder_tbl(struct mwifiex_private *priv, | ||
67 | struct mwifiex_ds_rx_reorder_tbl *buf); | ||
68 | int mwifiex_get_tx_ba_stream_tbl(struct mwifiex_private *priv, | ||
69 | struct mwifiex_ds_tx_ba_stream_tbl *buf); | ||
70 | int mwifiex_ret_amsdu_aggr_ctrl(struct mwifiex_private *priv, | ||
71 | struct host_cmd_ds_command | ||
72 | *resp, | ||
73 | void *data_buf); | ||
74 | int mwifiex_cmd_recfg_tx_buf(struct mwifiex_private *priv, | ||
75 | struct host_cmd_ds_command *cmd, | ||
76 | int cmd_action, void *data_buf); | ||
77 | int mwifiex_cmd_amsdu_aggr_ctrl(struct mwifiex_private *priv, | ||
78 | struct host_cmd_ds_command *cmd, | ||
79 | int cmd_action, | ||
80 | void *data_buf); | ||
81 | |||
82 | /* | ||
83 | * This function checks whether AMPDU is allowed or not for a particular TID. | ||
84 | */ | ||
85 | static inline u8 | ||
86 | mwifiex_is_ampdu_allowed(struct mwifiex_private *priv, | ||
87 | struct mwifiex_ra_list_tbl *ptr, int tid) | ||
88 | { | ||
89 | return ((priv->aggr_prio_tbl[tid].ampdu_ap != BA_STREAM_NOT_ALLOWED) | ||
90 | ? true : false); | ||
91 | } | ||
92 | |||
93 | /* | ||
94 | * This function checks whether AMSDU is allowed or not for a particular TID. | ||
95 | */ | ||
96 | static inline u8 | ||
97 | mwifiex_is_amsdu_allowed(struct mwifiex_private *priv, | ||
98 | struct mwifiex_ra_list_tbl *ptr, int tid) | ||
99 | { | ||
100 | return (((priv->aggr_prio_tbl[tid].amsdu != BA_STREAM_NOT_ALLOWED) | ||
101 | && ((priv->is_data_rate_auto) | ||
102 | || !((priv->bitmap_rates[2]) & 0x03))) | ||
103 | ? true : false); | ||
104 | } | ||
105 | |||
106 | /* | ||
107 | * This function checks whether a BA stream is available or not. | ||
108 | */ | ||
109 | static inline u8 | ||
110 | mwifiex_is_ba_stream_avail(struct mwifiex_private *priv) | ||
111 | { | ||
112 | struct mwifiex_private *pmpriv = NULL; | ||
113 | u8 i = 0; | ||
114 | u32 ba_stream_num = 0; | ||
115 | |||
116 | for (i = 0; i < priv->adapter->priv_num; i++) { | ||
117 | pmpriv = priv->adapter->priv[i]; | ||
118 | if (pmpriv) | ||
119 | ba_stream_num += | ||
120 | mwifiex_wmm_list_len(priv->adapter, | ||
121 | (struct list_head | ||
122 | *) &pmpriv-> | ||
123 | tx_ba_stream_tbl_ptr); | ||
124 | } | ||
125 | |||
126 | return ((ba_stream_num < | ||
127 | MWIFIEX_MAX_TX_BASTREAM_SUPPORTED) ? true : false); | ||
128 | } | ||
129 | |||
130 | /* | ||
131 | * This function finds the correct Tx BA stream to delete. | ||
132 | * | ||
133 | * Upon successfully locating, both the TID and the RA are returned. | ||
134 | */ | ||
135 | static inline u8 | ||
136 | mwifiex_find_stream_to_delete(struct mwifiex_private *priv, | ||
137 | struct mwifiex_ra_list_tbl *ptr, int ptr_tid, | ||
138 | int *ptid, u8 *ra) | ||
139 | { | ||
140 | int tid; | ||
141 | u8 ret = false; | ||
142 | struct mwifiex_tx_ba_stream_tbl *tx_tbl; | ||
143 | unsigned long flags; | ||
144 | |||
145 | tid = priv->aggr_prio_tbl[ptr_tid].ampdu_user; | ||
146 | |||
147 | spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags); | ||
148 | list_for_each_entry(tx_tbl, &priv->tx_ba_stream_tbl_ptr, list) { | ||
149 | if (tid > priv->aggr_prio_tbl[tx_tbl->tid].ampdu_user) { | ||
150 | tid = priv->aggr_prio_tbl[tx_tbl->tid].ampdu_user; | ||
151 | *ptid = tx_tbl->tid; | ||
152 | memcpy(ra, tx_tbl->ra, ETH_ALEN); | ||
153 | ret = true; | ||
154 | } | ||
155 | } | ||
156 | spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags); | ||
157 | |||
158 | return ret; | ||
159 | } | ||
160 | |||
161 | /* | ||
162 | * This function checks whether BA stream is set up or not. | ||
163 | */ | ||
164 | static inline int | ||
165 | mwifiex_is_ba_stream_setup(struct mwifiex_private *priv, | ||
166 | struct mwifiex_ra_list_tbl *ptr, int tid) | ||
167 | { | ||
168 | struct mwifiex_tx_ba_stream_tbl *tx_tbl; | ||
169 | |||
170 | tx_tbl = mwifiex_11n_get_tx_ba_stream_tbl(priv, tid, ptr->ra); | ||
171 | if (tx_tbl && IS_BASTREAM_SETUP(tx_tbl)) | ||
172 | return true; | ||
173 | |||
174 | return false; | ||
175 | } | ||
176 | #endif /* !_MWIFIEX_11N_H_ */ | ||
diff --git a/drivers/net/wireless/mwifiex/11n_aggr.c b/drivers/net/wireless/mwifiex/11n_aggr.c new file mode 100644 index 000000000000..c2abced66957 --- /dev/null +++ b/drivers/net/wireless/mwifiex/11n_aggr.c | |||
@@ -0,0 +1,423 @@ | |||
1 | /* | ||
2 | * Marvell Wireless LAN device driver: 802.11n Aggregation | ||
3 | * | ||
4 | * Copyright (C) 2011, Marvell International Ltd. | ||
5 | * | ||
6 | * This software file (the "File") is distributed by Marvell International | ||
7 | * Ltd. under the terms of the GNU General Public License Version 2, June 1991 | ||
8 | * (the "License"). You may use, redistribute and/or modify this File in | ||
9 | * accordance with the terms and conditions of the License, a copy of which | ||
10 | * is available by writing to the Free Software Foundation, Inc., | ||
11 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the | ||
12 | * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. | ||
13 | * | ||
14 | * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE | ||
15 | * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE | ||
16 | * ARE EXPRESSLY DISCLAIMED. The License provides additional details about | ||
17 | * this warranty disclaimer. | ||
18 | */ | ||
19 | |||
20 | #include "decl.h" | ||
21 | #include "ioctl.h" | ||
22 | #include "util.h" | ||
23 | #include "fw.h" | ||
24 | #include "main.h" | ||
25 | #include "wmm.h" | ||
26 | #include "11n.h" | ||
27 | #include "11n_aggr.h" | ||
28 | |||
29 | /* | ||
30 | * Creates an AMSDU subframe for aggregation into one AMSDU packet. | ||
31 | * | ||
32 | * The resultant AMSDU subframe format is - | ||
33 | * | ||
34 | * +---- ~ -----+---- ~ ------+---- ~ -----+----- ~ -----+---- ~ -----+ | ||
35 | * | DA | SA | Length | SNAP header | MSDU | | ||
36 | * | data[0..5] | data[6..11] | | | data[14..] | | ||
37 | * +---- ~ -----+---- ~ ------+---- ~ -----+----- ~ -----+---- ~ -----+ | ||
38 | * <--6-bytes--> <--6-bytes--> <--2-bytes--><--8-bytes--> <--n-bytes--> | ||
39 | * | ||
40 | * This function also computes the amount of padding required to make the | ||
41 | * buffer length multiple of 4 bytes. | ||
42 | * | ||
43 | * Data => |DA|SA|SNAP-TYPE|........ .| | ||
44 | * MSDU => |DA|SA|Length|SNAP|...... ..| | ||
45 | */ | ||
46 | static int | ||
47 | mwifiex_11n_form_amsdu_pkt(struct mwifiex_adapter *adapter, | ||
48 | struct sk_buff *skb_aggr, | ||
49 | struct sk_buff *skb_src, int *pad) | ||
50 | |||
51 | { | ||
52 | int dt_offset; | ||
53 | struct rfc_1042_hdr snap = { | ||
54 | 0xaa, /* LLC DSAP */ | ||
55 | 0xaa, /* LLC SSAP */ | ||
56 | 0x03, /* LLC CTRL */ | ||
57 | {0x00, 0x00, 0x00}, /* SNAP OUI */ | ||
58 | 0x0000 /* SNAP type */ | ||
59 | /* | ||
60 | * This field will be overwritten | ||
61 | * later with ethertype | ||
62 | */ | ||
63 | }; | ||
64 | struct tx_packet_hdr *tx_header = NULL; | ||
65 | |||
66 | skb_put(skb_aggr, sizeof(*tx_header)); | ||
67 | |||
68 | tx_header = (struct tx_packet_hdr *) skb_aggr->data; | ||
69 | |||
70 | /* Copy DA and SA */ | ||
71 | dt_offset = 2 * ETH_ALEN; | ||
72 | memcpy(&tx_header->eth803_hdr, skb_src->data, dt_offset); | ||
73 | |||
74 | /* Copy SNAP header */ | ||
75 | snap.snap_type = *(u16 *) ((u8 *)skb_src->data + dt_offset); | ||
76 | dt_offset += sizeof(u16); | ||
77 | |||
78 | memcpy(&tx_header->rfc1042_hdr, &snap, sizeof(struct rfc_1042_hdr)); | ||
79 | |||
80 | skb_pull(skb_src, dt_offset); | ||
81 | |||
82 | /* Update Length field */ | ||
83 | tx_header->eth803_hdr.h_proto = htons(skb_src->len + LLC_SNAP_LEN); | ||
84 | |||
85 | /* Add payload */ | ||
86 | skb_put(skb_aggr, skb_src->len); | ||
87 | memcpy(skb_aggr->data + sizeof(*tx_header), skb_src->data, | ||
88 | skb_src->len); | ||
89 | *pad = (((skb_src->len + LLC_SNAP_LEN) & 3)) ? (4 - (((skb_src->len + | ||
90 | LLC_SNAP_LEN)) & 3)) : 0; | ||
91 | skb_put(skb_aggr, *pad); | ||
92 | |||
93 | return skb_aggr->len + *pad; | ||
94 | } | ||
95 | |||
96 | /* | ||
97 | * Adds TxPD to AMSDU header. | ||
98 | * | ||
99 | * Each AMSDU packet will contain one TxPD at the beginning, | ||
100 | * followed by multiple AMSDU subframes. | ||
101 | */ | ||
102 | static void | ||
103 | mwifiex_11n_form_amsdu_txpd(struct mwifiex_private *priv, | ||
104 | struct sk_buff *skb) | ||
105 | { | ||
106 | struct txpd *local_tx_pd; | ||
107 | |||
108 | skb_push(skb, sizeof(*local_tx_pd)); | ||
109 | |||
110 | local_tx_pd = (struct txpd *) skb->data; | ||
111 | memset(local_tx_pd, 0, sizeof(struct txpd)); | ||
112 | |||
113 | /* Original priority has been overwritten */ | ||
114 | local_tx_pd->priority = (u8) skb->priority; | ||
115 | local_tx_pd->pkt_delay_2ms = | ||
116 | mwifiex_wmm_compute_drv_pkt_delay(priv, skb); | ||
117 | local_tx_pd->bss_num = priv->bss_num; | ||
118 | local_tx_pd->bss_type = priv->bss_type; | ||
119 | /* Always zero as the data is followed by struct txpd */ | ||
120 | local_tx_pd->tx_pkt_offset = cpu_to_le16(sizeof(struct txpd)); | ||
121 | local_tx_pd->tx_pkt_type = cpu_to_le16(PKT_TYPE_AMSDU); | ||
122 | local_tx_pd->tx_pkt_length = cpu_to_le16(skb->len - | ||
123 | sizeof(*local_tx_pd)); | ||
124 | |||
125 | if (local_tx_pd->tx_control == 0) | ||
126 | /* TxCtrl set by user or default */ | ||
127 | local_tx_pd->tx_control = cpu_to_le32(priv->pkt_tx_ctrl); | ||
128 | |||
129 | if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) && | ||
130 | (priv->adapter->pps_uapsd_mode)) { | ||
131 | if (true == mwifiex_check_last_packet_indication(priv)) { | ||
132 | priv->adapter->tx_lock_flag = true; | ||
133 | local_tx_pd->flags = | ||
134 | MWIFIEX_TxPD_POWER_MGMT_LAST_PACKET; | ||
135 | } | ||
136 | } | ||
137 | } | ||
138 | |||
139 | /* | ||
140 | * Counts the number of subframes in an aggregate packet. | ||
141 | * | ||
142 | * This function parses an aggregate packet buffer, looking for | ||
143 | * subframes and counting the number of such subframe found. The | ||
144 | * function automatically skips the DA/SA fields at the beginning | ||
145 | * of each subframe and padding at the end. | ||
146 | */ | ||
147 | static int | ||
148 | mwifiex_11n_get_num_aggr_pkts(u8 *data, int total_pkt_len) | ||
149 | { | ||
150 | int pkt_count = 0, pkt_len, pad; | ||
151 | |||
152 | while (total_pkt_len > 0) { | ||
153 | /* Length will be in network format, change it to host */ | ||
154 | pkt_len = ntohs((*(__be16 *)(data + 2 * ETH_ALEN))); | ||
155 | pad = (((pkt_len + sizeof(struct ethhdr)) & 3)) ? | ||
156 | (4 - ((pkt_len + sizeof(struct ethhdr)) & 3)) : 0; | ||
157 | data += pkt_len + pad + sizeof(struct ethhdr); | ||
158 | total_pkt_len -= pkt_len + pad + sizeof(struct ethhdr); | ||
159 | ++pkt_count; | ||
160 | } | ||
161 | |||
162 | return pkt_count; | ||
163 | } | ||
164 | |||
165 | /* | ||
166 | * De-aggregate received packets. | ||
167 | * | ||
168 | * This function parses the received aggregate buffer, extracts each subframe, | ||
169 | * strips off the SNAP header from them and sends the data portion for further | ||
170 | * processing. | ||
171 | * | ||
172 | * Each subframe body is copied onto a separate buffer, which are freed by | ||
173 | * upper layer after processing. The function also performs sanity tests on | ||
174 | * the received buffer. | ||
175 | */ | ||
176 | int mwifiex_11n_deaggregate_pkt(struct mwifiex_private *priv, | ||
177 | struct sk_buff *skb) | ||
178 | { | ||
179 | u16 pkt_len; | ||
180 | int total_pkt_len; | ||
181 | u8 *data; | ||
182 | int pad; | ||
183 | struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb); | ||
184 | struct rxpd *local_rx_pd = (struct rxpd *) skb->data; | ||
185 | struct sk_buff *skb_daggr; | ||
186 | struct mwifiex_rxinfo *rx_info_daggr = NULL; | ||
187 | int ret = -1; | ||
188 | struct rx_packet_hdr *rx_pkt_hdr; | ||
189 | struct mwifiex_adapter *adapter = priv->adapter; | ||
190 | u8 rfc1042_eth_hdr[ETH_ALEN] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00}; | ||
191 | |||
192 | data = (u8 *) (local_rx_pd + local_rx_pd->rx_pkt_offset); | ||
193 | total_pkt_len = local_rx_pd->rx_pkt_length; | ||
194 | |||
195 | /* Sanity test */ | ||
196 | if (total_pkt_len > MWIFIEX_RX_DATA_BUF_SIZE) { | ||
197 | dev_err(adapter->dev, "total pkt len greater than buffer" | ||
198 | " size %d\n", total_pkt_len); | ||
199 | return -1; | ||
200 | } | ||
201 | |||
202 | rx_info->use_count = mwifiex_11n_get_num_aggr_pkts(data, total_pkt_len); | ||
203 | |||
204 | while (total_pkt_len > 0) { | ||
205 | rx_pkt_hdr = (struct rx_packet_hdr *) data; | ||
206 | /* Length will be in network format, change it to host */ | ||
207 | pkt_len = ntohs((*(__be16 *) (data + 2 * ETH_ALEN))); | ||
208 | if (pkt_len > total_pkt_len) { | ||
209 | dev_err(adapter->dev, "pkt_len %d > total_pkt_len %d\n", | ||
210 | total_pkt_len, pkt_len); | ||
211 | break; | ||
212 | } | ||
213 | |||
214 | pad = (((pkt_len + sizeof(struct ethhdr)) & 3)) ? | ||
215 | (4 - ((pkt_len + sizeof(struct ethhdr)) & 3)) : 0; | ||
216 | |||
217 | total_pkt_len -= pkt_len + pad + sizeof(struct ethhdr); | ||
218 | |||
219 | if (memcmp(&rx_pkt_hdr->rfc1042_hdr, | ||
220 | rfc1042_eth_hdr, sizeof(rfc1042_eth_hdr)) == 0) { | ||
221 | memmove(data + LLC_SNAP_LEN, data, 2 * ETH_ALEN); | ||
222 | data += LLC_SNAP_LEN; | ||
223 | pkt_len += sizeof(struct ethhdr) - LLC_SNAP_LEN; | ||
224 | } else { | ||
225 | *(u16 *) (data + 2 * ETH_ALEN) = (u16) 0; | ||
226 | pkt_len += sizeof(struct ethhdr); | ||
227 | } | ||
228 | |||
229 | skb_daggr = dev_alloc_skb(pkt_len); | ||
230 | if (!skb_daggr) { | ||
231 | dev_err(adapter->dev, "%s: failed to alloc skb_daggr\n", | ||
232 | __func__); | ||
233 | return -1; | ||
234 | } | ||
235 | rx_info_daggr = MWIFIEX_SKB_RXCB(skb_daggr); | ||
236 | |||
237 | rx_info_daggr->bss_index = rx_info->bss_index; | ||
238 | skb_daggr->tstamp = skb->tstamp; | ||
239 | rx_info_daggr->parent = skb; | ||
240 | skb_daggr->priority = skb->priority; | ||
241 | skb_put(skb_daggr, pkt_len); | ||
242 | memcpy(skb_daggr->data, data, pkt_len); | ||
243 | |||
244 | ret = mwifiex_recv_packet(adapter, skb_daggr); | ||
245 | |||
246 | switch (ret) { | ||
247 | case -EINPROGRESS: | ||
248 | break; | ||
249 | case -1: | ||
250 | dev_err(adapter->dev, "deaggr: host_to_card failed\n"); | ||
251 | case 0: | ||
252 | mwifiex_recv_packet_complete(adapter, skb_daggr, ret); | ||
253 | break; | ||
254 | default: | ||
255 | break; | ||
256 | } | ||
257 | |||
258 | data += pkt_len + pad; | ||
259 | } | ||
260 | |||
261 | return ret; | ||
262 | } | ||
263 | |||
264 | /* | ||
265 | * Create aggregated packet. | ||
266 | * | ||
267 | * This function creates an aggregated MSDU packet, by combining buffers | ||
268 | * from the RA list. Each individual buffer is encapsulated as an AMSDU | ||
269 | * subframe and all such subframes are concatenated together to form the | ||
270 | * AMSDU packet. | ||
271 | * | ||
272 | * A TxPD is also added to the front of the resultant AMSDU packets for | ||
273 | * transmission. The resultant packets format is - | ||
274 | * | ||
275 | * +---- ~ ----+------ ~ ------+------ ~ ------+-..-+------ ~ ------+ | ||
276 | * | TxPD |AMSDU sub-frame|AMSDU sub-frame| .. |AMSDU sub-frame| | ||
277 | * | | 1 | 2 | .. | n | | ||
278 | * +---- ~ ----+------ ~ ------+------ ~ ------+ .. +------ ~ ------+ | ||
279 | */ | ||
280 | int | ||
281 | mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, | ||
282 | struct mwifiex_ra_list_tbl *pra_list, int headroom, | ||
283 | int ptrindex, unsigned long ra_list_flags) | ||
284 | __releases(&priv->wmm.ra_list_spinlock) | ||
285 | { | ||
286 | struct mwifiex_adapter *adapter = priv->adapter; | ||
287 | struct sk_buff *skb_aggr, *skb_src; | ||
288 | struct mwifiex_txinfo *tx_info_aggr, *tx_info_src; | ||
289 | int pad = 0; | ||
290 | int ret = 0; | ||
291 | struct mwifiex_tx_param tx_param; | ||
292 | struct txpd *ptx_pd = NULL; | ||
293 | |||
294 | if (skb_queue_empty(&pra_list->skb_head)) { | ||
295 | spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, | ||
296 | ra_list_flags); | ||
297 | return 0; | ||
298 | } | ||
299 | skb_src = skb_peek(&pra_list->skb_head); | ||
300 | tx_info_src = MWIFIEX_SKB_TXCB(skb_src); | ||
301 | skb_aggr = dev_alloc_skb(adapter->tx_buf_size); | ||
302 | if (!skb_aggr) { | ||
303 | dev_err(adapter->dev, "%s: alloc skb_aggr\n", __func__); | ||
304 | spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, | ||
305 | ra_list_flags); | ||
306 | return -1; | ||
307 | } | ||
308 | skb_reserve(skb_aggr, headroom + sizeof(struct txpd)); | ||
309 | tx_info_aggr = MWIFIEX_SKB_TXCB(skb_aggr); | ||
310 | |||
311 | tx_info_aggr->bss_index = tx_info_src->bss_index; | ||
312 | skb_aggr->priority = skb_src->priority; | ||
313 | |||
314 | while (skb_src && ((skb_headroom(skb_aggr) + skb_src->len | ||
315 | + LLC_SNAP_LEN) | ||
316 | <= adapter->tx_buf_size)) { | ||
317 | |||
318 | if (!skb_queue_empty(&pra_list->skb_head)) | ||
319 | skb_src = skb_dequeue(&pra_list->skb_head); | ||
320 | else | ||
321 | skb_src = NULL; | ||
322 | |||
323 | pra_list->total_pkts_size -= skb_src->len; | ||
324 | |||
325 | spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, | ||
326 | ra_list_flags); | ||
327 | mwifiex_11n_form_amsdu_pkt(adapter, skb_aggr, skb_src, &pad); | ||
328 | |||
329 | mwifiex_write_data_complete(adapter, skb_src, 0); | ||
330 | |||
331 | spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags); | ||
332 | |||
333 | if (!mwifiex_is_ralist_valid(priv, pra_list, ptrindex)) { | ||
334 | spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, | ||
335 | ra_list_flags); | ||
336 | return -1; | ||
337 | } | ||
338 | |||
339 | if (!skb_queue_empty(&pra_list->skb_head)) | ||
340 | skb_src = skb_peek(&pra_list->skb_head); | ||
341 | else | ||
342 | skb_src = NULL; | ||
343 | } | ||
344 | |||
345 | spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ra_list_flags); | ||
346 | |||
347 | /* Last AMSDU packet does not need padding */ | ||
348 | skb_trim(skb_aggr, skb_aggr->len - pad); | ||
349 | |||
350 | /* Form AMSDU */ | ||
351 | mwifiex_11n_form_amsdu_txpd(priv, skb_aggr); | ||
352 | if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) | ||
353 | ptx_pd = (struct txpd *)skb_aggr->data; | ||
354 | |||
355 | skb_push(skb_aggr, headroom); | ||
356 | |||
357 | tx_param.next_pkt_len = ((pra_list->total_pkts_size) ? | ||
358 | (((pra_list->total_pkts_size) > | ||
359 | adapter->tx_buf_size) ? adapter-> | ||
360 | tx_buf_size : pra_list->total_pkts_size + | ||
361 | LLC_SNAP_LEN + sizeof(struct txpd)) : 0); | ||
362 | ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA, | ||
363 | skb_aggr->data, | ||
364 | skb_aggr->len, &tx_param); | ||
365 | switch (ret) { | ||
366 | case -EBUSY: | ||
367 | spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags); | ||
368 | if (!mwifiex_is_ralist_valid(priv, pra_list, ptrindex)) { | ||
369 | spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, | ||
370 | ra_list_flags); | ||
371 | mwifiex_write_data_complete(adapter, skb_aggr, -1); | ||
372 | return -1; | ||
373 | } | ||
374 | if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) && | ||
375 | (adapter->pps_uapsd_mode) && | ||
376 | (adapter->tx_lock_flag)) { | ||
377 | priv->adapter->tx_lock_flag = false; | ||
378 | ptx_pd->flags = 0; | ||
379 | } | ||
380 | |||
381 | skb_queue_tail(&pra_list->skb_head, skb_aggr); | ||
382 | |||
383 | pra_list->total_pkts_size += skb_aggr->len; | ||
384 | |||
385 | tx_info_aggr->flags |= MWIFIEX_BUF_FLAG_REQUEUED_PKT; | ||
386 | spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, | ||
387 | ra_list_flags); | ||
388 | dev_dbg(adapter->dev, "data: -EBUSY is returned\n"); | ||
389 | break; | ||
390 | case -1: | ||
391 | adapter->data_sent = false; | ||
392 | dev_err(adapter->dev, "%s: host_to_card failed: %#x\n", | ||
393 | __func__, ret); | ||
394 | adapter->dbg.num_tx_host_to_card_failure++; | ||
395 | mwifiex_write_data_complete(adapter, skb_aggr, ret); | ||
396 | return 0; | ||
397 | case -EINPROGRESS: | ||
398 | adapter->data_sent = false; | ||
399 | break; | ||
400 | case 0: | ||
401 | mwifiex_write_data_complete(adapter, skb_aggr, ret); | ||
402 | break; | ||
403 | default: | ||
404 | break; | ||
405 | } | ||
406 | if (ret != -EBUSY) { | ||
407 | spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags); | ||
408 | if (mwifiex_is_ralist_valid(priv, pra_list, ptrindex)) { | ||
409 | priv->wmm.packets_out[ptrindex]++; | ||
410 | priv->wmm.tid_tbl_ptr[ptrindex].ra_list_curr = pra_list; | ||
411 | } | ||
412 | /* Now bss_prio_cur pointer points to next node */ | ||
413 | adapter->bss_prio_tbl[priv->bss_priority].bss_prio_cur = | ||
414 | list_first_entry( | ||
415 | &adapter->bss_prio_tbl[priv->bss_priority] | ||
416 | .bss_prio_cur->list, | ||
417 | struct mwifiex_bss_prio_node, list); | ||
418 | spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, | ||
419 | ra_list_flags); | ||
420 | } | ||
421 | |||
422 | return 0; | ||
423 | } | ||
diff --git a/drivers/net/wireless/mwifiex/11n_aggr.h b/drivers/net/wireless/mwifiex/11n_aggr.h new file mode 100644 index 000000000000..9c6dca7ab02c --- /dev/null +++ b/drivers/net/wireless/mwifiex/11n_aggr.h | |||
@@ -0,0 +1,32 @@ | |||
1 | /* | ||
2 | * Marvell Wireless LAN device driver: 802.11n Aggregation | ||
3 | * | ||
4 | * Copyright (C) 2011, Marvell International Ltd. | ||
5 | * | ||
6 | * This software file (the "File") is distributed by Marvell International | ||
7 | * Ltd. under the terms of the GNU General Public License Version 2, June 1991 | ||
8 | * (the "License"). You may use, redistribute and/or modify this File in | ||
9 | * accordance with the terms and conditions of the License, a copy of which | ||
10 | * is available by writing to the Free Software Foundation, Inc., | ||
11 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the | ||
12 | * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. | ||
13 | * | ||
14 | * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE | ||
15 | * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE | ||
16 | * ARE EXPRESSLY DISCLAIMED. The License provides additional details about | ||
17 | * this warranty disclaimer. | ||
18 | */ | ||
19 | |||
20 | #ifndef _MWIFIEX_11N_AGGR_H_ | ||
21 | #define _MWIFIEX_11N_AGGR_H_ | ||
22 | |||
23 | #define PKT_TYPE_AMSDU 0xE6 | ||
24 | |||
25 | int mwifiex_11n_deaggregate_pkt(struct mwifiex_private *priv, | ||
26 | struct sk_buff *skb); | ||
27 | int mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, | ||
28 | struct mwifiex_ra_list_tbl *ptr, int headroom, | ||
29 | int ptr_index, unsigned long flags) | ||
30 | __releases(&priv->wmm.ra_list_spinlock); | ||
31 | |||
32 | #endif /* !_MWIFIEX_11N_AGGR_H_ */ | ||
diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.c b/drivers/net/wireless/mwifiex/11n_rxreorder.c new file mode 100644 index 000000000000..8e94e620e6f4 --- /dev/null +++ b/drivers/net/wireless/mwifiex/11n_rxreorder.c | |||
@@ -0,0 +1,637 @@ | |||
1 | /* | ||
2 | * Marvell Wireless LAN device driver: 802.11n RX Re-ordering | ||
3 | * | ||
4 | * Copyright (C) 2011, Marvell International Ltd. | ||
5 | * | ||
6 | * This software file (the "File") is distributed by Marvell International | ||
7 | * Ltd. under the terms of the GNU General Public License Version 2, June 1991 | ||
8 | * (the "License"). You may use, redistribute and/or modify this File in | ||
9 | * accordance with the terms and conditions of the License, a copy of which | ||
10 | * is available by writing to the Free Software Foundation, Inc., | ||
11 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the | ||
12 | * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. | ||
13 | * | ||
14 | * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE | ||
15 | * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE | ||
16 | * ARE EXPRESSLY DISCLAIMED. The License provides additional details about | ||
17 | * this warranty disclaimer. | ||
18 | */ | ||
19 | |||
20 | #include "decl.h" | ||
21 | #include "ioctl.h" | ||
22 | #include "util.h" | ||
23 | #include "fw.h" | ||
24 | #include "main.h" | ||
25 | #include "wmm.h" | ||
26 | #include "11n.h" | ||
27 | #include "11n_rxreorder.h" | ||
28 | |||
29 | /* | ||
30 | * This function processes a received packet and forwards | ||
31 | * it to the kernel/upper layer. | ||
32 | */ | ||
33 | static int mwifiex_11n_dispatch_pkt(struct mwifiex_private *priv, void *payload) | ||
34 | { | ||
35 | int ret = 0; | ||
36 | struct mwifiex_adapter *adapter = priv->adapter; | ||
37 | |||
38 | ret = mwifiex_process_rx_packet(adapter, (struct sk_buff *) payload); | ||
39 | return ret; | ||
40 | } | ||
41 | |||
42 | /* | ||
43 | * This function dispatches all packets in the Rx reorder table. | ||
44 | * | ||
45 | * There could be holes in the buffer, which are skipped by the function. | ||
46 | * Since the buffer is linear, the function uses rotation to simulate | ||
47 | * circular buffer. | ||
48 | */ | ||
49 | static int | ||
50 | mwifiex_11n_dispatch_pkt_until_start_win(struct mwifiex_private *priv, | ||
51 | struct mwifiex_rx_reorder_tbl | ||
52 | *rx_reor_tbl_ptr, int start_win) | ||
53 | { | ||
54 | int no_pkt_to_send, i, xchg; | ||
55 | void *rx_tmp_ptr = NULL; | ||
56 | unsigned long flags; | ||
57 | |||
58 | no_pkt_to_send = (start_win > rx_reor_tbl_ptr->start_win) ? | ||
59 | min((start_win - rx_reor_tbl_ptr->start_win), | ||
60 | rx_reor_tbl_ptr->win_size) : rx_reor_tbl_ptr->win_size; | ||
61 | |||
62 | for (i = 0; i < no_pkt_to_send; ++i) { | ||
63 | spin_lock_irqsave(&priv->rx_pkt_lock, flags); | ||
64 | rx_tmp_ptr = NULL; | ||
65 | if (rx_reor_tbl_ptr->rx_reorder_ptr[i]) { | ||
66 | rx_tmp_ptr = rx_reor_tbl_ptr->rx_reorder_ptr[i]; | ||
67 | rx_reor_tbl_ptr->rx_reorder_ptr[i] = NULL; | ||
68 | } | ||
69 | spin_unlock_irqrestore(&priv->rx_pkt_lock, flags); | ||
70 | if (rx_tmp_ptr) | ||
71 | mwifiex_11n_dispatch_pkt(priv, rx_tmp_ptr); | ||
72 | } | ||
73 | |||
74 | spin_lock_irqsave(&priv->rx_pkt_lock, flags); | ||
75 | /* | ||
76 | * We don't have a circular buffer, hence use rotation to simulate | ||
77 | * circular buffer | ||
78 | */ | ||
79 | xchg = rx_reor_tbl_ptr->win_size - no_pkt_to_send; | ||
80 | for (i = 0; i < xchg; ++i) { | ||
81 | rx_reor_tbl_ptr->rx_reorder_ptr[i] = | ||
82 | rx_reor_tbl_ptr->rx_reorder_ptr[no_pkt_to_send + i]; | ||
83 | rx_reor_tbl_ptr->rx_reorder_ptr[no_pkt_to_send + i] = NULL; | ||
84 | } | ||
85 | |||
86 | rx_reor_tbl_ptr->start_win = start_win; | ||
87 | spin_unlock_irqrestore(&priv->rx_pkt_lock, flags); | ||
88 | |||
89 | return 0; | ||
90 | } | ||
91 | |||
92 | /* | ||
93 | * This function dispatches all packets in the Rx reorder table until | ||
94 | * a hole is found. | ||
95 | * | ||
96 | * The start window is adjusted automatically when a hole is located. | ||
97 | * Since the buffer is linear, the function uses rotation to simulate | ||
98 | * circular buffer. | ||
99 | */ | ||
100 | static int | ||
101 | mwifiex_11n_scan_and_dispatch(struct mwifiex_private *priv, | ||
102 | struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr) | ||
103 | { | ||
104 | int i, j, xchg; | ||
105 | void *rx_tmp_ptr = NULL; | ||
106 | unsigned long flags; | ||
107 | |||
108 | for (i = 0; i < rx_reor_tbl_ptr->win_size; ++i) { | ||
109 | spin_lock_irqsave(&priv->rx_pkt_lock, flags); | ||
110 | if (!rx_reor_tbl_ptr->rx_reorder_ptr[i]) { | ||
111 | spin_unlock_irqrestore(&priv->rx_pkt_lock, flags); | ||
112 | break; | ||
113 | } | ||
114 | rx_tmp_ptr = rx_reor_tbl_ptr->rx_reorder_ptr[i]; | ||
115 | rx_reor_tbl_ptr->rx_reorder_ptr[i] = NULL; | ||
116 | spin_unlock_irqrestore(&priv->rx_pkt_lock, flags); | ||
117 | mwifiex_11n_dispatch_pkt(priv, rx_tmp_ptr); | ||
118 | } | ||
119 | |||
120 | spin_lock_irqsave(&priv->rx_pkt_lock, flags); | ||
121 | /* | ||
122 | * We don't have a circular buffer, hence use rotation to simulate | ||
123 | * circular buffer | ||
124 | */ | ||
125 | if (i > 0) { | ||
126 | xchg = rx_reor_tbl_ptr->win_size - i; | ||
127 | for (j = 0; j < xchg; ++j) { | ||
128 | rx_reor_tbl_ptr->rx_reorder_ptr[j] = | ||
129 | rx_reor_tbl_ptr->rx_reorder_ptr[i + j]; | ||
130 | rx_reor_tbl_ptr->rx_reorder_ptr[i + j] = NULL; | ||
131 | } | ||
132 | } | ||
133 | rx_reor_tbl_ptr->start_win = (rx_reor_tbl_ptr->start_win + i) | ||
134 | &(MAX_TID_VALUE - 1); | ||
135 | spin_unlock_irqrestore(&priv->rx_pkt_lock, flags); | ||
136 | return 0; | ||
137 | } | ||
138 | |||
139 | /* | ||
140 | * This function deletes the Rx reorder table and frees the memory. | ||
141 | * | ||
142 | * The function stops the associated timer and dispatches all the | ||
143 | * pending packets in the Rx reorder table before deletion. | ||
144 | */ | ||
145 | static void | ||
146 | mwifiex_11n_delete_rx_reorder_tbl_entry(struct mwifiex_private *priv, | ||
147 | struct mwifiex_rx_reorder_tbl | ||
148 | *rx_reor_tbl_ptr) | ||
149 | { | ||
150 | unsigned long flags; | ||
151 | |||
152 | if (!rx_reor_tbl_ptr) | ||
153 | return; | ||
154 | |||
155 | mwifiex_11n_dispatch_pkt_until_start_win(priv, rx_reor_tbl_ptr, | ||
156 | (rx_reor_tbl_ptr->start_win + | ||
157 | rx_reor_tbl_ptr->win_size) | ||
158 | &(MAX_TID_VALUE - 1)); | ||
159 | |||
160 | del_timer(&rx_reor_tbl_ptr->timer_context.timer); | ||
161 | |||
162 | spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags); | ||
163 | list_del(&rx_reor_tbl_ptr->list); | ||
164 | spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags); | ||
165 | |||
166 | kfree(rx_reor_tbl_ptr->rx_reorder_ptr); | ||
167 | kfree(rx_reor_tbl_ptr); | ||
168 | } | ||
169 | |||
170 | /* | ||
171 | * This function returns the pointer to an entry in Rx reordering | ||
172 | * table which matches the given TA/TID pair. | ||
173 | */ | ||
174 | static struct mwifiex_rx_reorder_tbl * | ||
175 | mwifiex_11n_get_rx_reorder_tbl(struct mwifiex_private *priv, int tid, u8 *ta) | ||
176 | { | ||
177 | struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr; | ||
178 | unsigned long flags; | ||
179 | |||
180 | spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags); | ||
181 | list_for_each_entry(rx_reor_tbl_ptr, &priv->rx_reorder_tbl_ptr, list) { | ||
182 | if ((!memcmp(rx_reor_tbl_ptr->ta, ta, ETH_ALEN)) | ||
183 | && (rx_reor_tbl_ptr->tid == tid)) { | ||
184 | spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, | ||
185 | flags); | ||
186 | return rx_reor_tbl_ptr; | ||
187 | } | ||
188 | } | ||
189 | spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags); | ||
190 | |||
191 | return NULL; | ||
192 | } | ||
193 | |||
194 | /* | ||
195 | * This function finds the last sequence number used in the packets | ||
196 | * buffered in Rx reordering table. | ||
197 | */ | ||
198 | static int | ||
199 | mwifiex_11n_find_last_seq_num(struct mwifiex_rx_reorder_tbl *rx_reorder_tbl_ptr) | ||
200 | { | ||
201 | int i; | ||
202 | |||
203 | for (i = (rx_reorder_tbl_ptr->win_size - 1); i >= 0; --i) | ||
204 | if (rx_reorder_tbl_ptr->rx_reorder_ptr[i]) | ||
205 | return i; | ||
206 | |||
207 | return -1; | ||
208 | } | ||
209 | |||
210 | /* | ||
211 | * This function flushes all the packets in Rx reordering table. | ||
212 | * | ||
213 | * The function checks if any packets are currently buffered in the | ||
214 | * table or not. In case there are packets available, it dispatches | ||
215 | * them and then dumps the Rx reordering table. | ||
216 | */ | ||
217 | static void | ||
218 | mwifiex_flush_data(unsigned long context) | ||
219 | { | ||
220 | struct reorder_tmr_cnxt *reorder_cnxt = | ||
221 | (struct reorder_tmr_cnxt *) context; | ||
222 | int start_win; | ||
223 | |||
224 | start_win = mwifiex_11n_find_last_seq_num(reorder_cnxt->ptr); | ||
225 | if (start_win >= 0) { | ||
226 | dev_dbg(reorder_cnxt->priv->adapter->dev, | ||
227 | "info: flush data %d\n", start_win); | ||
228 | mwifiex_11n_dispatch_pkt_until_start_win(reorder_cnxt->priv, | ||
229 | reorder_cnxt->ptr, | ||
230 | ((reorder_cnxt->ptr->start_win + | ||
231 | start_win + 1) & (MAX_TID_VALUE - 1))); | ||
232 | } | ||
233 | } | ||
234 | |||
235 | /* | ||
236 | * This function creates an entry in Rx reordering table for the | ||
237 | * given TA/TID. | ||
238 | * | ||
239 | * The function also initializes the entry with sequence number, window | ||
240 | * size as well as initializes the timer. | ||
241 | * | ||
242 | * If the received TA/TID pair is already present, all the packets are | ||
243 | * dispatched and the window size is moved until the SSN. | ||
244 | */ | ||
245 | static void | ||
246 | mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta, | ||
247 | int tid, int win_size, int seq_num) | ||
248 | { | ||
249 | int i; | ||
250 | struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr, *new_node; | ||
251 | u16 last_seq = 0; | ||
252 | unsigned long flags; | ||
253 | |||
254 | /* | ||
255 | * If we get a TID, ta pair which is already present dispatch all the | ||
256 | * the packets and move the window size until the ssn | ||
257 | */ | ||
258 | rx_reor_tbl_ptr = mwifiex_11n_get_rx_reorder_tbl(priv, tid, ta); | ||
259 | if (rx_reor_tbl_ptr) { | ||
260 | mwifiex_11n_dispatch_pkt_until_start_win(priv, rx_reor_tbl_ptr, | ||
261 | seq_num); | ||
262 | return; | ||
263 | } | ||
264 | /* if !rx_reor_tbl_ptr then create one */ | ||
265 | new_node = kzalloc(sizeof(struct mwifiex_rx_reorder_tbl), GFP_KERNEL); | ||
266 | if (!new_node) { | ||
267 | dev_err(priv->adapter->dev, "%s: failed to alloc new_node\n", | ||
268 | __func__); | ||
269 | return; | ||
270 | } | ||
271 | |||
272 | INIT_LIST_HEAD(&new_node->list); | ||
273 | new_node->tid = tid; | ||
274 | memcpy(new_node->ta, ta, ETH_ALEN); | ||
275 | new_node->start_win = seq_num; | ||
276 | if (mwifiex_queuing_ra_based(priv)) | ||
277 | /* TODO for adhoc */ | ||
278 | dev_dbg(priv->adapter->dev, | ||
279 | "info: ADHOC:last_seq=%d start_win=%d\n", | ||
280 | last_seq, new_node->start_win); | ||
281 | else | ||
282 | last_seq = priv->rx_seq[tid]; | ||
283 | |||
284 | if (last_seq >= new_node->start_win) | ||
285 | new_node->start_win = last_seq + 1; | ||
286 | |||
287 | new_node->win_size = win_size; | ||
288 | |||
289 | new_node->rx_reorder_ptr = kzalloc(sizeof(void *) * win_size, | ||
290 | GFP_KERNEL); | ||
291 | if (!new_node->rx_reorder_ptr) { | ||
292 | kfree((u8 *) new_node); | ||
293 | dev_err(priv->adapter->dev, | ||
294 | "%s: failed to alloc reorder_ptr\n", __func__); | ||
295 | return; | ||
296 | } | ||
297 | |||
298 | new_node->timer_context.ptr = new_node; | ||
299 | new_node->timer_context.priv = priv; | ||
300 | |||
301 | init_timer(&new_node->timer_context.timer); | ||
302 | new_node->timer_context.timer.function = mwifiex_flush_data; | ||
303 | new_node->timer_context.timer.data = | ||
304 | (unsigned long) &new_node->timer_context; | ||
305 | |||
306 | for (i = 0; i < win_size; ++i) | ||
307 | new_node->rx_reorder_ptr[i] = NULL; | ||
308 | |||
309 | spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags); | ||
310 | list_add_tail(&new_node->list, &priv->rx_reorder_tbl_ptr); | ||
311 | spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags); | ||
312 | |||
313 | return; | ||
314 | } | ||
315 | |||
316 | /* | ||
317 | * This function prepares command for adding a BA request. | ||
318 | * | ||
319 | * Preparation includes - | ||
320 | * - Setting command ID and proper size | ||
321 | * - Setting add BA request buffer | ||
322 | * - Ensuring correct endian-ness | ||
323 | */ | ||
324 | int mwifiex_cmd_11n_addba_req(struct mwifiex_private *priv, | ||
325 | struct host_cmd_ds_command *cmd, void *data_buf) | ||
326 | { | ||
327 | struct host_cmd_ds_11n_addba_req *add_ba_req = | ||
328 | (struct host_cmd_ds_11n_addba_req *) | ||
329 | &cmd->params.add_ba_req; | ||
330 | |||
331 | cmd->command = cpu_to_le16(HostCmd_CMD_11N_ADDBA_REQ); | ||
332 | cmd->size = cpu_to_le16(sizeof(*add_ba_req) + S_DS_GEN); | ||
333 | memcpy(add_ba_req, data_buf, sizeof(*add_ba_req)); | ||
334 | |||
335 | return 0; | ||
336 | } | ||
337 | |||
338 | /* | ||
339 | * This function prepares command for adding a BA response. | ||
340 | * | ||
341 | * Preparation includes - | ||
342 | * - Setting command ID and proper size | ||
343 | * - Setting add BA response buffer | ||
344 | * - Ensuring correct endian-ness | ||
345 | */ | ||
346 | int mwifiex_cmd_11n_addba_rsp_gen(struct mwifiex_private *priv, | ||
347 | struct host_cmd_ds_command *cmd, | ||
348 | void *data_buf) | ||
349 | { | ||
350 | struct host_cmd_ds_11n_addba_rsp *add_ba_rsp = | ||
351 | (struct host_cmd_ds_11n_addba_rsp *) | ||
352 | &cmd->params.add_ba_rsp; | ||
353 | struct host_cmd_ds_11n_addba_req *cmd_addba_req = | ||
354 | (struct host_cmd_ds_11n_addba_req *) data_buf; | ||
355 | u8 tid = 0; | ||
356 | int win_size = 0; | ||
357 | uint16_t block_ack_param_set; | ||
358 | |||
359 | cmd->command = cpu_to_le16(HostCmd_CMD_11N_ADDBA_RSP); | ||
360 | cmd->size = cpu_to_le16(sizeof(*add_ba_rsp) + S_DS_GEN); | ||
361 | |||
362 | memcpy(add_ba_rsp->peer_mac_addr, cmd_addba_req->peer_mac_addr, | ||
363 | ETH_ALEN); | ||
364 | add_ba_rsp->dialog_token = cmd_addba_req->dialog_token; | ||
365 | add_ba_rsp->block_ack_tmo = cmd_addba_req->block_ack_tmo; | ||
366 | add_ba_rsp->ssn = cmd_addba_req->ssn; | ||
367 | |||
368 | block_ack_param_set = le16_to_cpu(cmd_addba_req->block_ack_param_set); | ||
369 | tid = (block_ack_param_set & IEEE80211_ADDBA_PARAM_TID_MASK) | ||
370 | >> BLOCKACKPARAM_TID_POS; | ||
371 | add_ba_rsp->status_code = cpu_to_le16(ADDBA_RSP_STATUS_ACCEPT); | ||
372 | block_ack_param_set &= ~IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK; | ||
373 | /* We donot support AMSDU inside AMPDU, hence reset the bit */ | ||
374 | block_ack_param_set &= ~BLOCKACKPARAM_AMSDU_SUPP_MASK; | ||
375 | block_ack_param_set |= (priv->add_ba_param.rx_win_size << | ||
376 | BLOCKACKPARAM_WINSIZE_POS); | ||
377 | add_ba_rsp->block_ack_param_set = cpu_to_le16(block_ack_param_set); | ||
378 | win_size = (le16_to_cpu(add_ba_rsp->block_ack_param_set) | ||
379 | & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) | ||
380 | >> BLOCKACKPARAM_WINSIZE_POS; | ||
381 | cmd_addba_req->block_ack_param_set = cpu_to_le16(block_ack_param_set); | ||
382 | |||
383 | mwifiex_11n_create_rx_reorder_tbl(priv, cmd_addba_req->peer_mac_addr, | ||
384 | tid, win_size, le16_to_cpu(cmd_addba_req->ssn)); | ||
385 | return 0; | ||
386 | } | ||
387 | |||
388 | /* | ||
389 | * This function prepares command for deleting a BA request. | ||
390 | * | ||
391 | * Preparation includes - | ||
392 | * - Setting command ID and proper size | ||
393 | * - Setting del BA request buffer | ||
394 | * - Ensuring correct endian-ness | ||
395 | */ | ||
396 | int mwifiex_cmd_11n_delba(struct mwifiex_private *priv, | ||
397 | struct host_cmd_ds_command *cmd, void *data_buf) | ||
398 | { | ||
399 | struct host_cmd_ds_11n_delba *del_ba = (struct host_cmd_ds_11n_delba *) | ||
400 | &cmd->params.del_ba; | ||
401 | |||
402 | cmd->command = cpu_to_le16(HostCmd_CMD_11N_DELBA); | ||
403 | cmd->size = cpu_to_le16(sizeof(*del_ba) + S_DS_GEN); | ||
404 | memcpy(del_ba, data_buf, sizeof(*del_ba)); | ||
405 | |||
406 | return 0; | ||
407 | } | ||
408 | |||
409 | /* | ||
410 | * This function identifies if Rx reordering is needed for a received packet. | ||
411 | * | ||
412 | * In case reordering is required, the function will do the reordering | ||
413 | * before sending it to kernel. | ||
414 | * | ||
415 | * The Rx reorder table is checked first with the received TID/TA pair. If | ||
416 | * not found, the received packet is dispatched immediately. But if found, | ||
417 | * the packet is reordered and all the packets in the updated Rx reordering | ||
418 | * table is dispatched until a hole is found. | ||
419 | * | ||
420 | * For sequence number less than the starting window, the packet is dropped. | ||
421 | */ | ||
422 | int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *priv, | ||
423 | u16 seq_num, u16 tid, | ||
424 | u8 *ta, u8 pkt_type, void *payload) | ||
425 | { | ||
426 | struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr; | ||
427 | int start_win, end_win, win_size; | ||
428 | int ret = 0; | ||
429 | u16 pkt_index = 0; | ||
430 | |||
431 | rx_reor_tbl_ptr = | ||
432 | mwifiex_11n_get_rx_reorder_tbl((struct mwifiex_private *) priv, | ||
433 | tid, ta); | ||
434 | if (!rx_reor_tbl_ptr) { | ||
435 | if (pkt_type != PKT_TYPE_BAR) | ||
436 | mwifiex_11n_dispatch_pkt(priv, payload); | ||
437 | return 0; | ||
438 | } | ||
439 | start_win = rx_reor_tbl_ptr->start_win; | ||
440 | win_size = rx_reor_tbl_ptr->win_size; | ||
441 | end_win = ((start_win + win_size) - 1) & (MAX_TID_VALUE - 1); | ||
442 | del_timer(&rx_reor_tbl_ptr->timer_context.timer); | ||
443 | mod_timer(&rx_reor_tbl_ptr->timer_context.timer, jiffies | ||
444 | + (MIN_FLUSH_TIMER_MS * win_size * HZ) / 1000); | ||
445 | |||
446 | /* | ||
447 | * If seq_num is less then starting win then ignore and drop the | ||
448 | * packet | ||
449 | */ | ||
450 | if ((start_win + TWOPOW11) > (MAX_TID_VALUE - 1)) {/* Wrap */ | ||
451 | if (seq_num >= ((start_win + (TWOPOW11)) & (MAX_TID_VALUE - 1)) | ||
452 | && (seq_num < start_win)) | ||
453 | return -1; | ||
454 | } else if ((seq_num < start_win) | ||
455 | || (seq_num > (start_win + (TWOPOW11)))) { | ||
456 | return -1; | ||
457 | } | ||
458 | |||
459 | /* | ||
460 | * If this packet is a BAR we adjust seq_num as | ||
461 | * WinStart = seq_num | ||
462 | */ | ||
463 | if (pkt_type == PKT_TYPE_BAR) | ||
464 | seq_num = ((seq_num + win_size) - 1) & (MAX_TID_VALUE - 1); | ||
465 | |||
466 | if (((end_win < start_win) | ||
467 | && (seq_num < (TWOPOW11 - (MAX_TID_VALUE - start_win))) | ||
468 | && (seq_num > end_win)) || ((end_win > start_win) | ||
469 | && ((seq_num > end_win) || (seq_num < start_win)))) { | ||
470 | end_win = seq_num; | ||
471 | if (((seq_num - win_size) + 1) >= 0) | ||
472 | start_win = (end_win - win_size) + 1; | ||
473 | else | ||
474 | start_win = (MAX_TID_VALUE - (win_size - seq_num)) + 1; | ||
475 | ret = mwifiex_11n_dispatch_pkt_until_start_win(priv, | ||
476 | rx_reor_tbl_ptr, start_win); | ||
477 | |||
478 | if (ret) | ||
479 | return ret; | ||
480 | } | ||
481 | |||
482 | if (pkt_type != PKT_TYPE_BAR) { | ||
483 | if (seq_num >= start_win) | ||
484 | pkt_index = seq_num - start_win; | ||
485 | else | ||
486 | pkt_index = (seq_num+MAX_TID_VALUE) - start_win; | ||
487 | |||
488 | if (rx_reor_tbl_ptr->rx_reorder_ptr[pkt_index]) | ||
489 | return -1; | ||
490 | |||
491 | rx_reor_tbl_ptr->rx_reorder_ptr[pkt_index] = payload; | ||
492 | } | ||
493 | |||
494 | /* | ||
495 | * Dispatch all packets sequentially from start_win until a | ||
496 | * hole is found and adjust the start_win appropriately | ||
497 | */ | ||
498 | ret = mwifiex_11n_scan_and_dispatch(priv, rx_reor_tbl_ptr); | ||
499 | |||
500 | return ret; | ||
501 | } | ||
502 | |||
503 | /* | ||
504 | * This function deletes an entry for a given TID/TA pair. | ||
505 | * | ||
506 | * The TID/TA are taken from del BA event body. | ||
507 | */ | ||
508 | void | ||
509 | mwifiex_11n_delete_ba_stream_tbl(struct mwifiex_private *priv, int tid, | ||
510 | u8 *peer_mac, u8 type, int initiator) | ||
511 | { | ||
512 | struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr; | ||
513 | struct mwifiex_tx_ba_stream_tbl *ptx_tbl; | ||
514 | u8 cleanup_rx_reorder_tbl; | ||
515 | unsigned long flags; | ||
516 | |||
517 | if (type == TYPE_DELBA_RECEIVE) | ||
518 | cleanup_rx_reorder_tbl = (initiator) ? true : false; | ||
519 | else | ||
520 | cleanup_rx_reorder_tbl = (initiator) ? false : true; | ||
521 | |||
522 | dev_dbg(priv->adapter->dev, "event: DELBA: %pM tid=%d, " | ||
523 | "initiator=%d\n", peer_mac, tid, initiator); | ||
524 | |||
525 | if (cleanup_rx_reorder_tbl) { | ||
526 | rx_reor_tbl_ptr = mwifiex_11n_get_rx_reorder_tbl(priv, tid, | ||
527 | peer_mac); | ||
528 | if (!rx_reor_tbl_ptr) { | ||
529 | dev_dbg(priv->adapter->dev, | ||
530 | "event: TID, TA not found in table\n"); | ||
531 | return; | ||
532 | } | ||
533 | mwifiex_11n_delete_rx_reorder_tbl_entry(priv, rx_reor_tbl_ptr); | ||
534 | } else { | ||
535 | ptx_tbl = mwifiex_11n_get_tx_ba_stream_tbl(priv, tid, peer_mac); | ||
536 | if (!ptx_tbl) { | ||
537 | dev_dbg(priv->adapter->dev, | ||
538 | "event: TID, RA not found in table\n"); | ||
539 | return; | ||
540 | } | ||
541 | |||
542 | spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags); | ||
543 | mwifiex_11n_delete_tx_ba_stream_tbl_entry(priv, ptx_tbl); | ||
544 | spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags); | ||
545 | } | ||
546 | } | ||
547 | |||
548 | /* | ||
549 | * This function handles the command response of an add BA response. | ||
550 | * | ||
551 | * Handling includes changing the header fields into CPU format and | ||
552 | * creating the stream, provided the add BA is accepted. | ||
553 | */ | ||
554 | int mwifiex_ret_11n_addba_resp(struct mwifiex_private *priv, | ||
555 | struct host_cmd_ds_command *resp) | ||
556 | { | ||
557 | struct host_cmd_ds_11n_addba_rsp *add_ba_rsp = | ||
558 | (struct host_cmd_ds_11n_addba_rsp *) | ||
559 | &resp->params.add_ba_rsp; | ||
560 | int tid, win_size; | ||
561 | struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr = NULL; | ||
562 | uint16_t block_ack_param_set; | ||
563 | |||
564 | block_ack_param_set = le16_to_cpu(add_ba_rsp->block_ack_param_set); | ||
565 | |||
566 | tid = (block_ack_param_set & IEEE80211_ADDBA_PARAM_TID_MASK) | ||
567 | >> BLOCKACKPARAM_TID_POS; | ||
568 | /* | ||
569 | * Check if we had rejected the ADDBA, if yes then do not create | ||
570 | * the stream | ||
571 | */ | ||
572 | if (le16_to_cpu(add_ba_rsp->status_code) == BA_RESULT_SUCCESS) { | ||
573 | win_size = (block_ack_param_set & | ||
574 | IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) | ||
575 | >> BLOCKACKPARAM_WINSIZE_POS; | ||
576 | |||
577 | dev_dbg(priv->adapter->dev, "cmd: ADDBA RSP: %pM" | ||
578 | " tid=%d ssn=%d win_size=%d\n", | ||
579 | add_ba_rsp->peer_mac_addr, | ||
580 | tid, add_ba_rsp->ssn, win_size); | ||
581 | } else { | ||
582 | dev_err(priv->adapter->dev, "ADDBA RSP: failed %pM tid=%d)\n", | ||
583 | add_ba_rsp->peer_mac_addr, tid); | ||
584 | |||
585 | rx_reor_tbl_ptr = mwifiex_11n_get_rx_reorder_tbl(priv, | ||
586 | tid, add_ba_rsp->peer_mac_addr); | ||
587 | if (rx_reor_tbl_ptr) | ||
588 | mwifiex_11n_delete_rx_reorder_tbl_entry(priv, | ||
589 | rx_reor_tbl_ptr); | ||
590 | } | ||
591 | |||
592 | return 0; | ||
593 | } | ||
594 | |||
595 | /* | ||
596 | * This function handles BA stream timeout event by preparing and sending | ||
597 | * a command to the firmware. | ||
598 | */ | ||
599 | void mwifiex_11n_ba_stream_timeout(struct mwifiex_private *priv, | ||
600 | struct host_cmd_ds_11n_batimeout *event) | ||
601 | { | ||
602 | struct host_cmd_ds_11n_delba delba; | ||
603 | |||
604 | memset(&delba, 0, sizeof(struct host_cmd_ds_11n_delba)); | ||
605 | memcpy(delba.peer_mac_addr, event->peer_mac_addr, ETH_ALEN); | ||
606 | |||
607 | delba.del_ba_param_set |= | ||
608 | cpu_to_le16((u16) event->tid << DELBA_TID_POS); | ||
609 | delba.del_ba_param_set |= cpu_to_le16( | ||
610 | (u16) event->origninator << DELBA_INITIATOR_POS); | ||
611 | delba.reason_code = cpu_to_le16(WLAN_REASON_QSTA_TIMEOUT); | ||
612 | mwifiex_prepare_cmd(priv, HostCmd_CMD_11N_DELBA, 0, 0, NULL, &delba); | ||
613 | |||
614 | return; | ||
615 | } | ||
616 | |||
617 | /* | ||
618 | * This function cleans up the Rx reorder table by deleting all the entries | ||
619 | * and re-initializing. | ||
620 | */ | ||
621 | void mwifiex_11n_cleanup_reorder_tbl(struct mwifiex_private *priv) | ||
622 | { | ||
623 | struct mwifiex_rx_reorder_tbl *del_tbl_ptr, *tmp_node; | ||
624 | unsigned long flags; | ||
625 | |||
626 | spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags); | ||
627 | list_for_each_entry_safe(del_tbl_ptr, tmp_node, | ||
628 | &priv->rx_reorder_tbl_ptr, list) { | ||
629 | spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags); | ||
630 | mwifiex_11n_delete_rx_reorder_tbl_entry(priv, del_tbl_ptr); | ||
631 | spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags); | ||
632 | } | ||
633 | spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags); | ||
634 | |||
635 | INIT_LIST_HEAD(&priv->rx_reorder_tbl_ptr); | ||
636 | memset(priv->rx_seq, 0, sizeof(priv->rx_seq)); | ||
637 | } | ||
diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.h b/drivers/net/wireless/mwifiex/11n_rxreorder.h new file mode 100644 index 000000000000..42f569035745 --- /dev/null +++ b/drivers/net/wireless/mwifiex/11n_rxreorder.h | |||
@@ -0,0 +1,67 @@ | |||
1 | /* | ||
2 | * Marvell Wireless LAN device driver: 802.11n RX Re-ordering | ||
3 | * | ||
4 | * Copyright (C) 2011, Marvell International Ltd. | ||
5 | * | ||
6 | * This software file (the "File") is distributed by Marvell International | ||
7 | * Ltd. under the terms of the GNU General Public License Version 2, June 1991 | ||
8 | * (the "License"). You may use, redistribute and/or modify this File in | ||
9 | * accordance with the terms and conditions of the License, a copy of which | ||
10 | * is available by writing to the Free Software Foundation, Inc., | ||
11 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the | ||
12 | * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. | ||
13 | * | ||
14 | * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE | ||
15 | * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE | ||
16 | * ARE EXPRESSLY DISCLAIMED. The License provides additional details about | ||
17 | * this warranty disclaimer. | ||
18 | */ | ||
19 | |||
20 | #ifndef _MWIFIEX_11N_RXREORDER_H_ | ||
21 | #define _MWIFIEX_11N_RXREORDER_H_ | ||
22 | |||
23 | #define MIN_FLUSH_TIMER_MS 50 | ||
24 | |||
25 | #define PKT_TYPE_BAR 0xE7 | ||
26 | #define MAX_TID_VALUE (2 << 11) | ||
27 | #define TWOPOW11 (2 << 10) | ||
28 | |||
29 | #define BLOCKACKPARAM_TID_POS 2 | ||
30 | #define BLOCKACKPARAM_AMSDU_SUPP_MASK 0x1 | ||
31 | #define BLOCKACKPARAM_WINSIZE_POS 6 | ||
32 | #define DELBA_TID_POS 12 | ||
33 | #define DELBA_INITIATOR_POS 11 | ||
34 | #define TYPE_DELBA_SENT 1 | ||
35 | #define TYPE_DELBA_RECEIVE 2 | ||
36 | #define IMMEDIATE_BLOCK_ACK 0x2 | ||
37 | |||
38 | #define ADDBA_RSP_STATUS_ACCEPT 0 | ||
39 | |||
40 | int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *, | ||
41 | u16 seqNum, | ||
42 | u16 tid, u8 *ta, | ||
43 | u8 pkttype, void *payload); | ||
44 | void mwifiex_11n_delete_ba_stream_tbl(struct mwifiex_private *priv, int Tid, | ||
45 | u8 *PeerMACAddr, u8 type, | ||
46 | int initiator); | ||
47 | void mwifiex_11n_ba_stream_timeout(struct mwifiex_private *priv, | ||
48 | struct host_cmd_ds_11n_batimeout *event); | ||
49 | int mwifiex_ret_11n_addba_resp(struct mwifiex_private *priv, | ||
50 | struct host_cmd_ds_command | ||
51 | *resp); | ||
52 | int mwifiex_cmd_11n_delba(struct mwifiex_private *priv, | ||
53 | struct host_cmd_ds_command *cmd, | ||
54 | void *data_buf); | ||
55 | int mwifiex_cmd_11n_addba_rsp_gen(struct mwifiex_private *priv, | ||
56 | struct host_cmd_ds_command | ||
57 | *cmd, void *data_buf); | ||
58 | int mwifiex_cmd_11n_addba_req(struct mwifiex_private *priv, | ||
59 | struct host_cmd_ds_command *cmd, | ||
60 | void *data_buf); | ||
61 | void mwifiex_11n_cleanup_reorder_tbl(struct mwifiex_private *priv); | ||
62 | struct mwifiex_rx_reorder_tbl *mwifiex_11n_get_rxreorder_tbl(struct | ||
63 | mwifiex_private | ||
64 | *priv, int tid, | ||
65 | u8 *ta); | ||
66 | |||
67 | #endif /* _MWIFIEX_11N_RXREORDER_H_ */ | ||
diff --git a/drivers/net/wireless/mwifiex/Kconfig b/drivers/net/wireless/mwifiex/Kconfig new file mode 100644 index 000000000000..86962920cef3 --- /dev/null +++ b/drivers/net/wireless/mwifiex/Kconfig | |||
@@ -0,0 +1,21 @@ | |||
1 | config MWIFIEX | ||
2 | tristate "Marvell WiFi-Ex Driver" | ||
3 | depends on CFG80211 | ||
4 | select LIB80211 | ||
5 | ---help--- | ||
6 | This adds support for wireless adapters based on Marvell | ||
7 | 802.11n chipsets. | ||
8 | |||
9 | If you choose to build it as a module, it will be called | ||
10 | mwifiex. | ||
11 | |||
12 | config MWIFIEX_SDIO | ||
13 | tristate "Marvell WiFi-Ex Driver for SD8787" | ||
14 | depends on MWIFIEX && MMC | ||
15 | select FW_LOADER | ||
16 | ---help--- | ||
17 | This adds support for wireless adapters based on Marvell | ||
18 | 8787 chipset with SDIO interface. | ||
19 | |||
20 | If you choose to build it as a module, it will be called | ||
21 | mwifiex_sdio. | ||
diff --git a/drivers/net/wireless/mwifiex/Makefile b/drivers/net/wireless/mwifiex/Makefile new file mode 100644 index 000000000000..42cb733ea33a --- /dev/null +++ b/drivers/net/wireless/mwifiex/Makefile | |||
@@ -0,0 +1,41 @@ | |||
1 | # | ||
2 | # Copyright (C) 2011, Marvell International Ltd. | ||
3 | # | ||
4 | # This software file (the "File") is distributed by Marvell International | ||
5 | # Ltd. under the terms of the GNU General Public License Version 2, June 1991 | ||
6 | # (the "License"). You may use, redistribute and/or modify this File in | ||
7 | # accordance with the terms and conditions of the License, a copy of which | ||
8 | # is available by writing to the Free Software Foundation, Inc., | ||
9 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the | ||
10 | # worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. | ||
11 | # | ||
12 | # THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE | ||
13 | # IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE | ||
14 | # ARE EXPRESSLY DISCLAIMED. The License provides additional details about | ||
15 | # this warranty disclaimer. | ||
16 | |||
17 | |||
18 | mwifiex-y += main.o | ||
19 | mwifiex-y += init.o | ||
20 | mwifiex-y += cfp.o | ||
21 | mwifiex-y += cmdevt.o | ||
22 | mwifiex-y += util.o | ||
23 | mwifiex-y += txrx.o | ||
24 | mwifiex-y += wmm.o | ||
25 | mwifiex-y += 11n.o | ||
26 | mwifiex-y += 11n_aggr.o | ||
27 | mwifiex-y += 11n_rxreorder.o | ||
28 | mwifiex-y += scan.o | ||
29 | mwifiex-y += join.o | ||
30 | mwifiex-y += sta_ioctl.o | ||
31 | mwifiex-y += sta_cmd.o | ||
32 | mwifiex-y += sta_cmdresp.o | ||
33 | mwifiex-y += sta_event.o | ||
34 | mwifiex-y += sta_tx.o | ||
35 | mwifiex-y += sta_rx.o | ||
36 | mwifiex-y += cfg80211.o | ||
37 | mwifiex-$(CONFIG_DEBUG_FS) += debugfs.o | ||
38 | obj-$(CONFIG_MWIFIEX) += mwifiex.o | ||
39 | |||
40 | mwifiex_sdio-y += sdio.o | ||
41 | obj-$(CONFIG_MWIFIEX_SDIO) += mwifiex_sdio.o | ||
diff --git a/drivers/net/wireless/mwifiex/README b/drivers/net/wireless/mwifiex/README new file mode 100644 index 000000000000..338377f7093b --- /dev/null +++ b/drivers/net/wireless/mwifiex/README | |||
@@ -0,0 +1,204 @@ | |||
1 | # Copyright (C) 2011, Marvell International Ltd. | ||
2 | # | ||
3 | # This software file (the "File") is distributed by Marvell International | ||
4 | # Ltd. under the terms of the GNU General Public License Version 2, June 1991 | ||
5 | # (the "License"). You may use, redistribute and/or modify this File in | ||
6 | # accordance with the terms and conditions of the License, a copy of which | ||
7 | # is available by writing to the Free Software Foundation, Inc., | ||
8 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the | ||
9 | # worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. | ||
10 | # | ||
11 | # THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE | ||
12 | # IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE | ||
13 | # ARE EXPRESSLY DISCLAIMED. The License provides additional details about | ||
14 | # this warranty disclaimer. | ||
15 | |||
16 | |||
17 | =============================================================================== | ||
18 | U S E R M A N U A L | ||
19 | |||
20 | 1) FOR DRIVER INSTALL | ||
21 | |||
22 | a) Copy sd8787.bin to /lib/firmware/mrvl/ directory, | ||
23 | create the directory if it doesn't exist. | ||
24 | b) Install WLAN driver, | ||
25 | insmod mwifiex.ko | ||
26 | c) Uninstall WLAN driver, | ||
27 | ifconfig mlanX down | ||
28 | rmmod mwifiex | ||
29 | |||
30 | |||
31 | 2) FOR DRIVER CONFIGURATION AND INFO | ||
32 | The configurations can be done either using the 'iw' user space | ||
33 | utility or debugfs. | ||
34 | |||
35 | a) 'iw' utility commands | ||
36 | |||
37 | Following are some useful iw commands:- | ||
38 | |||
39 | iw dev mlan0 scan | ||
40 | |||
41 | This command will trigger a scan. | ||
42 | The command will then display the scan table entries | ||
43 | |||
44 | iw dev mlan0 connect -w <SSID> [<freq in MHz>] [<bssid>] [key 0:abcde d:1123456789a] | ||
45 | The above command can be used to connect to an AP with a particular SSID. | ||
46 | Ap's operating frequency can be specified or even the bssid. If the AP is using | ||
47 | WEP encryption, wep keys can be specified in the command. | ||
48 | Note: Every time before connecting to an AP scan command (iw dev mlan0 scan) should be used by user. | ||
49 | |||
50 | iw dev mlan0 disconnect | ||
51 | This command will be used to disconnect from an AP. | ||
52 | |||
53 | |||
54 | iw dev mlan0 ibss join <SSID> <freq in MHz> [fixed-freq] [fixed-bssid] [key 0:abcde] | ||
55 | The command will be used to join or create an ibss. Optionally, operating frequency, | ||
56 | bssid and the security related parameters can be specified while joining/creating | ||
57 | and ibss. | ||
58 | |||
59 | iw dev mlan0 ibss leave | ||
60 | The command will be used to leave an ibss network. | ||
61 | |||
62 | iw dev mlan0 link | ||
63 | The command will be used to get the connection status. The command will return parameters | ||
64 | such as SSID, operating frequency, rx/tx packets, signal strength, tx bitrate. | ||
65 | |||
66 | Apart from the iw utility all standard configurations using the 'iwconfig' utility are also supported. | ||
67 | |||
68 | b) Debugfs interface | ||
69 | |||
70 | The debugfs interface can be used for configurations and for getting | ||
71 | some useful information from the driver. | ||
72 | The section below explains the configurations that can be | ||
73 | done. | ||
74 | |||
75 | Mount debugfs to /debugfs mount point: | ||
76 | |||
77 | mkdir /debugfs | ||
78 | mount -t debugfs debugfs /debugfs | ||
79 | |||
80 | The information is provided in /debugfs/mwifiex/mlanX/: | ||
81 | |||
82 | iw reg set <country code> | ||
83 | The command will be used to change the regulatory domain. | ||
84 | |||
85 | iw reg get | ||
86 | The command will be used to get current regulatory domain. | ||
87 | |||
88 | info | ||
89 | This command is used to get driver info. | ||
90 | |||
91 | Usage: | ||
92 | cat info | ||
93 | |||
94 | driver_name = "mwifiex" | ||
95 | driver_version = <driver_name, driver_version, (firmware_version)> | ||
96 | interface_name = "mlanX" | ||
97 | bss_mode = "Ad-hoc" | "Managed" | "Auto" | "Unknown" | ||
98 | media_state = "Disconnected" | "Connected" | ||
99 | mac_address = <6-byte adapter MAC address> | ||
100 | multicase_count = <multicast address count> | ||
101 | essid = <current SSID> | ||
102 | bssid = <current BSSID> | ||
103 | channel = <current channel> | ||
104 | region_code = <current region code> | ||
105 | multicasr_address[n] = <multicast address> | ||
106 | num_tx_bytes = <number of bytes sent to device> | ||
107 | num_rx_bytes = <number of bytes received from device and sent to kernel> | ||
108 | num_tx_pkts = <number of packets sent to device> | ||
109 | num_rx_pkts = <number of packets received from device and sent to kernel> | ||
110 | num_tx_pkts_dropped = <number of Tx packets dropped by driver> | ||
111 | num_rx_pkts_dropped = <number of Rx packets dropped by driver> | ||
112 | num_tx_pkts_err = <number of Tx packets failed to send to device> | ||
113 | num_rx_pkts_err = <number of Rx packets failed to receive from device> | ||
114 | carrier "on" | "off" | ||
115 | tx queue "stopped" | "started" | ||
116 | |||
117 | The following debug info are provided in /debugfs/mwifiex/mlanX/debug: | ||
118 | |||
119 | int_counter = <interrupt count, cleared when interrupt handled> | ||
120 | wmm_ac_vo = <number of packets sent to device from WMM AcVo queue> | ||
121 | wmm_ac_vi = <number of packets sent to device from WMM AcVi queue> | ||
122 | wmm_ac_be = <number of packets sent to device from WMM AcBE queue> | ||
123 | wmm_ac_bk = <number of packets sent to device from WMM AcBK queue> | ||
124 | max_tx_buf_size = <maximum Tx buffer size> | ||
125 | tx_buf_size = <current Tx buffer size> | ||
126 | curr_tx_buf_size = <current Tx buffer size> | ||
127 | ps_mode = <0/1, CAM mode/PS mode> | ||
128 | ps_state = <0/1/2/3, full power state/awake state/pre-sleep state/sleep state> | ||
129 | is_deep_sleep = <0/1, not deep sleep state/deep sleep state> | ||
130 | wakeup_dev_req = <0/1, wakeup device not required/required> | ||
131 | wakeup_tries = <wakeup device count, cleared when device awake> | ||
132 | hs_configured = <0/1, host sleep not configured/configured> | ||
133 | hs_activated = <0/1, extended host sleep not activated/activated> | ||
134 | num_tx_timeout = <number of Tx timeout> | ||
135 | num_cmd_timeout = <number of timeout commands> | ||
136 | timeout_cmd_id = <command id of the last timeout command> | ||
137 | timeout_cmd_act = <command action of the last timeout command> | ||
138 | last_cmd_id = <command id of the last several commands sent to device> | ||
139 | last_cmd_act = <command action of the last several commands sent to device> | ||
140 | last_cmd_index = <0 based last command index> | ||
141 | last_cmd_resp_id = <command id of the last several command responses received from device> | ||
142 | last_cmd_resp_index = <0 based last command response index> | ||
143 | last_event = <event id of the last several events received from device> | ||
144 | last_event_index = <0 based last event index> | ||
145 | num_cmd_h2c_fail = <number of commands failed to send to device> | ||
146 | num_cmd_sleep_cfm_fail = <number of sleep confirm failed to send to device> | ||
147 | num_tx_h2c_fail = <number of data packets failed to send to device> | ||
148 | num_evt_deauth = <number of deauthenticated events received from device> | ||
149 | num_evt_disassoc = <number of disassociated events received from device> | ||
150 | num_evt_link_lost = <number of link lost events received from device> | ||
151 | num_cmd_deauth = <number of deauthenticate commands sent to device> | ||
152 | num_cmd_assoc_ok = <number of associate commands with success return> | ||
153 | num_cmd_assoc_fail = <number of associate commands with failure return> | ||
154 | cmd_sent = <0/1, send command resources available/sending command to device> | ||
155 | data_sent = <0/1, send data resources available/sending data to device> | ||
156 | mp_rd_bitmap = <SDIO multi-port read bitmap> | ||
157 | mp_wr_bitmap = <SDIO multi-port write bitmap> | ||
158 | cmd_resp_received = <0/1, no cmd response to process/response received and yet to process> | ||
159 | event_received = <0/1, no event to process/event received and yet to process> | ||
160 | ioctl_pending = <number of ioctl pending> | ||
161 | tx_pending = <number of Tx packet pending> | ||
162 | rx_pending = <number of Rx packet pending> | ||
163 | |||
164 | |||
165 | 3) FOR DRIVER CONFIGURATION | ||
166 | |||
167 | regrdwr | ||
168 | This command is used to read/write the adapter register. | ||
169 | |||
170 | Usage: | ||
171 | echo " <type> <offset> [value]" > regrdwr | ||
172 | cat regrdwr | ||
173 | |||
174 | where the parameters are, | ||
175 | <type>: 1:MAC/SOC, 2:BBP, 3:RF, 4:PMIC, 5:CAU | ||
176 | <offset>: offset of register | ||
177 | [value]: value to be written | ||
178 | |||
179 | Examples: | ||
180 | echo "1 0xa060" > regrdwr : Read the MAC register | ||
181 | echo "1 0xa060 0x12" > regrdwr : Write the MAC register | ||
182 | echo "1 0xa794 0x80000000" > regrdwr | ||
183 | : Write 0x80000000 to MAC register | ||
184 | rdeeprom | ||
185 | This command is used to read the EEPROM contents of the card. | ||
186 | |||
187 | Usage: | ||
188 | echo "<offset> <length>" > rdeeprom | ||
189 | cat rdeeprom | ||
190 | |||
191 | where the parameters are, | ||
192 | <offset>: multiples of 4 | ||
193 | <length>: 4-20, multiples of 4 | ||
194 | |||
195 | Example: | ||
196 | echo "0 20" > rdeeprom : Read 20 bytes of EEPROM data from offset 0 | ||
197 | |||
198 | getlog | ||
199 | This command is used to get the statistics available in the station. | ||
200 | Usage: | ||
201 | |||
202 | cat getlog | ||
203 | |||
204 | =============================================================================== | ||
diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c new file mode 100644 index 000000000000..ec0895f4e8d3 --- /dev/null +++ b/drivers/net/wireless/mwifiex/cfg80211.c | |||
@@ -0,0 +1,1456 @@ | |||
1 | /* | ||
2 | * Marvell Wireless LAN device driver: CFG80211 | ||
3 | * | ||
4 | * Copyright (C) 2011, Marvell International Ltd. | ||
5 | * | ||
6 | * This software file (the "File") is distributed by Marvell International | ||
7 | * Ltd. under the terms of the GNU General Public License Version 2, June 1991 | ||
8 | * (the "License"). You may use, redistribute and/or modify this File in | ||
9 | * accordance with the terms and conditions of the License, a copy of which | ||
10 | * is available by writing to the Free Software Foundation, Inc., | ||
11 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the | ||
12 | * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. | ||
13 | * | ||
14 | * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE | ||
15 | * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE | ||
16 | * ARE EXPRESSLY DISCLAIMED. The License provides additional details about | ||
17 | * this warranty disclaimer. | ||
18 | */ | ||
19 | |||
20 | #include "cfg80211.h" | ||
21 | #include "main.h" | ||
22 | |||
23 | /* | ||
24 | * This function maps the nl802.11 channel type into driver channel type. | ||
25 | * | ||
26 | * The mapping is as follows - | ||
27 | * NL80211_CHAN_NO_HT -> NO_SEC_CHANNEL | ||
28 | * NL80211_CHAN_HT20 -> NO_SEC_CHANNEL | ||
29 | * NL80211_CHAN_HT40PLUS -> SEC_CHANNEL_ABOVE | ||
30 | * NL80211_CHAN_HT40MINUS -> SEC_CHANNEL_BELOW | ||
31 | * Others -> NO_SEC_CHANNEL | ||
32 | */ | ||
33 | static int | ||
34 | mwifiex_cfg80211_channel_type_to_mwifiex_channels(enum nl80211_channel_type | ||
35 | channel_type) | ||
36 | { | ||
37 | int channel; | ||
38 | switch (channel_type) { | ||
39 | case NL80211_CHAN_NO_HT: | ||
40 | case NL80211_CHAN_HT20: | ||
41 | channel = NO_SEC_CHANNEL; | ||
42 | break; | ||
43 | case NL80211_CHAN_HT40PLUS: | ||
44 | channel = SEC_CHANNEL_ABOVE; | ||
45 | break; | ||
46 | case NL80211_CHAN_HT40MINUS: | ||
47 | channel = SEC_CHANNEL_BELOW; | ||
48 | break; | ||
49 | default: | ||
50 | channel = NO_SEC_CHANNEL; | ||
51 | } | ||
52 | return channel; | ||
53 | } | ||
54 | |||
55 | /* | ||
56 | * This function maps the driver channel type into nl802.11 channel type. | ||
57 | * | ||
58 | * The mapping is as follows - | ||
59 | * NO_SEC_CHANNEL -> NL80211_CHAN_HT20 | ||
60 | * SEC_CHANNEL_ABOVE -> NL80211_CHAN_HT40PLUS | ||
61 | * SEC_CHANNEL_BELOW -> NL80211_CHAN_HT40MINUS | ||
62 | * Others -> NL80211_CHAN_HT20 | ||
63 | */ | ||
64 | static enum nl80211_channel_type | ||
65 | mwifiex_channels_to_cfg80211_channel_type(int channel_type) | ||
66 | { | ||
67 | int channel; | ||
68 | switch (channel_type) { | ||
69 | case NO_SEC_CHANNEL: | ||
70 | channel = NL80211_CHAN_HT20; | ||
71 | break; | ||
72 | case SEC_CHANNEL_ABOVE: | ||
73 | channel = NL80211_CHAN_HT40PLUS; | ||
74 | break; | ||
75 | case SEC_CHANNEL_BELOW: | ||
76 | channel = NL80211_CHAN_HT40MINUS; | ||
77 | break; | ||
78 | default: | ||
79 | channel = NL80211_CHAN_HT20; | ||
80 | } | ||
81 | return channel; | ||
82 | } | ||
83 | |||
84 | /* | ||
85 | * This function checks whether WEP is set. | ||
86 | */ | ||
87 | static int | ||
88 | mwifiex_is_alg_wep(u32 cipher) | ||
89 | { | ||
90 | int alg = 0; | ||
91 | |||
92 | switch (cipher) { | ||
93 | case WLAN_CIPHER_SUITE_WEP40: | ||
94 | case WLAN_CIPHER_SUITE_WEP104: | ||
95 | alg = 1; | ||
96 | break; | ||
97 | default: | ||
98 | alg = 0; | ||
99 | break; | ||
100 | } | ||
101 | return alg; | ||
102 | } | ||
103 | |||
104 | /* | ||
105 | * This function retrieves the private structure from kernel wiphy structure. | ||
106 | */ | ||
107 | static void *mwifiex_cfg80211_get_priv(struct wiphy *wiphy) | ||
108 | { | ||
109 | return (void *) (*(unsigned long *) wiphy_priv(wiphy)); | ||
110 | } | ||
111 | |||
112 | /* | ||
113 | * CFG802.11 operation handler to delete a network key. | ||
114 | */ | ||
115 | static int | ||
116 | mwifiex_cfg80211_del_key(struct wiphy *wiphy, struct net_device *netdev, | ||
117 | u8 key_index, bool pairwise, const u8 *mac_addr) | ||
118 | { | ||
119 | struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); | ||
120 | int ret = 0; | ||
121 | |||
122 | ret = mwifiex_set_encode(priv, NULL, 0, key_index, 1); | ||
123 | if (ret) { | ||
124 | wiphy_err(wiphy, "deleting the crypto keys\n"); | ||
125 | return -EFAULT; | ||
126 | } | ||
127 | |||
128 | wiphy_dbg(wiphy, "info: crypto keys deleted\n"); | ||
129 | return 0; | ||
130 | } | ||
131 | |||
132 | /* | ||
133 | * CFG802.11 operation handler to set Tx power. | ||
134 | */ | ||
135 | static int | ||
136 | mwifiex_cfg80211_set_tx_power(struct wiphy *wiphy, | ||
137 | enum nl80211_tx_power_setting type, | ||
138 | int dbm) | ||
139 | { | ||
140 | int ret = 0; | ||
141 | struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); | ||
142 | |||
143 | ret = mwifiex_set_tx_power(priv, type, dbm); | ||
144 | |||
145 | return ret; | ||
146 | } | ||
147 | |||
148 | /* | ||
149 | * CFG802.11 operation handler to set Power Save option. | ||
150 | * | ||
151 | * The timeout value, if provided, is currently ignored. | ||
152 | */ | ||
153 | static int | ||
154 | mwifiex_cfg80211_set_power_mgmt(struct wiphy *wiphy, | ||
155 | struct net_device *dev, | ||
156 | bool enabled, int timeout) | ||
157 | { | ||
158 | int ret = 0; | ||
159 | struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); | ||
160 | |||
161 | if (timeout) | ||
162 | wiphy_dbg(wiphy, | ||
163 | "info: ignoring the timeout value" | ||
164 | " for IEEE power save\n"); | ||
165 | |||
166 | ret = mwifiex_drv_set_power(priv, enabled); | ||
167 | |||
168 | return ret; | ||
169 | } | ||
170 | |||
171 | /* | ||
172 | * CFG802.11 operation handler to set the default network key. | ||
173 | */ | ||
174 | static int | ||
175 | mwifiex_cfg80211_set_default_key(struct wiphy *wiphy, struct net_device *netdev, | ||
176 | u8 key_index, bool unicast, | ||
177 | bool multicast) | ||
178 | { | ||
179 | struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); | ||
180 | int ret; | ||
181 | |||
182 | /* Return if WEP key not configured */ | ||
183 | if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED) | ||
184 | return 0; | ||
185 | |||
186 | ret = mwifiex_set_encode(priv, NULL, 0, key_index, 0); | ||
187 | |||
188 | wiphy_dbg(wiphy, "info: set default Tx key index\n"); | ||
189 | |||
190 | if (ret) | ||
191 | return -EFAULT; | ||
192 | |||
193 | return 0; | ||
194 | } | ||
195 | |||
196 | /* | ||
197 | * CFG802.11 operation handler to add a network key. | ||
198 | */ | ||
199 | static int | ||
200 | mwifiex_cfg80211_add_key(struct wiphy *wiphy, struct net_device *netdev, | ||
201 | u8 key_index, bool pairwise, const u8 *mac_addr, | ||
202 | struct key_params *params) | ||
203 | { | ||
204 | struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); | ||
205 | int ret = 0; | ||
206 | |||
207 | ret = mwifiex_set_encode(priv, params->key, params->key_len, | ||
208 | key_index, 0); | ||
209 | |||
210 | wiphy_dbg(wiphy, "info: crypto keys added\n"); | ||
211 | |||
212 | if (ret) | ||
213 | return -EFAULT; | ||
214 | |||
215 | return 0; | ||
216 | } | ||
217 | |||
218 | /* | ||
219 | * This function sends domain information to the firmware. | ||
220 | * | ||
221 | * The following information are passed to the firmware - | ||
222 | * - Country codes | ||
223 | * - Sub bands (first channel, number of channels, maximum Tx power) | ||
224 | */ | ||
225 | static int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy) | ||
226 | { | ||
227 | u8 no_of_triplet = 0; | ||
228 | struct ieee80211_country_ie_triplet *t; | ||
229 | u8 no_of_parsed_chan = 0; | ||
230 | u8 first_chan = 0, next_chan = 0, max_pwr = 0; | ||
231 | u8 i, flag = 0; | ||
232 | enum ieee80211_band band; | ||
233 | struct ieee80211_supported_band *sband; | ||
234 | struct ieee80211_channel *ch; | ||
235 | struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); | ||
236 | struct mwifiex_adapter *adapter = priv->adapter; | ||
237 | struct mwifiex_802_11d_domain_reg *domain_info = &adapter->domain_reg; | ||
238 | int ret = 0; | ||
239 | |||
240 | /* Set country code */ | ||
241 | domain_info->country_code[0] = priv->country_code[0]; | ||
242 | domain_info->country_code[1] = priv->country_code[1]; | ||
243 | domain_info->country_code[2] = ' '; | ||
244 | |||
245 | band = mwifiex_band_to_radio_type(adapter->config_bands); | ||
246 | if (!wiphy->bands[band]) { | ||
247 | wiphy_err(wiphy, "11D: setting domain info in FW\n"); | ||
248 | return -1; | ||
249 | } | ||
250 | |||
251 | sband = wiphy->bands[band]; | ||
252 | |||
253 | for (i = 0; i < sband->n_channels ; i++) { | ||
254 | ch = &sband->channels[i]; | ||
255 | if (ch->flags & IEEE80211_CHAN_DISABLED) | ||
256 | continue; | ||
257 | |||
258 | if (!flag) { | ||
259 | flag = 1; | ||
260 | first_chan = (u32) ch->hw_value; | ||
261 | next_chan = first_chan; | ||
262 | max_pwr = ch->max_power; | ||
263 | no_of_parsed_chan = 1; | ||
264 | continue; | ||
265 | } | ||
266 | |||
267 | if (ch->hw_value == next_chan + 1 && | ||
268 | ch->max_power == max_pwr) { | ||
269 | next_chan++; | ||
270 | no_of_parsed_chan++; | ||
271 | } else { | ||
272 | t = &domain_info->triplet[no_of_triplet]; | ||
273 | t->chans.first_channel = first_chan; | ||
274 | t->chans.num_channels = no_of_parsed_chan; | ||
275 | t->chans.max_power = max_pwr; | ||
276 | no_of_triplet++; | ||
277 | first_chan = (u32) ch->hw_value; | ||
278 | next_chan = first_chan; | ||
279 | max_pwr = ch->max_power; | ||
280 | no_of_parsed_chan = 1; | ||
281 | } | ||
282 | } | ||
283 | |||
284 | if (flag) { | ||
285 | t = &domain_info->triplet[no_of_triplet]; | ||
286 | t->chans.first_channel = first_chan; | ||
287 | t->chans.num_channels = no_of_parsed_chan; | ||
288 | t->chans.max_power = max_pwr; | ||
289 | no_of_triplet++; | ||
290 | } | ||
291 | |||
292 | domain_info->no_of_triplet = no_of_triplet; | ||
293 | /* Send cmd to FW to set domain info */ | ||
294 | ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11D_DOMAIN_INFO, | ||
295 | HostCmd_ACT_GEN_SET, 0, NULL, NULL); | ||
296 | if (ret) | ||
297 | wiphy_err(wiphy, "11D: setting domain info in FW\n"); | ||
298 | |||
299 | return ret; | ||
300 | } | ||
301 | |||
302 | /* | ||
303 | * CFG802.11 regulatory domain callback function. | ||
304 | * | ||
305 | * This function is called when the regulatory domain is changed due to the | ||
306 | * following reasons - | ||
307 | * - Set by driver | ||
308 | * - Set by system core | ||
309 | * - Set by user | ||
310 | * - Set bt Country IE | ||
311 | */ | ||
312 | static int mwifiex_reg_notifier(struct wiphy *wiphy, | ||
313 | struct regulatory_request *request) | ||
314 | { | ||
315 | struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); | ||
316 | |||
317 | wiphy_dbg(wiphy, "info: cfg80211 regulatory domain callback for domain" | ||
318 | " %c%c\n", request->alpha2[0], request->alpha2[1]); | ||
319 | |||
320 | memcpy(priv->country_code, request->alpha2, sizeof(request->alpha2)); | ||
321 | |||
322 | switch (request->initiator) { | ||
323 | case NL80211_REGDOM_SET_BY_DRIVER: | ||
324 | case NL80211_REGDOM_SET_BY_CORE: | ||
325 | case NL80211_REGDOM_SET_BY_USER: | ||
326 | break; | ||
327 | /* Todo: apply driver specific changes in channel flags based | ||
328 | on the request initiator if necessary. */ | ||
329 | case NL80211_REGDOM_SET_BY_COUNTRY_IE: | ||
330 | break; | ||
331 | } | ||
332 | mwifiex_send_domain_info_cmd_fw(wiphy); | ||
333 | |||
334 | return 0; | ||
335 | } | ||
336 | |||
337 | /* | ||
338 | * This function sets the RF channel. | ||
339 | * | ||
340 | * This function creates multiple IOCTL requests, populates them accordingly | ||
341 | * and issues them to set the band/channel and frequency. | ||
342 | */ | ||
343 | static int | ||
344 | mwifiex_set_rf_channel(struct mwifiex_private *priv, | ||
345 | struct ieee80211_channel *chan, | ||
346 | enum nl80211_channel_type channel_type) | ||
347 | { | ||
348 | struct mwifiex_chan_freq_power cfp; | ||
349 | int ret = 0; | ||
350 | int status = 0; | ||
351 | struct mwifiex_ds_band_cfg band_cfg; | ||
352 | u32 config_bands = 0; | ||
353 | struct wiphy *wiphy = priv->wdev->wiphy; | ||
354 | |||
355 | if (chan) { | ||
356 | memset(&band_cfg, 0, sizeof(band_cfg)); | ||
357 | /* Set appropriate bands */ | ||
358 | if (chan->band == IEEE80211_BAND_2GHZ) | ||
359 | config_bands = BAND_B | BAND_G | BAND_GN; | ||
360 | else | ||
361 | config_bands = BAND_AN | BAND_A; | ||
362 | if (priv->bss_mode == NL80211_IFTYPE_STATION | ||
363 | || priv->bss_mode == NL80211_IFTYPE_UNSPECIFIED) { | ||
364 | band_cfg.config_bands = config_bands; | ||
365 | } else if (priv->bss_mode == NL80211_IFTYPE_ADHOC) { | ||
366 | band_cfg.config_bands = config_bands; | ||
367 | band_cfg.adhoc_start_band = config_bands; | ||
368 | } | ||
369 | /* Set channel offset */ | ||
370 | band_cfg.sec_chan_offset = | ||
371 | mwifiex_cfg80211_channel_type_to_mwifiex_channels | ||
372 | (channel_type); | ||
373 | status = mwifiex_radio_ioctl_band_cfg(priv, HostCmd_ACT_GEN_SET, | ||
374 | &band_cfg); | ||
375 | |||
376 | if (status) | ||
377 | return -EFAULT; | ||
378 | mwifiex_send_domain_info_cmd_fw(wiphy); | ||
379 | } | ||
380 | |||
381 | wiphy_dbg(wiphy, "info: setting band %d, channel offset %d and " | ||
382 | "mode %d\n", config_bands, band_cfg.sec_chan_offset, | ||
383 | priv->bss_mode); | ||
384 | if (!chan) | ||
385 | return ret; | ||
386 | |||
387 | memset(&cfp, 0, sizeof(cfp)); | ||
388 | cfp.freq = chan->center_freq; | ||
389 | /* Convert frequency to channel */ | ||
390 | cfp.channel = ieee80211_frequency_to_channel(chan->center_freq); | ||
391 | |||
392 | status = mwifiex_bss_ioctl_channel(priv, HostCmd_ACT_GEN_SET, &cfp); | ||
393 | if (status) | ||
394 | return -EFAULT; | ||
395 | |||
396 | ret = mwifiex_drv_change_adhoc_chan(priv, cfp.channel); | ||
397 | |||
398 | return ret; | ||
399 | } | ||
400 | |||
401 | /* | ||
402 | * CFG802.11 operation handler to set channel. | ||
403 | * | ||
404 | * This function can only be used when station is not connected. | ||
405 | */ | ||
406 | static int | ||
407 | mwifiex_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev, | ||
408 | struct ieee80211_channel *chan, | ||
409 | enum nl80211_channel_type channel_type) | ||
410 | { | ||
411 | struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); | ||
412 | |||
413 | if (priv->media_connected) { | ||
414 | wiphy_err(wiphy, "This setting is valid only when station " | ||
415 | "is not connected\n"); | ||
416 | return -EINVAL; | ||
417 | } | ||
418 | |||
419 | return mwifiex_set_rf_channel(priv, chan, channel_type); | ||
420 | } | ||
421 | |||
422 | /* | ||
423 | * This function sets the fragmentation threshold. | ||
424 | * | ||
425 | * This function creates an IOCTL request, populates it accordingly | ||
426 | * and issues an IOCTL. | ||
427 | * | ||
428 | * The fragmentation threshold value must lies between MWIFIEX_FRAG_MIN_VALUE | ||
429 | * and MWIFIEX_FRAG_MAX_VALUE. | ||
430 | */ | ||
431 | static int | ||
432 | mwifiex_set_frag(struct mwifiex_private *priv, u32 frag_thr) | ||
433 | { | ||
434 | int ret = 0; | ||
435 | int status = 0; | ||
436 | struct mwifiex_wait_queue *wait = NULL; | ||
437 | u8 wait_option = MWIFIEX_IOCTL_WAIT; | ||
438 | |||
439 | if (frag_thr < MWIFIEX_FRAG_MIN_VALUE | ||
440 | || frag_thr > MWIFIEX_FRAG_MAX_VALUE) | ||
441 | return -EINVAL; | ||
442 | |||
443 | wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); | ||
444 | if (!wait) | ||
445 | return -ENOMEM; | ||
446 | |||
447 | status = mwifiex_snmp_mib_ioctl(priv, wait, FRAG_THRESH_I, | ||
448 | HostCmd_ACT_GEN_SET, &frag_thr); | ||
449 | |||
450 | if (mwifiex_request_ioctl(priv, wait, status, wait_option)) | ||
451 | ret = -EFAULT; | ||
452 | |||
453 | kfree(wait); | ||
454 | return ret; | ||
455 | } | ||
456 | |||
457 | /* | ||
458 | * This function sets the RTS threshold. | ||
459 | * | ||
460 | * This function creates an IOCTL request, populates it accordingly | ||
461 | * and issues an IOCTL. | ||
462 | */ | ||
463 | static int | ||
464 | mwifiex_set_rts(struct mwifiex_private *priv, u32 rts_thr) | ||
465 | { | ||
466 | int ret = 0; | ||
467 | struct mwifiex_wait_queue *wait = NULL; | ||
468 | int status = 0; | ||
469 | u8 wait_option = MWIFIEX_IOCTL_WAIT; | ||
470 | |||
471 | if (rts_thr < MWIFIEX_RTS_MIN_VALUE || rts_thr > MWIFIEX_RTS_MAX_VALUE) | ||
472 | rts_thr = MWIFIEX_RTS_MAX_VALUE; | ||
473 | |||
474 | wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); | ||
475 | if (!wait) | ||
476 | return -ENOMEM; | ||
477 | |||
478 | status = mwifiex_snmp_mib_ioctl(priv, wait, RTS_THRESH_I, | ||
479 | HostCmd_ACT_GEN_SET, &rts_thr); | ||
480 | |||
481 | if (mwifiex_request_ioctl(priv, wait, status, wait_option)) | ||
482 | ret = -EFAULT; | ||
483 | |||
484 | kfree(wait); | ||
485 | return ret; | ||
486 | } | ||
487 | |||
488 | /* | ||
489 | * CFG802.11 operation handler to set wiphy parameters. | ||
490 | * | ||
491 | * This function can be used to set the RTS threshold and the | ||
492 | * Fragmentation threshold of the driver. | ||
493 | */ | ||
494 | static int | ||
495 | mwifiex_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) | ||
496 | { | ||
497 | struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); | ||
498 | |||
499 | int ret = 0; | ||
500 | |||
501 | if (changed & WIPHY_PARAM_RTS_THRESHOLD) | ||
502 | ret = mwifiex_set_rts(priv, wiphy->rts_threshold); | ||
503 | |||
504 | if (changed & WIPHY_PARAM_FRAG_THRESHOLD) | ||
505 | ret = mwifiex_set_frag(priv, wiphy->frag_threshold); | ||
506 | |||
507 | return ret; | ||
508 | } | ||
509 | |||
510 | /* | ||
511 | * CFG802.11 operation handler to change interface type. | ||
512 | */ | ||
513 | static int | ||
514 | mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy, | ||
515 | struct net_device *dev, | ||
516 | enum nl80211_iftype type, u32 *flags, | ||
517 | struct vif_params *params) | ||
518 | { | ||
519 | int ret = 0; | ||
520 | struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); | ||
521 | struct mwifiex_wait_queue *wait = NULL; | ||
522 | |||
523 | if (priv->bss_mode == type) { | ||
524 | wiphy_warn(wiphy, "already set to required type\n"); | ||
525 | return 0; | ||
526 | } | ||
527 | |||
528 | priv->bss_mode = type; | ||
529 | |||
530 | switch (type) { | ||
531 | case NL80211_IFTYPE_ADHOC: | ||
532 | dev->ieee80211_ptr->iftype = NL80211_IFTYPE_ADHOC; | ||
533 | wiphy_dbg(wiphy, "info: setting interface type to adhoc\n"); | ||
534 | break; | ||
535 | case NL80211_IFTYPE_STATION: | ||
536 | dev->ieee80211_ptr->iftype = NL80211_IFTYPE_STATION; | ||
537 | wiphy_dbg(wiphy, "info: setting interface type to managed\n"); | ||
538 | break; | ||
539 | case NL80211_IFTYPE_UNSPECIFIED: | ||
540 | dev->ieee80211_ptr->iftype = NL80211_IFTYPE_STATION; | ||
541 | wiphy_dbg(wiphy, "info: setting interface type to auto\n"); | ||
542 | return 0; | ||
543 | default: | ||
544 | wiphy_err(wiphy, "unknown interface type: %d\n", type); | ||
545 | return -EINVAL; | ||
546 | } | ||
547 | |||
548 | wait = mwifiex_alloc_fill_wait_queue(priv, MWIFIEX_IOCTL_WAIT); | ||
549 | if (!wait) | ||
550 | return -ENOMEM; | ||
551 | |||
552 | mwifiex_deauthenticate(priv, wait, NULL); | ||
553 | |||
554 | priv->sec_info.authentication_mode = NL80211_AUTHTYPE_OPEN_SYSTEM; | ||
555 | |||
556 | ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_SET_BSS_MODE, | ||
557 | HostCmd_ACT_GEN_SET, 0, wait, NULL); | ||
558 | if (!ret) | ||
559 | ret = -EINPROGRESS; | ||
560 | |||
561 | ret = mwifiex_request_ioctl(priv, wait, ret, MWIFIEX_IOCTL_WAIT); | ||
562 | if (ret) | ||
563 | ret = -EFAULT; | ||
564 | |||
565 | kfree(wait); | ||
566 | return ret; | ||
567 | } | ||
568 | |||
569 | /* | ||
570 | * This function dumps the station information on a buffer. | ||
571 | * | ||
572 | * The following information are shown - | ||
573 | * - Total bytes transmitted | ||
574 | * - Total bytes received | ||
575 | * - Total packets transmitted | ||
576 | * - Total packets received | ||
577 | * - Signal quality level | ||
578 | * - Transmission rate | ||
579 | */ | ||
580 | static int | ||
581 | mwifiex_dump_station_info(struct mwifiex_private *priv, | ||
582 | struct station_info *sinfo) | ||
583 | { | ||
584 | struct mwifiex_ds_get_signal signal; | ||
585 | struct mwifiex_rate_cfg rate; | ||
586 | int ret = 0; | ||
587 | |||
588 | sinfo->filled = STATION_INFO_RX_BYTES | STATION_INFO_TX_BYTES | | ||
589 | STATION_INFO_RX_PACKETS | | ||
590 | STATION_INFO_TX_PACKETS | ||
591 | | STATION_INFO_SIGNAL | STATION_INFO_TX_BITRATE; | ||
592 | |||
593 | /* Get signal information from the firmware */ | ||
594 | memset(&signal, 0, sizeof(struct mwifiex_ds_get_signal)); | ||
595 | if (mwifiex_get_signal_info(priv, MWIFIEX_IOCTL_WAIT, &signal)) { | ||
596 | dev_err(priv->adapter->dev, "getting signal information\n"); | ||
597 | ret = -EFAULT; | ||
598 | } | ||
599 | |||
600 | if (mwifiex_drv_get_data_rate(priv, &rate)) { | ||
601 | dev_err(priv->adapter->dev, "getting data rate\n"); | ||
602 | ret = -EFAULT; | ||
603 | } | ||
604 | |||
605 | sinfo->rx_bytes = priv->stats.rx_bytes; | ||
606 | sinfo->tx_bytes = priv->stats.tx_bytes; | ||
607 | sinfo->rx_packets = priv->stats.rx_packets; | ||
608 | sinfo->tx_packets = priv->stats.tx_packets; | ||
609 | sinfo->signal = priv->w_stats.qual.level; | ||
610 | sinfo->txrate.legacy = rate.rate; | ||
611 | |||
612 | return ret; | ||
613 | } | ||
614 | |||
615 | /* | ||
616 | * CFG802.11 operation handler to get station information. | ||
617 | * | ||
618 | * This function only works in connected mode, and dumps the | ||
619 | * requested station information, if available. | ||
620 | */ | ||
621 | static int | ||
622 | mwifiex_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, | ||
623 | u8 *mac, struct station_info *sinfo) | ||
624 | { | ||
625 | struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); | ||
626 | int ret = 0; | ||
627 | |||
628 | mwifiex_dump_station_info(priv, sinfo); | ||
629 | |||
630 | if (!priv->media_connected) | ||
631 | return -ENOENT; | ||
632 | if (memcmp(mac, priv->cfg_bssid, ETH_ALEN)) | ||
633 | return -ENOENT; | ||
634 | |||
635 | |||
636 | ret = mwifiex_dump_station_info(priv, sinfo); | ||
637 | |||
638 | return ret; | ||
639 | } | ||
640 | |||
641 | /* Supported rates to be advertised to the cfg80211 */ | ||
642 | |||
643 | static struct ieee80211_rate mwifiex_rates[] = { | ||
644 | {.bitrate = 10, .hw_value = 2, }, | ||
645 | {.bitrate = 20, .hw_value = 4, }, | ||
646 | {.bitrate = 55, .hw_value = 11, }, | ||
647 | {.bitrate = 110, .hw_value = 22, }, | ||
648 | {.bitrate = 220, .hw_value = 44, }, | ||
649 | {.bitrate = 60, .hw_value = 12, }, | ||
650 | {.bitrate = 90, .hw_value = 18, }, | ||
651 | {.bitrate = 120, .hw_value = 24, }, | ||
652 | {.bitrate = 180, .hw_value = 36, }, | ||
653 | {.bitrate = 240, .hw_value = 48, }, | ||
654 | {.bitrate = 360, .hw_value = 72, }, | ||
655 | {.bitrate = 480, .hw_value = 96, }, | ||
656 | {.bitrate = 540, .hw_value = 108, }, | ||
657 | {.bitrate = 720, .hw_value = 144, }, | ||
658 | }; | ||
659 | |||
660 | /* Channel definitions to be advertised to cfg80211 */ | ||
661 | |||
662 | static struct ieee80211_channel mwifiex_channels_2ghz[] = { | ||
663 | {.center_freq = 2412, .hw_value = 1, }, | ||
664 | {.center_freq = 2417, .hw_value = 2, }, | ||
665 | {.center_freq = 2422, .hw_value = 3, }, | ||
666 | {.center_freq = 2427, .hw_value = 4, }, | ||
667 | {.center_freq = 2432, .hw_value = 5, }, | ||
668 | {.center_freq = 2437, .hw_value = 6, }, | ||
669 | {.center_freq = 2442, .hw_value = 7, }, | ||
670 | {.center_freq = 2447, .hw_value = 8, }, | ||
671 | {.center_freq = 2452, .hw_value = 9, }, | ||
672 | {.center_freq = 2457, .hw_value = 10, }, | ||
673 | {.center_freq = 2462, .hw_value = 11, }, | ||
674 | {.center_freq = 2467, .hw_value = 12, }, | ||
675 | {.center_freq = 2472, .hw_value = 13, }, | ||
676 | {.center_freq = 2484, .hw_value = 14, }, | ||
677 | }; | ||
678 | |||
679 | static struct ieee80211_supported_band mwifiex_band_2ghz = { | ||
680 | .channels = mwifiex_channels_2ghz, | ||
681 | .n_channels = ARRAY_SIZE(mwifiex_channels_2ghz), | ||
682 | .bitrates = mwifiex_rates, | ||
683 | .n_bitrates = 14, | ||
684 | }; | ||
685 | |||
686 | static struct ieee80211_channel mwifiex_channels_5ghz[] = { | ||
687 | {.center_freq = 5040, .hw_value = 8, }, | ||
688 | {.center_freq = 5060, .hw_value = 12, }, | ||
689 | {.center_freq = 5080, .hw_value = 16, }, | ||
690 | {.center_freq = 5170, .hw_value = 34, }, | ||
691 | {.center_freq = 5190, .hw_value = 38, }, | ||
692 | {.center_freq = 5210, .hw_value = 42, }, | ||
693 | {.center_freq = 5230, .hw_value = 46, }, | ||
694 | {.center_freq = 5180, .hw_value = 36, }, | ||
695 | {.center_freq = 5200, .hw_value = 40, }, | ||
696 | {.center_freq = 5220, .hw_value = 44, }, | ||
697 | {.center_freq = 5240, .hw_value = 48, }, | ||
698 | {.center_freq = 5260, .hw_value = 52, }, | ||
699 | {.center_freq = 5280, .hw_value = 56, }, | ||
700 | {.center_freq = 5300, .hw_value = 60, }, | ||
701 | {.center_freq = 5320, .hw_value = 64, }, | ||
702 | {.center_freq = 5500, .hw_value = 100, }, | ||
703 | {.center_freq = 5520, .hw_value = 104, }, | ||
704 | {.center_freq = 5540, .hw_value = 108, }, | ||
705 | {.center_freq = 5560, .hw_value = 112, }, | ||
706 | {.center_freq = 5580, .hw_value = 116, }, | ||
707 | {.center_freq = 5600, .hw_value = 120, }, | ||
708 | {.center_freq = 5620, .hw_value = 124, }, | ||
709 | {.center_freq = 5640, .hw_value = 128, }, | ||
710 | {.center_freq = 5660, .hw_value = 132, }, | ||
711 | {.center_freq = 5680, .hw_value = 136, }, | ||
712 | {.center_freq = 5700, .hw_value = 140, }, | ||
713 | {.center_freq = 5745, .hw_value = 149, }, | ||
714 | {.center_freq = 5765, .hw_value = 153, }, | ||
715 | {.center_freq = 5785, .hw_value = 157, }, | ||
716 | {.center_freq = 5805, .hw_value = 161, }, | ||
717 | {.center_freq = 5825, .hw_value = 165, }, | ||
718 | }; | ||
719 | |||
720 | static struct ieee80211_supported_band mwifiex_band_5ghz = { | ||
721 | .channels = mwifiex_channels_5ghz, | ||
722 | .n_channels = ARRAY_SIZE(mwifiex_channels_5ghz), | ||
723 | .bitrates = mwifiex_rates - 4, | ||
724 | .n_bitrates = ARRAY_SIZE(mwifiex_rates) + 4, | ||
725 | }; | ||
726 | |||
727 | |||
728 | /* Supported crypto cipher suits to be advertised to cfg80211 */ | ||
729 | |||
730 | static const u32 mwifiex_cipher_suites[] = { | ||
731 | WLAN_CIPHER_SUITE_WEP40, | ||
732 | WLAN_CIPHER_SUITE_WEP104, | ||
733 | WLAN_CIPHER_SUITE_TKIP, | ||
734 | WLAN_CIPHER_SUITE_CCMP, | ||
735 | }; | ||
736 | |||
737 | /* | ||
738 | * CFG802.11 operation handler for disconnection request. | ||
739 | * | ||
740 | * This function does not work when there is already a disconnection | ||
741 | * procedure going on. | ||
742 | */ | ||
743 | static int | ||
744 | mwifiex_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, | ||
745 | u16 reason_code) | ||
746 | { | ||
747 | struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); | ||
748 | |||
749 | if (priv->disconnect) | ||
750 | return -EBUSY; | ||
751 | |||
752 | priv->disconnect = 1; | ||
753 | if (mwifiex_disconnect(priv, MWIFIEX_IOCTL_WAIT, NULL)) | ||
754 | return -EFAULT; | ||
755 | |||
756 | wiphy_dbg(wiphy, "info: successfully disconnected from %pM:" | ||
757 | " reason code %d\n", priv->cfg_bssid, reason_code); | ||
758 | |||
759 | queue_work(priv->workqueue, &priv->cfg_workqueue); | ||
760 | |||
761 | return 0; | ||
762 | } | ||
763 | |||
764 | /* | ||
765 | * This function informs the CFG802.11 subsystem of a new IBSS. | ||
766 | * | ||
767 | * The following information are sent to the CFG802.11 subsystem | ||
768 | * to register the new IBSS. If we do not register the new IBSS, | ||
769 | * a kernel panic will result. | ||
770 | * - SSID | ||
771 | * - SSID length | ||
772 | * - BSSID | ||
773 | * - Channel | ||
774 | */ | ||
775 | static int mwifiex_cfg80211_inform_ibss_bss(struct mwifiex_private *priv) | ||
776 | { | ||
777 | int ret = 0; | ||
778 | struct ieee80211_channel *chan; | ||
779 | struct mwifiex_bss_info bss_info; | ||
780 | int ie_len = 0; | ||
781 | u8 ie_buf[IEEE80211_MAX_SSID_LEN + sizeof(struct ieee_types_header)]; | ||
782 | |||
783 | ret = mwifiex_get_bss_info(priv, &bss_info); | ||
784 | if (ret) | ||
785 | return ret; | ||
786 | |||
787 | ie_buf[0] = WLAN_EID_SSID; | ||
788 | ie_buf[1] = bss_info.ssid.ssid_len; | ||
789 | |||
790 | memcpy(&ie_buf[sizeof(struct ieee_types_header)], | ||
791 | &bss_info.ssid.ssid, | ||
792 | bss_info.ssid.ssid_len); | ||
793 | ie_len = ie_buf[1] + sizeof(struct ieee_types_header); | ||
794 | |||
795 | chan = __ieee80211_get_channel(priv->wdev->wiphy, | ||
796 | ieee80211_channel_to_frequency(bss_info.bss_chan, | ||
797 | priv->curr_bss_params.band)); | ||
798 | |||
799 | cfg80211_inform_bss(priv->wdev->wiphy, chan, | ||
800 | bss_info.bssid, 0, WLAN_CAPABILITY_IBSS, | ||
801 | 0, ie_buf, ie_len, 0, GFP_KERNEL); | ||
802 | memcpy(priv->cfg_bssid, bss_info.bssid, ETH_ALEN); | ||
803 | |||
804 | return ret; | ||
805 | } | ||
806 | |||
807 | /* | ||
808 | * This function informs the CFG802.11 subsystem of a new BSS connection. | ||
809 | * | ||
810 | * The following information are sent to the CFG802.11 subsystem | ||
811 | * to register the new BSS connection. If we do not register the new BSS, | ||
812 | * a kernel panic will result. | ||
813 | * - MAC address | ||
814 | * - Capabilities | ||
815 | * - Beacon period | ||
816 | * - RSSI value | ||
817 | * - Channel | ||
818 | * - Supported rates IE | ||
819 | * - Extended capabilities IE | ||
820 | * - DS parameter set IE | ||
821 | * - HT Capability IE | ||
822 | * - Vendor Specific IE (221) | ||
823 | * - WPA IE | ||
824 | * - RSN IE | ||
825 | */ | ||
826 | static int mwifiex_inform_bss_from_scan_result(struct mwifiex_private *priv, | ||
827 | struct mwifiex_802_11_ssid *ssid) | ||
828 | { | ||
829 | struct mwifiex_scan_resp scan_resp; | ||
830 | struct mwifiex_bssdescriptor *scan_table; | ||
831 | int i, j; | ||
832 | struct ieee80211_channel *chan; | ||
833 | u8 *ie, *tmp, *ie_buf; | ||
834 | u32 ie_len; | ||
835 | u64 ts = 0; | ||
836 | u8 *beacon; | ||
837 | int beacon_size; | ||
838 | u8 element_id, element_len; | ||
839 | |||
840 | memset(&scan_resp, 0, sizeof(scan_resp)); | ||
841 | if (mwifiex_get_scan_table(priv, MWIFIEX_IOCTL_WAIT, &scan_resp)) | ||
842 | return -EFAULT; | ||
843 | |||
844 | #define MAX_IE_BUF 2048 | ||
845 | ie_buf = kzalloc(MAX_IE_BUF, GFP_KERNEL); | ||
846 | if (!ie_buf) { | ||
847 | dev_err(priv->adapter->dev, "%s: failed to alloc ie_buf\n", | ||
848 | __func__); | ||
849 | return -ENOMEM; | ||
850 | } | ||
851 | |||
852 | scan_table = (struct mwifiex_bssdescriptor *) scan_resp.scan_table; | ||
853 | for (i = 0; i < scan_resp.num_in_scan_table; i++) { | ||
854 | if (ssid) { | ||
855 | /* Inform specific BSS only */ | ||
856 | if (memcmp(ssid->ssid, scan_table[i].ssid.ssid, | ||
857 | ssid->ssid_len)) | ||
858 | continue; | ||
859 | } | ||
860 | memset(ie_buf, 0, MAX_IE_BUF); | ||
861 | ie_buf[0] = WLAN_EID_SSID; | ||
862 | ie_buf[1] = scan_table[i].ssid.ssid_len; | ||
863 | memcpy(&ie_buf[sizeof(struct ieee_types_header)], | ||
864 | scan_table[i].ssid.ssid, ie_buf[1]); | ||
865 | |||
866 | ie = ie_buf + ie_buf[1] + sizeof(struct ieee_types_header); | ||
867 | ie_len = ie_buf[1] + sizeof(struct ieee_types_header); | ||
868 | |||
869 | ie[0] = WLAN_EID_SUPP_RATES; | ||
870 | |||
871 | for (j = 0; j < sizeof(scan_table[i].supported_rates); j++) { | ||
872 | if (!scan_table[i].supported_rates[j]) | ||
873 | break; | ||
874 | else | ||
875 | ie[j + sizeof(struct ieee_types_header)] = | ||
876 | scan_table[i].supported_rates[j]; | ||
877 | } | ||
878 | |||
879 | ie[1] = j; | ||
880 | ie_len += ie[1] + sizeof(struct ieee_types_header); | ||
881 | |||
882 | beacon = scan_table[i].beacon_buf; | ||
883 | beacon_size = scan_table[i].beacon_buf_size; | ||
884 | |||
885 | /* Skip time stamp, beacon interval and capability */ | ||
886 | |||
887 | if (beacon) { | ||
888 | beacon += sizeof(scan_table[i].beacon_period) | ||
889 | + sizeof(scan_table[i].time_stamp) + | ||
890 | +sizeof(scan_table[i].cap_info_bitmap); | ||
891 | |||
892 | beacon_size -= sizeof(scan_table[i].beacon_period) | ||
893 | + sizeof(scan_table[i].time_stamp) | ||
894 | + sizeof(scan_table[i].cap_info_bitmap); | ||
895 | } | ||
896 | |||
897 | while (beacon_size >= sizeof(struct ieee_types_header)) { | ||
898 | ie = ie_buf + ie_len; | ||
899 | element_id = *beacon; | ||
900 | element_len = *(beacon + 1); | ||
901 | if (beacon_size < (int) element_len + | ||
902 | sizeof(struct ieee_types_header)) { | ||
903 | dev_err(priv->adapter->dev, "%s: in processing" | ||
904 | " IE, bytes left < IE length\n", | ||
905 | __func__); | ||
906 | break; | ||
907 | } | ||
908 | switch (element_id) { | ||
909 | case WLAN_EID_EXT_CAPABILITY: | ||
910 | case WLAN_EID_DS_PARAMS: | ||
911 | case WLAN_EID_HT_CAPABILITY: | ||
912 | case WLAN_EID_VENDOR_SPECIFIC: | ||
913 | case WLAN_EID_RSN: | ||
914 | case WLAN_EID_BSS_AC_ACCESS_DELAY: | ||
915 | ie[0] = element_id; | ||
916 | ie[1] = element_len; | ||
917 | tmp = (u8 *) beacon; | ||
918 | memcpy(&ie[sizeof(struct ieee_types_header)], | ||
919 | tmp + sizeof(struct ieee_types_header), | ||
920 | element_len); | ||
921 | ie_len += ie[1] + | ||
922 | sizeof(struct ieee_types_header); | ||
923 | break; | ||
924 | default: | ||
925 | break; | ||
926 | } | ||
927 | beacon += element_len + | ||
928 | sizeof(struct ieee_types_header); | ||
929 | beacon_size -= element_len + | ||
930 | sizeof(struct ieee_types_header); | ||
931 | } | ||
932 | chan = ieee80211_get_channel(priv->wdev->wiphy, | ||
933 | scan_table[i].freq); | ||
934 | cfg80211_inform_bss(priv->wdev->wiphy, chan, | ||
935 | scan_table[i].mac_address, | ||
936 | ts, scan_table[i].cap_info_bitmap, | ||
937 | scan_table[i].beacon_period, | ||
938 | ie_buf, ie_len, | ||
939 | scan_table[i].rssi, GFP_KERNEL); | ||
940 | } | ||
941 | |||
942 | kfree(ie_buf); | ||
943 | return 0; | ||
944 | } | ||
945 | |||
946 | /* | ||
947 | * This function connects with a BSS. | ||
948 | * | ||
949 | * This function handles both Infra and Ad-Hoc modes. It also performs | ||
950 | * validity checking on the provided parameters, disconnects from the | ||
951 | * current BSS (if any), sets up the association/scan parameters, | ||
952 | * including security settings, and performs specific SSID scan before | ||
953 | * trying to connect. | ||
954 | * | ||
955 | * For Infra mode, the function returns failure if the specified SSID | ||
956 | * is not found in scan table. However, for Ad-Hoc mode, it can create | ||
957 | * the IBSS if it does not exist. On successful completion in either case, | ||
958 | * the function notifies the CFG802.11 subsystem of the new BSS connection, | ||
959 | * otherwise the kernel will panic. | ||
960 | */ | ||
961 | static int | ||
962 | mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid, | ||
963 | u8 *bssid, int mode, struct ieee80211_channel *channel, | ||
964 | struct cfg80211_connect_params *sme, bool privacy) | ||
965 | { | ||
966 | struct mwifiex_802_11_ssid req_ssid; | ||
967 | struct mwifiex_ssid_bssid ssid_bssid; | ||
968 | int ret = 0; | ||
969 | int auth_type = 0, pairwise_encrypt_mode = 0; | ||
970 | int group_encrypt_mode = 0; | ||
971 | int alg_is_wep = 0; | ||
972 | |||
973 | memset(&req_ssid, 0, sizeof(struct mwifiex_802_11_ssid)); | ||
974 | memset(&ssid_bssid, 0, sizeof(struct mwifiex_ssid_bssid)); | ||
975 | |||
976 | req_ssid.ssid_len = ssid_len; | ||
977 | if (ssid_len > IEEE80211_MAX_SSID_LEN) { | ||
978 | dev_err(priv->adapter->dev, "invalid SSID - aborting\n"); | ||
979 | return -EINVAL; | ||
980 | } | ||
981 | |||
982 | memcpy(req_ssid.ssid, ssid, ssid_len); | ||
983 | if (!req_ssid.ssid_len || req_ssid.ssid[0] < 0x20) { | ||
984 | dev_err(priv->adapter->dev, "invalid SSID - aborting\n"); | ||
985 | return -EINVAL; | ||
986 | } | ||
987 | |||
988 | /* disconnect before try to associate */ | ||
989 | mwifiex_disconnect(priv, MWIFIEX_IOCTL_WAIT, NULL); | ||
990 | |||
991 | if (channel) | ||
992 | ret = mwifiex_set_rf_channel(priv, channel, | ||
993 | mwifiex_channels_to_cfg80211_channel_type | ||
994 | (priv->adapter->chan_offset)); | ||
995 | |||
996 | ret = mwifiex_set_encode(priv, NULL, 0, 0, 1); /* Disable keys */ | ||
997 | |||
998 | if (mode == NL80211_IFTYPE_ADHOC) { | ||
999 | /* "privacy" is set only for ad-hoc mode */ | ||
1000 | if (privacy) { | ||
1001 | /* | ||
1002 | * Keep WLAN_CIPHER_SUITE_WEP104 for now so that | ||
1003 | * the firmware can find a matching network from the | ||
1004 | * scan. The cfg80211 does not give us the encryption | ||
1005 | * mode at this stage so just setting it to WEP here. | ||
1006 | */ | ||
1007 | priv->sec_info.encryption_mode = | ||
1008 | WLAN_CIPHER_SUITE_WEP104; | ||
1009 | priv->sec_info.authentication_mode = | ||
1010 | NL80211_AUTHTYPE_OPEN_SYSTEM; | ||
1011 | } | ||
1012 | |||
1013 | goto done; | ||
1014 | } | ||
1015 | |||
1016 | /* Now handle infra mode. "sme" is valid for infra mode only */ | ||
1017 | if (sme->auth_type == NL80211_AUTHTYPE_AUTOMATIC | ||
1018 | || sme->auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM) | ||
1019 | auth_type = NL80211_AUTHTYPE_OPEN_SYSTEM; | ||
1020 | else if (sme->auth_type == NL80211_AUTHTYPE_SHARED_KEY) | ||
1021 | auth_type = NL80211_AUTHTYPE_SHARED_KEY; | ||
1022 | |||
1023 | if (sme->crypto.n_ciphers_pairwise) { | ||
1024 | priv->sec_info.encryption_mode = | ||
1025 | sme->crypto.ciphers_pairwise[0]; | ||
1026 | priv->sec_info.authentication_mode = auth_type; | ||
1027 | } | ||
1028 | |||
1029 | if (sme->crypto.cipher_group) { | ||
1030 | priv->sec_info.encryption_mode = sme->crypto.cipher_group; | ||
1031 | priv->sec_info.authentication_mode = auth_type; | ||
1032 | } | ||
1033 | if (sme->ie) | ||
1034 | ret = mwifiex_set_gen_ie(priv, sme->ie, sme->ie_len); | ||
1035 | |||
1036 | if (sme->key) { | ||
1037 | alg_is_wep = mwifiex_is_alg_wep(pairwise_encrypt_mode) | ||
1038 | | mwifiex_is_alg_wep(group_encrypt_mode); | ||
1039 | if (alg_is_wep) { | ||
1040 | dev_dbg(priv->adapter->dev, | ||
1041 | "info: setting wep encryption" | ||
1042 | " with key len %d\n", sme->key_len); | ||
1043 | ret = mwifiex_set_encode(priv, sme->key, sme->key_len, | ||
1044 | sme->key_idx, 0); | ||
1045 | } | ||
1046 | } | ||
1047 | done: | ||
1048 | /* Do specific SSID scanning */ | ||
1049 | if (mwifiex_request_scan(priv, MWIFIEX_IOCTL_WAIT, &req_ssid)) { | ||
1050 | dev_err(priv->adapter->dev, "scan error\n"); | ||
1051 | return -EFAULT; | ||
1052 | } | ||
1053 | |||
1054 | |||
1055 | memcpy(&ssid_bssid.ssid, &req_ssid, sizeof(struct mwifiex_802_11_ssid)); | ||
1056 | |||
1057 | if (mode != NL80211_IFTYPE_ADHOC) { | ||
1058 | if (mwifiex_find_best_bss(priv, MWIFIEX_IOCTL_WAIT, | ||
1059 | &ssid_bssid)) | ||
1060 | return -EFAULT; | ||
1061 | /* Inform the BSS information to kernel, otherwise | ||
1062 | * kernel will give a panic after successful assoc */ | ||
1063 | if (mwifiex_inform_bss_from_scan_result(priv, &req_ssid)) | ||
1064 | return -EFAULT; | ||
1065 | } | ||
1066 | |||
1067 | dev_dbg(priv->adapter->dev, "info: trying to associate to %s and bssid %pM\n", | ||
1068 | (char *) req_ssid.ssid, ssid_bssid.bssid); | ||
1069 | |||
1070 | memcpy(&priv->cfg_bssid, ssid_bssid.bssid, 6); | ||
1071 | |||
1072 | /* Connect to BSS by ESSID */ | ||
1073 | memset(&ssid_bssid.bssid, 0, ETH_ALEN); | ||
1074 | |||
1075 | if (mwifiex_bss_start(priv, MWIFIEX_IOCTL_WAIT, &ssid_bssid)) | ||
1076 | return -EFAULT; | ||
1077 | |||
1078 | if (mode == NL80211_IFTYPE_ADHOC) { | ||
1079 | /* Inform the BSS information to kernel, otherwise | ||
1080 | * kernel will give a panic after successful assoc */ | ||
1081 | if (mwifiex_cfg80211_inform_ibss_bss(priv)) | ||
1082 | return -EFAULT; | ||
1083 | } | ||
1084 | |||
1085 | return ret; | ||
1086 | } | ||
1087 | |||
1088 | /* | ||
1089 | * CFG802.11 operation handler for association request. | ||
1090 | * | ||
1091 | * This function does not work when the current mode is set to Ad-Hoc, or | ||
1092 | * when there is already an association procedure going on. The given BSS | ||
1093 | * information is used to associate. | ||
1094 | */ | ||
1095 | static int | ||
1096 | mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, | ||
1097 | struct cfg80211_connect_params *sme) | ||
1098 | { | ||
1099 | struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); | ||
1100 | int ret = 0; | ||
1101 | |||
1102 | if (priv->assoc_request) | ||
1103 | return -EBUSY; | ||
1104 | |||
1105 | if (priv->bss_mode == NL80211_IFTYPE_ADHOC) { | ||
1106 | wiphy_err(wiphy, "received infra assoc request " | ||
1107 | "when station is in ibss mode\n"); | ||
1108 | goto done; | ||
1109 | } | ||
1110 | |||
1111 | priv->assoc_request = 1; | ||
1112 | |||
1113 | wiphy_dbg(wiphy, "info: Trying to associate to %s and bssid %pM\n", | ||
1114 | (char *) sme->ssid, sme->bssid); | ||
1115 | |||
1116 | ret = mwifiex_cfg80211_assoc(priv, sme->ssid_len, sme->ssid, sme->bssid, | ||
1117 | priv->bss_mode, sme->channel, sme, 0); | ||
1118 | |||
1119 | done: | ||
1120 | priv->assoc_result = ret; | ||
1121 | queue_work(priv->workqueue, &priv->cfg_workqueue); | ||
1122 | return ret; | ||
1123 | } | ||
1124 | |||
1125 | /* | ||
1126 | * CFG802.11 operation handler to join an IBSS. | ||
1127 | * | ||
1128 | * This function does not work in any mode other than Ad-Hoc, or if | ||
1129 | * a join operation is already in progress. | ||
1130 | */ | ||
1131 | static int | ||
1132 | mwifiex_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, | ||
1133 | struct cfg80211_ibss_params *params) | ||
1134 | { | ||
1135 | struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); | ||
1136 | int ret = 0; | ||
1137 | |||
1138 | if (priv->ibss_join_request) | ||
1139 | return -EBUSY; | ||
1140 | |||
1141 | if (priv->bss_mode != NL80211_IFTYPE_ADHOC) { | ||
1142 | wiphy_err(wiphy, "request to join ibss received " | ||
1143 | "when station is not in ibss mode\n"); | ||
1144 | goto done; | ||
1145 | } | ||
1146 | |||
1147 | priv->ibss_join_request = 1; | ||
1148 | |||
1149 | wiphy_dbg(wiphy, "info: trying to join to %s and bssid %pM\n", | ||
1150 | (char *) params->ssid, params->bssid); | ||
1151 | |||
1152 | ret = mwifiex_cfg80211_assoc(priv, params->ssid_len, params->ssid, | ||
1153 | params->bssid, priv->bss_mode, | ||
1154 | params->channel, NULL, params->privacy); | ||
1155 | done: | ||
1156 | priv->ibss_join_result = ret; | ||
1157 | queue_work(priv->workqueue, &priv->cfg_workqueue); | ||
1158 | return ret; | ||
1159 | } | ||
1160 | |||
1161 | /* | ||
1162 | * CFG802.11 operation handler to leave an IBSS. | ||
1163 | * | ||
1164 | * This function does not work if a leave operation is | ||
1165 | * already in progress. | ||
1166 | */ | ||
1167 | static int | ||
1168 | mwifiex_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev) | ||
1169 | { | ||
1170 | struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); | ||
1171 | |||
1172 | if (priv->disconnect) | ||
1173 | return -EBUSY; | ||
1174 | |||
1175 | priv->disconnect = 1; | ||
1176 | |||
1177 | wiphy_dbg(wiphy, "info: disconnecting from essid %pM\n", | ||
1178 | priv->cfg_bssid); | ||
1179 | if (mwifiex_disconnect(priv, MWIFIEX_IOCTL_WAIT, NULL)) | ||
1180 | return -EFAULT; | ||
1181 | |||
1182 | queue_work(priv->workqueue, &priv->cfg_workqueue); | ||
1183 | |||
1184 | return 0; | ||
1185 | } | ||
1186 | |||
1187 | /* | ||
1188 | * CFG802.11 operation handler for scan request. | ||
1189 | * | ||
1190 | * This function issues a scan request to the firmware based upon | ||
1191 | * the user specified scan configuration. On successfull completion, | ||
1192 | * it also informs the results. | ||
1193 | */ | ||
1194 | static int | ||
1195 | mwifiex_cfg80211_scan(struct wiphy *wiphy, struct net_device *dev, | ||
1196 | struct cfg80211_scan_request *request) | ||
1197 | { | ||
1198 | struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); | ||
1199 | |||
1200 | wiphy_dbg(wiphy, "info: received scan request on %s\n", dev->name); | ||
1201 | |||
1202 | if (priv->scan_request && priv->scan_request != request) | ||
1203 | return -EBUSY; | ||
1204 | |||
1205 | priv->scan_request = request; | ||
1206 | |||
1207 | queue_work(priv->workqueue, &priv->cfg_workqueue); | ||
1208 | return 0; | ||
1209 | } | ||
1210 | |||
1211 | /* | ||
1212 | * This function sets up the CFG802.11 specific HT capability fields | ||
1213 | * with default values. | ||
1214 | * | ||
1215 | * The following default values are set - | ||
1216 | * - HT Supported = True | ||
1217 | * - Maximum AMPDU length factor = 0x3 | ||
1218 | * - Minimum AMPDU spacing = 0x6 | ||
1219 | * - HT Capabilities map = IEEE80211_HT_CAP_SUP_WIDTH_20_40 (0x0002) | ||
1220 | * - MCS information, Rx mask = 0xff | ||
1221 | * - MCD information, Tx parameters = IEEE80211_HT_MCS_TX_DEFINED (0x01) | ||
1222 | */ | ||
1223 | static void | ||
1224 | mwifiex_setup_ht_caps(struct ieee80211_sta_ht_cap *ht_info, | ||
1225 | struct mwifiex_private *priv) | ||
1226 | { | ||
1227 | int rx_mcs_supp; | ||
1228 | struct ieee80211_mcs_info mcs_set; | ||
1229 | u8 *mcs = (u8 *)&mcs_set; | ||
1230 | struct mwifiex_adapter *adapter = priv->adapter; | ||
1231 | |||
1232 | ht_info->ht_supported = true; | ||
1233 | ht_info->ampdu_factor = 0x3; | ||
1234 | ht_info->ampdu_density = 0x6; | ||
1235 | |||
1236 | memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); | ||
1237 | ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||
1238 | |||
1239 | rx_mcs_supp = GET_RXMCSSUPP(priv->adapter->hw_dev_mcs_support); | ||
1240 | /* Set MCS for 1x1 */ | ||
1241 | memset(mcs, 0xff, rx_mcs_supp); | ||
1242 | /* Clear all the other values */ | ||
1243 | memset(&mcs[rx_mcs_supp], 0, | ||
1244 | sizeof(struct ieee80211_mcs_info) - rx_mcs_supp); | ||
1245 | if (priv->bss_mode == NL80211_IFTYPE_STATION || | ||
1246 | ISSUPP_CHANWIDTH40(adapter->hw_dot_11n_dev_cap)) | ||
1247 | /* Set MCS32 for infra mode or ad-hoc mode with 40MHz support */ | ||
1248 | SETHT_MCS32(mcs_set.rx_mask); | ||
1249 | |||
1250 | memcpy((u8 *) &ht_info->mcs, mcs, sizeof(struct ieee80211_mcs_info)); | ||
1251 | |||
1252 | ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; | ||
1253 | } | ||
1254 | |||
1255 | /* station cfg80211 operations */ | ||
1256 | static struct cfg80211_ops mwifiex_cfg80211_ops = { | ||
1257 | .change_virtual_intf = mwifiex_cfg80211_change_virtual_intf, | ||
1258 | .scan = mwifiex_cfg80211_scan, | ||
1259 | .connect = mwifiex_cfg80211_connect, | ||
1260 | .disconnect = mwifiex_cfg80211_disconnect, | ||
1261 | .get_station = mwifiex_cfg80211_get_station, | ||
1262 | .set_wiphy_params = mwifiex_cfg80211_set_wiphy_params, | ||
1263 | .set_channel = mwifiex_cfg80211_set_channel, | ||
1264 | .join_ibss = mwifiex_cfg80211_join_ibss, | ||
1265 | .leave_ibss = mwifiex_cfg80211_leave_ibss, | ||
1266 | .add_key = mwifiex_cfg80211_add_key, | ||
1267 | .del_key = mwifiex_cfg80211_del_key, | ||
1268 | .set_default_key = mwifiex_cfg80211_set_default_key, | ||
1269 | .set_power_mgmt = mwifiex_cfg80211_set_power_mgmt, | ||
1270 | .set_tx_power = mwifiex_cfg80211_set_tx_power, | ||
1271 | }; | ||
1272 | |||
1273 | /* | ||
1274 | * This function registers the device with CFG802.11 subsystem. | ||
1275 | * | ||
1276 | * The function creates the wireless device/wiphy, populates it with | ||
1277 | * default parameters and handler function pointers, and finally | ||
1278 | * registers the device. | ||
1279 | */ | ||
1280 | int mwifiex_register_cfg80211(struct net_device *dev, u8 *mac, | ||
1281 | struct mwifiex_private *priv) | ||
1282 | { | ||
1283 | int ret = 0; | ||
1284 | void *wdev_priv = NULL; | ||
1285 | struct wireless_dev *wdev; | ||
1286 | |||
1287 | wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); | ||
1288 | if (!wdev) { | ||
1289 | dev_err(priv->adapter->dev, "%s: allocating wireless device\n", | ||
1290 | __func__); | ||
1291 | return -ENOMEM; | ||
1292 | } | ||
1293 | wdev->wiphy = | ||
1294 | wiphy_new(&mwifiex_cfg80211_ops, | ||
1295 | sizeof(struct mwifiex_private *)); | ||
1296 | if (!wdev->wiphy) | ||
1297 | return -ENOMEM; | ||
1298 | wdev->iftype = NL80211_IFTYPE_STATION; | ||
1299 | wdev->wiphy->max_scan_ssids = 10; | ||
1300 | wdev->wiphy->interface_modes = | ||
1301 | BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); | ||
1302 | wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &mwifiex_band_2ghz; | ||
1303 | wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &mwifiex_band_5ghz; | ||
1304 | |||
1305 | /* Initialize cipher suits */ | ||
1306 | wdev->wiphy->cipher_suites = mwifiex_cipher_suites; | ||
1307 | wdev->wiphy->n_cipher_suites = ARRAY_SIZE(mwifiex_cipher_suites); | ||
1308 | |||
1309 | /* Initialize parameters for 2GHz band */ | ||
1310 | |||
1311 | mwifiex_setup_ht_caps(&wdev->wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap, | ||
1312 | priv); | ||
1313 | mwifiex_setup_ht_caps(&wdev->wiphy->bands[IEEE80211_BAND_5GHZ]->ht_cap, | ||
1314 | priv); | ||
1315 | |||
1316 | memcpy(wdev->wiphy->perm_addr, mac, 6); | ||
1317 | wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; | ||
1318 | |||
1319 | /* We are using custom domains */ | ||
1320 | wdev->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; | ||
1321 | |||
1322 | wdev->wiphy->reg_notifier = mwifiex_reg_notifier; | ||
1323 | |||
1324 | /* Set struct mwifiex_private pointer in wiphy_priv */ | ||
1325 | wdev_priv = wiphy_priv(wdev->wiphy); | ||
1326 | |||
1327 | *(unsigned long *) wdev_priv = (unsigned long) priv; | ||
1328 | |||
1329 | ret = wiphy_register(wdev->wiphy); | ||
1330 | if (ret < 0) { | ||
1331 | dev_err(priv->adapter->dev, "%s: registering cfg80211 device\n", | ||
1332 | __func__); | ||
1333 | wiphy_free(wdev->wiphy); | ||
1334 | return ret; | ||
1335 | } else { | ||
1336 | dev_dbg(priv->adapter->dev, | ||
1337 | "info: successfully registered wiphy device\n"); | ||
1338 | } | ||
1339 | |||
1340 | dev_net_set(dev, wiphy_net(wdev->wiphy)); | ||
1341 | dev->ieee80211_ptr = wdev; | ||
1342 | memcpy(dev->dev_addr, wdev->wiphy->perm_addr, 6); | ||
1343 | memcpy(dev->perm_addr, wdev->wiphy->perm_addr, 6); | ||
1344 | SET_NETDEV_DEV(dev, wiphy_dev(wdev->wiphy)); | ||
1345 | priv->wdev = wdev; | ||
1346 | |||
1347 | dev->flags |= IFF_BROADCAST | IFF_MULTICAST; | ||
1348 | dev->watchdog_timeo = MWIFIEX_DEFAULT_WATCHDOG_TIMEOUT; | ||
1349 | dev->hard_header_len += MWIFIEX_MIN_DATA_HEADER_LEN; | ||
1350 | |||
1351 | return ret; | ||
1352 | } | ||
1353 | |||
1354 | /* | ||
1355 | * This function handles the result of different pending network operations. | ||
1356 | * | ||
1357 | * The following operations are handled and CFG802.11 subsystem is | ||
1358 | * notified accordingly - | ||
1359 | * - Scan request completion | ||
1360 | * - Association request completion | ||
1361 | * - IBSS join request completion | ||
1362 | * - Disconnect request completion | ||
1363 | */ | ||
1364 | void | ||
1365 | mwifiex_cfg80211_results(struct work_struct *work) | ||
1366 | { | ||
1367 | struct mwifiex_private *priv = | ||
1368 | container_of(work, struct mwifiex_private, cfg_workqueue); | ||
1369 | struct mwifiex_user_scan_cfg *scan_req; | ||
1370 | int ret = 0, i; | ||
1371 | struct ieee80211_channel *chan; | ||
1372 | |||
1373 | if (priv->scan_request) { | ||
1374 | scan_req = kzalloc(sizeof(struct mwifiex_user_scan_cfg), | ||
1375 | GFP_KERNEL); | ||
1376 | if (!scan_req) { | ||
1377 | dev_err(priv->adapter->dev, "failed to alloc " | ||
1378 | "scan_req\n"); | ||
1379 | return; | ||
1380 | } | ||
1381 | for (i = 0; i < priv->scan_request->n_ssids; i++) { | ||
1382 | memcpy(scan_req->ssid_list[i].ssid, | ||
1383 | priv->scan_request->ssids[i].ssid, | ||
1384 | priv->scan_request->ssids[i].ssid_len); | ||
1385 | scan_req->ssid_list[i].max_len = | ||
1386 | priv->scan_request->ssids[i].ssid_len; | ||
1387 | } | ||
1388 | for (i = 0; i < priv->scan_request->n_channels; i++) { | ||
1389 | chan = priv->scan_request->channels[i]; | ||
1390 | scan_req->chan_list[i].chan_number = chan->hw_value; | ||
1391 | scan_req->chan_list[i].radio_type = chan->band; | ||
1392 | if (chan->flags & IEEE80211_CHAN_DISABLED) | ||
1393 | scan_req->chan_list[i].scan_type = | ||
1394 | MWIFIEX_SCAN_TYPE_PASSIVE; | ||
1395 | else | ||
1396 | scan_req->chan_list[i].scan_type = | ||
1397 | MWIFIEX_SCAN_TYPE_ACTIVE; | ||
1398 | scan_req->chan_list[i].scan_time = 0; | ||
1399 | } | ||
1400 | if (mwifiex_set_user_scan_ioctl(priv, scan_req)) { | ||
1401 | ret = -EFAULT; | ||
1402 | goto done; | ||
1403 | } | ||
1404 | if (mwifiex_inform_bss_from_scan_result(priv, NULL)) | ||
1405 | ret = -EFAULT; | ||
1406 | done: | ||
1407 | priv->scan_result_status = ret; | ||
1408 | dev_dbg(priv->adapter->dev, "info: %s: sending scan results\n", | ||
1409 | __func__); | ||
1410 | cfg80211_scan_done(priv->scan_request, | ||
1411 | (priv->scan_result_status < 0)); | ||
1412 | priv->scan_request = NULL; | ||
1413 | kfree(scan_req); | ||
1414 | } | ||
1415 | |||
1416 | if (priv->assoc_request) { | ||
1417 | if (!priv->assoc_result) { | ||
1418 | cfg80211_connect_result(priv->netdev, priv->cfg_bssid, | ||
1419 | NULL, 0, NULL, 0, | ||
1420 | WLAN_STATUS_SUCCESS, | ||
1421 | GFP_KERNEL); | ||
1422 | dev_dbg(priv->adapter->dev, | ||
1423 | "info: associated to bssid %pM successfully\n", | ||
1424 | priv->cfg_bssid); | ||
1425 | } else { | ||
1426 | dev_dbg(priv->adapter->dev, | ||
1427 | "info: association to bssid %pM failed\n", | ||
1428 | priv->cfg_bssid); | ||
1429 | memset(priv->cfg_bssid, 0, ETH_ALEN); | ||
1430 | } | ||
1431 | priv->assoc_request = 0; | ||
1432 | priv->assoc_result = 0; | ||
1433 | } | ||
1434 | |||
1435 | if (priv->ibss_join_request) { | ||
1436 | if (!priv->ibss_join_result) { | ||
1437 | cfg80211_ibss_joined(priv->netdev, priv->cfg_bssid, | ||
1438 | GFP_KERNEL); | ||
1439 | dev_dbg(priv->adapter->dev, | ||
1440 | "info: joined/created adhoc network with bssid" | ||
1441 | " %pM successfully\n", priv->cfg_bssid); | ||
1442 | } else { | ||
1443 | dev_dbg(priv->adapter->dev, | ||
1444 | "info: failed creating/joining adhoc network\n"); | ||
1445 | } | ||
1446 | priv->ibss_join_request = 0; | ||
1447 | priv->ibss_join_result = 0; | ||
1448 | } | ||
1449 | |||
1450 | if (priv->disconnect) { | ||
1451 | memset(priv->cfg_bssid, 0, ETH_ALEN); | ||
1452 | priv->disconnect = 0; | ||
1453 | } | ||
1454 | |||
1455 | return; | ||
1456 | } | ||
diff --git a/drivers/net/wireless/mwifiex/cfg80211.h b/drivers/net/wireless/mwifiex/cfg80211.h new file mode 100644 index 000000000000..c4db8f36aa16 --- /dev/null +++ b/drivers/net/wireless/mwifiex/cfg80211.h | |||
@@ -0,0 +1,31 @@ | |||
1 | /* | ||
2 | * Marvell Wireless LAN device driver: CFG80211 | ||
3 | * | ||
4 | * Copyright (C) 2011, Marvell International Ltd. | ||
5 | * | ||
6 | * This software file (the "File") is distributed by Marvell International | ||
7 | * Ltd. under the terms of the GNU General Public License Version 2, June 1991 | ||
8 | * (the "License"). You may use, redistribute and/or modify this File in | ||
9 | * accordance with the terms and conditions of the License, a copy of which | ||
10 | * is available by writing to the Free Software Foundation, Inc., | ||
11 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the | ||
12 | * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. | ||
13 | * | ||
14 | * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE | ||
15 | * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE | ||
16 | * ARE EXPRESSLY DISCLAIMED. The License provides additional details about | ||
17 | * this warranty disclaimer. | ||
18 | */ | ||
19 | |||
20 | #ifndef __MWIFIEX_CFG80211__ | ||
21 | #define __MWIFIEX_CFG80211__ | ||
22 | |||
23 | #include <net/cfg80211.h> | ||
24 | |||
25 | #include "main.h" | ||
26 | |||
27 | int mwifiex_register_cfg80211(struct net_device *, u8 *, | ||
28 | struct mwifiex_private *); | ||
29 | |||
30 | void mwifiex_cfg80211_results(struct work_struct *work); | ||
31 | #endif | ||
diff --git a/drivers/net/wireless/mwifiex/cfp.c b/drivers/net/wireless/mwifiex/cfp.c new file mode 100644 index 000000000000..07187a405fee --- /dev/null +++ b/drivers/net/wireless/mwifiex/cfp.c | |||
@@ -0,0 +1,367 @@ | |||
1 | /* | ||
2 | * Marvell Wireless LAN device driver: Channel, Frequence and Power | ||
3 | * | ||
4 | * Copyright (C) 2011, Marvell International Ltd. | ||
5 | * | ||
6 | * This software file (the "File") is distributed by Marvell International | ||
7 | * Ltd. under the terms of the GNU General Public License Version 2, June 1991 | ||
8 | * (the "License"). You may use, redistribute and/or modify this File in | ||
9 | * accordance with the terms and conditions of the License, a copy of which | ||
10 | * is available by writing to the Free Software Foundation, Inc., | ||
11 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the | ||
12 | * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. | ||
13 | * | ||
14 | * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE | ||
15 | * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE | ||
16 | * ARE EXPRESSLY DISCLAIMED. The License provides additional details about | ||
17 | * this warranty disclaimer. | ||
18 | */ | ||
19 | |||
20 | #include "decl.h" | ||
21 | #include "ioctl.h" | ||
22 | #include "util.h" | ||
23 | #include "fw.h" | ||
24 | #include "main.h" | ||
25 | #include "cfg80211.h" | ||
26 | |||
27 | /* 100mW */ | ||
28 | #define MWIFIEX_TX_PWR_DEFAULT 20 | ||
29 | /* 100mW */ | ||
30 | #define MWIFIEX_TX_PWR_US_DEFAULT 20 | ||
31 | /* 50mW */ | ||
32 | #define MWIFIEX_TX_PWR_JP_DEFAULT 16 | ||
33 | /* 100mW */ | ||
34 | #define MWIFIEX_TX_PWR_FR_100MW 20 | ||
35 | /* 10mW */ | ||
36 | #define MWIFIEX_TX_PWR_FR_10MW 10 | ||
37 | /* 100mW */ | ||
38 | #define MWIFIEX_TX_PWR_EMEA_DEFAULT 20 | ||
39 | |||
40 | static u8 adhoc_rates_b[B_SUPPORTED_RATES] = { 0x82, 0x84, 0x8b, 0x96, 0 }; | ||
41 | |||
42 | static u8 adhoc_rates_g[G_SUPPORTED_RATES] = { 0x8c, 0x12, 0x98, 0x24, | ||
43 | 0xb0, 0x48, 0x60, 0x6c, 0 }; | ||
44 | |||
45 | static u8 adhoc_rates_bg[BG_SUPPORTED_RATES] = { 0x82, 0x84, 0x8b, 0x96, | ||
46 | 0x0c, 0x12, 0x18, 0x24, | ||
47 | 0x30, 0x48, 0x60, 0x6c, 0 }; | ||
48 | |||
49 | static u8 adhoc_rates_a[A_SUPPORTED_RATES] = { 0x8c, 0x12, 0x98, 0x24, | ||
50 | 0xb0, 0x48, 0x60, 0x6c, 0 }; | ||
51 | u8 supported_rates_a[A_SUPPORTED_RATES] = { 0x0c, 0x12, 0x18, 0x24, | ||
52 | 0xb0, 0x48, 0x60, 0x6c, 0 }; | ||
53 | static u16 mwifiex_data_rates[MWIFIEX_SUPPORTED_RATES_EXT] = { 0x02, 0x04, | ||
54 | 0x0B, 0x16, 0x00, 0x0C, 0x12, 0x18, | ||
55 | 0x24, 0x30, 0x48, 0x60, 0x6C, 0x90, | ||
56 | 0x0D, 0x1A, 0x27, 0x34, 0x4E, 0x68, | ||
57 | 0x75, 0x82, 0x0C, 0x1B, 0x36, 0x51, | ||
58 | 0x6C, 0xA2, 0xD8, 0xF3, 0x10E, 0x00 }; | ||
59 | |||
60 | u8 supported_rates_b[B_SUPPORTED_RATES] = { 0x02, 0x04, 0x0b, 0x16, 0 }; | ||
61 | |||
62 | u8 supported_rates_g[G_SUPPORTED_RATES] = { 0x0c, 0x12, 0x18, 0x24, | ||
63 | 0x30, 0x48, 0x60, 0x6c, 0 }; | ||
64 | |||
65 | u8 supported_rates_bg[BG_SUPPORTED_RATES] = { 0x02, 0x04, 0x0b, 0x0c, | ||
66 | 0x12, 0x16, 0x18, 0x24, 0x30, 0x48, | ||
67 | 0x60, 0x6c, 0 }; | ||
68 | |||
69 | u16 region_code_index[MWIFIEX_MAX_REGION_CODE] = { 0x10, 0x20, 0x30, | ||
70 | 0x32, 0x40, 0x41, 0xff }; | ||
71 | |||
72 | u8 supported_rates_n[N_SUPPORTED_RATES] = { 0x02, 0x04, 0 }; | ||
73 | |||
74 | /* | ||
75 | * This function maps an index in supported rates table into | ||
76 | * the corresponding data rate. | ||
77 | */ | ||
78 | u32 mwifiex_index_to_data_rate(struct mwifiex_adapter *adapter, u8 index, | ||
79 | u8 ht_info) | ||
80 | { | ||
81 | u16 mcs_rate[4][8] = { | ||
82 | {0x1b, 0x36, 0x51, 0x6c, 0xa2, 0xd8, 0xf3, 0x10e} | ||
83 | , /* LG 40M */ | ||
84 | {0x1e, 0x3c, 0x5a, 0x78, 0xb4, 0xf0, 0x10e, 0x12c} | ||
85 | , /* SG 40M */ | ||
86 | {0x0d, 0x1a, 0x27, 0x34, 0x4e, 0x68, 0x75, 0x82} | ||
87 | , /* LG 20M */ | ||
88 | {0x0e, 0x1c, 0x2b, 0x39, 0x56, 0x73, 0x82, 0x90} | ||
89 | }; /* SG 20M */ | ||
90 | |||
91 | u32 rate; | ||
92 | |||
93 | if (ht_info & BIT(0)) { | ||
94 | if (index == MWIFIEX_RATE_BITMAP_MCS0) { | ||
95 | if (ht_info & BIT(2)) | ||
96 | rate = 0x0D; /* MCS 32 SGI rate */ | ||
97 | else | ||
98 | rate = 0x0C; /* MCS 32 LGI rate */ | ||
99 | } else if (index < 8) { | ||
100 | if (ht_info & BIT(1)) { | ||
101 | if (ht_info & BIT(2)) | ||
102 | /* SGI, 40M */ | ||
103 | rate = mcs_rate[1][index]; | ||
104 | else | ||
105 | /* LGI, 40M */ | ||
106 | rate = mcs_rate[0][index]; | ||
107 | } else { | ||
108 | if (ht_info & BIT(2)) | ||
109 | /* SGI, 20M */ | ||
110 | rate = mcs_rate[3][index]; | ||
111 | else | ||
112 | /* LGI, 20M */ | ||
113 | rate = mcs_rate[2][index]; | ||
114 | } | ||
115 | } else | ||
116 | rate = mwifiex_data_rates[0]; | ||
117 | } else { | ||
118 | if (index >= MWIFIEX_SUPPORTED_RATES_EXT) | ||
119 | index = 0; | ||
120 | rate = mwifiex_data_rates[index]; | ||
121 | } | ||
122 | return rate; | ||
123 | } | ||
124 | |||
125 | /* | ||
126 | * This function maps a data rate value into corresponding index in supported | ||
127 | * rates table. | ||
128 | */ | ||
129 | u8 mwifiex_data_rate_to_index(struct mwifiex_adapter *adapter, u32 rate) | ||
130 | { | ||
131 | u16 *ptr; | ||
132 | |||
133 | if (rate) { | ||
134 | ptr = memchr(mwifiex_data_rates, rate, | ||
135 | sizeof(mwifiex_data_rates)); | ||
136 | if (ptr) | ||
137 | return (u8) (ptr - mwifiex_data_rates); | ||
138 | } | ||
139 | return 0; | ||
140 | } | ||
141 | |||
142 | /* | ||
143 | * This function returns the current active data rates. | ||
144 | * | ||
145 | * The result may vary depending upon connection status. | ||
146 | */ | ||
147 | u32 mwifiex_get_active_data_rates(struct mwifiex_private *priv, u8 *rates) | ||
148 | { | ||
149 | u32 k; | ||
150 | |||
151 | if (!priv->media_connected) | ||
152 | k = mwifiex_get_supported_rates(priv, rates); | ||
153 | else | ||
154 | k = mwifiex_copy_rates(rates, 0, | ||
155 | priv->curr_bss_params.data_rates, | ||
156 | priv->curr_bss_params.num_of_rates); | ||
157 | |||
158 | return k; | ||
159 | } | ||
160 | |||
161 | /* | ||
162 | * This function locates the Channel-Frequency-Power triplet based upon | ||
163 | * band and channel parameters. | ||
164 | */ | ||
165 | struct mwifiex_chan_freq_power * | ||
166 | mwifiex_get_cfp_by_band_and_channel_from_cfg80211(struct mwifiex_private | ||
167 | *priv, u8 band, u16 channel) | ||
168 | { | ||
169 | struct mwifiex_chan_freq_power *cfp = NULL; | ||
170 | struct ieee80211_supported_band *sband; | ||
171 | struct ieee80211_channel *ch; | ||
172 | int i; | ||
173 | |||
174 | if (mwifiex_band_to_radio_type(band) == HostCmd_SCAN_RADIO_TYPE_BG) | ||
175 | sband = priv->wdev->wiphy->bands[IEEE80211_BAND_2GHZ]; | ||
176 | else | ||
177 | sband = priv->wdev->wiphy->bands[IEEE80211_BAND_5GHZ]; | ||
178 | |||
179 | if (!sband) { | ||
180 | dev_err(priv->adapter->dev, "%s: cannot find cfp by band %d" | ||
181 | " & channel %d\n", __func__, band, channel); | ||
182 | return cfp; | ||
183 | } | ||
184 | |||
185 | for (i = 0; i < sband->n_channels; i++) { | ||
186 | ch = &sband->channels[i]; | ||
187 | if (((ch->hw_value == channel) || | ||
188 | (channel == FIRST_VALID_CHANNEL)) | ||
189 | && !(ch->flags & IEEE80211_CHAN_DISABLED)) { | ||
190 | priv->cfp.channel = channel; | ||
191 | priv->cfp.freq = ch->center_freq; | ||
192 | priv->cfp.max_tx_power = ch->max_power; | ||
193 | cfp = &priv->cfp; | ||
194 | break; | ||
195 | } | ||
196 | } | ||
197 | if (i == sband->n_channels) | ||
198 | dev_err(priv->adapter->dev, "%s: cannot find cfp by band %d" | ||
199 | " & channel %d\n", __func__, band, channel); | ||
200 | |||
201 | return cfp; | ||
202 | } | ||
203 | |||
204 | /* | ||
205 | * This function locates the Channel-Frequency-Power triplet based upon | ||
206 | * band and frequency parameters. | ||
207 | */ | ||
208 | struct mwifiex_chan_freq_power * | ||
209 | mwifiex_get_cfp_by_band_and_freq_from_cfg80211(struct mwifiex_private *priv, | ||
210 | u8 band, u32 freq) | ||
211 | { | ||
212 | struct mwifiex_chan_freq_power *cfp = NULL; | ||
213 | struct ieee80211_supported_band *sband; | ||
214 | struct ieee80211_channel *ch; | ||
215 | int i; | ||
216 | |||
217 | if (mwifiex_band_to_radio_type(band) == HostCmd_SCAN_RADIO_TYPE_BG) | ||
218 | sband = priv->wdev->wiphy->bands[IEEE80211_BAND_2GHZ]; | ||
219 | else | ||
220 | sband = priv->wdev->wiphy->bands[IEEE80211_BAND_5GHZ]; | ||
221 | |||
222 | if (!sband) { | ||
223 | dev_err(priv->adapter->dev, "%s: cannot find cfp by band %d" | ||
224 | " & freq %d\n", __func__, band, freq); | ||
225 | return cfp; | ||
226 | } | ||
227 | |||
228 | for (i = 0; i < sband->n_channels; i++) { | ||
229 | ch = &sband->channels[i]; | ||
230 | if ((ch->center_freq == freq) && | ||
231 | !(ch->flags & IEEE80211_CHAN_DISABLED)) { | ||
232 | priv->cfp.channel = ch->hw_value; | ||
233 | priv->cfp.freq = freq; | ||
234 | priv->cfp.max_tx_power = ch->max_power; | ||
235 | cfp = &priv->cfp; | ||
236 | break; | ||
237 | } | ||
238 | } | ||
239 | if (i == sband->n_channels) | ||
240 | dev_err(priv->adapter->dev, "%s: cannot find cfp by band %d" | ||
241 | " & freq %d\n", __func__, band, freq); | ||
242 | |||
243 | return cfp; | ||
244 | } | ||
245 | |||
246 | /* | ||
247 | * This function checks if the data rate is set to auto. | ||
248 | */ | ||
249 | u8 | ||
250 | mwifiex_is_rate_auto(struct mwifiex_private *priv) | ||
251 | { | ||
252 | u32 i; | ||
253 | int rate_num = 0; | ||
254 | |||
255 | for (i = 0; i < ARRAY_SIZE(priv->bitmap_rates); i++) | ||
256 | if (priv->bitmap_rates[i]) | ||
257 | rate_num++; | ||
258 | |||
259 | if (rate_num > 1) | ||
260 | return true; | ||
261 | else | ||
262 | return false; | ||
263 | } | ||
264 | |||
265 | /* | ||
266 | * This function converts rate bitmap into rate index. | ||
267 | */ | ||
268 | int | ||
269 | mwifiex_get_rate_index(struct mwifiex_adapter *adapter, u16 *rate_bitmap, | ||
270 | int size) | ||
271 | { | ||
272 | int i; | ||
273 | |||
274 | for (i = 0; i < size * 8; i++) | ||
275 | if (rate_bitmap[i / 16] & (1 << (i % 16))) | ||
276 | return i; | ||
277 | |||
278 | return 0; | ||
279 | } | ||
280 | |||
281 | /* | ||
282 | * This function gets the supported data rates. | ||
283 | * | ||
284 | * The function works in both Ad-Hoc and infra mode by printing the | ||
285 | * band and returning the data rates. | ||
286 | */ | ||
287 | u32 mwifiex_get_supported_rates(struct mwifiex_private *priv, u8 *rates) | ||
288 | { | ||
289 | u32 k = 0; | ||
290 | struct mwifiex_adapter *adapter = priv->adapter; | ||
291 | if (priv->bss_mode == NL80211_IFTYPE_STATION) { | ||
292 | switch (adapter->config_bands) { | ||
293 | case BAND_B: | ||
294 | dev_dbg(adapter->dev, "info: infra band=%d " | ||
295 | "supported_rates_b\n", adapter->config_bands); | ||
296 | k = mwifiex_copy_rates(rates, k, supported_rates_b, | ||
297 | sizeof(supported_rates_b)); | ||
298 | break; | ||
299 | case BAND_G: | ||
300 | case BAND_G | BAND_GN: | ||
301 | dev_dbg(adapter->dev, "info: infra band=%d " | ||
302 | "supported_rates_g\n", adapter->config_bands); | ||
303 | k = mwifiex_copy_rates(rates, k, supported_rates_g, | ||
304 | sizeof(supported_rates_g)); | ||
305 | break; | ||
306 | case BAND_B | BAND_G: | ||
307 | case BAND_A | BAND_B | BAND_G: | ||
308 | case BAND_A | BAND_B: | ||
309 | case BAND_A | BAND_B | BAND_G | BAND_GN | BAND_AN: | ||
310 | case BAND_B | BAND_G | BAND_GN: | ||
311 | dev_dbg(adapter->dev, "info: infra band=%d " | ||
312 | "supported_rates_bg\n", adapter->config_bands); | ||
313 | k = mwifiex_copy_rates(rates, k, supported_rates_bg, | ||
314 | sizeof(supported_rates_bg)); | ||
315 | break; | ||
316 | case BAND_A: | ||
317 | case BAND_A | BAND_G: | ||
318 | dev_dbg(adapter->dev, "info: infra band=%d " | ||
319 | "supported_rates_a\n", adapter->config_bands); | ||
320 | k = mwifiex_copy_rates(rates, k, supported_rates_a, | ||
321 | sizeof(supported_rates_a)); | ||
322 | break; | ||
323 | case BAND_A | BAND_AN: | ||
324 | case BAND_A | BAND_G | BAND_AN | BAND_GN: | ||
325 | dev_dbg(adapter->dev, "info: infra band=%d " | ||
326 | "supported_rates_a\n", adapter->config_bands); | ||
327 | k = mwifiex_copy_rates(rates, k, supported_rates_a, | ||
328 | sizeof(supported_rates_a)); | ||
329 | break; | ||
330 | case BAND_GN: | ||
331 | dev_dbg(adapter->dev, "info: infra band=%d " | ||
332 | "supported_rates_n\n", adapter->config_bands); | ||
333 | k = mwifiex_copy_rates(rates, k, supported_rates_n, | ||
334 | sizeof(supported_rates_n)); | ||
335 | break; | ||
336 | } | ||
337 | } else { | ||
338 | /* Ad-hoc mode */ | ||
339 | switch (adapter->adhoc_start_band) { | ||
340 | case BAND_B: | ||
341 | dev_dbg(adapter->dev, "info: adhoc B\n"); | ||
342 | k = mwifiex_copy_rates(rates, k, adhoc_rates_b, | ||
343 | sizeof(adhoc_rates_b)); | ||
344 | break; | ||
345 | case BAND_G: | ||
346 | case BAND_G | BAND_GN: | ||
347 | dev_dbg(adapter->dev, "info: adhoc G only\n"); | ||
348 | k = mwifiex_copy_rates(rates, k, adhoc_rates_g, | ||
349 | sizeof(adhoc_rates_g)); | ||
350 | break; | ||
351 | case BAND_B | BAND_G: | ||
352 | case BAND_B | BAND_G | BAND_GN: | ||
353 | dev_dbg(adapter->dev, "info: adhoc BG\n"); | ||
354 | k = mwifiex_copy_rates(rates, k, adhoc_rates_bg, | ||
355 | sizeof(adhoc_rates_bg)); | ||
356 | break; | ||
357 | case BAND_A: | ||
358 | case BAND_A | BAND_AN: | ||
359 | dev_dbg(adapter->dev, "info: adhoc A\n"); | ||
360 | k = mwifiex_copy_rates(rates, k, adhoc_rates_a, | ||
361 | sizeof(adhoc_rates_a)); | ||
362 | break; | ||
363 | } | ||
364 | } | ||
365 | |||
366 | return k; | ||
367 | } | ||
diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c new file mode 100644 index 000000000000..a9aeb31af455 --- /dev/null +++ b/drivers/net/wireless/mwifiex/cmdevt.c | |||
@@ -0,0 +1,1459 @@ | |||
1 | /* | ||
2 | * Marvell Wireless LAN device driver: commands and events | ||
3 | * | ||
4 | * Copyright (C) 2011, Marvell International Ltd. | ||
5 | * | ||
6 | * This software file (the "File") is distributed by Marvell International | ||
7 | * Ltd. under the terms of the GNU General Public License Version 2, June 1991 | ||
8 | * (the "License"). You may use, redistribute and/or modify this File in | ||
9 | * accordance with the terms and conditions of the License, a copy of which | ||
10 | * is available by writing to the Free Software Foundation, Inc., | ||
11 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the | ||
12 | * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. | ||
13 | * | ||
14 | * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE | ||
15 | * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE | ||
16 | * ARE EXPRESSLY DISCLAIMED. The License provides additional details about | ||
17 | * this warranty disclaimer. | ||
18 | */ | ||
19 | |||
20 | #include "decl.h" | ||
21 | #include "ioctl.h" | ||
22 | #include "util.h" | ||
23 | #include "fw.h" | ||
24 | #include "main.h" | ||
25 | #include "wmm.h" | ||
26 | #include "11n.h" | ||
27 | |||
28 | /* | ||
29 | * This function initializes a command node. | ||
30 | * | ||
31 | * The actual allocation of the node is not done by this function. It only | ||
32 | * initiates a node by filling it with default parameters. Similarly, | ||
33 | * allocation of the different buffers used (IOCTL buffer, data buffer) are | ||
34 | * not done by this function either. | ||
35 | */ | ||
36 | static void | ||
37 | mwifiex_init_cmd_node(struct mwifiex_private *priv, | ||
38 | struct cmd_ctrl_node *cmd_node, | ||
39 | u32 cmd_oid, void *wait_queue, void *data_buf) | ||
40 | { | ||
41 | cmd_node->priv = priv; | ||
42 | cmd_node->cmd_oid = cmd_oid; | ||
43 | cmd_node->wq_buf = wait_queue; | ||
44 | cmd_node->data_buf = data_buf; | ||
45 | cmd_node->cmd_skb = cmd_node->skb; | ||
46 | } | ||
47 | |||
48 | /* | ||
49 | * This function returns a command node from the free queue depending upon | ||
50 | * availability. | ||
51 | */ | ||
52 | static struct cmd_ctrl_node * | ||
53 | mwifiex_get_cmd_node(struct mwifiex_adapter *adapter) | ||
54 | { | ||
55 | struct cmd_ctrl_node *cmd_node; | ||
56 | unsigned long flags; | ||
57 | |||
58 | spin_lock_irqsave(&adapter->cmd_free_q_lock, flags); | ||
59 | if (list_empty(&adapter->cmd_free_q)) { | ||
60 | dev_err(adapter->dev, "GET_CMD_NODE: cmd node not available\n"); | ||
61 | spin_unlock_irqrestore(&adapter->cmd_free_q_lock, flags); | ||
62 | return NULL; | ||
63 | } | ||
64 | cmd_node = list_first_entry(&adapter->cmd_free_q, | ||
65 | struct cmd_ctrl_node, list); | ||
66 | list_del(&cmd_node->list); | ||
67 | spin_unlock_irqrestore(&adapter->cmd_free_q_lock, flags); | ||
68 | |||
69 | return cmd_node; | ||
70 | } | ||
71 | |||
72 | /* | ||
73 | * This function cleans up a command node. | ||
74 | * | ||
75 | * The function resets the fields including the buffer pointers. | ||
76 | * This function does not try to free the buffers. They must be | ||
77 | * freed before calling this function. | ||
78 | * | ||
79 | * This function will however call the receive completion callback | ||
80 | * in case a response buffer is still available before resetting | ||
81 | * the pointer. | ||
82 | */ | ||
83 | static void | ||
84 | mwifiex_clean_cmd_node(struct mwifiex_adapter *adapter, | ||
85 | struct cmd_ctrl_node *cmd_node) | ||
86 | { | ||
87 | cmd_node->cmd_oid = 0; | ||
88 | cmd_node->cmd_flag = 0; | ||
89 | cmd_node->wq_buf = NULL; | ||
90 | cmd_node->data_buf = NULL; | ||
91 | |||
92 | if (cmd_node->resp_skb) { | ||
93 | mwifiex_recv_complete(adapter, cmd_node->resp_skb, 0); | ||
94 | cmd_node->resp_skb = NULL; | ||
95 | } | ||
96 | |||
97 | return; | ||
98 | } | ||
99 | |||
100 | /* | ||
101 | * This function returns a command node from the pending queue which | ||
102 | * matches the given IOCTL request. | ||
103 | */ | ||
104 | static struct cmd_ctrl_node * | ||
105 | mwifiex_get_pending_ioctl_cmd(struct mwifiex_adapter *adapter, | ||
106 | struct mwifiex_wait_queue *wait_queue) | ||
107 | { | ||
108 | unsigned long flags; | ||
109 | struct cmd_ctrl_node *cmd_node; | ||
110 | |||
111 | spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags); | ||
112 | list_for_each_entry(cmd_node, &adapter->cmd_pending_q, list) { | ||
113 | if (cmd_node->wq_buf == wait_queue) { | ||
114 | spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, | ||
115 | flags); | ||
116 | return cmd_node; | ||
117 | } | ||
118 | } | ||
119 | spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags); | ||
120 | |||
121 | return NULL; | ||
122 | } | ||
123 | |||
124 | /* | ||
125 | * This function sends a host command to the firmware. | ||
126 | * | ||
127 | * The function copies the host command into the driver command | ||
128 | * buffer, which will be transferred to the firmware later by the | ||
129 | * main thread. | ||
130 | */ | ||
131 | static int mwifiex_cmd_host_cmd(struct mwifiex_private *priv, | ||
132 | struct host_cmd_ds_command *cmd, void *data_buf) | ||
133 | { | ||
134 | struct mwifiex_ds_misc_cmd *pcmd_ptr = | ||
135 | (struct mwifiex_ds_misc_cmd *) data_buf; | ||
136 | |||
137 | /* Copy the HOST command to command buffer */ | ||
138 | memcpy((void *) cmd, pcmd_ptr->cmd, pcmd_ptr->len); | ||
139 | dev_dbg(priv->adapter->dev, "cmd: host cmd size = %d\n", pcmd_ptr->len); | ||
140 | return 0; | ||
141 | } | ||
142 | |||
143 | /* | ||
144 | * This function downloads a command to the firmware. | ||
145 | * | ||
146 | * The function performs sanity tests, sets the command sequence | ||
147 | * number and size, converts the header fields to CPU format before | ||
148 | * sending. Afterwards, it logs the command ID and action for debugging | ||
149 | * and sets up the command timeout timer. | ||
150 | */ | ||
151 | static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv, | ||
152 | struct cmd_ctrl_node *cmd_node) | ||
153 | { | ||
154 | |||
155 | struct mwifiex_adapter *adapter = priv->adapter; | ||
156 | int ret = 0; | ||
157 | struct host_cmd_ds_command *host_cmd; | ||
158 | struct mwifiex_wait_queue *wait_queue = NULL; | ||
159 | uint16_t cmd_code; | ||
160 | uint16_t cmd_size; | ||
161 | struct timeval tstamp; | ||
162 | unsigned long flags; | ||
163 | |||
164 | if (!adapter || !cmd_node) | ||
165 | return -1; | ||
166 | |||
167 | host_cmd = (struct host_cmd_ds_command *) (cmd_node->cmd_skb->data); | ||
168 | if (cmd_node->wq_buf) | ||
169 | wait_queue = (struct mwifiex_wait_queue *) cmd_node->wq_buf; | ||
170 | |||
171 | /* Sanity test */ | ||
172 | if (host_cmd == NULL || host_cmd->size == 0) { | ||
173 | dev_err(adapter->dev, "DNLD_CMD: host_cmd is null" | ||
174 | " or cmd size is 0, not sending\n"); | ||
175 | if (wait_queue) | ||
176 | wait_queue->status = MWIFIEX_ERROR_CMD_DNLD_FAIL; | ||
177 | mwifiex_insert_cmd_to_free_q(adapter, cmd_node); | ||
178 | return -1; | ||
179 | } | ||
180 | |||
181 | /* Set command sequence number */ | ||
182 | adapter->seq_num++; | ||
183 | host_cmd->seq_num = cpu_to_le16(HostCmd_SET_SEQ_NO_BSS_INFO | ||
184 | (adapter->seq_num, cmd_node->priv->bss_num, | ||
185 | cmd_node->priv->bss_type)); | ||
186 | |||
187 | spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); | ||
188 | adapter->curr_cmd = cmd_node; | ||
189 | spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); | ||
190 | |||
191 | cmd_code = le16_to_cpu(host_cmd->command); | ||
192 | cmd_size = le16_to_cpu(host_cmd->size); | ||
193 | |||
194 | skb_trim(cmd_node->cmd_skb, cmd_size); | ||
195 | |||
196 | do_gettimeofday(&tstamp); | ||
197 | dev_dbg(adapter->dev, "cmd: DNLD_CMD: (%lu.%lu): %#x, act %#x, len %d," | ||
198 | " seqno %#x\n", | ||
199 | tstamp.tv_sec, tstamp.tv_usec, cmd_code, | ||
200 | le16_to_cpu(*(__le16 *) ((u8 *) host_cmd + S_DS_GEN)), cmd_size, | ||
201 | le16_to_cpu(host_cmd->seq_num)); | ||
202 | |||
203 | skb_push(cmd_node->cmd_skb, INTF_HEADER_LEN); | ||
204 | |||
205 | ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_CMD, | ||
206 | cmd_node->cmd_skb->data, | ||
207 | cmd_node->cmd_skb->len, NULL); | ||
208 | |||
209 | if (ret == -1) { | ||
210 | dev_err(adapter->dev, "DNLD_CMD: host to card failed\n"); | ||
211 | if (wait_queue) | ||
212 | wait_queue->status = MWIFIEX_ERROR_CMD_DNLD_FAIL; | ||
213 | mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd); | ||
214 | |||
215 | spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); | ||
216 | adapter->curr_cmd = NULL; | ||
217 | spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); | ||
218 | |||
219 | adapter->dbg.num_cmd_host_to_card_failure++; | ||
220 | return -1; | ||
221 | } | ||
222 | |||
223 | /* Save the last command id and action to debug log */ | ||
224 | adapter->dbg.last_cmd_index = | ||
225 | (adapter->dbg.last_cmd_index + 1) % DBG_CMD_NUM; | ||
226 | adapter->dbg.last_cmd_id[adapter->dbg.last_cmd_index] = cmd_code; | ||
227 | adapter->dbg.last_cmd_act[adapter->dbg.last_cmd_index] = | ||
228 | le16_to_cpu(*(__le16 *) ((u8 *) host_cmd + S_DS_GEN)); | ||
229 | |||
230 | /* Clear BSS_NO_BITS from HostCmd */ | ||
231 | cmd_code &= HostCmd_CMD_ID_MASK; | ||
232 | |||
233 | /* Setup the timer after transmit command */ | ||
234 | mod_timer(&adapter->cmd_timer, | ||
235 | jiffies + (MWIFIEX_TIMER_10S * HZ) / 1000); | ||
236 | |||
237 | return 0; | ||
238 | } | ||
239 | |||
240 | /* | ||
241 | * This function downloads a sleep confirm command to the firmware. | ||
242 | * | ||
243 | * The function performs sanity tests, sets the command sequence | ||
244 | * number and size, converts the header fields to CPU format before | ||
245 | * sending. | ||
246 | * | ||
247 | * No responses are needed for sleep confirm command. | ||
248 | */ | ||
249 | static int mwifiex_dnld_sleep_confirm_cmd(struct mwifiex_adapter *adapter) | ||
250 | { | ||
251 | int ret = 0; | ||
252 | u16 cmd_len = 0; | ||
253 | struct mwifiex_private *priv; | ||
254 | struct mwifiex_opt_sleep_confirm_buffer *sleep_cfm_buf = | ||
255 | (struct mwifiex_opt_sleep_confirm_buffer *) | ||
256 | adapter->sleep_cfm->data; | ||
257 | cmd_len = sizeof(struct mwifiex_opt_sleep_confirm); | ||
258 | priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); | ||
259 | |||
260 | sleep_cfm_buf->ps_cfm_sleep.seq_num = | ||
261 | cpu_to_le16((HostCmd_SET_SEQ_NO_BSS_INFO | ||
262 | (adapter->seq_num, priv->bss_num, | ||
263 | priv->bss_type))); | ||
264 | adapter->seq_num++; | ||
265 | |||
266 | ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_CMD, | ||
267 | adapter->sleep_cfm->data, | ||
268 | adapter->sleep_cfm->len + | ||
269 | INTF_HEADER_LEN, NULL); | ||
270 | |||
271 | if (ret == -1) { | ||
272 | dev_err(adapter->dev, "SLEEP_CFM: failed\n"); | ||
273 | adapter->dbg.num_cmd_sleep_cfm_host_to_card_failure++; | ||
274 | return -1; | ||
275 | } | ||
276 | if (GET_BSS_ROLE(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY)) | ||
277 | == MWIFIEX_BSS_ROLE_STA) { | ||
278 | if (!sleep_cfm_buf->ps_cfm_sleep.resp_ctrl) | ||
279 | /* Response is not needed for sleep | ||
280 | confirm command */ | ||
281 | adapter->ps_state = PS_STATE_SLEEP; | ||
282 | else | ||
283 | adapter->ps_state = PS_STATE_SLEEP_CFM; | ||
284 | |||
285 | if (!sleep_cfm_buf->ps_cfm_sleep.resp_ctrl | ||
286 | && (adapter->is_hs_configured | ||
287 | && !adapter->sleep_period.period)) { | ||
288 | adapter->pm_wakeup_card_req = true; | ||
289 | mwifiex_hs_activated_event(mwifiex_get_priv(adapter, | ||
290 | MWIFIEX_BSS_ROLE_STA), true); | ||
291 | } | ||
292 | } | ||
293 | |||
294 | return ret; | ||
295 | } | ||
296 | |||
297 | /* | ||
298 | * This function allocates the command buffers and links them to | ||
299 | * the command free queue. | ||
300 | * | ||
301 | * The driver uses a pre allocated number of command buffers, which | ||
302 | * are created at driver initializations and freed at driver cleanup. | ||
303 | * Every command needs to obtain a command buffer from this pool before | ||
304 | * it can be issued. The command free queue lists the command buffers | ||
305 | * currently free to use, while the command pending queue lists the | ||
306 | * command buffers already in use and awaiting handling. Command buffers | ||
307 | * are returned to the free queue after use. | ||
308 | */ | ||
309 | int mwifiex_alloc_cmd_buffer(struct mwifiex_adapter *adapter) | ||
310 | { | ||
311 | struct cmd_ctrl_node *cmd_array; | ||
312 | u32 buf_size; | ||
313 | u32 i; | ||
314 | |||
315 | /* Allocate and initialize struct cmd_ctrl_node */ | ||
316 | buf_size = sizeof(struct cmd_ctrl_node) * MWIFIEX_NUM_OF_CMD_BUFFER; | ||
317 | cmd_array = kzalloc(buf_size, GFP_KERNEL); | ||
318 | if (!cmd_array) { | ||
319 | dev_err(adapter->dev, "%s: failed to alloc cmd_array\n", | ||
320 | __func__); | ||
321 | return -1; | ||
322 | } | ||
323 | |||
324 | adapter->cmd_pool = cmd_array; | ||
325 | memset(adapter->cmd_pool, 0, buf_size); | ||
326 | |||
327 | /* Allocate and initialize command buffers */ | ||
328 | for (i = 0; i < MWIFIEX_NUM_OF_CMD_BUFFER; i++) { | ||
329 | cmd_array[i].skb = dev_alloc_skb(MWIFIEX_SIZE_OF_CMD_BUFFER); | ||
330 | if (!cmd_array[i].skb) { | ||
331 | dev_err(adapter->dev, "ALLOC_CMD_BUF: out of memory\n"); | ||
332 | return -1; | ||
333 | } | ||
334 | } | ||
335 | |||
336 | for (i = 0; i < MWIFIEX_NUM_OF_CMD_BUFFER; i++) | ||
337 | mwifiex_insert_cmd_to_free_q(adapter, &cmd_array[i]); | ||
338 | |||
339 | return 0; | ||
340 | } | ||
341 | |||
342 | /* | ||
343 | * This function frees the command buffers. | ||
344 | * | ||
345 | * The function calls the completion callback for all the command | ||
346 | * buffers that still have response buffers associated with them. | ||
347 | */ | ||
348 | int mwifiex_free_cmd_buffer(struct mwifiex_adapter *adapter) | ||
349 | { | ||
350 | struct cmd_ctrl_node *cmd_array; | ||
351 | u32 i; | ||
352 | |||
353 | /* Need to check if cmd pool is allocated or not */ | ||
354 | if (!adapter->cmd_pool) { | ||
355 | dev_dbg(adapter->dev, "info: FREE_CMD_BUF: cmd_pool is null\n"); | ||
356 | return 0; | ||
357 | } | ||
358 | |||
359 | cmd_array = adapter->cmd_pool; | ||
360 | |||
361 | /* Release shared memory buffers */ | ||
362 | for (i = 0; i < MWIFIEX_NUM_OF_CMD_BUFFER; i++) { | ||
363 | if (cmd_array[i].skb) { | ||
364 | dev_dbg(adapter->dev, "cmd: free cmd buffer %d\n", i); | ||
365 | dev_kfree_skb_any(cmd_array[i].skb); | ||
366 | } | ||
367 | if (!cmd_array[i].resp_skb) | ||
368 | continue; | ||
369 | mwifiex_recv_complete(adapter, cmd_array[i].resp_skb, 0); | ||
370 | } | ||
371 | /* Release struct cmd_ctrl_node */ | ||
372 | if (adapter->cmd_pool) { | ||
373 | dev_dbg(adapter->dev, "cmd: free cmd pool\n"); | ||
374 | kfree(adapter->cmd_pool); | ||
375 | adapter->cmd_pool = NULL; | ||
376 | } | ||
377 | |||
378 | return 0; | ||
379 | } | ||
380 | |||
381 | /* | ||
382 | * This function handles events generated by firmware. | ||
383 | * | ||
384 | * Event body of events received from firmware are not used (though they are | ||
385 | * saved), only the event ID is used. Some events are re-invoked by | ||
386 | * the driver, with a new event body. | ||
387 | * | ||
388 | * After processing, the function calls the completion callback | ||
389 | * for cleanup. | ||
390 | */ | ||
391 | int mwifiex_process_event(struct mwifiex_adapter *adapter) | ||
392 | { | ||
393 | int ret = 0; | ||
394 | struct mwifiex_private *priv = | ||
395 | mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); | ||
396 | struct sk_buff *skb = adapter->event_skb; | ||
397 | u32 eventcause = adapter->event_cause; | ||
398 | struct timeval tstamp; | ||
399 | struct mwifiex_rxinfo *rx_info = NULL; | ||
400 | |||
401 | /* Save the last event to debug log */ | ||
402 | adapter->dbg.last_event_index = | ||
403 | (adapter->dbg.last_event_index + 1) % DBG_CMD_NUM; | ||
404 | adapter->dbg.last_event[adapter->dbg.last_event_index] = | ||
405 | (u16) eventcause; | ||
406 | |||
407 | /* Get BSS number and corresponding priv */ | ||
408 | priv = mwifiex_get_priv_by_id(adapter, EVENT_GET_BSS_NUM(eventcause), | ||
409 | EVENT_GET_BSS_TYPE(eventcause)); | ||
410 | if (!priv) | ||
411 | priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); | ||
412 | /* Clear BSS_NO_BITS from event */ | ||
413 | eventcause &= EVENT_ID_MASK; | ||
414 | adapter->event_cause = eventcause; | ||
415 | |||
416 | if (skb) { | ||
417 | rx_info = MWIFIEX_SKB_RXCB(skb); | ||
418 | rx_info->bss_index = priv->bss_index; | ||
419 | } | ||
420 | |||
421 | if (eventcause != EVENT_PS_SLEEP && eventcause != EVENT_PS_AWAKE) { | ||
422 | do_gettimeofday(&tstamp); | ||
423 | dev_dbg(adapter->dev, "event: %lu.%lu: cause: %#x\n", | ||
424 | tstamp.tv_sec, tstamp.tv_usec, eventcause); | ||
425 | } | ||
426 | |||
427 | ret = mwifiex_process_sta_event(priv); | ||
428 | |||
429 | adapter->event_cause = 0; | ||
430 | adapter->event_skb = NULL; | ||
431 | |||
432 | mwifiex_recv_complete(adapter, skb, 0); | ||
433 | |||
434 | return ret; | ||
435 | } | ||
436 | |||
437 | /* | ||
438 | * This function prepares a command before sending it to the firmware. | ||
439 | * | ||
440 | * Preparation includes - | ||
441 | * - Sanity tests to make sure the card is still present or the FW | ||
442 | * is not reset | ||
443 | * - Getting a new command node from the command free queue | ||
444 | * - Initializing the command node for default parameters | ||
445 | * - Fill up the non-default parameters and buffer pointers | ||
446 | * - Add the command to pending queue | ||
447 | */ | ||
448 | int mwifiex_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no, | ||
449 | u16 cmd_action, u32 cmd_oid, | ||
450 | void *wait_queue, void *data_buf) | ||
451 | { | ||
452 | int ret = 0; | ||
453 | struct mwifiex_adapter *adapter = priv->adapter; | ||
454 | struct cmd_ctrl_node *cmd_node = NULL; | ||
455 | struct host_cmd_ds_command *cmd_ptr = NULL; | ||
456 | |||
457 | if (!adapter) { | ||
458 | pr_err("PREP_CMD: adapter is NULL\n"); | ||
459 | return -1; | ||
460 | } | ||
461 | |||
462 | if (adapter->is_suspended) { | ||
463 | dev_err(adapter->dev, "PREP_CMD: device in suspended state\n"); | ||
464 | return -1; | ||
465 | } | ||
466 | |||
467 | if (adapter->surprise_removed) { | ||
468 | dev_err(adapter->dev, "PREP_CMD: card is removed\n"); | ||
469 | return -1; | ||
470 | } | ||
471 | |||
472 | if (adapter->hw_status == MWIFIEX_HW_STATUS_RESET) { | ||
473 | if (cmd_no != HostCmd_CMD_FUNC_INIT) { | ||
474 | dev_err(adapter->dev, "PREP_CMD: FW in reset state\n"); | ||
475 | return -1; | ||
476 | } | ||
477 | } | ||
478 | |||
479 | /* Get a new command node */ | ||
480 | cmd_node = mwifiex_get_cmd_node(adapter); | ||
481 | |||
482 | if (!cmd_node) { | ||
483 | dev_err(adapter->dev, "PREP_CMD: no free cmd node\n"); | ||
484 | return -1; | ||
485 | } | ||
486 | |||
487 | /* Initialize the command node */ | ||
488 | mwifiex_init_cmd_node(priv, cmd_node, cmd_oid, wait_queue, data_buf); | ||
489 | |||
490 | if (!cmd_node->cmd_skb) { | ||
491 | dev_err(adapter->dev, "PREP_CMD: no free cmd buf\n"); | ||
492 | return -1; | ||
493 | } | ||
494 | |||
495 | memset(skb_put(cmd_node->cmd_skb, sizeof(struct host_cmd_ds_command)), | ||
496 | 0, sizeof(struct host_cmd_ds_command)); | ||
497 | |||
498 | cmd_ptr = (struct host_cmd_ds_command *) (cmd_node->cmd_skb->data); | ||
499 | cmd_ptr->command = cpu_to_le16(cmd_no); | ||
500 | cmd_ptr->result = 0; | ||
501 | |||
502 | /* Prepare command */ | ||
503 | if (cmd_no) { | ||
504 | ret = mwifiex_sta_prepare_cmd(priv, cmd_no, cmd_action, | ||
505 | cmd_oid, data_buf, cmd_ptr); | ||
506 | } else { | ||
507 | ret = mwifiex_cmd_host_cmd(priv, cmd_ptr, data_buf); | ||
508 | cmd_node->cmd_flag |= CMD_F_HOSTCMD; | ||
509 | } | ||
510 | |||
511 | /* Return error, since the command preparation failed */ | ||
512 | if (ret) { | ||
513 | dev_err(adapter->dev, "PREP_CMD: cmd %#x preparation failed\n", | ||
514 | cmd_no); | ||
515 | mwifiex_insert_cmd_to_free_q(adapter, cmd_node); | ||
516 | return -1; | ||
517 | } | ||
518 | |||
519 | /* Send command */ | ||
520 | if (cmd_no == HostCmd_CMD_802_11_SCAN) | ||
521 | mwifiex_queue_scan_cmd(priv, cmd_node); | ||
522 | else | ||
523 | mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, true); | ||
524 | |||
525 | return ret; | ||
526 | } | ||
527 | |||
528 | /* | ||
529 | * This function returns a command to the command free queue. | ||
530 | * | ||
531 | * The function also calls the completion callback if required, before | ||
532 | * cleaning the command node and re-inserting it into the free queue. | ||
533 | */ | ||
534 | void | ||
535 | mwifiex_insert_cmd_to_free_q(struct mwifiex_adapter *adapter, | ||
536 | struct cmd_ctrl_node *cmd_node) | ||
537 | { | ||
538 | struct mwifiex_wait_queue *wait_queue = NULL; | ||
539 | unsigned long flags; | ||
540 | |||
541 | if (cmd_node == NULL) | ||
542 | return; | ||
543 | if (cmd_node->wq_buf) { | ||
544 | wait_queue = (struct mwifiex_wait_queue *) cmd_node->wq_buf; | ||
545 | if (wait_queue->status != MWIFIEX_ERROR_NO_ERROR) | ||
546 | mwifiex_ioctl_complete(adapter, wait_queue, -1); | ||
547 | else | ||
548 | mwifiex_ioctl_complete(adapter, wait_queue, 0); | ||
549 | } | ||
550 | /* Clean the node */ | ||
551 | mwifiex_clean_cmd_node(adapter, cmd_node); | ||
552 | |||
553 | /* Insert node into cmd_free_q */ | ||
554 | spin_lock_irqsave(&adapter->cmd_free_q_lock, flags); | ||
555 | list_add_tail(&cmd_node->list, &adapter->cmd_free_q); | ||
556 | spin_unlock_irqrestore(&adapter->cmd_free_q_lock, flags); | ||
557 | |||
558 | return; | ||
559 | } | ||
560 | |||
561 | /* | ||
562 | * This function queues a command to the command pending queue. | ||
563 | * | ||
564 | * This in effect adds the command to the command list to be executed. | ||
565 | * Exit PS command is handled specially, by placing it always to the | ||
566 | * front of the command queue. | ||
567 | */ | ||
568 | void | ||
569 | mwifiex_insert_cmd_to_pending_q(struct mwifiex_adapter *adapter, | ||
570 | struct cmd_ctrl_node *cmd_node, u32 add_tail) | ||
571 | { | ||
572 | struct host_cmd_ds_command *host_cmd = NULL; | ||
573 | u16 command; | ||
574 | unsigned long flags; | ||
575 | |||
576 | host_cmd = (struct host_cmd_ds_command *) (cmd_node->cmd_skb->data); | ||
577 | if (!host_cmd) { | ||
578 | dev_err(adapter->dev, "QUEUE_CMD: host_cmd is NULL\n"); | ||
579 | return; | ||
580 | } | ||
581 | |||
582 | command = le16_to_cpu(host_cmd->command); | ||
583 | |||
584 | /* Exit_PS command needs to be queued in the header always. */ | ||
585 | if (command == HostCmd_CMD_802_11_PS_MODE_ENH) { | ||
586 | struct host_cmd_ds_802_11_ps_mode_enh *pm = | ||
587 | &host_cmd->params.psmode_enh; | ||
588 | if ((le16_to_cpu(pm->action) == DIS_PS) | ||
589 | || (le16_to_cpu(pm->action) == DIS_AUTO_PS)) { | ||
590 | if (adapter->ps_state != PS_STATE_AWAKE) | ||
591 | add_tail = false; | ||
592 | } | ||
593 | } | ||
594 | |||
595 | spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags); | ||
596 | if (add_tail) | ||
597 | list_add_tail(&cmd_node->list, &adapter->cmd_pending_q); | ||
598 | else | ||
599 | list_add(&cmd_node->list, &adapter->cmd_pending_q); | ||
600 | spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags); | ||
601 | |||
602 | dev_dbg(adapter->dev, "cmd: QUEUE_CMD: cmd=%#x is queued\n", command); | ||
603 | |||
604 | return; | ||
605 | } | ||
606 | |||
607 | /* | ||
608 | * This function executes the next command in command pending queue. | ||
609 | * | ||
610 | * This function will fail if a command is already in processing stage, | ||
611 | * otherwise it will dequeue the first command from the command pending | ||
612 | * queue and send to the firmware. | ||
613 | * | ||
614 | * If the device is currently in host sleep mode, any commands, except the | ||
615 | * host sleep configuration command will de-activate the host sleep. For PS | ||
616 | * mode, the function will put the firmware back to sleep if applicable. | ||
617 | */ | ||
618 | int mwifiex_exec_next_cmd(struct mwifiex_adapter *adapter) | ||
619 | { | ||
620 | struct mwifiex_private *priv = NULL; | ||
621 | struct cmd_ctrl_node *cmd_node = NULL; | ||
622 | int ret = 0; | ||
623 | struct host_cmd_ds_command *host_cmd; | ||
624 | unsigned long cmd_flags; | ||
625 | unsigned long cmd_pending_q_flags; | ||
626 | |||
627 | /* Check if already in processing */ | ||
628 | if (adapter->curr_cmd) { | ||
629 | dev_err(adapter->dev, "EXEC_NEXT_CMD: cmd in processing\n"); | ||
630 | return -1; | ||
631 | } | ||
632 | |||
633 | spin_lock_irqsave(&adapter->mwifiex_cmd_lock, cmd_flags); | ||
634 | /* Check if any command is pending */ | ||
635 | spin_lock_irqsave(&adapter->cmd_pending_q_lock, cmd_pending_q_flags); | ||
636 | if (list_empty(&adapter->cmd_pending_q)) { | ||
637 | spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, | ||
638 | cmd_pending_q_flags); | ||
639 | spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags); | ||
640 | return 0; | ||
641 | } | ||
642 | cmd_node = list_first_entry(&adapter->cmd_pending_q, | ||
643 | struct cmd_ctrl_node, list); | ||
644 | spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, | ||
645 | cmd_pending_q_flags); | ||
646 | |||
647 | host_cmd = (struct host_cmd_ds_command *) (cmd_node->cmd_skb->data); | ||
648 | priv = cmd_node->priv; | ||
649 | |||
650 | if (adapter->ps_state != PS_STATE_AWAKE) { | ||
651 | dev_err(adapter->dev, "%s: cannot send cmd in sleep state," | ||
652 | " this should not happen\n", __func__); | ||
653 | spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags); | ||
654 | return ret; | ||
655 | } | ||
656 | |||
657 | spin_lock_irqsave(&adapter->cmd_pending_q_lock, cmd_pending_q_flags); | ||
658 | list_del(&cmd_node->list); | ||
659 | spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, | ||
660 | cmd_pending_q_flags); | ||
661 | |||
662 | spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags); | ||
663 | ret = mwifiex_dnld_cmd_to_fw(priv, cmd_node); | ||
664 | priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); | ||
665 | /* Any command sent to the firmware when host is in sleep | ||
666 | * mode should de-configure host sleep. We should skip the | ||
667 | * host sleep configuration command itself though | ||
668 | */ | ||
669 | if (priv && (host_cmd->command != | ||
670 | cpu_to_le16(HostCmd_CMD_802_11_HS_CFG_ENH))) { | ||
671 | if (adapter->hs_activated) { | ||
672 | adapter->is_hs_configured = false; | ||
673 | mwifiex_hs_activated_event(priv, false); | ||
674 | } | ||
675 | } | ||
676 | |||
677 | return ret; | ||
678 | } | ||
679 | |||
680 | /* | ||
681 | * This function handles the command response. | ||
682 | * | ||
683 | * After processing, the function cleans the command node and puts | ||
684 | * it back to the command free queue. | ||
685 | */ | ||
686 | int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter) | ||
687 | { | ||
688 | struct host_cmd_ds_command *resp = NULL; | ||
689 | struct mwifiex_private *priv = | ||
690 | mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); | ||
691 | int ret = 0; | ||
692 | uint16_t orig_cmdresp_no; | ||
693 | uint16_t cmdresp_no; | ||
694 | uint16_t cmdresp_result; | ||
695 | struct mwifiex_wait_queue *wait_queue = NULL; | ||
696 | struct timeval tstamp; | ||
697 | unsigned long flags; | ||
698 | |||
699 | /* Now we got response from FW, cancel the command timer */ | ||
700 | del_timer(&adapter->cmd_timer); | ||
701 | |||
702 | if (!adapter->curr_cmd || !adapter->curr_cmd->resp_skb) { | ||
703 | resp = (struct host_cmd_ds_command *) adapter->upld_buf; | ||
704 | dev_err(adapter->dev, "CMD_RESP: NULL curr_cmd, %#x\n", | ||
705 | le16_to_cpu(resp->command)); | ||
706 | return -1; | ||
707 | } | ||
708 | |||
709 | if (adapter->curr_cmd->wq_buf) | ||
710 | wait_queue = (struct mwifiex_wait_queue *) | ||
711 | adapter->curr_cmd->wq_buf; | ||
712 | |||
713 | adapter->num_cmd_timeout = 0; | ||
714 | |||
715 | resp = (struct host_cmd_ds_command *) adapter->curr_cmd->resp_skb->data; | ||
716 | if (adapter->curr_cmd->cmd_flag & CMD_F_CANCELED) { | ||
717 | dev_err(adapter->dev, "CMD_RESP: %#x been canceled\n", | ||
718 | le16_to_cpu(resp->command)); | ||
719 | mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd); | ||
720 | spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); | ||
721 | adapter->curr_cmd = NULL; | ||
722 | spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); | ||
723 | return -1; | ||
724 | } | ||
725 | |||
726 | if (adapter->curr_cmd->cmd_flag & CMD_F_HOSTCMD) { | ||
727 | /* Copy original response back to response buffer */ | ||
728 | struct mwifiex_ds_misc_cmd *hostcmd = NULL; | ||
729 | uint16_t size = le16_to_cpu(resp->size); | ||
730 | dev_dbg(adapter->dev, "info: host cmd resp size = %d\n", size); | ||
731 | size = min_t(u16, size, MWIFIEX_SIZE_OF_CMD_BUFFER); | ||
732 | if (adapter->curr_cmd->data_buf) { | ||
733 | hostcmd = (struct mwifiex_ds_misc_cmd *) | ||
734 | adapter->curr_cmd->data_buf; | ||
735 | hostcmd->len = size; | ||
736 | memcpy(hostcmd->cmd, (void *) resp, size); | ||
737 | } | ||
738 | } | ||
739 | orig_cmdresp_no = le16_to_cpu(resp->command); | ||
740 | |||
741 | /* Get BSS number and corresponding priv */ | ||
742 | priv = mwifiex_get_priv_by_id(adapter, | ||
743 | HostCmd_GET_BSS_NO(le16_to_cpu(resp->seq_num)), | ||
744 | HostCmd_GET_BSS_TYPE(le16_to_cpu(resp->seq_num))); | ||
745 | if (!priv) | ||
746 | priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); | ||
747 | /* Clear RET_BIT from HostCmd */ | ||
748 | resp->command = cpu_to_le16(orig_cmdresp_no & HostCmd_CMD_ID_MASK); | ||
749 | |||
750 | cmdresp_no = le16_to_cpu(resp->command); | ||
751 | cmdresp_result = le16_to_cpu(resp->result); | ||
752 | |||
753 | /* Save the last command response to debug log */ | ||
754 | adapter->dbg.last_cmd_resp_index = | ||
755 | (adapter->dbg.last_cmd_resp_index + 1) % DBG_CMD_NUM; | ||
756 | adapter->dbg.last_cmd_resp_id[adapter->dbg.last_cmd_resp_index] = | ||
757 | orig_cmdresp_no; | ||
758 | |||
759 | do_gettimeofday(&tstamp); | ||
760 | dev_dbg(adapter->dev, "cmd: CMD_RESP: (%lu.%lu): 0x%x, result %d," | ||
761 | " len %d, seqno 0x%x\n", | ||
762 | tstamp.tv_sec, tstamp.tv_usec, orig_cmdresp_no, cmdresp_result, | ||
763 | le16_to_cpu(resp->size), le16_to_cpu(resp->seq_num)); | ||
764 | |||
765 | if (!(orig_cmdresp_no & HostCmd_RET_BIT)) { | ||
766 | dev_err(adapter->dev, "CMD_RESP: invalid cmd resp\n"); | ||
767 | if (wait_queue) | ||
768 | wait_queue->status = MWIFIEX_ERROR_FW_CMDRESP; | ||
769 | |||
770 | mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd); | ||
771 | spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); | ||
772 | adapter->curr_cmd = NULL; | ||
773 | spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); | ||
774 | return -1; | ||
775 | } | ||
776 | |||
777 | if (adapter->curr_cmd->cmd_flag & CMD_F_HOSTCMD) { | ||
778 | adapter->curr_cmd->cmd_flag &= ~CMD_F_HOSTCMD; | ||
779 | if ((cmdresp_result == HostCmd_RESULT_OK) | ||
780 | && (cmdresp_no == HostCmd_CMD_802_11_HS_CFG_ENH)) | ||
781 | ret = mwifiex_ret_802_11_hs_cfg(priv, resp); | ||
782 | } else { | ||
783 | /* handle response */ | ||
784 | ret = mwifiex_process_sta_cmdresp(priv, cmdresp_no, resp, | ||
785 | wait_queue); | ||
786 | } | ||
787 | |||
788 | /* Check init command response */ | ||
789 | if (adapter->hw_status == MWIFIEX_HW_STATUS_INITIALIZING) { | ||
790 | if (ret == -1) { | ||
791 | dev_err(adapter->dev, "%s: cmd %#x failed during " | ||
792 | "initialization\n", __func__, cmdresp_no); | ||
793 | mwifiex_init_fw_complete(adapter); | ||
794 | return -1; | ||
795 | } else if (adapter->last_init_cmd == cmdresp_no) | ||
796 | adapter->hw_status = MWIFIEX_HW_STATUS_INIT_DONE; | ||
797 | } | ||
798 | |||
799 | if (adapter->curr_cmd) { | ||
800 | if (wait_queue && (!ret)) | ||
801 | wait_queue->status = MWIFIEX_ERROR_NO_ERROR; | ||
802 | else if (wait_queue && (ret == -1)) | ||
803 | wait_queue->status = MWIFIEX_ERROR_CMD_RESP_FAIL; | ||
804 | |||
805 | /* Clean up and put current command back to cmd_free_q */ | ||
806 | mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd); | ||
807 | |||
808 | spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); | ||
809 | adapter->curr_cmd = NULL; | ||
810 | spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); | ||
811 | } | ||
812 | |||
813 | return ret; | ||
814 | } | ||
815 | |||
816 | /* | ||
817 | * This function handles the timeout of command sending. | ||
818 | * | ||
819 | * It will re-send the same command again. | ||
820 | */ | ||
821 | void | ||
822 | mwifiex_cmd_timeout_func(unsigned long function_context) | ||
823 | { | ||
824 | struct mwifiex_adapter *adapter = | ||
825 | (struct mwifiex_adapter *) function_context; | ||
826 | struct cmd_ctrl_node *cmd_node = NULL; | ||
827 | struct mwifiex_wait_queue *wait_queue = NULL; | ||
828 | struct timeval tstamp; | ||
829 | |||
830 | adapter->num_cmd_timeout++; | ||
831 | adapter->dbg.num_cmd_timeout++; | ||
832 | if (!adapter->curr_cmd) { | ||
833 | dev_dbg(adapter->dev, "cmd: empty curr_cmd\n"); | ||
834 | return; | ||
835 | } | ||
836 | cmd_node = adapter->curr_cmd; | ||
837 | if (cmd_node->wq_buf) { | ||
838 | wait_queue = (struct mwifiex_wait_queue *) cmd_node->wq_buf; | ||
839 | wait_queue->status = MWIFIEX_ERROR_CMD_TIMEOUT; | ||
840 | } | ||
841 | |||
842 | if (cmd_node) { | ||
843 | adapter->dbg.timeout_cmd_id = | ||
844 | adapter->dbg.last_cmd_id[adapter->dbg.last_cmd_index]; | ||
845 | adapter->dbg.timeout_cmd_act = | ||
846 | adapter->dbg.last_cmd_act[adapter->dbg.last_cmd_index]; | ||
847 | do_gettimeofday(&tstamp); | ||
848 | dev_err(adapter->dev, "%s: Timeout cmd id (%lu.%lu) = %#x," | ||
849 | " act = %#x\n", __func__, | ||
850 | tstamp.tv_sec, tstamp.tv_usec, | ||
851 | adapter->dbg.timeout_cmd_id, | ||
852 | adapter->dbg.timeout_cmd_act); | ||
853 | |||
854 | dev_err(adapter->dev, "num_data_h2c_failure = %d\n", | ||
855 | adapter->dbg.num_tx_host_to_card_failure); | ||
856 | dev_err(adapter->dev, "num_cmd_h2c_failure = %d\n", | ||
857 | adapter->dbg.num_cmd_host_to_card_failure); | ||
858 | |||
859 | dev_err(adapter->dev, "num_cmd_timeout = %d\n", | ||
860 | adapter->dbg.num_cmd_timeout); | ||
861 | dev_err(adapter->dev, "num_tx_timeout = %d\n", | ||
862 | adapter->dbg.num_tx_timeout); | ||
863 | |||
864 | dev_err(adapter->dev, "last_cmd_index = %d\n", | ||
865 | adapter->dbg.last_cmd_index); | ||
866 | print_hex_dump_bytes("last_cmd_id: ", DUMP_PREFIX_OFFSET, | ||
867 | adapter->dbg.last_cmd_id, DBG_CMD_NUM); | ||
868 | print_hex_dump_bytes("last_cmd_act: ", DUMP_PREFIX_OFFSET, | ||
869 | adapter->dbg.last_cmd_act, DBG_CMD_NUM); | ||
870 | |||
871 | dev_err(adapter->dev, "last_cmd_resp_index = %d\n", | ||
872 | adapter->dbg.last_cmd_resp_index); | ||
873 | print_hex_dump_bytes("last_cmd_resp_id: ", DUMP_PREFIX_OFFSET, | ||
874 | adapter->dbg.last_cmd_resp_id, DBG_CMD_NUM); | ||
875 | |||
876 | dev_err(adapter->dev, "last_event_index = %d\n", | ||
877 | adapter->dbg.last_event_index); | ||
878 | print_hex_dump_bytes("last_event: ", DUMP_PREFIX_OFFSET, | ||
879 | adapter->dbg.last_event, DBG_CMD_NUM); | ||
880 | |||
881 | dev_err(adapter->dev, "data_sent=%d cmd_sent=%d\n", | ||
882 | adapter->data_sent, adapter->cmd_sent); | ||
883 | |||
884 | dev_err(adapter->dev, "ps_mode=%d ps_state=%d\n", | ||
885 | adapter->ps_mode, adapter->ps_state); | ||
886 | } | ||
887 | if (adapter->hw_status == MWIFIEX_HW_STATUS_INITIALIZING) | ||
888 | mwifiex_init_fw_complete(adapter); | ||
889 | |||
890 | return; | ||
891 | } | ||
892 | |||
893 | /* | ||
894 | * This function cancels all the pending commands. | ||
895 | * | ||
896 | * The current command, all commands in command pending queue and all scan | ||
897 | * commands in scan pending queue are cancelled. All the completion callbacks | ||
898 | * are called with failure status to ensure cleanup. | ||
899 | */ | ||
900 | void | ||
901 | mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter) | ||
902 | { | ||
903 | struct cmd_ctrl_node *cmd_node = NULL, *tmp_node = NULL; | ||
904 | struct mwifiex_wait_queue *wait_queue = NULL; | ||
905 | unsigned long flags; | ||
906 | |||
907 | /* Cancel current cmd */ | ||
908 | if ((adapter->curr_cmd) && (adapter->curr_cmd->wq_buf)) { | ||
909 | wait_queue = | ||
910 | (struct mwifiex_wait_queue *) adapter->curr_cmd->wq_buf; | ||
911 | spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); | ||
912 | adapter->curr_cmd->wq_buf = NULL; | ||
913 | spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); | ||
914 | wait_queue->status = MWIFIEX_ERROR_CMD_CANCEL; | ||
915 | mwifiex_ioctl_complete(adapter, wait_queue, -1); | ||
916 | } | ||
917 | /* Cancel all pending command */ | ||
918 | spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags); | ||
919 | list_for_each_entry_safe(cmd_node, tmp_node, | ||
920 | &adapter->cmd_pending_q, list) { | ||
921 | list_del(&cmd_node->list); | ||
922 | spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags); | ||
923 | |||
924 | if (cmd_node->wq_buf) { | ||
925 | wait_queue = | ||
926 | (struct mwifiex_wait_queue *) cmd_node->wq_buf; | ||
927 | wait_queue->status = MWIFIEX_ERROR_CMD_CANCEL; | ||
928 | mwifiex_ioctl_complete(adapter, wait_queue, -1); | ||
929 | cmd_node->wq_buf = NULL; | ||
930 | } | ||
931 | mwifiex_insert_cmd_to_free_q(adapter, cmd_node); | ||
932 | spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags); | ||
933 | } | ||
934 | spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags); | ||
935 | |||
936 | /* Cancel all pending scan command */ | ||
937 | spin_lock_irqsave(&adapter->scan_pending_q_lock, flags); | ||
938 | list_for_each_entry_safe(cmd_node, tmp_node, | ||
939 | &adapter->scan_pending_q, list) { | ||
940 | list_del(&cmd_node->list); | ||
941 | spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags); | ||
942 | |||
943 | cmd_node->wq_buf = NULL; | ||
944 | mwifiex_insert_cmd_to_free_q(adapter, cmd_node); | ||
945 | spin_lock_irqsave(&adapter->scan_pending_q_lock, flags); | ||
946 | } | ||
947 | spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags); | ||
948 | |||
949 | spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); | ||
950 | adapter->scan_processing = false; | ||
951 | spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); | ||
952 | } | ||
953 | |||
954 | /* | ||
955 | * This function cancels all pending commands that matches with | ||
956 | * the given IOCTL request. | ||
957 | * | ||
958 | * Both the current command buffer and the pending command queue are | ||
959 | * searched for matching IOCTL request. The completion callback of | ||
960 | * the matched command is called with failure status to ensure cleanup. | ||
961 | * In case of scan commands, all pending commands in scan pending queue | ||
962 | * are cancelled. | ||
963 | */ | ||
964 | void | ||
965 | mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter, | ||
966 | struct mwifiex_wait_queue *wait_queue) | ||
967 | { | ||
968 | struct cmd_ctrl_node *cmd_node = NULL, *tmp_node = NULL; | ||
969 | unsigned long cmd_flags; | ||
970 | unsigned long cmd_pending_q_flags; | ||
971 | unsigned long scan_pending_q_flags; | ||
972 | uint16_t cancel_scan_cmd = false; | ||
973 | |||
974 | if ((adapter->curr_cmd) && | ||
975 | (adapter->curr_cmd->wq_buf == wait_queue)) { | ||
976 | spin_lock_irqsave(&adapter->mwifiex_cmd_lock, cmd_flags); | ||
977 | cmd_node = adapter->curr_cmd; | ||
978 | cmd_node->wq_buf = NULL; | ||
979 | cmd_node->cmd_flag |= CMD_F_CANCELED; | ||
980 | spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags); | ||
981 | } | ||
982 | |||
983 | spin_lock_irqsave(&adapter->mwifiex_cmd_lock, cmd_flags); | ||
984 | while (1) { | ||
985 | cmd_node = mwifiex_get_pending_ioctl_cmd(adapter, wait_queue); | ||
986 | if (!cmd_node) | ||
987 | break; | ||
988 | |||
989 | spin_lock_irqsave(&adapter->cmd_pending_q_lock, | ||
990 | cmd_pending_q_flags); | ||
991 | list_del(&cmd_node->list); | ||
992 | spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, | ||
993 | cmd_pending_q_flags); | ||
994 | |||
995 | cmd_node->wq_buf = NULL; | ||
996 | mwifiex_insert_cmd_to_free_q(adapter, cmd_node); | ||
997 | } | ||
998 | spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags); | ||
999 | /* Cancel all pending scan command */ | ||
1000 | spin_lock_irqsave(&adapter->scan_pending_q_lock, | ||
1001 | scan_pending_q_flags); | ||
1002 | list_for_each_entry_safe(cmd_node, tmp_node, | ||
1003 | &adapter->scan_pending_q, list) { | ||
1004 | if (cmd_node->wq_buf == wait_queue) { | ||
1005 | list_del(&cmd_node->list); | ||
1006 | spin_unlock_irqrestore(&adapter->scan_pending_q_lock, | ||
1007 | scan_pending_q_flags); | ||
1008 | cmd_node->wq_buf = NULL; | ||
1009 | mwifiex_insert_cmd_to_free_q(adapter, cmd_node); | ||
1010 | spin_lock_irqsave(&adapter->scan_pending_q_lock, | ||
1011 | scan_pending_q_flags); | ||
1012 | cancel_scan_cmd = true; | ||
1013 | } | ||
1014 | } | ||
1015 | spin_unlock_irqrestore(&adapter->scan_pending_q_lock, | ||
1016 | scan_pending_q_flags); | ||
1017 | |||
1018 | if (cancel_scan_cmd) { | ||
1019 | spin_lock_irqsave(&adapter->mwifiex_cmd_lock, cmd_flags); | ||
1020 | adapter->scan_processing = false; | ||
1021 | spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags); | ||
1022 | } | ||
1023 | wait_queue->status = MWIFIEX_ERROR_CMD_CANCEL; | ||
1024 | mwifiex_ioctl_complete(adapter, wait_queue, -1); | ||
1025 | |||
1026 | return; | ||
1027 | } | ||
1028 | |||
1029 | /* | ||
1030 | * This function sends the sleep confirm command to firmware, if | ||
1031 | * possible. | ||
1032 | * | ||
1033 | * The sleep confirm command cannot be issued if command response, | ||
1034 | * data response or event response is awaiting handling, or if we | ||
1035 | * are in the middle of sending a command, or expecting a command | ||
1036 | * response. | ||
1037 | */ | ||
1038 | void | ||
1039 | mwifiex_check_ps_cond(struct mwifiex_adapter *adapter) | ||
1040 | { | ||
1041 | if (!adapter->cmd_sent && | ||
1042 | !adapter->curr_cmd && !IS_CARD_RX_RCVD(adapter)) | ||
1043 | mwifiex_dnld_sleep_confirm_cmd(adapter); | ||
1044 | else | ||
1045 | dev_dbg(adapter->dev, | ||
1046 | "cmd: Delay Sleep Confirm (%s%s%s)\n", | ||
1047 | (adapter->cmd_sent) ? "D" : "", | ||
1048 | (adapter->curr_cmd) ? "C" : "", | ||
1049 | (IS_CARD_RX_RCVD(adapter)) ? "R" : ""); | ||
1050 | } | ||
1051 | |||
1052 | /* | ||
1053 | * This function sends a Host Sleep activated event to applications. | ||
1054 | * | ||
1055 | * This event is generated by the driver, with a blank event body. | ||
1056 | */ | ||
1057 | void | ||
1058 | mwifiex_hs_activated_event(struct mwifiex_private *priv, u8 activated) | ||
1059 | { | ||
1060 | if (activated) { | ||
1061 | if (priv->adapter->is_hs_configured) { | ||
1062 | priv->adapter->hs_activated = true; | ||
1063 | dev_dbg(priv->adapter->dev, "event: hs_activated\n"); | ||
1064 | priv->adapter->hs_activate_wait_q_woken = true; | ||
1065 | wake_up_interruptible( | ||
1066 | &priv->adapter->hs_activate_wait_q); | ||
1067 | } else { | ||
1068 | dev_dbg(priv->adapter->dev, "event: HS not configured\n"); | ||
1069 | } | ||
1070 | } else { | ||
1071 | dev_dbg(priv->adapter->dev, "event: hs_deactivated\n"); | ||
1072 | priv->adapter->hs_activated = false; | ||
1073 | } | ||
1074 | } | ||
1075 | |||
1076 | /* | ||
1077 | * This function handles the command response of a Host Sleep configuration | ||
1078 | * command. | ||
1079 | * | ||
1080 | * Handling includes changing the header fields into CPU format | ||
1081 | * and setting the current host sleep activation status in driver. | ||
1082 | * | ||
1083 | * In case host sleep status change, the function generates an event to | ||
1084 | * notify the applications. | ||
1085 | */ | ||
1086 | int mwifiex_ret_802_11_hs_cfg(struct mwifiex_private *priv, | ||
1087 | struct host_cmd_ds_command *resp) | ||
1088 | { | ||
1089 | struct mwifiex_adapter *adapter = priv->adapter; | ||
1090 | struct host_cmd_ds_802_11_hs_cfg_enh *phs_cfg = | ||
1091 | &resp->params.opt_hs_cfg; | ||
1092 | uint32_t conditions = le32_to_cpu(phs_cfg->params.hs_config.conditions); | ||
1093 | |||
1094 | if (phs_cfg->action == cpu_to_le16(HS_ACTIVATE)) { | ||
1095 | mwifiex_hs_activated_event(priv, true); | ||
1096 | return 0; | ||
1097 | } else { | ||
1098 | dev_dbg(adapter->dev, "cmd: CMD_RESP: HS_CFG cmd reply" | ||
1099 | " result=%#x, conditions=0x%x gpio=0x%x gap=0x%x\n", | ||
1100 | resp->result, conditions, | ||
1101 | phs_cfg->params.hs_config.gpio, | ||
1102 | phs_cfg->params.hs_config.gap); | ||
1103 | } | ||
1104 | if (conditions != HOST_SLEEP_CFG_CANCEL) { | ||
1105 | adapter->is_hs_configured = true; | ||
1106 | } else { | ||
1107 | adapter->is_hs_configured = false; | ||
1108 | if (adapter->hs_activated) | ||
1109 | mwifiex_hs_activated_event(priv, false); | ||
1110 | } | ||
1111 | |||
1112 | return 0; | ||
1113 | } | ||
1114 | |||
1115 | /* | ||
1116 | * This function wakes up the adapter and generates a Host Sleep | ||
1117 | * cancel event on receiving the power up interrupt. | ||
1118 | */ | ||
1119 | void | ||
1120 | mwifiex_process_hs_config(struct mwifiex_adapter *adapter) | ||
1121 | { | ||
1122 | dev_dbg(adapter->dev, "info: %s: auto cancelling host sleep" | ||
1123 | " since there is interrupt from the firmware\n", __func__); | ||
1124 | |||
1125 | adapter->if_ops.wakeup(adapter); | ||
1126 | adapter->hs_activated = false; | ||
1127 | adapter->is_hs_configured = false; | ||
1128 | mwifiex_hs_activated_event(mwifiex_get_priv(adapter, | ||
1129 | MWIFIEX_BSS_ROLE_ANY), false); | ||
1130 | return; | ||
1131 | } | ||
1132 | |||
1133 | /* | ||
1134 | * This function handles the command response of a sleep confirm command. | ||
1135 | * | ||
1136 | * The function sets the card state to SLEEP if the response indicates success. | ||
1137 | */ | ||
1138 | void | ||
1139 | mwifiex_process_sleep_confirm_resp(struct mwifiex_adapter *adapter, | ||
1140 | u8 *pbuf, u32 upld_len) | ||
1141 | { | ||
1142 | struct host_cmd_ds_command *cmd = (struct host_cmd_ds_command *) pbuf; | ||
1143 | struct mwifiex_private *priv = | ||
1144 | mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); | ||
1145 | uint16_t result = le16_to_cpu(cmd->result); | ||
1146 | uint16_t command = le16_to_cpu(cmd->command); | ||
1147 | uint16_t seq_num = le16_to_cpu(cmd->seq_num); | ||
1148 | |||
1149 | if (!upld_len) { | ||
1150 | dev_err(adapter->dev, "%s: cmd size is 0\n", __func__); | ||
1151 | return; | ||
1152 | } | ||
1153 | |||
1154 | /* Get BSS number and corresponding priv */ | ||
1155 | priv = mwifiex_get_priv_by_id(adapter, HostCmd_GET_BSS_NO(seq_num), | ||
1156 | HostCmd_GET_BSS_TYPE(seq_num)); | ||
1157 | if (!priv) | ||
1158 | priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); | ||
1159 | |||
1160 | /* Update sequence number */ | ||
1161 | seq_num = HostCmd_GET_SEQ_NO(seq_num); | ||
1162 | /* Clear RET_BIT from HostCmd */ | ||
1163 | command &= HostCmd_CMD_ID_MASK; | ||
1164 | |||
1165 | if (command != HostCmd_CMD_802_11_PS_MODE_ENH) { | ||
1166 | dev_err(adapter->dev, "%s: received unexpected response for" | ||
1167 | " cmd %x, result = %x\n", __func__, command, result); | ||
1168 | return; | ||
1169 | } | ||
1170 | |||
1171 | if (result) { | ||
1172 | dev_err(adapter->dev, "%s: sleep confirm cmd failed\n", | ||
1173 | __func__); | ||
1174 | adapter->pm_wakeup_card_req = false; | ||
1175 | adapter->ps_state = PS_STATE_AWAKE; | ||
1176 | return; | ||
1177 | } | ||
1178 | adapter->pm_wakeup_card_req = true; | ||
1179 | if (adapter->is_hs_configured) | ||
1180 | mwifiex_hs_activated_event(mwifiex_get_priv(adapter, | ||
1181 | MWIFIEX_BSS_ROLE_ANY), true); | ||
1182 | adapter->ps_state = PS_STATE_SLEEP; | ||
1183 | cmd->command = cpu_to_le16(command); | ||
1184 | cmd->seq_num = cpu_to_le16(seq_num); | ||
1185 | } | ||
1186 | EXPORT_SYMBOL_GPL(mwifiex_process_sleep_confirm_resp); | ||
1187 | |||
1188 | /* | ||
1189 | * This function prepares an enhanced power mode command. | ||
1190 | * | ||
1191 | * This function can be used to disable power save or to configure | ||
1192 | * power save with auto PS or STA PS or auto deep sleep. | ||
1193 | * | ||
1194 | * Preparation includes - | ||
1195 | * - Setting command ID, action and proper size | ||
1196 | * - Setting Power Save bitmap, PS parameters TLV, PS mode TLV, | ||
1197 | * auto deep sleep TLV (as required) | ||
1198 | * - Ensuring correct endian-ness | ||
1199 | */ | ||
1200 | int mwifiex_cmd_enh_power_mode(struct mwifiex_private *priv, | ||
1201 | struct host_cmd_ds_command *cmd, | ||
1202 | u16 cmd_action, uint16_t ps_bitmap, | ||
1203 | void *data_buf) | ||
1204 | { | ||
1205 | struct host_cmd_ds_802_11_ps_mode_enh *psmode_enh = | ||
1206 | &cmd->params.psmode_enh; | ||
1207 | u8 *tlv = NULL; | ||
1208 | u16 cmd_size = 0; | ||
1209 | |||
1210 | cmd->command = cpu_to_le16(HostCmd_CMD_802_11_PS_MODE_ENH); | ||
1211 | if (cmd_action == DIS_AUTO_PS) { | ||
1212 | psmode_enh->action = cpu_to_le16(DIS_AUTO_PS); | ||
1213 | psmode_enh->params.ps_bitmap = cpu_to_le16(ps_bitmap); | ||
1214 | cmd->size = cpu_to_le16(S_DS_GEN + sizeof(psmode_enh->action) + | ||
1215 | sizeof(psmode_enh->params.ps_bitmap)); | ||
1216 | } else if (cmd_action == GET_PS) { | ||
1217 | psmode_enh->action = cpu_to_le16(GET_PS); | ||
1218 | psmode_enh->params.ps_bitmap = cpu_to_le16(ps_bitmap); | ||
1219 | cmd->size = cpu_to_le16(S_DS_GEN + sizeof(psmode_enh->action) + | ||
1220 | sizeof(psmode_enh->params.ps_bitmap)); | ||
1221 | } else if (cmd_action == EN_AUTO_PS) { | ||
1222 | psmode_enh->action = cpu_to_le16(EN_AUTO_PS); | ||
1223 | psmode_enh->params.ps_bitmap = cpu_to_le16(ps_bitmap); | ||
1224 | cmd_size = S_DS_GEN + sizeof(psmode_enh->action) + | ||
1225 | sizeof(psmode_enh->params.ps_bitmap); | ||
1226 | tlv = (u8 *) cmd + cmd_size; | ||
1227 | if (ps_bitmap & BITMAP_STA_PS) { | ||
1228 | struct mwifiex_adapter *adapter = priv->adapter; | ||
1229 | struct mwifiex_ie_types_ps_param *ps_tlv = | ||
1230 | (struct mwifiex_ie_types_ps_param *) tlv; | ||
1231 | struct mwifiex_ps_param *ps_mode = &ps_tlv->param; | ||
1232 | ps_tlv->header.type = cpu_to_le16(TLV_TYPE_PS_PARAM); | ||
1233 | ps_tlv->header.len = cpu_to_le16(sizeof(*ps_tlv) - | ||
1234 | sizeof(struct mwifiex_ie_types_header)); | ||
1235 | cmd_size += sizeof(*ps_tlv); | ||
1236 | tlv += sizeof(*ps_tlv); | ||
1237 | dev_dbg(adapter->dev, "cmd: PS Command: Enter PS\n"); | ||
1238 | ps_mode->null_pkt_interval = | ||
1239 | cpu_to_le16(adapter->null_pkt_interval); | ||
1240 | ps_mode->multiple_dtims = | ||
1241 | cpu_to_le16(adapter->multiple_dtim); | ||
1242 | ps_mode->bcn_miss_timeout = | ||
1243 | cpu_to_le16(adapter->bcn_miss_time_out); | ||
1244 | ps_mode->local_listen_interval = | ||
1245 | cpu_to_le16(adapter->local_listen_interval); | ||
1246 | ps_mode->adhoc_wake_period = | ||
1247 | cpu_to_le16(adapter->adhoc_awake_period); | ||
1248 | ps_mode->delay_to_ps = | ||
1249 | cpu_to_le16(adapter->delay_to_ps); | ||
1250 | ps_mode->mode = | ||
1251 | cpu_to_le16(adapter->enhanced_ps_mode); | ||
1252 | |||
1253 | } | ||
1254 | if (ps_bitmap & BITMAP_AUTO_DS) { | ||
1255 | struct mwifiex_ie_types_auto_ds_param *auto_ds_tlv = | ||
1256 | (struct mwifiex_ie_types_auto_ds_param *) tlv; | ||
1257 | u16 idletime = 0; | ||
1258 | |||
1259 | auto_ds_tlv->header.type = | ||
1260 | cpu_to_le16(TLV_TYPE_AUTO_DS_PARAM); | ||
1261 | auto_ds_tlv->header.len = | ||
1262 | cpu_to_le16(sizeof(*auto_ds_tlv) - | ||
1263 | sizeof(struct mwifiex_ie_types_header)); | ||
1264 | cmd_size += sizeof(*auto_ds_tlv); | ||
1265 | tlv += sizeof(*auto_ds_tlv); | ||
1266 | if (data_buf) | ||
1267 | idletime = ((struct mwifiex_ds_auto_ds *) | ||
1268 | data_buf)->idle_time; | ||
1269 | dev_dbg(priv->adapter->dev, | ||
1270 | "cmd: PS Command: Enter Auto Deep Sleep\n"); | ||
1271 | auto_ds_tlv->deep_sleep_timeout = cpu_to_le16(idletime); | ||
1272 | } | ||
1273 | cmd->size = cpu_to_le16(cmd_size); | ||
1274 | } | ||
1275 | return 0; | ||
1276 | } | ||
1277 | |||
1278 | /* | ||
1279 | * This function handles the command response of an enhanced power mode | ||
1280 | * command. | ||
1281 | * | ||
1282 | * Handling includes changing the header fields into CPU format | ||
1283 | * and setting the current enhanced power mode in driver. | ||
1284 | */ | ||
1285 | int mwifiex_ret_enh_power_mode(struct mwifiex_private *priv, | ||
1286 | struct host_cmd_ds_command *resp, | ||
1287 | void *data_buf) | ||
1288 | { | ||
1289 | struct mwifiex_adapter *adapter = priv->adapter; | ||
1290 | struct host_cmd_ds_802_11_ps_mode_enh *ps_mode = | ||
1291 | &resp->params.psmode_enh; | ||
1292 | uint16_t action = le16_to_cpu(ps_mode->action); | ||
1293 | uint16_t ps_bitmap = le16_to_cpu(ps_mode->params.ps_bitmap); | ||
1294 | uint16_t auto_ps_bitmap = | ||
1295 | le16_to_cpu(ps_mode->params.ps_bitmap); | ||
1296 | |||
1297 | dev_dbg(adapter->dev, "info: %s: PS_MODE cmd reply result=%#x action=%#X\n", | ||
1298 | __func__, resp->result, action); | ||
1299 | if (action == EN_AUTO_PS) { | ||
1300 | if (auto_ps_bitmap & BITMAP_AUTO_DS) { | ||
1301 | dev_dbg(adapter->dev, "cmd: Enabled auto deep sleep\n"); | ||
1302 | priv->adapter->is_deep_sleep = true; | ||
1303 | } | ||
1304 | if (auto_ps_bitmap & BITMAP_STA_PS) { | ||
1305 | dev_dbg(adapter->dev, "cmd: Enabled STA power save\n"); | ||
1306 | if (adapter->sleep_period.period) | ||
1307 | dev_dbg(adapter->dev, "cmd: set to uapsd/pps mode\n"); | ||
1308 | } | ||
1309 | } else if (action == DIS_AUTO_PS) { | ||
1310 | if (ps_bitmap & BITMAP_AUTO_DS) { | ||
1311 | priv->adapter->is_deep_sleep = false; | ||
1312 | dev_dbg(adapter->dev, "cmd: Disabled auto deep sleep\n"); | ||
1313 | } | ||
1314 | if (ps_bitmap & BITMAP_STA_PS) { | ||
1315 | dev_dbg(adapter->dev, "cmd: Disabled STA power save\n"); | ||
1316 | if (adapter->sleep_period.period) { | ||
1317 | adapter->delay_null_pkt = false; | ||
1318 | adapter->tx_lock_flag = false; | ||
1319 | adapter->pps_uapsd_mode = false; | ||
1320 | } | ||
1321 | } | ||
1322 | } else if (action == GET_PS) { | ||
1323 | if (ps_bitmap & BITMAP_STA_PS) | ||
1324 | adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_PSP; | ||
1325 | else | ||
1326 | adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_CAM; | ||
1327 | |||
1328 | dev_dbg(adapter->dev, "cmd: ps_bitmap=%#x\n", ps_bitmap); | ||
1329 | |||
1330 | if (data_buf) { | ||
1331 | /* This section is for get power save mode */ | ||
1332 | struct mwifiex_ds_pm_cfg *pm_cfg = | ||
1333 | (struct mwifiex_ds_pm_cfg *)data_buf; | ||
1334 | if (ps_bitmap & BITMAP_STA_PS) | ||
1335 | pm_cfg->param.ps_mode = 1; | ||
1336 | else | ||
1337 | pm_cfg->param.ps_mode = 0; | ||
1338 | } | ||
1339 | } | ||
1340 | return 0; | ||
1341 | } | ||
1342 | |||
1343 | /* | ||
1344 | * This function prepares command to get hardware specifications. | ||
1345 | * | ||
1346 | * Preparation includes - | ||
1347 | * - Setting command ID, action and proper size | ||
1348 | * - Setting permanent address parameter | ||
1349 | * - Ensuring correct endian-ness | ||
1350 | */ | ||
1351 | int mwifiex_cmd_get_hw_spec(struct mwifiex_private *priv, | ||
1352 | struct host_cmd_ds_command *cmd) | ||
1353 | { | ||
1354 | struct host_cmd_ds_get_hw_spec *hw_spec = &cmd->params.hw_spec; | ||
1355 | |||
1356 | cmd->command = cpu_to_le16(HostCmd_CMD_GET_HW_SPEC); | ||
1357 | cmd->size = | ||
1358 | cpu_to_le16(sizeof(struct host_cmd_ds_get_hw_spec) + S_DS_GEN); | ||
1359 | memcpy(hw_spec->permanent_addr, priv->curr_addr, ETH_ALEN); | ||
1360 | |||
1361 | return 0; | ||
1362 | } | ||
1363 | |||
1364 | /* | ||
1365 | * This function handles the command response of get hardware | ||
1366 | * specifications. | ||
1367 | * | ||
1368 | * Handling includes changing the header fields into CPU format | ||
1369 | * and saving/updating the following parameters in driver - | ||
1370 | * - Firmware capability information | ||
1371 | * - Firmware band settings | ||
1372 | * - Ad-hoc start band and channel | ||
1373 | * - Ad-hoc 11n activation status | ||
1374 | * - Firmware release number | ||
1375 | * - Number of antennas | ||
1376 | * - Hardware address | ||
1377 | * - Hardware interface version | ||
1378 | * - Firmware version | ||
1379 | * - Region code | ||
1380 | * - 11n capabilities | ||
1381 | * - MCS support fields | ||
1382 | * - MP end port | ||
1383 | */ | ||
1384 | int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv, | ||
1385 | struct host_cmd_ds_command *resp) | ||
1386 | { | ||
1387 | struct host_cmd_ds_get_hw_spec *hw_spec = &resp->params.hw_spec; | ||
1388 | struct mwifiex_adapter *adapter = priv->adapter; | ||
1389 | int i; | ||
1390 | |||
1391 | adapter->fw_cap_info = le32_to_cpu(hw_spec->fw_cap_info); | ||
1392 | |||
1393 | if (IS_SUPPORT_MULTI_BANDS(adapter)) | ||
1394 | adapter->fw_bands = (u8) GET_FW_DEFAULT_BANDS(adapter); | ||
1395 | else | ||
1396 | adapter->fw_bands = BAND_B; | ||
1397 | |||
1398 | adapter->config_bands = adapter->fw_bands; | ||
1399 | |||
1400 | if (adapter->fw_bands & BAND_A) { | ||
1401 | if (adapter->fw_bands & BAND_GN) { | ||
1402 | adapter->config_bands |= BAND_AN; | ||
1403 | adapter->fw_bands |= BAND_AN; | ||
1404 | } | ||
1405 | if (adapter->fw_bands & BAND_AN) { | ||
1406 | adapter->adhoc_start_band = BAND_A | BAND_AN; | ||
1407 | adapter->adhoc_11n_enabled = true; | ||
1408 | } else { | ||
1409 | adapter->adhoc_start_band = BAND_A; | ||
1410 | } | ||
1411 | priv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL_A; | ||
1412 | } else if (adapter->fw_bands & BAND_GN) { | ||
1413 | adapter->adhoc_start_band = BAND_G | BAND_B | BAND_GN; | ||
1414 | priv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL; | ||
1415 | adapter->adhoc_11n_enabled = true; | ||
1416 | } else if (adapter->fw_bands & BAND_G) { | ||
1417 | adapter->adhoc_start_band = BAND_G | BAND_B; | ||
1418 | priv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL; | ||
1419 | } else if (adapter->fw_bands & BAND_B) { | ||
1420 | adapter->adhoc_start_band = BAND_B; | ||
1421 | priv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL; | ||
1422 | } | ||
1423 | |||
1424 | adapter->fw_release_number = le32_to_cpu(hw_spec->fw_release_number); | ||
1425 | adapter->number_of_antenna = le16_to_cpu(hw_spec->number_of_antenna); | ||
1426 | |||
1427 | dev_dbg(adapter->dev, "info: GET_HW_SPEC: fw_release_number- %#x\n", | ||
1428 | adapter->fw_release_number); | ||
1429 | dev_dbg(adapter->dev, "info: GET_HW_SPEC: permanent addr: %pM\n", | ||
1430 | hw_spec->permanent_addr); | ||
1431 | dev_dbg(adapter->dev, "info: GET_HW_SPEC: hw_if_version=%#x version=%#x\n", | ||
1432 | le16_to_cpu(hw_spec->hw_if_version), | ||
1433 | le16_to_cpu(hw_spec->version)); | ||
1434 | |||
1435 | if (priv->curr_addr[0] == 0xff) | ||
1436 | memmove(priv->curr_addr, hw_spec->permanent_addr, ETH_ALEN); | ||
1437 | |||
1438 | adapter->region_code = le16_to_cpu(hw_spec->region_code); | ||
1439 | |||
1440 | for (i = 0; i < MWIFIEX_MAX_REGION_CODE; i++) | ||
1441 | /* Use the region code to search for the index */ | ||
1442 | if (adapter->region_code == region_code_index[i]) | ||
1443 | break; | ||
1444 | |||
1445 | /* If it's unidentified region code, use the default (USA) */ | ||
1446 | if (i >= MWIFIEX_MAX_REGION_CODE) { | ||
1447 | adapter->region_code = 0x10; | ||
1448 | dev_dbg(adapter->dev, "cmd: unknown region code, use default (USA)\n"); | ||
1449 | } | ||
1450 | |||
1451 | adapter->hw_dot_11n_dev_cap = le32_to_cpu(hw_spec->dot_11n_dev_cap); | ||
1452 | adapter->hw_dev_mcs_support = hw_spec->dev_mcs_support; | ||
1453 | |||
1454 | if (adapter->if_ops.update_mp_end_port) | ||
1455 | adapter->if_ops.update_mp_end_port(adapter, | ||
1456 | le16_to_cpu(hw_spec->mp_end_port)); | ||
1457 | |||
1458 | return 0; | ||
1459 | } | ||
diff --git a/drivers/net/wireless/mwifiex/debugfs.c b/drivers/net/wireless/mwifiex/debugfs.c new file mode 100644 index 000000000000..63b09692f27d --- /dev/null +++ b/drivers/net/wireless/mwifiex/debugfs.c | |||
@@ -0,0 +1,773 @@ | |||
1 | /* | ||
2 | * Marvell Wireless LAN device driver: debugfs | ||
3 | * | ||
4 | * Copyright (C) 2011, Marvell International Ltd. | ||
5 | * | ||
6 | * This software file (the "File") is distributed by Marvell International | ||
7 | * Ltd. under the terms of the GNU General Public License Version 2, June 1991 | ||
8 | * (the "License"). You may use, redistribute and/or modify this File in | ||
9 | * accordance with the terms and conditions of the License, a copy of which | ||
10 | * is available by writing to the Free Software Foundation, Inc., | ||
11 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the | ||
12 | * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. | ||
13 | * | ||
14 | * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE | ||
15 | * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE | ||
16 | * ARE EXPRESSLY DISCLAIMED. The License provides additional details about | ||
17 | * this warranty disclaimer. | ||
18 | */ | ||
19 | |||
20 | #include <linux/debugfs.h> | ||
21 | |||
22 | #include "main.h" | ||
23 | #include "11n.h" | ||
24 | |||
25 | |||
26 | static struct dentry *mwifiex_dfs_dir; | ||
27 | |||
28 | static char *bss_modes[] = { | ||
29 | "Unknown", | ||
30 | "Managed", | ||
31 | "Ad-hoc", | ||
32 | "Auto" | ||
33 | }; | ||
34 | |||
35 | /* size/addr for mwifiex_debug_info */ | ||
36 | #define item_size(n) (FIELD_SIZEOF(struct mwifiex_debug_info, n)) | ||
37 | #define item_addr(n) (offsetof(struct mwifiex_debug_info, n)) | ||
38 | |||
39 | /* size/addr for struct mwifiex_adapter */ | ||
40 | #define adapter_item_size(n) (FIELD_SIZEOF(struct mwifiex_adapter, n)) | ||
41 | #define adapter_item_addr(n) (offsetof(struct mwifiex_adapter, n)) | ||
42 | |||
43 | struct mwifiex_debug_data { | ||
44 | char name[32]; /* variable/array name */ | ||
45 | u32 size; /* size of the variable/array */ | ||
46 | size_t addr; /* address of the variable/array */ | ||
47 | int num; /* number of variables in an array */ | ||
48 | }; | ||
49 | |||
50 | static struct mwifiex_debug_data items[] = { | ||
51 | {"int_counter", item_size(int_counter), | ||
52 | item_addr(int_counter), 1}, | ||
53 | {"wmm_ac_vo", item_size(packets_out[WMM_AC_VO]), | ||
54 | item_addr(packets_out[WMM_AC_VO]), 1}, | ||
55 | {"wmm_ac_vi", item_size(packets_out[WMM_AC_VI]), | ||
56 | item_addr(packets_out[WMM_AC_VI]), 1}, | ||
57 | {"wmm_ac_be", item_size(packets_out[WMM_AC_BE]), | ||
58 | item_addr(packets_out[WMM_AC_BE]), 1}, | ||
59 | {"wmm_ac_bk", item_size(packets_out[WMM_AC_BK]), | ||
60 | item_addr(packets_out[WMM_AC_BK]), 1}, | ||
61 | {"max_tx_buf_size", item_size(max_tx_buf_size), | ||
62 | item_addr(max_tx_buf_size), 1}, | ||
63 | {"tx_buf_size", item_size(tx_buf_size), | ||
64 | item_addr(tx_buf_size), 1}, | ||
65 | {"curr_tx_buf_size", item_size(curr_tx_buf_size), | ||
66 | item_addr(curr_tx_buf_size), 1}, | ||
67 | {"ps_mode", item_size(ps_mode), | ||
68 | item_addr(ps_mode), 1}, | ||
69 | {"ps_state", item_size(ps_state), | ||
70 | item_addr(ps_state), 1}, | ||
71 | {"is_deep_sleep", item_size(is_deep_sleep), | ||
72 | item_addr(is_deep_sleep), 1}, | ||
73 | {"wakeup_dev_req", item_size(pm_wakeup_card_req), | ||
74 | item_addr(pm_wakeup_card_req), 1}, | ||
75 | {"wakeup_tries", item_size(pm_wakeup_fw_try), | ||
76 | item_addr(pm_wakeup_fw_try), 1}, | ||
77 | {"hs_configured", item_size(is_hs_configured), | ||
78 | item_addr(is_hs_configured), 1}, | ||
79 | {"hs_activated", item_size(hs_activated), | ||
80 | item_addr(hs_activated), 1}, | ||
81 | {"num_tx_timeout", item_size(num_tx_timeout), | ||
82 | item_addr(num_tx_timeout), 1}, | ||
83 | {"num_cmd_timeout", item_size(num_cmd_timeout), | ||
84 | item_addr(num_cmd_timeout), 1}, | ||
85 | {"timeout_cmd_id", item_size(timeout_cmd_id), | ||
86 | item_addr(timeout_cmd_id), 1}, | ||
87 | {"timeout_cmd_act", item_size(timeout_cmd_act), | ||
88 | item_addr(timeout_cmd_act), 1}, | ||
89 | {"last_cmd_id", item_size(last_cmd_id), | ||
90 | item_addr(last_cmd_id), DBG_CMD_NUM}, | ||
91 | {"last_cmd_act", item_size(last_cmd_act), | ||
92 | item_addr(last_cmd_act), DBG_CMD_NUM}, | ||
93 | {"last_cmd_index", item_size(last_cmd_index), | ||
94 | item_addr(last_cmd_index), 1}, | ||
95 | {"last_cmd_resp_id", item_size(last_cmd_resp_id), | ||
96 | item_addr(last_cmd_resp_id), DBG_CMD_NUM}, | ||
97 | {"last_cmd_resp_index", item_size(last_cmd_resp_index), | ||
98 | item_addr(last_cmd_resp_index), 1}, | ||
99 | {"last_event", item_size(last_event), | ||
100 | item_addr(last_event), DBG_CMD_NUM}, | ||
101 | {"last_event_index", item_size(last_event_index), | ||
102 | item_addr(last_event_index), 1}, | ||
103 | {"num_cmd_h2c_fail", item_size(num_cmd_host_to_card_failure), | ||
104 | item_addr(num_cmd_host_to_card_failure), 1}, | ||
105 | {"num_cmd_sleep_cfm_fail", | ||
106 | item_size(num_cmd_sleep_cfm_host_to_card_failure), | ||
107 | item_addr(num_cmd_sleep_cfm_host_to_card_failure), 1}, | ||
108 | {"num_tx_h2c_fail", item_size(num_tx_host_to_card_failure), | ||
109 | item_addr(num_tx_host_to_card_failure), 1}, | ||
110 | {"num_evt_deauth", item_size(num_event_deauth), | ||
111 | item_addr(num_event_deauth), 1}, | ||
112 | {"num_evt_disassoc", item_size(num_event_disassoc), | ||
113 | item_addr(num_event_disassoc), 1}, | ||
114 | {"num_evt_link_lost", item_size(num_event_link_lost), | ||
115 | item_addr(num_event_link_lost), 1}, | ||
116 | {"num_cmd_deauth", item_size(num_cmd_deauth), | ||
117 | item_addr(num_cmd_deauth), 1}, | ||
118 | {"num_cmd_assoc_ok", item_size(num_cmd_assoc_success), | ||
119 | item_addr(num_cmd_assoc_success), 1}, | ||
120 | {"num_cmd_assoc_fail", item_size(num_cmd_assoc_failure), | ||
121 | item_addr(num_cmd_assoc_failure), 1}, | ||
122 | {"cmd_sent", item_size(cmd_sent), | ||
123 | item_addr(cmd_sent), 1}, | ||
124 | {"data_sent", item_size(data_sent), | ||
125 | item_addr(data_sent), 1}, | ||
126 | {"cmd_resp_received", item_size(cmd_resp_received), | ||
127 | item_addr(cmd_resp_received), 1}, | ||
128 | {"event_received", item_size(event_received), | ||
129 | item_addr(event_received), 1}, | ||
130 | |||
131 | /* variables defined in struct mwifiex_adapter */ | ||
132 | {"ioctl_pending", adapter_item_size(ioctl_pending), | ||
133 | adapter_item_addr(ioctl_pending), 1}, | ||
134 | {"tx_pending", adapter_item_size(tx_pending), | ||
135 | adapter_item_addr(tx_pending), 1}, | ||
136 | {"rx_pending", adapter_item_size(rx_pending), | ||
137 | adapter_item_addr(rx_pending), 1}, | ||
138 | }; | ||
139 | |||
140 | static int num_of_items = ARRAY_SIZE(items); | ||
141 | |||
142 | /* | ||
143 | * Generic proc file open handler. | ||
144 | * | ||
145 | * This function is called every time a file is accessed for read or write. | ||
146 | */ | ||
147 | static int | ||
148 | mwifiex_open_generic(struct inode *inode, struct file *file) | ||
149 | { | ||
150 | file->private_data = inode->i_private; | ||
151 | return 0; | ||
152 | } | ||
153 | |||
154 | /* | ||
155 | * Proc info file read handler. | ||
156 | * | ||
157 | * This function is called when the 'info' file is opened for reading. | ||
158 | * It prints the following driver related information - | ||
159 | * - Driver name | ||
160 | * - Driver version | ||
161 | * - Driver extended version | ||
162 | * - Interface name | ||
163 | * - BSS mode | ||
164 | * - Media state (connected or disconnected) | ||
165 | * - MAC address | ||
166 | * - Total number of Tx bytes | ||
167 | * - Total number of Rx bytes | ||
168 | * - Total number of Tx packets | ||
169 | * - Total number of Rx packets | ||
170 | * - Total number of dropped Tx packets | ||
171 | * - Total number of dropped Rx packets | ||
172 | * - Total number of corrupted Tx packets | ||
173 | * - Total number of corrupted Rx packets | ||
174 | * - Carrier status (on or off) | ||
175 | * - Tx queue status (started or stopped) | ||
176 | * | ||
177 | * For STA mode drivers, it also prints the following extra - | ||
178 | * - ESSID | ||
179 | * - BSSID | ||
180 | * - Channel | ||
181 | * - Region code | ||
182 | * - Multicast count | ||
183 | * - Multicast addresses | ||
184 | */ | ||
185 | static ssize_t | ||
186 | mwifiex_info_read(struct file *file, char __user *ubuf, | ||
187 | size_t count, loff_t *ppos) | ||
188 | { | ||
189 | struct mwifiex_private *priv = | ||
190 | (struct mwifiex_private *) file->private_data; | ||
191 | struct net_device *netdev = priv->netdev; | ||
192 | struct netdev_hw_addr *ha; | ||
193 | unsigned long page = get_zeroed_page(GFP_KERNEL); | ||
194 | char *p = (char *) page, fmt[64]; | ||
195 | struct mwifiex_bss_info info; | ||
196 | ssize_t ret = 0; | ||
197 | int i = 0; | ||
198 | |||
199 | if (!p) | ||
200 | return -ENOMEM; | ||
201 | |||
202 | memset(&info, 0, sizeof(info)); | ||
203 | ret = mwifiex_get_bss_info(priv, &info); | ||
204 | if (ret) | ||
205 | goto free_and_exit; | ||
206 | |||
207 | mwifiex_drv_get_driver_version(priv->adapter, fmt, sizeof(fmt) - 1); | ||
208 | |||
209 | if (!priv->version_str[0]) | ||
210 | mwifiex_get_ver_ext(priv); | ||
211 | |||
212 | p += sprintf(p, "driver_name = " "\"mwifiex\"\n"); | ||
213 | p += sprintf(p, "driver_version = %s", fmt); | ||
214 | p += sprintf(p, "\nverext = %s", priv->version_str); | ||
215 | p += sprintf(p, "\ninterface_name=\"%s\"\n", netdev->name); | ||
216 | p += sprintf(p, "bss_mode=\"%s\"\n", bss_modes[info.bss_mode]); | ||
217 | p += sprintf(p, "media_state=\"%s\"\n", | ||
218 | (!priv->media_connected ? "Disconnected" : "Connected")); | ||
219 | p += sprintf(p, "mac_address=\"%02x:%02x:%02x:%02x:%02x:%02x\"\n", | ||
220 | netdev->dev_addr[0], netdev->dev_addr[1], | ||
221 | netdev->dev_addr[2], netdev->dev_addr[3], | ||
222 | netdev->dev_addr[4], netdev->dev_addr[5]); | ||
223 | |||
224 | if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) { | ||
225 | p += sprintf(p, "multicast_count=\"%d\"\n", | ||
226 | netdev_mc_count(netdev)); | ||
227 | p += sprintf(p, "essid=\"%s\"\n", info.ssid.ssid); | ||
228 | p += sprintf(p, "bssid=\"%02x:%02x:%02x:%02x:%02x:%02x\"\n", | ||
229 | info.bssid[0], info.bssid[1], | ||
230 | info.bssid[2], info.bssid[3], | ||
231 | info.bssid[4], info.bssid[5]); | ||
232 | p += sprintf(p, "channel=\"%d\"\n", (int) info.bss_chan); | ||
233 | p += sprintf(p, "region_code = \"%02x\"\n", info.region_code); | ||
234 | |||
235 | netdev_for_each_mc_addr(ha, netdev) | ||
236 | p += sprintf(p, "multicast_address[%d]=" | ||
237 | "\"%02x:%02x:%02x:%02x:%02x:%02x\"\n", i++, | ||
238 | ha->addr[0], ha->addr[1], | ||
239 | ha->addr[2], ha->addr[3], | ||
240 | ha->addr[4], ha->addr[5]); | ||
241 | } | ||
242 | |||
243 | p += sprintf(p, "num_tx_bytes = %lu\n", priv->stats.tx_bytes); | ||
244 | p += sprintf(p, "num_rx_bytes = %lu\n", priv->stats.rx_bytes); | ||
245 | p += sprintf(p, "num_tx_pkts = %lu\n", priv->stats.tx_packets); | ||
246 | p += sprintf(p, "num_rx_pkts = %lu\n", priv->stats.rx_packets); | ||
247 | p += sprintf(p, "num_tx_pkts_dropped = %lu\n", priv->stats.tx_dropped); | ||
248 | p += sprintf(p, "num_rx_pkts_dropped = %lu\n", priv->stats.rx_dropped); | ||
249 | p += sprintf(p, "num_tx_pkts_err = %lu\n", priv->stats.tx_errors); | ||
250 | p += sprintf(p, "num_rx_pkts_err = %lu\n", priv->stats.rx_errors); | ||
251 | p += sprintf(p, "carrier %s\n", ((netif_carrier_ok(priv->netdev)) | ||
252 | ? "on" : "off")); | ||
253 | p += sprintf(p, "tx queue %s\n", ((netif_queue_stopped(priv->netdev)) | ||
254 | ? "stopped" : "started")); | ||
255 | |||
256 | ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page, | ||
257 | (unsigned long) p - page); | ||
258 | |||
259 | free_and_exit: | ||
260 | free_page(page); | ||
261 | return ret; | ||
262 | } | ||
263 | |||
264 | /* | ||
265 | * Proc getlog file read handler. | ||
266 | * | ||
267 | * This function is called when the 'getlog' file is opened for reading | ||
268 | * It prints the following log information - | ||
269 | * - Number of multicast Tx frames | ||
270 | * - Number of failed packets | ||
271 | * - Number of Tx retries | ||
272 | * - Number of multicast Tx retries | ||
273 | * - Number of duplicate frames | ||
274 | * - Number of RTS successes | ||
275 | * - Number of RTS failures | ||
276 | * - Number of ACK failures | ||
277 | * - Number of fragmented Rx frames | ||
278 | * - Number of multicast Rx frames | ||
279 | * - Number of FCS errors | ||
280 | * - Number of Tx frames | ||
281 | * - WEP ICV error counts | ||
282 | */ | ||
283 | static ssize_t | ||
284 | mwifiex_getlog_read(struct file *file, char __user *ubuf, | ||
285 | size_t count, loff_t *ppos) | ||
286 | { | ||
287 | struct mwifiex_private *priv = | ||
288 | (struct mwifiex_private *) file->private_data; | ||
289 | unsigned long page = get_zeroed_page(GFP_KERNEL); | ||
290 | char *p = (char *) page; | ||
291 | ssize_t ret = 0; | ||
292 | struct mwifiex_ds_get_stats stats; | ||
293 | |||
294 | if (!p) | ||
295 | return -ENOMEM; | ||
296 | |||
297 | memset(&stats, 0, sizeof(stats)); | ||
298 | ret = mwifiex_get_stats_info(priv, &stats); | ||
299 | if (ret) | ||
300 | goto free_and_exit; | ||
301 | |||
302 | p += sprintf(p, "\n" | ||
303 | "mcasttxframe %u\n" | ||
304 | "failed %u\n" | ||
305 | "retry %u\n" | ||
306 | "multiretry %u\n" | ||
307 | "framedup %u\n" | ||
308 | "rtssuccess %u\n" | ||
309 | "rtsfailure %u\n" | ||
310 | "ackfailure %u\n" | ||
311 | "rxfrag %u\n" | ||
312 | "mcastrxframe %u\n" | ||
313 | "fcserror %u\n" | ||
314 | "txframe %u\n" | ||
315 | "wepicverrcnt-1 %u\n" | ||
316 | "wepicverrcnt-2 %u\n" | ||
317 | "wepicverrcnt-3 %u\n" | ||
318 | "wepicverrcnt-4 %u\n", | ||
319 | stats.mcast_tx_frame, | ||
320 | stats.failed, | ||
321 | stats.retry, | ||
322 | stats.multi_retry, | ||
323 | stats.frame_dup, | ||
324 | stats.rts_success, | ||
325 | stats.rts_failure, | ||
326 | stats.ack_failure, | ||
327 | stats.rx_frag, | ||
328 | stats.mcast_rx_frame, | ||
329 | stats.fcs_error, | ||
330 | stats.tx_frame, | ||
331 | stats.wep_icv_error[0], | ||
332 | stats.wep_icv_error[1], | ||
333 | stats.wep_icv_error[2], | ||
334 | stats.wep_icv_error[3]); | ||
335 | |||
336 | |||
337 | ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page, | ||
338 | (unsigned long) p - page); | ||
339 | |||
340 | free_and_exit: | ||
341 | free_page(page); | ||
342 | return ret; | ||
343 | } | ||
344 | |||
345 | static struct mwifiex_debug_info info; | ||
346 | |||
347 | /* | ||
348 | * Proc debug file read handler. | ||
349 | * | ||
350 | * This function is called when the 'debug' file is opened for reading | ||
351 | * It prints the following log information - | ||
352 | * - Interrupt count | ||
353 | * - WMM AC VO packets count | ||
354 | * - WMM AC VI packets count | ||
355 | * - WMM AC BE packets count | ||
356 | * - WMM AC BK packets count | ||
357 | * - Maximum Tx buffer size | ||
358 | * - Tx buffer size | ||
359 | * - Current Tx buffer size | ||
360 | * - Power Save mode | ||
361 | * - Power Save state | ||
362 | * - Deep Sleep status | ||
363 | * - Device wakeup required status | ||
364 | * - Number of wakeup tries | ||
365 | * - Host Sleep configured status | ||
366 | * - Host Sleep activated status | ||
367 | * - Number of Tx timeouts | ||
368 | * - Number of command timeouts | ||
369 | * - Last timed out command ID | ||
370 | * - Last timed out command action | ||
371 | * - Last command ID | ||
372 | * - Last command action | ||
373 | * - Last command index | ||
374 | * - Last command response ID | ||
375 | * - Last command response index | ||
376 | * - Last event | ||
377 | * - Last event index | ||
378 | * - Number of host to card command failures | ||
379 | * - Number of sleep confirm command failures | ||
380 | * - Number of host to card data failure | ||
381 | * - Number of deauthentication events | ||
382 | * - Number of disassociation events | ||
383 | * - Number of link lost events | ||
384 | * - Number of deauthentication commands | ||
385 | * - Number of association success commands | ||
386 | * - Number of association failure commands | ||
387 | * - Number of commands sent | ||
388 | * - Number of data packets sent | ||
389 | * - Number of command responses received | ||
390 | * - Number of events received | ||
391 | * - Tx BA stream table (TID, RA) | ||
392 | * - Rx reorder table (TID, TA, Start window, Window size, Buffer) | ||
393 | */ | ||
394 | static ssize_t | ||
395 | mwifiex_debug_read(struct file *file, char __user *ubuf, | ||
396 | size_t count, loff_t *ppos) | ||
397 | { | ||
398 | struct mwifiex_private *priv = | ||
399 | (struct mwifiex_private *) file->private_data; | ||
400 | struct mwifiex_debug_data *d = &items[0]; | ||
401 | unsigned long page = get_zeroed_page(GFP_KERNEL); | ||
402 | char *p = (char *) page; | ||
403 | ssize_t ret = 0; | ||
404 | size_t size, addr; | ||
405 | long val; | ||
406 | int i, j; | ||
407 | |||
408 | if (!p) | ||
409 | return -ENOMEM; | ||
410 | |||
411 | ret = mwifiex_get_debug_info(priv, &info); | ||
412 | if (ret) | ||
413 | goto free_and_exit; | ||
414 | |||
415 | for (i = 0; i < num_of_items; i++) { | ||
416 | p += sprintf(p, "%s=", d[i].name); | ||
417 | |||
418 | size = d[i].size / d[i].num; | ||
419 | |||
420 | if (i < (num_of_items - 3)) | ||
421 | addr = d[i].addr + (size_t) &info; | ||
422 | else /* The last 3 items are struct mwifiex_adapter variables */ | ||
423 | addr = d[i].addr + (size_t) priv->adapter; | ||
424 | |||
425 | for (j = 0; j < d[i].num; j++) { | ||
426 | switch (size) { | ||
427 | case 1: | ||
428 | val = *((u8 *) addr); | ||
429 | break; | ||
430 | case 2: | ||
431 | val = *((u16 *) addr); | ||
432 | break; | ||
433 | case 4: | ||
434 | val = *((u32 *) addr); | ||
435 | break; | ||
436 | case 8: | ||
437 | val = *((long long *) addr); | ||
438 | break; | ||
439 | default: | ||
440 | val = -1; | ||
441 | break; | ||
442 | } | ||
443 | |||
444 | p += sprintf(p, "%#lx ", val); | ||
445 | addr += size; | ||
446 | } | ||
447 | |||
448 | p += sprintf(p, "\n"); | ||
449 | } | ||
450 | |||
451 | if (info.tx_tbl_num) { | ||
452 | p += sprintf(p, "Tx BA stream table:\n"); | ||
453 | for (i = 0; i < info.tx_tbl_num; i++) | ||
454 | p += sprintf(p, "tid = %d, " | ||
455 | "ra = %02x:%02x:%02x:%02x:%02x:%02x\n", | ||
456 | info.tx_tbl[i].tid, info.tx_tbl[i].ra[0], | ||
457 | info.tx_tbl[i].ra[1], info.tx_tbl[i].ra[2], | ||
458 | info.tx_tbl[i].ra[3], info.tx_tbl[i].ra[4], | ||
459 | info.tx_tbl[i].ra[5]); | ||
460 | } | ||
461 | |||
462 | if (info.rx_tbl_num) { | ||
463 | p += sprintf(p, "Rx reorder table:\n"); | ||
464 | for (i = 0; i < info.rx_tbl_num; i++) { | ||
465 | |||
466 | p += sprintf(p, "tid = %d, " | ||
467 | "ta = %02x:%02x:%02x:%02x:%02x:%02x, " | ||
468 | "start_win = %d, " | ||
469 | "win_size = %d, buffer: ", | ||
470 | info.rx_tbl[i].tid, | ||
471 | info.rx_tbl[i].ta[0], info.rx_tbl[i].ta[1], | ||
472 | info.rx_tbl[i].ta[2], info.rx_tbl[i].ta[3], | ||
473 | info.rx_tbl[i].ta[4], info.rx_tbl[i].ta[5], | ||
474 | info.rx_tbl[i].start_win, | ||
475 | info.rx_tbl[i].win_size); | ||
476 | |||
477 | for (j = 0; j < info.rx_tbl[i].win_size; j++) | ||
478 | p += sprintf(p, "%c ", | ||
479 | info.rx_tbl[i].buffer[j] ? | ||
480 | '1' : '0'); | ||
481 | |||
482 | p += sprintf(p, "\n"); | ||
483 | } | ||
484 | } | ||
485 | |||
486 | ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page, | ||
487 | (unsigned long) p - page); | ||
488 | |||
489 | free_and_exit: | ||
490 | free_page(page); | ||
491 | return ret; | ||
492 | } | ||
493 | |||
494 | static u32 saved_reg_type, saved_reg_offset, saved_reg_value; | ||
495 | |||
496 | /* | ||
497 | * Proc regrdwr file write handler. | ||
498 | * | ||
499 | * This function is called when the 'regrdwr' file is opened for writing | ||
500 | * | ||
501 | * This function can be used to write to a register. | ||
502 | */ | ||
503 | static ssize_t | ||
504 | mwifiex_regrdwr_write(struct file *file, | ||
505 | const char __user *ubuf, size_t count, loff_t *ppos) | ||
506 | { | ||
507 | unsigned long addr = get_zeroed_page(GFP_KERNEL); | ||
508 | char *buf = (char *) addr; | ||
509 | size_t buf_size = min(count, (size_t) (PAGE_SIZE - 1)); | ||
510 | int ret = 0; | ||
511 | u32 reg_type = 0, reg_offset = 0, reg_value = UINT_MAX; | ||
512 | |||
513 | if (!buf) | ||
514 | return -ENOMEM; | ||
515 | |||
516 | |||
517 | if (copy_from_user(buf, ubuf, buf_size)) { | ||
518 | ret = -EFAULT; | ||
519 | goto done; | ||
520 | } | ||
521 | |||
522 | sscanf(buf, "%u %x %x", ®_type, ®_offset, ®_value); | ||
523 | |||
524 | if (reg_type == 0 || reg_offset == 0) { | ||
525 | ret = -EINVAL; | ||
526 | goto done; | ||
527 | } else { | ||
528 | saved_reg_type = reg_type; | ||
529 | saved_reg_offset = reg_offset; | ||
530 | saved_reg_value = reg_value; | ||
531 | ret = count; | ||
532 | } | ||
533 | done: | ||
534 | free_page(addr); | ||
535 | return ret; | ||
536 | } | ||
537 | |||
538 | /* | ||
539 | * Proc regrdwr file read handler. | ||
540 | * | ||
541 | * This function is called when the 'regrdwr' file is opened for reading | ||
542 | * | ||
543 | * This function can be used to read from a register. | ||
544 | */ | ||
545 | static ssize_t | ||
546 | mwifiex_regrdwr_read(struct file *file, char __user *ubuf, | ||
547 | size_t count, loff_t *ppos) | ||
548 | { | ||
549 | struct mwifiex_private *priv = | ||
550 | (struct mwifiex_private *) file->private_data; | ||
551 | unsigned long addr = get_zeroed_page(GFP_KERNEL); | ||
552 | char *buf = (char *) addr; | ||
553 | int pos = 0, ret = 0; | ||
554 | u32 reg_value; | ||
555 | |||
556 | if (!buf) | ||
557 | return -ENOMEM; | ||
558 | |||
559 | if (!saved_reg_type) { | ||
560 | /* No command has been given */ | ||
561 | pos += snprintf(buf, PAGE_SIZE, "0"); | ||
562 | goto done; | ||
563 | } | ||
564 | /* Set command has been given */ | ||
565 | if (saved_reg_value != UINT_MAX) { | ||
566 | ret = mwifiex_reg_write(priv, saved_reg_type, saved_reg_offset, | ||
567 | saved_reg_value); | ||
568 | |||
569 | pos += snprintf(buf, PAGE_SIZE, "%u 0x%x 0x%x\n", | ||
570 | saved_reg_type, saved_reg_offset, | ||
571 | saved_reg_value); | ||
572 | |||
573 | ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos); | ||
574 | |||
575 | goto done; | ||
576 | } | ||
577 | /* Get command has been given */ | ||
578 | ret = mwifiex_reg_read(priv, saved_reg_type, | ||
579 | saved_reg_offset, ®_value); | ||
580 | if (ret) { | ||
581 | ret = -EINVAL; | ||
582 | goto done; | ||
583 | } | ||
584 | |||
585 | pos += snprintf(buf, PAGE_SIZE, "%u 0x%x 0x%x\n", saved_reg_type, | ||
586 | saved_reg_offset, reg_value); | ||
587 | |||
588 | ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos); | ||
589 | |||
590 | done: | ||
591 | free_page(addr); | ||
592 | return ret; | ||
593 | } | ||
594 | |||
595 | static u32 saved_offset = -1, saved_bytes = -1; | ||
596 | |||
597 | /* | ||
598 | * Proc rdeeprom file write handler. | ||
599 | * | ||
600 | * This function is called when the 'rdeeprom' file is opened for writing | ||
601 | * | ||
602 | * This function can be used to write to a RDEEPROM location. | ||
603 | */ | ||
604 | static ssize_t | ||
605 | mwifiex_rdeeprom_write(struct file *file, | ||
606 | const char __user *ubuf, size_t count, loff_t *ppos) | ||
607 | { | ||
608 | unsigned long addr = get_zeroed_page(GFP_KERNEL); | ||
609 | char *buf = (char *) addr; | ||
610 | size_t buf_size = min(count, (size_t) (PAGE_SIZE - 1)); | ||
611 | int ret = 0; | ||
612 | int offset = -1, bytes = -1; | ||
613 | |||
614 | if (!buf) | ||
615 | return -ENOMEM; | ||
616 | |||
617 | |||
618 | if (copy_from_user(buf, ubuf, buf_size)) { | ||
619 | ret = -EFAULT; | ||
620 | goto done; | ||
621 | } | ||
622 | |||
623 | sscanf(buf, "%d %d", &offset, &bytes); | ||
624 | |||
625 | if (offset == -1 || bytes == -1) { | ||
626 | ret = -EINVAL; | ||
627 | goto done; | ||
628 | } else { | ||
629 | saved_offset = offset; | ||
630 | saved_bytes = bytes; | ||
631 | ret = count; | ||
632 | } | ||
633 | done: | ||
634 | free_page(addr); | ||
635 | return ret; | ||
636 | } | ||
637 | |||
638 | /* | ||
639 | * Proc rdeeprom read write handler. | ||
640 | * | ||
641 | * This function is called when the 'rdeeprom' file is opened for reading | ||
642 | * | ||
643 | * This function can be used to read from a RDEEPROM location. | ||
644 | */ | ||
645 | static ssize_t | ||
646 | mwifiex_rdeeprom_read(struct file *file, char __user *ubuf, | ||
647 | size_t count, loff_t *ppos) | ||
648 | { | ||
649 | struct mwifiex_private *priv = | ||
650 | (struct mwifiex_private *) file->private_data; | ||
651 | unsigned long addr = get_zeroed_page(GFP_KERNEL); | ||
652 | char *buf = (char *) addr; | ||
653 | int pos = 0, ret = 0, i = 0; | ||
654 | u8 value[MAX_EEPROM_DATA]; | ||
655 | |||
656 | if (!buf) | ||
657 | return -ENOMEM; | ||
658 | |||
659 | if (saved_offset == -1) { | ||
660 | /* No command has been given */ | ||
661 | pos += snprintf(buf, PAGE_SIZE, "0"); | ||
662 | goto done; | ||
663 | } | ||
664 | |||
665 | /* Get command has been given */ | ||
666 | ret = mwifiex_eeprom_read(priv, (u16) saved_offset, | ||
667 | (u16) saved_bytes, value); | ||
668 | if (ret) { | ||
669 | ret = -EINVAL; | ||
670 | goto done; | ||
671 | } | ||
672 | |||
673 | pos += snprintf(buf, PAGE_SIZE, "%d %d ", saved_offset, saved_bytes); | ||
674 | |||
675 | for (i = 0; i < saved_bytes; i++) | ||
676 | pos += snprintf(buf + strlen(buf), PAGE_SIZE, "%d ", value[i]); | ||
677 | |||
678 | ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos); | ||
679 | |||
680 | done: | ||
681 | free_page(addr); | ||
682 | return ret; | ||
683 | } | ||
684 | |||
685 | |||
686 | #define MWIFIEX_DFS_ADD_FILE(name) do { \ | ||
687 | if (!debugfs_create_file(#name, 0644, priv->dfs_dev_dir, \ | ||
688 | priv, &mwifiex_dfs_##name##_fops)) \ | ||
689 | return; \ | ||
690 | } while (0); | ||
691 | |||
692 | #define MWIFIEX_DFS_FILE_OPS(name) \ | ||
693 | static const struct file_operations mwifiex_dfs_##name##_fops = { \ | ||
694 | .read = mwifiex_##name##_read, \ | ||
695 | .write = mwifiex_##name##_write, \ | ||
696 | .open = mwifiex_open_generic, \ | ||
697 | }; | ||
698 | |||
699 | #define MWIFIEX_DFS_FILE_READ_OPS(name) \ | ||
700 | static const struct file_operations mwifiex_dfs_##name##_fops = { \ | ||
701 | .read = mwifiex_##name##_read, \ | ||
702 | .open = mwifiex_open_generic, \ | ||
703 | }; | ||
704 | |||
705 | #define MWIFIEX_DFS_FILE_WRITE_OPS(name) \ | ||
706 | static const struct file_operations mwifiex_dfs_##name##_fops = { \ | ||
707 | .write = mwifiex_##name##_write, \ | ||
708 | .open = mwifiex_open_generic, \ | ||
709 | }; | ||
710 | |||
711 | |||
712 | MWIFIEX_DFS_FILE_READ_OPS(info); | ||
713 | MWIFIEX_DFS_FILE_READ_OPS(debug); | ||
714 | MWIFIEX_DFS_FILE_READ_OPS(getlog); | ||
715 | MWIFIEX_DFS_FILE_OPS(regrdwr); | ||
716 | MWIFIEX_DFS_FILE_OPS(rdeeprom); | ||
717 | |||
718 | /* | ||
719 | * This function creates the debug FS directory structure and the files. | ||
720 | */ | ||
721 | void | ||
722 | mwifiex_dev_debugfs_init(struct mwifiex_private *priv) | ||
723 | { | ||
724 | if (!mwifiex_dfs_dir || !priv) | ||
725 | return; | ||
726 | |||
727 | priv->dfs_dev_dir = debugfs_create_dir(priv->netdev->name, | ||
728 | mwifiex_dfs_dir); | ||
729 | |||
730 | if (!priv->dfs_dev_dir) | ||
731 | return; | ||
732 | |||
733 | MWIFIEX_DFS_ADD_FILE(info); | ||
734 | MWIFIEX_DFS_ADD_FILE(debug); | ||
735 | MWIFIEX_DFS_ADD_FILE(getlog); | ||
736 | MWIFIEX_DFS_ADD_FILE(regrdwr); | ||
737 | MWIFIEX_DFS_ADD_FILE(rdeeprom); | ||
738 | |||
739 | return; | ||
740 | } | ||
741 | |||
742 | /* | ||
743 | * This function removes the debug FS directory structure and the files. | ||
744 | */ | ||
745 | void | ||
746 | mwifiex_dev_debugfs_remove(struct mwifiex_private *priv) | ||
747 | { | ||
748 | if (!priv) | ||
749 | return; | ||
750 | |||
751 | debugfs_remove_recursive(priv->dfs_dev_dir); | ||
752 | return; | ||
753 | } | ||
754 | |||
755 | /* | ||
756 | * This function creates the top level proc directory. | ||
757 | */ | ||
758 | void | ||
759 | mwifiex_debugfs_init(void) | ||
760 | { | ||
761 | if (!mwifiex_dfs_dir) | ||
762 | mwifiex_dfs_dir = debugfs_create_dir("mwifiex", NULL); | ||
763 | } | ||
764 | |||
765 | /* | ||
766 | * This function removes the top level proc directory. | ||
767 | */ | ||
768 | void | ||
769 | mwifiex_debugfs_remove(void) | ||
770 | { | ||
771 | if (mwifiex_dfs_dir) | ||
772 | debugfs_remove(mwifiex_dfs_dir); | ||
773 | } | ||
diff --git a/drivers/net/wireless/mwifiex/decl.h b/drivers/net/wireless/mwifiex/decl.h new file mode 100644 index 000000000000..c3c15f9e757e --- /dev/null +++ b/drivers/net/wireless/mwifiex/decl.h | |||
@@ -0,0 +1,153 @@ | |||
1 | /* | ||
2 | * Marvell Wireless LAN device driver: generic data structures and APIs | ||
3 | * | ||
4 | * Copyright (C) 2011, Marvell International Ltd. | ||
5 | * | ||
6 | * This software file (the "File") is distributed by Marvell International | ||
7 | * Ltd. under the terms of the GNU General Public License Version 2, June 1991 | ||
8 | * (the "License"). You may use, redistribute and/or modify this File in | ||
9 | * accordance with the terms and conditions of the License, a copy of which | ||
10 | * is available by writing to the Free Software Foundation, Inc., | ||
11 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the | ||
12 | * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. | ||
13 | * | ||
14 | * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE | ||
15 | * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE | ||
16 | * ARE EXPRESSLY DISCLAIMED. The License provides additional details about | ||
17 | * this warranty disclaimer. | ||
18 | */ | ||
19 | |||
20 | #ifndef _MWIFIEX_DECL_H_ | ||
21 | #define _MWIFIEX_DECL_H_ | ||
22 | |||
23 | #undef pr_fmt | ||
24 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
25 | |||
26 | #include <linux/wait.h> | ||
27 | #include <linux/timer.h> | ||
28 | #include <linux/ieee80211.h> | ||
29 | |||
30 | |||
31 | #define MWIFIEX_MAX_BSS_NUM (1) | ||
32 | |||
33 | #define MWIFIEX_MIN_DATA_HEADER_LEN 32 /* (sizeof(mwifiex_txpd)) */ | ||
34 | |||
35 | #define MWIFIEX_MAX_TX_BASTREAM_SUPPORTED 2 | ||
36 | #define MWIFIEX_MAX_RX_BASTREAM_SUPPORTED 16 | ||
37 | |||
38 | #define MWIFIEX_AMPDU_DEF_TXWINSIZE 32 | ||
39 | #define MWIFIEX_AMPDU_DEF_RXWINSIZE 16 | ||
40 | #define MWIFIEX_DEFAULT_BLOCK_ACK_TIMEOUT 0xffff | ||
41 | |||
42 | #define MWIFIEX_RATE_INDEX_HRDSSS0 0 | ||
43 | #define MWIFIEX_RATE_INDEX_HRDSSS3 3 | ||
44 | #define MWIFIEX_RATE_INDEX_OFDM0 4 | ||
45 | #define MWIFIEX_RATE_INDEX_OFDM7 11 | ||
46 | #define MWIFIEX_RATE_INDEX_MCS0 12 | ||
47 | |||
48 | #define MWIFIEX_RATE_BITMAP_OFDM0 16 | ||
49 | #define MWIFIEX_RATE_BITMAP_OFDM7 23 | ||
50 | #define MWIFIEX_RATE_BITMAP_MCS0 32 | ||
51 | #define MWIFIEX_RATE_BITMAP_MCS127 159 | ||
52 | |||
53 | #define MWIFIEX_RX_DATA_BUF_SIZE (4 * 1024) | ||
54 | |||
55 | #define MWIFIEX_RTS_MIN_VALUE (0) | ||
56 | #define MWIFIEX_RTS_MAX_VALUE (2347) | ||
57 | #define MWIFIEX_FRAG_MIN_VALUE (256) | ||
58 | #define MWIFIEX_FRAG_MAX_VALUE (2346) | ||
59 | |||
60 | #define MWIFIEX_SDIO_BLOCK_SIZE 256 | ||
61 | |||
62 | #define MWIFIEX_BUF_FLAG_REQUEUED_PKT BIT(0) | ||
63 | |||
64 | enum mwifiex_error_code { | ||
65 | MWIFIEX_ERROR_NO_ERROR = 0, | ||
66 | MWIFIEX_ERROR_FW_NOT_READY = 0x00000001, | ||
67 | MWIFIEX_ERROR_FW_BUSY, | ||
68 | MWIFIEX_ERROR_FW_CMDRESP, | ||
69 | MWIFIEX_ERROR_PKT_SIZE_INVALID = 0x80000001, | ||
70 | MWIFIEX_ERROR_PKT_TIMEOUT, | ||
71 | MWIFIEX_ERROR_CMD_INVALID, | ||
72 | MWIFIEX_ERROR_CMD_TIMEOUT, | ||
73 | MWIFIEX_ERROR_CMD_DNLD_FAIL, | ||
74 | MWIFIEX_ERROR_CMD_CANCEL, | ||
75 | MWIFIEX_ERROR_CMD_RESP_FAIL, | ||
76 | MWIFIEX_ERROR_ASSOC_FAIL, | ||
77 | MWIFIEX_ERROR_EVENT_UNKNOWN, | ||
78 | MWIFIEX_ERROR_INVALID_PARAMETER, | ||
79 | }; | ||
80 | |||
81 | enum mwifiex_bss_type { | ||
82 | MWIFIEX_BSS_TYPE_STA = 0, | ||
83 | MWIFIEX_BSS_TYPE_UAP = 1, | ||
84 | MWIFIEX_BSS_TYPE_ANY = 0xff, | ||
85 | }; | ||
86 | |||
87 | enum mwifiex_bss_role { | ||
88 | MWIFIEX_BSS_ROLE_STA = 0, | ||
89 | MWIFIEX_BSS_ROLE_UAP = 1, | ||
90 | MWIFIEX_BSS_ROLE_ANY = 0xff, | ||
91 | }; | ||
92 | |||
93 | #define BSS_ROLE_BIT_MASK BIT(0) | ||
94 | |||
95 | #define GET_BSS_ROLE(priv) ((priv)->bss_role & BSS_ROLE_BIT_MASK) | ||
96 | |||
97 | enum mwifiex_data_frame_type { | ||
98 | MWIFIEX_DATA_FRAME_TYPE_ETH_II = 0, | ||
99 | MWIFIEX_DATA_FRAME_TYPE_802_11, | ||
100 | }; | ||
101 | |||
102 | struct mwifiex_fw_image { | ||
103 | u8 *helper_buf; | ||
104 | u32 helper_len; | ||
105 | u8 *fw_buf; | ||
106 | u32 fw_len; | ||
107 | }; | ||
108 | |||
109 | struct mwifiex_802_11_ssid { | ||
110 | u32 ssid_len; | ||
111 | u8 ssid[IEEE80211_MAX_SSID_LEN]; | ||
112 | }; | ||
113 | |||
114 | struct mwifiex_wait_queue { | ||
115 | u32 bss_index; | ||
116 | wait_queue_head_t *wait; | ||
117 | u16 *condition; | ||
118 | u32 start_time; | ||
119 | int status; | ||
120 | u32 enabled; | ||
121 | }; | ||
122 | |||
123 | struct mwifiex_rxinfo { | ||
124 | u8 bss_index; | ||
125 | struct sk_buff *parent; | ||
126 | u8 use_count; | ||
127 | }; | ||
128 | |||
129 | struct mwifiex_txinfo { | ||
130 | u32 status_code; | ||
131 | u8 flags; | ||
132 | u8 bss_index; | ||
133 | }; | ||
134 | |||
135 | struct mwifiex_bss_attr { | ||
136 | u32 bss_type; | ||
137 | u32 frame_type; | ||
138 | u32 active; | ||
139 | u32 bss_priority; | ||
140 | u32 bss_num; | ||
141 | }; | ||
142 | |||
143 | enum mwifiex_wmm_ac_e { | ||
144 | WMM_AC_BK, | ||
145 | WMM_AC_BE, | ||
146 | WMM_AC_VI, | ||
147 | WMM_AC_VO | ||
148 | } __packed; | ||
149 | |||
150 | struct mwifiex_device { | ||
151 | struct mwifiex_bss_attr bss_attr[MWIFIEX_MAX_BSS_NUM]; | ||
152 | }; | ||
153 | #endif /* !_MWIFIEX_DECL_H_ */ | ||
diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h new file mode 100644 index 000000000000..2b938115b26a --- /dev/null +++ b/drivers/net/wireless/mwifiex/fw.h | |||
@@ -0,0 +1,1229 @@ | |||
1 | /* | ||
2 | * Marvell Wireless LAN device driver: Firmware specific macros & structures | ||
3 | * | ||
4 | * Copyright (C) 2011, Marvell International Ltd. | ||
5 | * | ||
6 | * This software file (the "File") is distributed by Marvell International | ||
7 | * Ltd. under the terms of the GNU General Public License Version 2, June 1991 | ||
8 | * (the "License"). You may use, redistribute and/or modify this File in | ||
9 | * accordance with the terms and conditions of the License, a copy of which | ||
10 | * is available by writing to the Free Software Foundation, Inc., | ||
11 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the | ||
12 | * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. | ||
13 | * | ||
14 | * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE | ||
15 | * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE | ||
16 | * ARE EXPRESSLY DISCLAIMED. The License provides additional details about | ||
17 | * this warranty disclaimer. | ||
18 | */ | ||
19 | |||
20 | #ifndef _MWIFIEX_FW_H_ | ||
21 | #define _MWIFIEX_FW_H_ | ||
22 | |||
23 | #include <linux/if_ether.h> | ||
24 | |||
25 | |||
26 | #define INTF_HEADER_LEN 4 | ||
27 | |||
28 | struct rfc_1042_hdr { | ||
29 | u8 llc_dsap; | ||
30 | u8 llc_ssap; | ||
31 | u8 llc_ctrl; | ||
32 | u8 snap_oui[3]; | ||
33 | u16 snap_type; | ||
34 | }; | ||
35 | |||
36 | struct rx_packet_hdr { | ||
37 | struct ethhdr eth803_hdr; | ||
38 | struct rfc_1042_hdr rfc1042_hdr; | ||
39 | }; | ||
40 | |||
41 | struct tx_packet_hdr { | ||
42 | struct ethhdr eth803_hdr; | ||
43 | struct rfc_1042_hdr rfc1042_hdr; | ||
44 | }; | ||
45 | |||
46 | #define B_SUPPORTED_RATES 5 | ||
47 | #define G_SUPPORTED_RATES 9 | ||
48 | #define BG_SUPPORTED_RATES 13 | ||
49 | #define A_SUPPORTED_RATES 9 | ||
50 | #define HOSTCMD_SUPPORTED_RATES 14 | ||
51 | #define N_SUPPORTED_RATES 3 | ||
52 | #define ALL_802_11_BANDS (BAND_A | BAND_B | BAND_G | BAND_GN) | ||
53 | |||
54 | #define FW_MULTI_BANDS_SUPPORT (BIT(8) | BIT(9) | BIT(10) | BIT(11)) | ||
55 | #define IS_SUPPORT_MULTI_BANDS(adapter) \ | ||
56 | (adapter->fw_cap_info & FW_MULTI_BANDS_SUPPORT) | ||
57 | #define GET_FW_DEFAULT_BANDS(adapter) \ | ||
58 | ((adapter->fw_cap_info >> 8) & ALL_802_11_BANDS) | ||
59 | |||
60 | extern u8 supported_rates_b[B_SUPPORTED_RATES]; | ||
61 | extern u8 supported_rates_g[G_SUPPORTED_RATES]; | ||
62 | extern u8 supported_rates_bg[BG_SUPPORTED_RATES]; | ||
63 | extern u8 supported_rates_a[A_SUPPORTED_RATES]; | ||
64 | extern u8 supported_rates_n[N_SUPPORTED_RATES]; | ||
65 | |||
66 | #define HostCmd_WEP_KEY_INDEX_MASK 0x3fff | ||
67 | |||
68 | #define KEY_INFO_ENABLED 0x01 | ||
69 | enum KEY_TYPE_ID { | ||
70 | KEY_TYPE_ID_WEP = 0, | ||
71 | KEY_TYPE_ID_TKIP, | ||
72 | KEY_TYPE_ID_AES, | ||
73 | KEY_TYPE_ID_WAPI, | ||
74 | }; | ||
75 | |||
76 | enum KEY_INFO_WEP { | ||
77 | KEY_INFO_WEP_MCAST = 0x01, | ||
78 | KEY_INFO_WEP_UNICAST = 0x02, | ||
79 | KEY_INFO_WEP_ENABLED = 0x04 | ||
80 | }; | ||
81 | |||
82 | enum KEY_INFO_TKIP { | ||
83 | KEY_INFO_TKIP_MCAST = 0x01, | ||
84 | KEY_INFO_TKIP_UNICAST = 0x02, | ||
85 | KEY_INFO_TKIP_ENABLED = 0x04 | ||
86 | }; | ||
87 | |||
88 | enum KEY_INFO_AES { | ||
89 | KEY_INFO_AES_MCAST = 0x01, | ||
90 | KEY_INFO_AES_UNICAST = 0x02, | ||
91 | KEY_INFO_AES_ENABLED = 0x04 | ||
92 | }; | ||
93 | |||
94 | #define WAPI_KEY_LEN 50 | ||
95 | |||
96 | enum KEY_INFO_WAPI { | ||
97 | KEY_INFO_WAPI_MCAST = 0x01, | ||
98 | KEY_INFO_WAPI_UNICAST = 0x02, | ||
99 | KEY_INFO_WAPI_ENABLED = 0x04 | ||
100 | }; | ||
101 | |||
102 | #define MAX_POLL_TRIES 100 | ||
103 | |||
104 | #define MAX_MULTI_INTERFACE_POLL_TRIES 1000 | ||
105 | |||
106 | #define MAX_FIRMWARE_POLL_TRIES 100 | ||
107 | |||
108 | #define FIRMWARE_READY 0xfedc | ||
109 | |||
110 | enum MWIFIEX_802_11_PRIVACY_FILTER { | ||
111 | MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL, | ||
112 | MWIFIEX_802_11_PRIV_FILTER_8021X_WEP | ||
113 | }; | ||
114 | |||
115 | enum MWIFIEX_802_11_WEP_STATUS { | ||
116 | MWIFIEX_802_11_WEP_ENABLED, | ||
117 | MWIFIEX_802_11_WEP_DISABLED, | ||
118 | }; | ||
119 | |||
120 | #define CAL_SNR(RSSI, NF) ((s16)((s16)(RSSI)-(s16)(NF))) | ||
121 | |||
122 | #define PROPRIETARY_TLV_BASE_ID 0x0100 | ||
123 | #define TLV_TYPE_KEY_MATERIAL (PROPRIETARY_TLV_BASE_ID + 0) | ||
124 | #define TLV_TYPE_CHANLIST (PROPRIETARY_TLV_BASE_ID + 1) | ||
125 | #define TLV_TYPE_NUMPROBES (PROPRIETARY_TLV_BASE_ID + 2) | ||
126 | #define TLV_TYPE_PASSTHROUGH (PROPRIETARY_TLV_BASE_ID + 10) | ||
127 | #define TLV_TYPE_WMMQSTATUS (PROPRIETARY_TLV_BASE_ID + 16) | ||
128 | #define TLV_TYPE_WILDCARDSSID (PROPRIETARY_TLV_BASE_ID + 18) | ||
129 | #define TLV_TYPE_TSFTIMESTAMP (PROPRIETARY_TLV_BASE_ID + 19) | ||
130 | #define TLV_TYPE_AUTH_TYPE (PROPRIETARY_TLV_BASE_ID + 31) | ||
131 | #define TLV_TYPE_CHANNELBANDLIST (PROPRIETARY_TLV_BASE_ID + 42) | ||
132 | #define TLV_TYPE_RATE_DROP_CONTROL (PROPRIETARY_TLV_BASE_ID + 82) | ||
133 | #define TLV_TYPE_RATE_SCOPE (PROPRIETARY_TLV_BASE_ID + 83) | ||
134 | #define TLV_TYPE_POWER_GROUP (PROPRIETARY_TLV_BASE_ID + 84) | ||
135 | #define TLV_TYPE_WAPI_IE (PROPRIETARY_TLV_BASE_ID + 94) | ||
136 | #define TLV_TYPE_AUTO_DS_PARAM (PROPRIETARY_TLV_BASE_ID + 113) | ||
137 | #define TLV_TYPE_PS_PARAM (PROPRIETARY_TLV_BASE_ID + 114) | ||
138 | |||
139 | #define MWIFIEX_TX_DATA_BUF_SIZE_2K 2048 | ||
140 | |||
141 | #define SSN_MASK 0xfff0 | ||
142 | |||
143 | #define BA_RESULT_SUCCESS 0x0 | ||
144 | #define BA_RESULT_TIMEOUT 0x2 | ||
145 | |||
146 | #define IS_BASTREAM_SETUP(ptr) (ptr->ba_status) | ||
147 | |||
148 | #define BA_STREAM_NOT_ALLOWED 0xff | ||
149 | |||
150 | #define IS_11N_ENABLED(priv) ((priv->adapter->config_bands & BAND_GN || \ | ||
151 | priv->adapter->config_bands & BAND_AN) \ | ||
152 | && priv->curr_bss_params.bss_descriptor.bcn_ht_cap) | ||
153 | #define INITIATOR_BIT(DelBAParamSet) (((DelBAParamSet) &\ | ||
154 | BIT(DELBA_INITIATOR_POS)) >> DELBA_INITIATOR_POS) | ||
155 | |||
156 | #define MWIFIEX_TX_DATA_BUF_SIZE_4K 4096 | ||
157 | #define MWIFIEX_TX_DATA_BUF_SIZE_8K 8192 | ||
158 | #define NON_GREENFIELD_STAS 0x04 | ||
159 | |||
160 | #define ISSUPP_11NENABLED(FwCapInfo) (FwCapInfo & BIT(11)) | ||
161 | |||
162 | /* dev_cap bitmap | ||
163 | * BIT | ||
164 | * 0-16 reserved | ||
165 | * 17 IEEE80211_HT_CAP_SUP_WIDTH_20_40 | ||
166 | * 18-22 reserved | ||
167 | * 23 IEEE80211_HT_CAP_SGI_20 | ||
168 | * 24 IEEE80211_HT_CAP_SGI_40 | ||
169 | * 25 IEEE80211_HT_CAP_TX_STBC | ||
170 | * 26 IEEE80211_HT_CAP_RX_STBC | ||
171 | * 27-28 reserved | ||
172 | * 29 IEEE80211_HT_CAP_GRN_FLD | ||
173 | * 30-31 reserved | ||
174 | */ | ||
175 | #define ISSUPP_CHANWIDTH40(Dot11nDevCap) (Dot11nDevCap & BIT(17)) | ||
176 | #define ISSUPP_SHORTGI20(Dot11nDevCap) (Dot11nDevCap & BIT(23)) | ||
177 | #define ISSUPP_SHORTGI40(Dot11nDevCap) (Dot11nDevCap & BIT(24)) | ||
178 | #define ISSUPP_TXSTBC(Dot11nDevCap) (Dot11nDevCap & BIT(25)) | ||
179 | #define ISSUPP_RXSTBC(Dot11nDevCap) (Dot11nDevCap & BIT(26)) | ||
180 | #define ISSUPP_GREENFIELD(Dot11nDevCap) (Dot11nDevCap & BIT(29)) | ||
181 | |||
182 | #define GET_RXMCSSUPP(DevMCSSupported) (DevMCSSupported & 0x0f) | ||
183 | #define RESETHT_EXTCAP_RDG(HTExtCap) (HTExtCap &= ~BIT(11)) | ||
184 | #define SETHT_MCS32(x) (x[4] |= 1) | ||
185 | |||
186 | #define SET_SECONDARYCHAN(RadioType, SECCHAN) (RadioType |= (SECCHAN << 4)) | ||
187 | |||
188 | #define LLC_SNAP_LEN 8 | ||
189 | |||
190 | #define MOD_CLASS_HR_DSSS 0x03 | ||
191 | #define MOD_CLASS_OFDM 0x07 | ||
192 | #define MOD_CLASS_HT 0x08 | ||
193 | #define HT_BW_20 0 | ||
194 | #define HT_BW_40 1 | ||
195 | |||
196 | #define HostCmd_CMD_GET_HW_SPEC 0x0003 | ||
197 | #define HostCmd_CMD_802_11_SCAN 0x0006 | ||
198 | #define HostCmd_CMD_802_11_GET_LOG 0x000b | ||
199 | #define HostCmd_CMD_MAC_MULTICAST_ADR 0x0010 | ||
200 | #define HostCmd_CMD_802_11_EEPROM_ACCESS 0x0059 | ||
201 | #define HostCmd_CMD_802_11_ASSOCIATE 0x0012 | ||
202 | #define HostCmd_CMD_802_11_SNMP_MIB 0x0016 | ||
203 | #define HostCmd_CMD_MAC_REG_ACCESS 0x0019 | ||
204 | #define HostCmd_CMD_BBP_REG_ACCESS 0x001a | ||
205 | #define HostCmd_CMD_RF_REG_ACCESS 0x001b | ||
206 | #define HostCmd_CMD_PMIC_REG_ACCESS 0x00ad | ||
207 | #define HostCmd_CMD_802_11_RF_CHANNEL 0x001d | ||
208 | #define HostCmd_CMD_802_11_DEAUTHENTICATE 0x0024 | ||
209 | #define HostCmd_CMD_MAC_CONTROL 0x0028 | ||
210 | #define HostCmd_CMD_802_11_AD_HOC_START 0x002b | ||
211 | #define HostCmd_CMD_802_11_AD_HOC_JOIN 0x002c | ||
212 | #define HostCmd_CMD_802_11_AD_HOC_STOP 0x0040 | ||
213 | #define HostCmd_CMD_802_11_MAC_ADDRESS 0x004D | ||
214 | #define HostCmd_CMD_802_11D_DOMAIN_INFO 0x005b | ||
215 | #define HostCmd_CMD_802_11_KEY_MATERIAL 0x005e | ||
216 | #define HostCmd_CMD_802_11_BG_SCAN_QUERY 0x006c | ||
217 | #define HostCmd_CMD_WMM_GET_STATUS 0x0071 | ||
218 | #define HostCmd_CMD_802_11_TX_RATE_QUERY 0x007f | ||
219 | #define HostCmd_CMD_802_11_IBSS_COALESCING_STATUS 0x0083 | ||
220 | #define HostCmd_CMD_VERSION_EXT 0x0097 | ||
221 | #define HostCmd_CMD_RSSI_INFO 0x00a4 | ||
222 | #define HostCmd_CMD_FUNC_INIT 0x00a9 | ||
223 | #define HostCmd_CMD_FUNC_SHUTDOWN 0x00aa | ||
224 | #define HostCmd_CMD_11N_CFG 0x00cd | ||
225 | #define HostCmd_CMD_11N_ADDBA_REQ 0x00ce | ||
226 | #define HostCmd_CMD_11N_ADDBA_RSP 0x00cf | ||
227 | #define HostCmd_CMD_11N_DELBA 0x00d0 | ||
228 | #define HostCmd_CMD_RECONFIGURE_TX_BUFF 0x00d9 | ||
229 | #define HostCmd_CMD_AMSDU_AGGR_CTRL 0x00df | ||
230 | #define HostCmd_CMD_TXPWR_CFG 0x00d1 | ||
231 | #define HostCmd_CMD_TX_RATE_CFG 0x00d6 | ||
232 | #define HostCmd_CMD_802_11_PS_MODE_ENH 0x00e4 | ||
233 | #define HostCmd_CMD_802_11_HS_CFG_ENH 0x00e5 | ||
234 | #define HostCmd_CMD_CAU_REG_ACCESS 0x00ed | ||
235 | #define HostCmd_CMD_SET_BSS_MODE 0x00f7 | ||
236 | |||
237 | |||
238 | enum ENH_PS_MODES { | ||
239 | EN_PS = 1, | ||
240 | DIS_PS = 2, | ||
241 | EN_AUTO_DS = 3, | ||
242 | DIS_AUTO_DS = 4, | ||
243 | SLEEP_CONFIRM = 5, | ||
244 | GET_PS = 0, | ||
245 | EN_AUTO_PS = 0xff, | ||
246 | DIS_AUTO_PS = 0xfe, | ||
247 | }; | ||
248 | |||
249 | #define HostCmd_RET_BIT 0x8000 | ||
250 | #define HostCmd_ACT_GEN_GET 0x0000 | ||
251 | #define HostCmd_ACT_GEN_SET 0x0001 | ||
252 | #define HostCmd_RESULT_OK 0x0000 | ||
253 | |||
254 | #define HostCmd_ACT_MAC_RX_ON 0x0001 | ||
255 | #define HostCmd_ACT_MAC_TX_ON 0x0002 | ||
256 | #define HostCmd_ACT_MAC_WEP_ENABLE 0x0008 | ||
257 | #define HostCmd_ACT_MAC_ETHERNETII_ENABLE 0x0010 | ||
258 | #define HostCmd_ACT_MAC_PROMISCUOUS_ENABLE 0x0080 | ||
259 | #define HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE 0x0100 | ||
260 | #define HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON 0x2000 | ||
261 | |||
262 | #define HostCmd_BSS_MODE_IBSS 0x0002 | ||
263 | #define HostCmd_BSS_MODE_ANY 0x0003 | ||
264 | |||
265 | #define HostCmd_SCAN_RADIO_TYPE_BG 0 | ||
266 | #define HostCmd_SCAN_RADIO_TYPE_A 1 | ||
267 | |||
268 | #define HOST_SLEEP_CFG_CANCEL 0xffffffff | ||
269 | #define HOST_SLEEP_CFG_COND_DEF 0x0000000f | ||
270 | #define HOST_SLEEP_CFG_GPIO_DEF 0xff | ||
271 | #define HOST_SLEEP_CFG_GAP_DEF 0 | ||
272 | |||
273 | #define CMD_F_HOSTCMD (1 << 0) | ||
274 | #define CMD_F_CANCELED (1 << 1) | ||
275 | |||
276 | #define HostCmd_CMD_ID_MASK 0x0fff | ||
277 | |||
278 | #define HostCmd_SEQ_NUM_MASK 0x00ff | ||
279 | |||
280 | #define HostCmd_BSS_NUM_MASK 0x0f00 | ||
281 | |||
282 | #define HostCmd_BSS_TYPE_MASK 0xf000 | ||
283 | |||
284 | #define HostCmd_SET_SEQ_NO_BSS_INFO(seq, num, type) { \ | ||
285 | (((seq) & 0x00ff) | \ | ||
286 | (((num) & 0x000f) << 8)) | \ | ||
287 | (((type) & 0x000f) << 12); } | ||
288 | |||
289 | #define HostCmd_GET_SEQ_NO(seq) \ | ||
290 | ((seq) & HostCmd_SEQ_NUM_MASK) | ||
291 | |||
292 | #define HostCmd_GET_BSS_NO(seq) \ | ||
293 | (((seq) & HostCmd_BSS_NUM_MASK) >> 8) | ||
294 | |||
295 | #define HostCmd_GET_BSS_TYPE(seq) \ | ||
296 | (((seq) & HostCmd_BSS_TYPE_MASK) >> 12) | ||
297 | |||
298 | #define EVENT_DUMMY_HOST_WAKEUP_SIGNAL 0x00000001 | ||
299 | #define EVENT_LINK_LOST 0x00000003 | ||
300 | #define EVENT_LINK_SENSED 0x00000004 | ||
301 | #define EVENT_MIB_CHANGED 0x00000006 | ||
302 | #define EVENT_INIT_DONE 0x00000007 | ||
303 | #define EVENT_DEAUTHENTICATED 0x00000008 | ||
304 | #define EVENT_DISASSOCIATED 0x00000009 | ||
305 | #define EVENT_PS_AWAKE 0x0000000a | ||
306 | #define EVENT_PS_SLEEP 0x0000000b | ||
307 | #define EVENT_MIC_ERR_MULTICAST 0x0000000d | ||
308 | #define EVENT_MIC_ERR_UNICAST 0x0000000e | ||
309 | #define EVENT_DEEP_SLEEP_AWAKE 0x00000010 | ||
310 | #define EVENT_ADHOC_BCN_LOST 0x00000011 | ||
311 | |||
312 | #define EVENT_WMM_STATUS_CHANGE 0x00000017 | ||
313 | #define EVENT_BG_SCAN_REPORT 0x00000018 | ||
314 | #define EVENT_RSSI_LOW 0x00000019 | ||
315 | #define EVENT_SNR_LOW 0x0000001a | ||
316 | #define EVENT_MAX_FAIL 0x0000001b | ||
317 | #define EVENT_RSSI_HIGH 0x0000001c | ||
318 | #define EVENT_SNR_HIGH 0x0000001d | ||
319 | #define EVENT_IBSS_COALESCED 0x0000001e | ||
320 | #define EVENT_DATA_RSSI_LOW 0x00000024 | ||
321 | #define EVENT_DATA_SNR_LOW 0x00000025 | ||
322 | #define EVENT_DATA_RSSI_HIGH 0x00000026 | ||
323 | #define EVENT_DATA_SNR_HIGH 0x00000027 | ||
324 | #define EVENT_LINK_QUALITY 0x00000028 | ||
325 | #define EVENT_PORT_RELEASE 0x0000002b | ||
326 | #define EVENT_PRE_BEACON_LOST 0x00000031 | ||
327 | #define EVENT_ADDBA 0x00000033 | ||
328 | #define EVENT_DELBA 0x00000034 | ||
329 | #define EVENT_BA_STREAM_TIEMOUT 0x00000037 | ||
330 | #define EVENT_AMSDU_AGGR_CTRL 0x00000042 | ||
331 | #define EVENT_WEP_ICV_ERR 0x00000046 | ||
332 | #define EVENT_HS_ACT_REQ 0x00000047 | ||
333 | #define EVENT_BW_CHANGE 0x00000048 | ||
334 | |||
335 | #define EVENT_HOSTWAKE_STAIE 0x0000004d | ||
336 | |||
337 | #define EVENT_ID_MASK 0xffff | ||
338 | #define BSS_NUM_MASK 0xf | ||
339 | |||
340 | #define EVENT_GET_BSS_NUM(event_cause) \ | ||
341 | (((event_cause) >> 16) & BSS_NUM_MASK) | ||
342 | |||
343 | #define EVENT_GET_BSS_TYPE(event_cause) \ | ||
344 | (((event_cause) >> 24) & 0x00ff) | ||
345 | |||
346 | struct mwifiex_ie_types_header { | ||
347 | __le16 type; | ||
348 | __le16 len; | ||
349 | } __packed; | ||
350 | |||
351 | struct mwifiex_ie_types_data { | ||
352 | struct mwifiex_ie_types_header header; | ||
353 | u8 data[1]; | ||
354 | } __packed; | ||
355 | |||
356 | #define MWIFIEX_TxPD_POWER_MGMT_NULL_PACKET 0x01 | ||
357 | #define MWIFIEX_TxPD_POWER_MGMT_LAST_PACKET 0x08 | ||
358 | |||
359 | struct txpd { | ||
360 | u8 bss_type; | ||
361 | u8 bss_num; | ||
362 | __le16 tx_pkt_length; | ||
363 | __le16 tx_pkt_offset; | ||
364 | __le16 tx_pkt_type; | ||
365 | __le32 tx_control; | ||
366 | u8 priority; | ||
367 | u8 flags; | ||
368 | u8 pkt_delay_2ms; | ||
369 | u8 reserved1; | ||
370 | } __packed; | ||
371 | |||
372 | struct rxpd { | ||
373 | u8 bss_type; | ||
374 | u8 bss_num; | ||
375 | u16 rx_pkt_length; | ||
376 | u16 rx_pkt_offset; | ||
377 | u16 rx_pkt_type; | ||
378 | u16 seq_num; | ||
379 | u8 priority; | ||
380 | u8 rx_rate; | ||
381 | s8 snr; | ||
382 | s8 nf; | ||
383 | /* Ht Info [Bit 0] RxRate format: LG=0, HT=1 | ||
384 | * [Bit 1] HT Bandwidth: BW20 = 0, BW40 = 1 | ||
385 | * [Bit 2] HT Guard Interval: LGI = 0, SGI = 1 */ | ||
386 | u8 ht_info; | ||
387 | u8 reserved; | ||
388 | } __packed; | ||
389 | |||
390 | enum mwifiex_chan_scan_mode_bitmasks { | ||
391 | MWIFIEX_PASSIVE_SCAN = BIT(0), | ||
392 | MWIFIEX_DISABLE_CHAN_FILT = BIT(1), | ||
393 | }; | ||
394 | |||
395 | #define SECOND_CHANNEL_BELOW 0x30 | ||
396 | #define SECOND_CHANNEL_ABOVE 0x10 | ||
397 | struct mwifiex_chan_scan_param_set { | ||
398 | u8 radio_type; | ||
399 | u8 chan_number; | ||
400 | u8 chan_scan_mode_bitmap; | ||
401 | __le16 min_scan_time; | ||
402 | __le16 max_scan_time; | ||
403 | } __packed; | ||
404 | |||
405 | struct mwifiex_ie_types_chan_list_param_set { | ||
406 | struct mwifiex_ie_types_header header; | ||
407 | struct mwifiex_chan_scan_param_set chan_scan_param[1]; | ||
408 | } __packed; | ||
409 | |||
410 | struct chan_band_param_set { | ||
411 | u8 radio_type; | ||
412 | u8 chan_number; | ||
413 | }; | ||
414 | |||
415 | struct mwifiex_ie_types_chan_band_list_param_set { | ||
416 | struct mwifiex_ie_types_header header; | ||
417 | struct chan_band_param_set chan_band_param[1]; | ||
418 | } __packed; | ||
419 | |||
420 | struct mwifiex_ie_types_rates_param_set { | ||
421 | struct mwifiex_ie_types_header header; | ||
422 | u8 rates[1]; | ||
423 | } __packed; | ||
424 | |||
425 | struct mwifiex_ie_types_ssid_param_set { | ||
426 | struct mwifiex_ie_types_header header; | ||
427 | u8 ssid[1]; | ||
428 | } __packed; | ||
429 | |||
430 | struct mwifiex_ie_types_num_probes { | ||
431 | struct mwifiex_ie_types_header header; | ||
432 | __le16 num_probes; | ||
433 | } __packed; | ||
434 | |||
435 | struct mwifiex_ie_types_wildcard_ssid_params { | ||
436 | struct mwifiex_ie_types_header header; | ||
437 | u8 max_ssid_length; | ||
438 | u8 ssid[1]; | ||
439 | } __packed; | ||
440 | |||
441 | #define TSF_DATA_SIZE 8 | ||
442 | struct mwifiex_ie_types_tsf_timestamp { | ||
443 | struct mwifiex_ie_types_header header; | ||
444 | u8 tsf_data[1]; | ||
445 | } __packed; | ||
446 | |||
447 | struct mwifiex_cf_param_set { | ||
448 | u8 cfp_cnt; | ||
449 | u8 cfp_period; | ||
450 | u16 cfp_max_duration; | ||
451 | u16 cfp_duration_remaining; | ||
452 | } __packed; | ||
453 | |||
454 | struct mwifiex_ibss_param_set { | ||
455 | u16 atim_window; | ||
456 | } __packed; | ||
457 | |||
458 | struct mwifiex_ie_types_ss_param_set { | ||
459 | struct mwifiex_ie_types_header header; | ||
460 | union { | ||
461 | struct mwifiex_cf_param_set cf_param_set[1]; | ||
462 | struct mwifiex_ibss_param_set ibss_param_set[1]; | ||
463 | } cf_ibss; | ||
464 | } __packed; | ||
465 | |||
466 | struct mwifiex_fh_param_set { | ||
467 | u16 dwell_time; | ||
468 | u8 hop_set; | ||
469 | u8 hop_pattern; | ||
470 | u8 hop_index; | ||
471 | } __packed; | ||
472 | |||
473 | struct mwifiex_ds_param_set { | ||
474 | u8 current_chan; | ||
475 | } __packed; | ||
476 | |||
477 | struct mwifiex_ie_types_phy_param_set { | ||
478 | struct mwifiex_ie_types_header header; | ||
479 | union { | ||
480 | struct mwifiex_fh_param_set fh_param_set[1]; | ||
481 | struct mwifiex_ds_param_set ds_param_set[1]; | ||
482 | } fh_ds; | ||
483 | } __packed; | ||
484 | |||
485 | struct mwifiex_ie_types_auth_type { | ||
486 | struct mwifiex_ie_types_header header; | ||
487 | __le16 auth_type; | ||
488 | } __packed; | ||
489 | |||
490 | struct mwifiex_ie_types_vendor_param_set { | ||
491 | struct mwifiex_ie_types_header header; | ||
492 | u8 ie[MWIFIEX_MAX_VSIE_LEN]; | ||
493 | }; | ||
494 | |||
495 | struct mwifiex_ie_types_rsn_param_set { | ||
496 | struct mwifiex_ie_types_header header; | ||
497 | u8 rsn_ie[1]; | ||
498 | } __packed; | ||
499 | |||
500 | #define KEYPARAMSET_FIXED_LEN 6 | ||
501 | |||
502 | struct mwifiex_ie_type_key_param_set { | ||
503 | __le16 type; | ||
504 | __le16 length; | ||
505 | __le16 key_type_id; | ||
506 | __le16 key_info; | ||
507 | __le16 key_len; | ||
508 | u8 key[50]; | ||
509 | } __packed; | ||
510 | |||
511 | struct host_cmd_ds_802_11_key_material { | ||
512 | __le16 action; | ||
513 | struct mwifiex_ie_type_key_param_set key_param_set; | ||
514 | } __packed; | ||
515 | |||
516 | struct host_cmd_ds_gen { | ||
517 | u16 command; | ||
518 | u16 size; | ||
519 | u16 seq_num; | ||
520 | u16 result; | ||
521 | }; | ||
522 | |||
523 | #define S_DS_GEN sizeof(struct host_cmd_ds_gen) | ||
524 | |||
525 | enum sleep_resp_ctrl { | ||
526 | RESP_NOT_NEEDED = 0, | ||
527 | RESP_NEEDED, | ||
528 | }; | ||
529 | |||
530 | struct mwifiex_ps_param { | ||
531 | __le16 null_pkt_interval; | ||
532 | __le16 multiple_dtims; | ||
533 | __le16 bcn_miss_timeout; | ||
534 | __le16 local_listen_interval; | ||
535 | __le16 adhoc_wake_period; | ||
536 | __le16 mode; | ||
537 | __le16 delay_to_ps; | ||
538 | }; | ||
539 | |||
540 | #define BITMAP_AUTO_DS 0x01 | ||
541 | #define BITMAP_STA_PS 0x10 | ||
542 | |||
543 | struct mwifiex_ie_types_auto_ds_param { | ||
544 | struct mwifiex_ie_types_header header; | ||
545 | __le16 deep_sleep_timeout; | ||
546 | } __packed; | ||
547 | |||
548 | struct mwifiex_ie_types_ps_param { | ||
549 | struct mwifiex_ie_types_header header; | ||
550 | struct mwifiex_ps_param param; | ||
551 | } __packed; | ||
552 | |||
553 | struct host_cmd_ds_802_11_ps_mode_enh { | ||
554 | __le16 action; | ||
555 | |||
556 | union { | ||
557 | struct mwifiex_ps_param opt_ps; | ||
558 | __le16 ps_bitmap; | ||
559 | } params; | ||
560 | } __packed; | ||
561 | |||
562 | struct host_cmd_ds_get_hw_spec { | ||
563 | __le16 hw_if_version; | ||
564 | __le16 version; | ||
565 | __le16 reserved; | ||
566 | __le16 num_of_mcast_adr; | ||
567 | u8 permanent_addr[ETH_ALEN]; | ||
568 | __le16 region_code; | ||
569 | __le16 number_of_antenna; | ||
570 | __le32 fw_release_number; | ||
571 | __le32 reserved_1; | ||
572 | __le32 reserved_2; | ||
573 | __le32 reserved_3; | ||
574 | __le32 fw_cap_info; | ||
575 | __le32 dot_11n_dev_cap; | ||
576 | u8 dev_mcs_support; | ||
577 | __le16 mp_end_port; /* SDIO only, reserved for other interfacces */ | ||
578 | __le16 reserved_4; | ||
579 | } __packed; | ||
580 | |||
581 | struct host_cmd_ds_802_11_rssi_info { | ||
582 | __le16 action; | ||
583 | __le16 ndata; | ||
584 | __le16 nbcn; | ||
585 | __le16 reserved[9]; | ||
586 | long long reserved_1; | ||
587 | }; | ||
588 | |||
589 | struct host_cmd_ds_802_11_rssi_info_rsp { | ||
590 | __le16 action; | ||
591 | __le16 ndata; | ||
592 | __le16 nbcn; | ||
593 | __le16 data_rssi_last; | ||
594 | __le16 data_nf_last; | ||
595 | __le16 data_rssi_avg; | ||
596 | __le16 data_nf_avg; | ||
597 | __le16 bcn_rssi_last; | ||
598 | __le16 bcn_nf_last; | ||
599 | __le16 bcn_rssi_avg; | ||
600 | __le16 bcn_nf_avg; | ||
601 | long long tsf_bcn; | ||
602 | }; | ||
603 | |||
604 | struct host_cmd_ds_802_11_mac_address { | ||
605 | __le16 action; | ||
606 | u8 mac_addr[ETH_ALEN]; | ||
607 | }; | ||
608 | |||
609 | struct host_cmd_ds_mac_control { | ||
610 | __le16 action; | ||
611 | __le16 reserved; | ||
612 | }; | ||
613 | |||
614 | struct host_cmd_ds_mac_multicast_adr { | ||
615 | __le16 action; | ||
616 | __le16 num_of_adrs; | ||
617 | u8 mac_list[MWIFIEX_MAX_MULTICAST_LIST_SIZE][ETH_ALEN]; | ||
618 | } __packed; | ||
619 | |||
620 | struct host_cmd_ds_802_11_deauthenticate { | ||
621 | u8 mac_addr[ETH_ALEN]; | ||
622 | __le16 reason_code; | ||
623 | } __packed; | ||
624 | |||
625 | struct host_cmd_ds_802_11_associate { | ||
626 | u8 peer_sta_addr[ETH_ALEN]; | ||
627 | __le16 cap_info_bitmap; | ||
628 | __le16 listen_interval; | ||
629 | __le16 beacon_period; | ||
630 | u8 dtim_period; | ||
631 | } __packed; | ||
632 | |||
633 | struct ieee_types_assoc_rsp { | ||
634 | __le16 cap_info_bitmap; | ||
635 | __le16 status_code; | ||
636 | __le16 a_id; | ||
637 | u8 ie_buffer[1]; | ||
638 | } __packed; | ||
639 | |||
640 | struct host_cmd_ds_802_11_associate_rsp { | ||
641 | struct ieee_types_assoc_rsp assoc_rsp; | ||
642 | } __packed; | ||
643 | |||
644 | struct ieee_types_cf_param_set { | ||
645 | u8 element_id; | ||
646 | u8 len; | ||
647 | u8 cfp_cnt; | ||
648 | u8 cfp_period; | ||
649 | u16 cfp_max_duration; | ||
650 | u16 cfp_duration_remaining; | ||
651 | } __packed; | ||
652 | |||
653 | struct ieee_types_ibss_param_set { | ||
654 | u8 element_id; | ||
655 | u8 len; | ||
656 | __le16 atim_window; | ||
657 | } __packed; | ||
658 | |||
659 | union ieee_types_ss_param_set { | ||
660 | struct ieee_types_cf_param_set cf_param_set; | ||
661 | struct ieee_types_ibss_param_set ibss_param_set; | ||
662 | } __packed; | ||
663 | |||
664 | struct ieee_types_fh_param_set { | ||
665 | u8 element_id; | ||
666 | u8 len; | ||
667 | __le16 dwell_time; | ||
668 | u8 hop_set; | ||
669 | u8 hop_pattern; | ||
670 | u8 hop_index; | ||
671 | } __packed; | ||
672 | |||
673 | struct ieee_types_ds_param_set { | ||
674 | u8 element_id; | ||
675 | u8 len; | ||
676 | u8 current_chan; | ||
677 | } __packed; | ||
678 | |||
679 | union ieee_types_phy_param_set { | ||
680 | struct ieee_types_fh_param_set fh_param_set; | ||
681 | struct ieee_types_ds_param_set ds_param_set; | ||
682 | } __packed; | ||
683 | |||
684 | struct host_cmd_ds_802_11_ad_hoc_start { | ||
685 | u8 ssid[IEEE80211_MAX_SSID_LEN]; | ||
686 | u8 bss_mode; | ||
687 | __le16 beacon_period; | ||
688 | u8 dtim_period; | ||
689 | union ieee_types_ss_param_set ss_param_set; | ||
690 | union ieee_types_phy_param_set phy_param_set; | ||
691 | u16 reserved1; | ||
692 | __le16 cap_info_bitmap; | ||
693 | u8 DataRate[HOSTCMD_SUPPORTED_RATES]; | ||
694 | } __packed; | ||
695 | |||
696 | struct host_cmd_ds_802_11_ad_hoc_result { | ||
697 | u8 pad[3]; | ||
698 | u8 bssid[ETH_ALEN]; | ||
699 | } __packed; | ||
700 | |||
701 | struct adhoc_bss_desc { | ||
702 | u8 bssid[ETH_ALEN]; | ||
703 | u8 ssid[IEEE80211_MAX_SSID_LEN]; | ||
704 | u8 bss_mode; | ||
705 | __le16 beacon_period; | ||
706 | u8 dtim_period; | ||
707 | u8 time_stamp[8]; | ||
708 | u8 local_time[8]; | ||
709 | union ieee_types_phy_param_set phy_param_set; | ||
710 | union ieee_types_ss_param_set ss_param_set; | ||
711 | __le16 cap_info_bitmap; | ||
712 | u8 data_rates[HOSTCMD_SUPPORTED_RATES]; | ||
713 | |||
714 | /* | ||
715 | * DO NOT ADD ANY FIELDS TO THIS STRUCTURE. | ||
716 | * It is used in the Adhoc join command and will cause a | ||
717 | * binary layout mismatch with the firmware | ||
718 | */ | ||
719 | } __packed; | ||
720 | |||
721 | struct host_cmd_ds_802_11_ad_hoc_join { | ||
722 | struct adhoc_bss_desc bss_descriptor; | ||
723 | u16 reserved1; | ||
724 | u16 reserved2; | ||
725 | } __packed; | ||
726 | |||
727 | struct host_cmd_ds_802_11_get_log { | ||
728 | __le32 mcast_tx_frame; | ||
729 | __le32 failed; | ||
730 | __le32 retry; | ||
731 | __le32 multi_retry; | ||
732 | __le32 frame_dup; | ||
733 | __le32 rts_success; | ||
734 | __le32 rts_failure; | ||
735 | __le32 ack_failure; | ||
736 | __le32 rx_frag; | ||
737 | __le32 mcast_rx_frame; | ||
738 | __le32 fcs_error; | ||
739 | __le32 tx_frame; | ||
740 | __le32 reserved; | ||
741 | __le32 wep_icv_err_cnt[4]; | ||
742 | }; | ||
743 | |||
744 | struct host_cmd_ds_tx_rate_query { | ||
745 | u8 tx_rate; | ||
746 | /* Ht Info [Bit 0] RxRate format: LG=0, HT=1 | ||
747 | * [Bit 1] HT Bandwidth: BW20 = 0, BW40 = 1 | ||
748 | * [Bit 2] HT Guard Interval: LGI = 0, SGI = 1 */ | ||
749 | u8 ht_info; | ||
750 | } __packed; | ||
751 | |||
752 | enum Host_Sleep_Action { | ||
753 | HS_CONFIGURE = 0x0001, | ||
754 | HS_ACTIVATE = 0x0002, | ||
755 | }; | ||
756 | |||
757 | struct mwifiex_hs_config_param { | ||
758 | __le32 conditions; | ||
759 | u8 gpio; | ||
760 | u8 gap; | ||
761 | } __packed; | ||
762 | |||
763 | struct hs_activate_param { | ||
764 | u16 resp_ctrl; | ||
765 | } __packed; | ||
766 | |||
767 | struct host_cmd_ds_802_11_hs_cfg_enh { | ||
768 | __le16 action; | ||
769 | |||
770 | union { | ||
771 | struct mwifiex_hs_config_param hs_config; | ||
772 | struct hs_activate_param hs_activate; | ||
773 | } params; | ||
774 | } __packed; | ||
775 | |||
776 | enum SNMP_MIB_INDEX { | ||
777 | OP_RATE_SET_I = 1, | ||
778 | DTIM_PERIOD_I = 3, | ||
779 | RTS_THRESH_I = 5, | ||
780 | SHORT_RETRY_LIM_I = 6, | ||
781 | LONG_RETRY_LIM_I = 7, | ||
782 | FRAG_THRESH_I = 8, | ||
783 | DOT11D_I = 9, | ||
784 | }; | ||
785 | |||
786 | #define MAX_SNMP_BUF_SIZE 128 | ||
787 | |||
788 | struct host_cmd_ds_802_11_snmp_mib { | ||
789 | __le16 query_type; | ||
790 | __le16 oid; | ||
791 | __le16 buf_size; | ||
792 | u8 value[1]; | ||
793 | } __packed; | ||
794 | |||
795 | struct mwifiex_rate_scope { | ||
796 | __le16 type; | ||
797 | __le16 length; | ||
798 | __le16 hr_dsss_rate_bitmap; | ||
799 | __le16 ofdm_rate_bitmap; | ||
800 | __le16 ht_mcs_rate_bitmap[8]; | ||
801 | } __packed; | ||
802 | |||
803 | struct mwifiex_rate_drop_pattern { | ||
804 | __le16 type; | ||
805 | __le16 length; | ||
806 | __le32 rate_drop_mode; | ||
807 | } __packed; | ||
808 | |||
809 | struct host_cmd_ds_tx_rate_cfg { | ||
810 | __le16 action; | ||
811 | __le16 cfg_index; | ||
812 | } __packed; | ||
813 | |||
814 | struct mwifiex_power_group { | ||
815 | u8 modulation_class; | ||
816 | u8 first_rate_code; | ||
817 | u8 last_rate_code; | ||
818 | s8 power_step; | ||
819 | s8 power_min; | ||
820 | s8 power_max; | ||
821 | u8 ht_bandwidth; | ||
822 | u8 reserved; | ||
823 | } __packed; | ||
824 | |||
825 | struct mwifiex_types_power_group { | ||
826 | u16 type; | ||
827 | u16 length; | ||
828 | } __packed; | ||
829 | |||
830 | struct host_cmd_ds_txpwr_cfg { | ||
831 | __le16 action; | ||
832 | __le16 cfg_index; | ||
833 | __le32 mode; | ||
834 | } __packed; | ||
835 | |||
836 | #define MWIFIEX_USER_SCAN_CHAN_MAX 50 | ||
837 | |||
838 | #define MWIFIEX_MAX_SSID_LIST_LENGTH 10 | ||
839 | |||
840 | struct mwifiex_scan_cmd_config { | ||
841 | /* | ||
842 | * BSS Type to be sent in the firmware command | ||
843 | * | ||
844 | * Field can be used to restrict the types of networks returned in the | ||
845 | * scan. Valid settings are: | ||
846 | * | ||
847 | * - MWIFIEX_SCAN_MODE_BSS (infrastructure) | ||
848 | * - MWIFIEX_SCAN_MODE_IBSS (adhoc) | ||
849 | * - MWIFIEX_SCAN_MODE_ANY (unrestricted, adhoc and infrastructure) | ||
850 | */ | ||
851 | u8 bss_mode; | ||
852 | |||
853 | /* Specific BSSID used to filter scan results in the firmware */ | ||
854 | u8 specific_bssid[ETH_ALEN]; | ||
855 | |||
856 | /* Length of TLVs sent in command starting at tlvBuffer */ | ||
857 | u32 tlv_buf_len; | ||
858 | |||
859 | /* | ||
860 | * SSID TLV(s) and ChanList TLVs to be sent in the firmware command | ||
861 | * | ||
862 | * TLV_TYPE_CHANLIST, mwifiex_ie_types_chan_list_param_set | ||
863 | * WLAN_EID_SSID, mwifiex_ie_types_ssid_param_set | ||
864 | */ | ||
865 | u8 tlv_buf[1]; /* SSID TLV(s) and ChanList TLVs are stored | ||
866 | here */ | ||
867 | } __packed; | ||
868 | |||
869 | struct mwifiex_user_scan_chan { | ||
870 | u8 chan_number; | ||
871 | u8 radio_type; | ||
872 | u8 scan_type; | ||
873 | u8 reserved; | ||
874 | u32 scan_time; | ||
875 | } __packed; | ||
876 | |||
877 | struct mwifiex_user_scan_ssid { | ||
878 | u8 ssid[IEEE80211_MAX_SSID_LEN + 1]; | ||
879 | u8 max_len; | ||
880 | } __packed; | ||
881 | |||
882 | struct mwifiex_user_scan_cfg { | ||
883 | /* | ||
884 | * Flag set to keep the previous scan table intact | ||
885 | * | ||
886 | * If set, the scan results will accumulate, replacing any previous | ||
887 | * matched entries for a BSS with the new scan data | ||
888 | */ | ||
889 | u8 keep_previous_scan; | ||
890 | /* | ||
891 | * BSS mode to be sent in the firmware command | ||
892 | * | ||
893 | * Field can be used to restrict the types of networks returned in the | ||
894 | * scan. Valid settings are: | ||
895 | * | ||
896 | * - MWIFIEX_SCAN_MODE_BSS (infrastructure) | ||
897 | * - MWIFIEX_SCAN_MODE_IBSS (adhoc) | ||
898 | * - MWIFIEX_SCAN_MODE_ANY (unrestricted, adhoc and infrastructure) | ||
899 | */ | ||
900 | u8 bss_mode; | ||
901 | /* Configure the number of probe requests for active chan scans */ | ||
902 | u8 num_probes; | ||
903 | u8 reserved; | ||
904 | /* BSSID filter sent in the firmware command to limit the results */ | ||
905 | u8 specific_bssid[ETH_ALEN]; | ||
906 | /* SSID filter list used in the to limit the scan results */ | ||
907 | struct mwifiex_user_scan_ssid ssid_list[MWIFIEX_MAX_SSID_LIST_LENGTH]; | ||
908 | /* Variable number (fixed maximum) of channels to scan up */ | ||
909 | struct mwifiex_user_scan_chan chan_list[MWIFIEX_USER_SCAN_CHAN_MAX]; | ||
910 | } __packed; | ||
911 | |||
912 | struct ie_body { | ||
913 | u8 grp_key_oui[4]; | ||
914 | u8 ptk_cnt[2]; | ||
915 | u8 ptk_body[4]; | ||
916 | } __packed; | ||
917 | |||
918 | struct host_cmd_ds_802_11_scan { | ||
919 | u8 bss_mode; | ||
920 | u8 bssid[ETH_ALEN]; | ||
921 | u8 tlv_buffer[1]; | ||
922 | } __packed; | ||
923 | |||
924 | struct host_cmd_ds_802_11_scan_rsp { | ||
925 | __le16 bss_descript_size; | ||
926 | u8 number_of_sets; | ||
927 | u8 bss_desc_and_tlv_buffer[1]; | ||
928 | } __packed; | ||
929 | |||
930 | struct host_cmd_ds_802_11_bg_scan_query { | ||
931 | u8 flush; | ||
932 | } __packed; | ||
933 | |||
934 | struct host_cmd_ds_802_11_bg_scan_query_rsp { | ||
935 | u32 report_condition; | ||
936 | struct host_cmd_ds_802_11_scan_rsp scan_resp; | ||
937 | } __packed; | ||
938 | |||
939 | struct mwifiex_ietypes_domain_param_set { | ||
940 | struct mwifiex_ie_types_header header; | ||
941 | u8 country_code[IEEE80211_COUNTRY_STRING_LEN]; | ||
942 | struct ieee80211_country_ie_triplet triplet[1]; | ||
943 | } __packed; | ||
944 | |||
945 | struct host_cmd_ds_802_11d_domain_info { | ||
946 | __le16 action; | ||
947 | struct mwifiex_ietypes_domain_param_set domain; | ||
948 | } __packed; | ||
949 | |||
950 | struct host_cmd_ds_802_11d_domain_info_rsp { | ||
951 | __le16 action; | ||
952 | struct mwifiex_ietypes_domain_param_set domain; | ||
953 | } __packed; | ||
954 | |||
955 | struct host_cmd_ds_11n_addba_req { | ||
956 | u8 add_req_result; | ||
957 | u8 peer_mac_addr[ETH_ALEN]; | ||
958 | u8 dialog_token; | ||
959 | __le16 block_ack_param_set; | ||
960 | __le16 block_ack_tmo; | ||
961 | __le16 ssn; | ||
962 | } __packed; | ||
963 | |||
964 | struct host_cmd_ds_11n_addba_rsp { | ||
965 | u8 add_rsp_result; | ||
966 | u8 peer_mac_addr[ETH_ALEN]; | ||
967 | u8 dialog_token; | ||
968 | __le16 status_code; | ||
969 | __le16 block_ack_param_set; | ||
970 | __le16 block_ack_tmo; | ||
971 | __le16 ssn; | ||
972 | } __packed; | ||
973 | |||
974 | struct host_cmd_ds_11n_delba { | ||
975 | u8 del_result; | ||
976 | u8 peer_mac_addr[ETH_ALEN]; | ||
977 | __le16 del_ba_param_set; | ||
978 | __le16 reason_code; | ||
979 | u8 reserved; | ||
980 | } __packed; | ||
981 | |||
982 | struct host_cmd_ds_11n_batimeout { | ||
983 | u8 tid; | ||
984 | u8 peer_mac_addr[ETH_ALEN]; | ||
985 | u8 origninator; | ||
986 | } __packed; | ||
987 | |||
988 | struct host_cmd_ds_11n_cfg { | ||
989 | __le16 action; | ||
990 | __le16 ht_tx_cap; | ||
991 | __le16 ht_tx_info; | ||
992 | } __packed; | ||
993 | |||
994 | struct host_cmd_ds_txbuf_cfg { | ||
995 | __le16 action; | ||
996 | __le16 buff_size; | ||
997 | __le16 mp_end_port; /* SDIO only, reserved for other interfacces */ | ||
998 | __le16 reserved3; | ||
999 | } __packed; | ||
1000 | |||
1001 | struct host_cmd_ds_amsdu_aggr_ctrl { | ||
1002 | __le16 action; | ||
1003 | __le16 enable; | ||
1004 | __le16 curr_buf_size; | ||
1005 | } __packed; | ||
1006 | |||
1007 | struct mwifiex_ie_types_wmm_param_set { | ||
1008 | struct mwifiex_ie_types_header header; | ||
1009 | u8 wmm_ie[1]; | ||
1010 | }; | ||
1011 | |||
1012 | struct mwifiex_ie_types_wmm_queue_status { | ||
1013 | struct mwifiex_ie_types_header header; | ||
1014 | u8 queue_index; | ||
1015 | u8 disabled; | ||
1016 | u16 medium_time; | ||
1017 | u8 flow_required; | ||
1018 | u8 flow_created; | ||
1019 | u32 reserved; | ||
1020 | }; | ||
1021 | |||
1022 | struct ieee_types_vendor_header { | ||
1023 | u8 element_id; | ||
1024 | u8 len; | ||
1025 | u8 oui[3]; | ||
1026 | u8 oui_type; | ||
1027 | u8 oui_subtype; | ||
1028 | u8 version; | ||
1029 | } __packed; | ||
1030 | |||
1031 | struct ieee_types_wmm_ac_parameters { | ||
1032 | u8 aci_aifsn_bitmap; | ||
1033 | u8 ecw_bitmap; | ||
1034 | __le16 tx_op_limit; | ||
1035 | } __packed; | ||
1036 | |||
1037 | struct ieee_types_wmm_parameter { | ||
1038 | /* | ||
1039 | * WMM Parameter IE - Vendor Specific Header: | ||
1040 | * element_id [221/0xdd] | ||
1041 | * Len [24] | ||
1042 | * Oui [00:50:f2] | ||
1043 | * OuiType [2] | ||
1044 | * OuiSubType [1] | ||
1045 | * Version [1] | ||
1046 | */ | ||
1047 | struct ieee_types_vendor_header vend_hdr; | ||
1048 | u8 qos_info_bitmap; | ||
1049 | u8 reserved; | ||
1050 | struct ieee_types_wmm_ac_parameters ac_params[IEEE80211_MAX_QUEUES]; | ||
1051 | } __packed; | ||
1052 | |||
1053 | struct ieee_types_wmm_info { | ||
1054 | |||
1055 | /* | ||
1056 | * WMM Info IE - Vendor Specific Header: | ||
1057 | * element_id [221/0xdd] | ||
1058 | * Len [7] | ||
1059 | * Oui [00:50:f2] | ||
1060 | * OuiType [2] | ||
1061 | * OuiSubType [0] | ||
1062 | * Version [1] | ||
1063 | */ | ||
1064 | struct ieee_types_vendor_header vend_hdr; | ||
1065 | |||
1066 | u8 qos_info_bitmap; | ||
1067 | } __packed; | ||
1068 | |||
1069 | struct host_cmd_ds_wmm_get_status { | ||
1070 | u8 queue_status_tlv[sizeof(struct mwifiex_ie_types_wmm_queue_status) * | ||
1071 | IEEE80211_MAX_QUEUES]; | ||
1072 | u8 wmm_param_tlv[sizeof(struct ieee_types_wmm_parameter) + 2]; | ||
1073 | } __packed; | ||
1074 | |||
1075 | struct mwifiex_wmm_ac_status { | ||
1076 | u8 disabled; | ||
1077 | u8 flow_required; | ||
1078 | u8 flow_created; | ||
1079 | }; | ||
1080 | |||
1081 | struct mwifiex_ie_types_htcap { | ||
1082 | struct mwifiex_ie_types_header header; | ||
1083 | struct ieee80211_ht_cap ht_cap; | ||
1084 | } __packed; | ||
1085 | |||
1086 | struct mwifiex_ie_types_htinfo { | ||
1087 | struct mwifiex_ie_types_header header; | ||
1088 | struct ieee80211_ht_info ht_info; | ||
1089 | } __packed; | ||
1090 | |||
1091 | struct mwifiex_ie_types_2040bssco { | ||
1092 | struct mwifiex_ie_types_header header; | ||
1093 | u8 bss_co_2040; | ||
1094 | } __packed; | ||
1095 | |||
1096 | struct mwifiex_ie_types_extcap { | ||
1097 | struct mwifiex_ie_types_header header; | ||
1098 | u8 ext_cap; | ||
1099 | } __packed; | ||
1100 | |||
1101 | struct host_cmd_ds_mac_reg_access { | ||
1102 | __le16 action; | ||
1103 | __le16 offset; | ||
1104 | __le32 value; | ||
1105 | } __packed; | ||
1106 | |||
1107 | struct host_cmd_ds_bbp_reg_access { | ||
1108 | __le16 action; | ||
1109 | __le16 offset; | ||
1110 | u8 value; | ||
1111 | u8 reserved[3]; | ||
1112 | } __packed; | ||
1113 | |||
1114 | struct host_cmd_ds_rf_reg_access { | ||
1115 | __le16 action; | ||
1116 | __le16 offset; | ||
1117 | u8 value; | ||
1118 | u8 reserved[3]; | ||
1119 | } __packed; | ||
1120 | |||
1121 | struct host_cmd_ds_pmic_reg_access { | ||
1122 | __le16 action; | ||
1123 | __le16 offset; | ||
1124 | u8 value; | ||
1125 | u8 reserved[3]; | ||
1126 | } __packed; | ||
1127 | |||
1128 | struct host_cmd_ds_802_11_eeprom_access { | ||
1129 | __le16 action; | ||
1130 | |||
1131 | __le16 offset; | ||
1132 | __le16 byte_count; | ||
1133 | u8 value; | ||
1134 | } __packed; | ||
1135 | |||
1136 | struct host_cmd_ds_802_11_rf_channel { | ||
1137 | __le16 action; | ||
1138 | __le16 current_channel; | ||
1139 | __le16 rf_type; | ||
1140 | __le16 reserved; | ||
1141 | u8 reserved_1[32]; | ||
1142 | } __packed; | ||
1143 | |||
1144 | struct host_cmd_ds_version_ext { | ||
1145 | u8 version_str_sel; | ||
1146 | char version_str[128]; | ||
1147 | } __packed; | ||
1148 | |||
1149 | struct host_cmd_ds_802_11_ibss_status { | ||
1150 | __le16 action; | ||
1151 | __le16 enable; | ||
1152 | u8 bssid[ETH_ALEN]; | ||
1153 | __le16 beacon_interval; | ||
1154 | __le16 atim_window; | ||
1155 | __le16 use_g_rate_protect; | ||
1156 | } __packed; | ||
1157 | |||
1158 | #define CONNECTION_TYPE_INFRA 0 | ||
1159 | #define CONNECTION_TYPE_ADHOC 1 | ||
1160 | |||
1161 | struct host_cmd_ds_set_bss_mode { | ||
1162 | u8 con_type; | ||
1163 | } __packed; | ||
1164 | |||
1165 | struct host_cmd_ds_command { | ||
1166 | __le16 command; | ||
1167 | __le16 size; | ||
1168 | __le16 seq_num; | ||
1169 | __le16 result; | ||
1170 | union { | ||
1171 | struct host_cmd_ds_get_hw_spec hw_spec; | ||
1172 | struct host_cmd_ds_mac_control mac_ctrl; | ||
1173 | struct host_cmd_ds_802_11_mac_address mac_addr; | ||
1174 | struct host_cmd_ds_mac_multicast_adr mc_addr; | ||
1175 | struct host_cmd_ds_802_11_get_log get_log; | ||
1176 | struct host_cmd_ds_802_11_rssi_info rssi_info; | ||
1177 | struct host_cmd_ds_802_11_rssi_info_rsp rssi_info_rsp; | ||
1178 | struct host_cmd_ds_802_11_snmp_mib smib; | ||
1179 | struct host_cmd_ds_802_11_rf_channel rf_channel; | ||
1180 | struct host_cmd_ds_tx_rate_query tx_rate; | ||
1181 | struct host_cmd_ds_tx_rate_cfg tx_rate_cfg; | ||
1182 | struct host_cmd_ds_txpwr_cfg txp_cfg; | ||
1183 | struct host_cmd_ds_802_11_ps_mode_enh psmode_enh; | ||
1184 | struct host_cmd_ds_802_11_hs_cfg_enh opt_hs_cfg; | ||
1185 | struct host_cmd_ds_802_11_scan scan; | ||
1186 | struct host_cmd_ds_802_11_scan_rsp scan_resp; | ||
1187 | struct host_cmd_ds_802_11_bg_scan_query bg_scan_query; | ||
1188 | struct host_cmd_ds_802_11_bg_scan_query_rsp bg_scan_query_resp; | ||
1189 | struct host_cmd_ds_802_11_associate associate; | ||
1190 | struct host_cmd_ds_802_11_associate_rsp associate_rsp; | ||
1191 | struct host_cmd_ds_802_11_deauthenticate deauth; | ||
1192 | struct host_cmd_ds_802_11_ad_hoc_start adhoc_start; | ||
1193 | struct host_cmd_ds_802_11_ad_hoc_result adhoc_result; | ||
1194 | struct host_cmd_ds_802_11_ad_hoc_join adhoc_join; | ||
1195 | struct host_cmd_ds_802_11d_domain_info domain_info; | ||
1196 | struct host_cmd_ds_802_11d_domain_info_rsp domain_info_resp; | ||
1197 | struct host_cmd_ds_11n_addba_req add_ba_req; | ||
1198 | struct host_cmd_ds_11n_addba_rsp add_ba_rsp; | ||
1199 | struct host_cmd_ds_11n_delba del_ba; | ||
1200 | struct host_cmd_ds_txbuf_cfg tx_buf; | ||
1201 | struct host_cmd_ds_amsdu_aggr_ctrl amsdu_aggr_ctrl; | ||
1202 | struct host_cmd_ds_11n_cfg htcfg; | ||
1203 | struct host_cmd_ds_wmm_get_status get_wmm_status; | ||
1204 | struct host_cmd_ds_802_11_key_material key_material; | ||
1205 | struct host_cmd_ds_version_ext verext; | ||
1206 | struct host_cmd_ds_802_11_ibss_status ibss_coalescing; | ||
1207 | struct host_cmd_ds_mac_reg_access mac_reg; | ||
1208 | struct host_cmd_ds_bbp_reg_access bbp_reg; | ||
1209 | struct host_cmd_ds_rf_reg_access rf_reg; | ||
1210 | struct host_cmd_ds_pmic_reg_access pmic_reg; | ||
1211 | struct host_cmd_ds_set_bss_mode bss_mode; | ||
1212 | struct host_cmd_ds_802_11_eeprom_access eeprom; | ||
1213 | } params; | ||
1214 | } __packed; | ||
1215 | |||
1216 | struct mwifiex_opt_sleep_confirm { | ||
1217 | __le16 command; | ||
1218 | __le16 size; | ||
1219 | __le16 seq_num; | ||
1220 | __le16 result; | ||
1221 | __le16 action; | ||
1222 | __le16 resp_ctrl; | ||
1223 | } __packed; | ||
1224 | |||
1225 | struct mwifiex_opt_sleep_confirm_buffer { | ||
1226 | u8 hdr[4]; | ||
1227 | struct mwifiex_opt_sleep_confirm ps_cfm_sleep; | ||
1228 | } __packed; | ||
1229 | #endif /* !_MWIFIEX_FW_H_ */ | ||
diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c new file mode 100644 index 000000000000..8189862da1f9 --- /dev/null +++ b/drivers/net/wireless/mwifiex/init.c | |||
@@ -0,0 +1,662 @@ | |||
1 | /* | ||
2 | * Marvell Wireless LAN device driver: HW/FW Initialization | ||
3 | * | ||
4 | * Copyright (C) 2011, Marvell International Ltd. | ||
5 | * | ||
6 | * This software file (the "File") is distributed by Marvell International | ||
7 | * Ltd. under the terms of the GNU General Public License Version 2, June 1991 | ||
8 | * (the "License"). You may use, redistribute and/or modify this File in | ||
9 | * accordance with the terms and conditions of the License, a copy of which | ||
10 | * is available by writing to the Free Software Foundation, Inc., | ||
11 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the | ||
12 | * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. | ||
13 | * | ||
14 | * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE | ||
15 | * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE | ||
16 | * ARE EXPRESSLY DISCLAIMED. The License provides additional details about | ||
17 | * this warranty disclaimer. | ||
18 | */ | ||
19 | |||
20 | #include "decl.h" | ||
21 | #include "ioctl.h" | ||
22 | #include "util.h" | ||
23 | #include "fw.h" | ||
24 | #include "main.h" | ||
25 | #include "wmm.h" | ||
26 | #include "11n.h" | ||
27 | |||
28 | /* | ||
29 | * This function adds a BSS priority table to the table list. | ||
30 | * | ||
31 | * The function allocates a new BSS priority table node and adds it to | ||
32 | * the end of BSS priority table list, kept in driver memory. | ||
33 | */ | ||
34 | static int mwifiex_add_bss_prio_tbl(struct mwifiex_private *priv) | ||
35 | { | ||
36 | struct mwifiex_adapter *adapter = priv->adapter; | ||
37 | struct mwifiex_bss_prio_node *bss_prio; | ||
38 | int status = 0; | ||
39 | unsigned long flags; | ||
40 | |||
41 | bss_prio = kzalloc(sizeof(struct mwifiex_bss_prio_node), GFP_KERNEL); | ||
42 | if (!bss_prio) { | ||
43 | dev_err(adapter->dev, "%s: failed to alloc bss_prio\n", | ||
44 | __func__); | ||
45 | return -1; | ||
46 | } | ||
47 | |||
48 | bss_prio->priv = priv; | ||
49 | INIT_LIST_HEAD(&bss_prio->list); | ||
50 | if (!adapter->bss_prio_tbl[priv->bss_priority].bss_prio_cur) | ||
51 | adapter->bss_prio_tbl[priv->bss_priority].bss_prio_cur = | ||
52 | bss_prio; | ||
53 | |||
54 | spin_lock_irqsave(&adapter->bss_prio_tbl[priv->bss_priority] | ||
55 | .bss_prio_lock, flags); | ||
56 | list_add_tail(&bss_prio->list, | ||
57 | &adapter->bss_prio_tbl[priv->bss_priority] | ||
58 | .bss_prio_head); | ||
59 | spin_unlock_irqrestore(&adapter->bss_prio_tbl[priv->bss_priority] | ||
60 | .bss_prio_lock, flags); | ||
61 | |||
62 | return status; | ||
63 | } | ||
64 | |||
65 | /* | ||
66 | * This function initializes the private structure and sets default | ||
67 | * values to the members. | ||
68 | * | ||
69 | * Additionally, it also initializes all the locks and sets up all the | ||
70 | * lists. | ||
71 | */ | ||
72 | static int mwifiex_init_priv(struct mwifiex_private *priv) | ||
73 | { | ||
74 | u32 i; | ||
75 | int ret = 0; | ||
76 | |||
77 | priv->media_connected = false; | ||
78 | memset(priv->curr_addr, 0xff, ETH_ALEN); | ||
79 | |||
80 | priv->pkt_tx_ctrl = 0; | ||
81 | priv->bss_mode = NL80211_IFTYPE_STATION; | ||
82 | priv->data_rate = 0; /* Initially indicate the rate as auto */ | ||
83 | priv->is_data_rate_auto = true; | ||
84 | priv->bcn_avg_factor = DEFAULT_BCN_AVG_FACTOR; | ||
85 | priv->data_avg_factor = DEFAULT_DATA_AVG_FACTOR; | ||
86 | |||
87 | priv->sec_info.wep_status = MWIFIEX_802_11_WEP_DISABLED; | ||
88 | priv->sec_info.authentication_mode = NL80211_AUTHTYPE_OPEN_SYSTEM; | ||
89 | priv->sec_info.encryption_mode = 0; | ||
90 | for (i = 0; i < ARRAY_SIZE(priv->wep_key); i++) | ||
91 | memset(&priv->wep_key[i], 0, sizeof(struct mwifiex_wep_key)); | ||
92 | priv->wep_key_curr_index = 0; | ||
93 | priv->curr_pkt_filter = HostCmd_ACT_MAC_RX_ON | HostCmd_ACT_MAC_TX_ON | | ||
94 | HostCmd_ACT_MAC_ETHERNETII_ENABLE; | ||
95 | |||
96 | priv->beacon_period = 100; /* beacon interval */ ; | ||
97 | priv->attempted_bss_desc = NULL; | ||
98 | memset(&priv->curr_bss_params, 0, sizeof(priv->curr_bss_params)); | ||
99 | priv->listen_interval = MWIFIEX_DEFAULT_LISTEN_INTERVAL; | ||
100 | |||
101 | memset(&priv->prev_ssid, 0, sizeof(priv->prev_ssid)); | ||
102 | memset(&priv->prev_bssid, 0, sizeof(priv->prev_bssid)); | ||
103 | memset(&priv->assoc_rsp_buf, 0, sizeof(priv->assoc_rsp_buf)); | ||
104 | priv->assoc_rsp_size = 0; | ||
105 | priv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL; | ||
106 | priv->atim_window = 0; | ||
107 | priv->adhoc_state = ADHOC_IDLE; | ||
108 | priv->tx_power_level = 0; | ||
109 | priv->max_tx_power_level = 0; | ||
110 | priv->min_tx_power_level = 0; | ||
111 | priv->tx_rate = 0; | ||
112 | priv->rxpd_htinfo = 0; | ||
113 | priv->rxpd_rate = 0; | ||
114 | priv->rate_bitmap = 0; | ||
115 | priv->data_rssi_last = 0; | ||
116 | priv->data_rssi_avg = 0; | ||
117 | priv->data_nf_avg = 0; | ||
118 | priv->data_nf_last = 0; | ||
119 | priv->bcn_rssi_last = 0; | ||
120 | priv->bcn_rssi_avg = 0; | ||
121 | priv->bcn_nf_avg = 0; | ||
122 | priv->bcn_nf_last = 0; | ||
123 | memset(&priv->wpa_ie, 0, sizeof(priv->wpa_ie)); | ||
124 | memset(&priv->aes_key, 0, sizeof(priv->aes_key)); | ||
125 | priv->wpa_ie_len = 0; | ||
126 | priv->wpa_is_gtk_set = false; | ||
127 | |||
128 | memset(&priv->assoc_tlv_buf, 0, sizeof(priv->assoc_tlv_buf)); | ||
129 | priv->assoc_tlv_buf_len = 0; | ||
130 | memset(&priv->wps, 0, sizeof(priv->wps)); | ||
131 | memset(&priv->gen_ie_buf, 0, sizeof(priv->gen_ie_buf)); | ||
132 | priv->gen_ie_buf_len = 0; | ||
133 | memset(priv->vs_ie, 0, sizeof(priv->vs_ie)); | ||
134 | |||
135 | priv->wmm_required = true; | ||
136 | priv->wmm_enabled = false; | ||
137 | priv->wmm_qosinfo = 0; | ||
138 | priv->curr_bcn_buf = NULL; | ||
139 | priv->curr_bcn_size = 0; | ||
140 | |||
141 | priv->scan_block = false; | ||
142 | |||
143 | ret = mwifiex_add_bss_prio_tbl(priv); | ||
144 | |||
145 | return ret; | ||
146 | } | ||
147 | |||
148 | /* | ||
149 | * This function allocates buffers for members of the adapter | ||
150 | * structure. | ||
151 | * | ||
152 | * The memory allocated includes scan table, command buffers, and | ||
153 | * sleep confirm command buffer. In addition, the queues are | ||
154 | * also initialized. | ||
155 | */ | ||
156 | static int mwifiex_allocate_adapter(struct mwifiex_adapter *adapter) | ||
157 | { | ||
158 | int ret = 0; | ||
159 | u32 buf_size; | ||
160 | struct mwifiex_bssdescriptor *temp_scan_table; | ||
161 | |||
162 | /* Allocate buffer to store the BSSID list */ | ||
163 | buf_size = sizeof(struct mwifiex_bssdescriptor) * IW_MAX_AP; | ||
164 | temp_scan_table = kzalloc(buf_size, GFP_KERNEL); | ||
165 | if (!temp_scan_table) { | ||
166 | dev_err(adapter->dev, "%s: failed to alloc temp_scan_table\n", | ||
167 | __func__); | ||
168 | return -1; | ||
169 | } | ||
170 | |||
171 | adapter->scan_table = temp_scan_table; | ||
172 | |||
173 | /* Allocate command buffer */ | ||
174 | ret = mwifiex_alloc_cmd_buffer(adapter); | ||
175 | if (ret) { | ||
176 | dev_err(adapter->dev, "%s: failed to alloc cmd buffer\n", | ||
177 | __func__); | ||
178 | return -1; | ||
179 | } | ||
180 | |||
181 | adapter->sleep_cfm = | ||
182 | dev_alloc_skb(sizeof(struct mwifiex_opt_sleep_confirm_buffer) | ||
183 | + INTF_HEADER_LEN); | ||
184 | |||
185 | if (!adapter->sleep_cfm) { | ||
186 | dev_err(adapter->dev, "%s: failed to alloc sleep cfm" | ||
187 | " cmd buffer\n", __func__); | ||
188 | return -1; | ||
189 | } | ||
190 | skb_reserve(adapter->sleep_cfm, INTF_HEADER_LEN); | ||
191 | |||
192 | return 0; | ||
193 | } | ||
194 | |||
195 | /* | ||
196 | * This function initializes the adapter structure and sets default | ||
197 | * values to the members of adapter. | ||
198 | * | ||
199 | * This also initializes the WMM related parameters in the driver private | ||
200 | * structures. | ||
201 | */ | ||
202 | static void mwifiex_init_adapter(struct mwifiex_adapter *adapter) | ||
203 | { | ||
204 | struct mwifiex_opt_sleep_confirm_buffer *sleep_cfm_buf = NULL; | ||
205 | |||
206 | skb_put(adapter->sleep_cfm, sizeof(sleep_cfm_buf->ps_cfm_sleep)); | ||
207 | sleep_cfm_buf = (struct mwifiex_opt_sleep_confirm_buffer *) | ||
208 | (adapter->sleep_cfm->data); | ||
209 | |||
210 | adapter->cmd_sent = false; | ||
211 | adapter->data_sent = true; | ||
212 | adapter->cmd_resp_received = false; | ||
213 | adapter->event_received = false; | ||
214 | adapter->data_received = false; | ||
215 | |||
216 | adapter->surprise_removed = false; | ||
217 | |||
218 | adapter->hw_status = MWIFIEX_HW_STATUS_INITIALIZING; | ||
219 | |||
220 | adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_CAM; | ||
221 | adapter->ps_state = PS_STATE_AWAKE; | ||
222 | adapter->need_to_wakeup = false; | ||
223 | |||
224 | adapter->scan_mode = HostCmd_BSS_MODE_ANY; | ||
225 | adapter->specific_scan_time = MWIFIEX_SPECIFIC_SCAN_CHAN_TIME; | ||
226 | adapter->active_scan_time = MWIFIEX_ACTIVE_SCAN_CHAN_TIME; | ||
227 | adapter->passive_scan_time = MWIFIEX_PASSIVE_SCAN_CHAN_TIME; | ||
228 | |||
229 | adapter->num_in_scan_table = 0; | ||
230 | memset(adapter->scan_table, 0, | ||
231 | (sizeof(struct mwifiex_bssdescriptor) * IW_MAX_AP)); | ||
232 | adapter->scan_probes = 1; | ||
233 | |||
234 | memset(adapter->bcn_buf, 0, sizeof(adapter->bcn_buf)); | ||
235 | adapter->bcn_buf_end = adapter->bcn_buf; | ||
236 | |||
237 | adapter->multiple_dtim = 1; | ||
238 | |||
239 | adapter->local_listen_interval = 0; /* default value in firmware | ||
240 | will be used */ | ||
241 | |||
242 | adapter->is_deep_sleep = false; | ||
243 | |||
244 | adapter->delay_null_pkt = false; | ||
245 | adapter->delay_to_ps = 1000; | ||
246 | adapter->enhanced_ps_mode = PS_MODE_AUTO; | ||
247 | |||
248 | adapter->gen_null_pkt = false; /* Disable NULL Pkg generation by | ||
249 | default */ | ||
250 | adapter->pps_uapsd_mode = false; /* Disable pps/uapsd mode by | ||
251 | default */ | ||
252 | adapter->pm_wakeup_card_req = false; | ||
253 | |||
254 | adapter->pm_wakeup_fw_try = false; | ||
255 | |||
256 | adapter->max_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K; | ||
257 | adapter->tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K; | ||
258 | adapter->curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K; | ||
259 | |||
260 | adapter->is_hs_configured = false; | ||
261 | adapter->hs_cfg.conditions = cpu_to_le32(HOST_SLEEP_CFG_COND_DEF); | ||
262 | adapter->hs_cfg.gpio = HOST_SLEEP_CFG_GPIO_DEF; | ||
263 | adapter->hs_cfg.gap = HOST_SLEEP_CFG_GAP_DEF; | ||
264 | adapter->hs_activated = false; | ||
265 | |||
266 | memset(adapter->event_body, 0, sizeof(adapter->event_body)); | ||
267 | adapter->hw_dot_11n_dev_cap = 0; | ||
268 | adapter->hw_dev_mcs_support = 0; | ||
269 | adapter->chan_offset = 0; | ||
270 | adapter->adhoc_11n_enabled = false; | ||
271 | |||
272 | mwifiex_wmm_init(adapter); | ||
273 | |||
274 | if (adapter->sleep_cfm) { | ||
275 | memset(&sleep_cfm_buf->ps_cfm_sleep, 0, | ||
276 | adapter->sleep_cfm->len); | ||
277 | sleep_cfm_buf->ps_cfm_sleep.command = | ||
278 | cpu_to_le16(HostCmd_CMD_802_11_PS_MODE_ENH); | ||
279 | sleep_cfm_buf->ps_cfm_sleep.size = | ||
280 | cpu_to_le16(adapter->sleep_cfm->len); | ||
281 | sleep_cfm_buf->ps_cfm_sleep.result = 0; | ||
282 | sleep_cfm_buf->ps_cfm_sleep.action = cpu_to_le16(SLEEP_CONFIRM); | ||
283 | sleep_cfm_buf->ps_cfm_sleep.resp_ctrl = | ||
284 | cpu_to_le16(RESP_NEEDED); | ||
285 | } | ||
286 | memset(&adapter->sleep_params, 0, sizeof(adapter->sleep_params)); | ||
287 | memset(&adapter->sleep_period, 0, sizeof(adapter->sleep_period)); | ||
288 | adapter->tx_lock_flag = false; | ||
289 | adapter->null_pkt_interval = 0; | ||
290 | adapter->fw_bands = 0; | ||
291 | adapter->config_bands = 0; | ||
292 | adapter->adhoc_start_band = 0; | ||
293 | adapter->scan_channels = NULL; | ||
294 | adapter->fw_release_number = 0; | ||
295 | adapter->fw_cap_info = 0; | ||
296 | memset(&adapter->upld_buf, 0, sizeof(adapter->upld_buf)); | ||
297 | adapter->event_cause = 0; | ||
298 | adapter->region_code = 0; | ||
299 | adapter->bcn_miss_time_out = DEFAULT_BCN_MISS_TIMEOUT; | ||
300 | adapter->adhoc_awake_period = 0; | ||
301 | memset(&adapter->arp_filter, 0, sizeof(adapter->arp_filter)); | ||
302 | adapter->arp_filter_size = 0; | ||
303 | |||
304 | return; | ||
305 | } | ||
306 | |||
307 | /* | ||
308 | * This function frees the adapter structure. | ||
309 | * | ||
310 | * The freeing operation is done recursively, by canceling all | ||
311 | * pending commands, freeing the member buffers previously | ||
312 | * allocated (command buffers, scan table buffer, sleep confirm | ||
313 | * command buffer), stopping the timers and calling the cleanup | ||
314 | * routines for every interface, before the actual adapter | ||
315 | * structure is freed. | ||
316 | */ | ||
317 | static void | ||
318 | mwifiex_free_adapter(struct mwifiex_adapter *adapter) | ||
319 | { | ||
320 | if (!adapter) { | ||
321 | pr_err("%s: adapter is NULL\n", __func__); | ||
322 | return; | ||
323 | } | ||
324 | |||
325 | mwifiex_cancel_all_pending_cmd(adapter); | ||
326 | |||
327 | /* Free lock variables */ | ||
328 | mwifiex_free_lock_list(adapter); | ||
329 | |||
330 | /* Free command buffer */ | ||
331 | dev_dbg(adapter->dev, "info: free cmd buffer\n"); | ||
332 | mwifiex_free_cmd_buffer(adapter); | ||
333 | |||
334 | del_timer(&adapter->cmd_timer); | ||
335 | |||
336 | dev_dbg(adapter->dev, "info: free scan table\n"); | ||
337 | kfree(adapter->scan_table); | ||
338 | adapter->scan_table = NULL; | ||
339 | |||
340 | adapter->if_ops.cleanup_if(adapter); | ||
341 | |||
342 | dev_kfree_skb_any(adapter->sleep_cfm); | ||
343 | |||
344 | return; | ||
345 | } | ||
346 | |||
347 | /* | ||
348 | * This function intializes the lock variables and | ||
349 | * the list heads. | ||
350 | */ | ||
351 | int mwifiex_init_lock_list(struct mwifiex_adapter *adapter) | ||
352 | { | ||
353 | struct mwifiex_private *priv = NULL; | ||
354 | s32 i = 0; | ||
355 | u32 j = 0; | ||
356 | |||
357 | spin_lock_init(&adapter->mwifiex_lock); | ||
358 | spin_lock_init(&adapter->int_lock); | ||
359 | spin_lock_init(&adapter->main_proc_lock); | ||
360 | spin_lock_init(&adapter->mwifiex_cmd_lock); | ||
361 | for (i = 0; i < adapter->priv_num; i++) { | ||
362 | if (adapter->priv[i]) { | ||
363 | priv = adapter->priv[i]; | ||
364 | spin_lock_init(&priv->rx_pkt_lock); | ||
365 | spin_lock_init(&priv->wmm.ra_list_spinlock); | ||
366 | spin_lock_init(&priv->curr_bcn_buf_lock); | ||
367 | } | ||
368 | } | ||
369 | |||
370 | /* Initialize cmd_free_q */ | ||
371 | INIT_LIST_HEAD(&adapter->cmd_free_q); | ||
372 | /* Initialize cmd_pending_q */ | ||
373 | INIT_LIST_HEAD(&adapter->cmd_pending_q); | ||
374 | /* Initialize scan_pending_q */ | ||
375 | INIT_LIST_HEAD(&adapter->scan_pending_q); | ||
376 | |||
377 | spin_lock_init(&adapter->cmd_free_q_lock); | ||
378 | spin_lock_init(&adapter->cmd_pending_q_lock); | ||
379 | spin_lock_init(&adapter->scan_pending_q_lock); | ||
380 | |||
381 | for (i = 0; i < adapter->priv_num; ++i) { | ||
382 | INIT_LIST_HEAD(&adapter->bss_prio_tbl[i].bss_prio_head); | ||
383 | adapter->bss_prio_tbl[i].bss_prio_cur = NULL; | ||
384 | spin_lock_init(&adapter->bss_prio_tbl[i].bss_prio_lock); | ||
385 | } | ||
386 | |||
387 | for (i = 0; i < adapter->priv_num; i++) { | ||
388 | if (!adapter->priv[i]) | ||
389 | continue; | ||
390 | priv = adapter->priv[i]; | ||
391 | for (j = 0; j < MAX_NUM_TID; ++j) { | ||
392 | INIT_LIST_HEAD(&priv->wmm.tid_tbl_ptr[j].ra_list); | ||
393 | spin_lock_init(&priv->wmm.tid_tbl_ptr[j].tid_tbl_lock); | ||
394 | } | ||
395 | INIT_LIST_HEAD(&priv->tx_ba_stream_tbl_ptr); | ||
396 | INIT_LIST_HEAD(&priv->rx_reorder_tbl_ptr); | ||
397 | |||
398 | spin_lock_init(&priv->tx_ba_stream_tbl_lock); | ||
399 | spin_lock_init(&priv->rx_reorder_tbl_lock); | ||
400 | } | ||
401 | |||
402 | return 0; | ||
403 | } | ||
404 | |||
405 | /* | ||
406 | * This function releases the lock variables and frees the locks and | ||
407 | * associated locks. | ||
408 | */ | ||
409 | void mwifiex_free_lock_list(struct mwifiex_adapter *adapter) | ||
410 | { | ||
411 | struct mwifiex_private *priv = NULL; | ||
412 | s32 i = 0; | ||
413 | s32 j = 0; | ||
414 | |||
415 | /* Free lists */ | ||
416 | list_del(&adapter->cmd_free_q); | ||
417 | list_del(&adapter->cmd_pending_q); | ||
418 | list_del(&adapter->scan_pending_q); | ||
419 | |||
420 | for (i = 0; i < adapter->priv_num; i++) | ||
421 | list_del(&adapter->bss_prio_tbl[i].bss_prio_head); | ||
422 | |||
423 | for (i = 0; i < adapter->priv_num; i++) { | ||
424 | if (adapter->priv[i]) { | ||
425 | priv = adapter->priv[i]; | ||
426 | for (j = 0; j < MAX_NUM_TID; ++j) | ||
427 | list_del(&priv->wmm.tid_tbl_ptr[j].ra_list); | ||
428 | list_del(&priv->tx_ba_stream_tbl_ptr); | ||
429 | list_del(&priv->rx_reorder_tbl_ptr); | ||
430 | } | ||
431 | } | ||
432 | |||
433 | return; | ||
434 | } | ||
435 | |||
436 | /* | ||
437 | * This function initializes the firmware. | ||
438 | * | ||
439 | * The following operations are performed sequentially - | ||
440 | * - Allocate adapter structure | ||
441 | * - Initialize the adapter structure | ||
442 | * - Initialize the private structure | ||
443 | * - Add BSS priority tables to the adapter structure | ||
444 | * - For each interface, send the init commands to firmware | ||
445 | * - Send the first command in command pending queue, if available | ||
446 | */ | ||
447 | int mwifiex_init_fw(struct mwifiex_adapter *adapter) | ||
448 | { | ||
449 | int ret = 0; | ||
450 | struct mwifiex_private *priv = NULL; | ||
451 | u8 i = 0; | ||
452 | u8 first_sta = true; | ||
453 | int is_cmd_pend_q_empty; | ||
454 | unsigned long flags; | ||
455 | |||
456 | adapter->hw_status = MWIFIEX_HW_STATUS_INITIALIZING; | ||
457 | |||
458 | /* Allocate memory for member of adapter structure */ | ||
459 | ret = mwifiex_allocate_adapter(adapter); | ||
460 | if (ret) | ||
461 | return -1; | ||
462 | |||
463 | /* Initialize adapter structure */ | ||
464 | mwifiex_init_adapter(adapter); | ||
465 | |||
466 | for (i = 0; i < adapter->priv_num; i++) { | ||
467 | if (adapter->priv[i]) { | ||
468 | priv = adapter->priv[i]; | ||
469 | |||
470 | /* Initialize private structure */ | ||
471 | ret = mwifiex_init_priv(priv); | ||
472 | if (ret) | ||
473 | return -1; | ||
474 | } | ||
475 | } | ||
476 | for (i = 0; i < adapter->priv_num; i++) { | ||
477 | if (adapter->priv[i]) { | ||
478 | ret = mwifiex_sta_init_cmd(adapter->priv[i], first_sta); | ||
479 | if (ret == -1) | ||
480 | return -1; | ||
481 | |||
482 | first_sta = false; | ||
483 | } | ||
484 | } | ||
485 | |||
486 | spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags); | ||
487 | is_cmd_pend_q_empty = list_empty(&adapter->cmd_pending_q); | ||
488 | spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags); | ||
489 | if (!is_cmd_pend_q_empty) { | ||
490 | /* Send the first command in queue and return */ | ||
491 | if (mwifiex_main_process(adapter) != -1) | ||
492 | ret = -EINPROGRESS; | ||
493 | } else { | ||
494 | adapter->hw_status = MWIFIEX_HW_STATUS_READY; | ||
495 | } | ||
496 | |||
497 | return ret; | ||
498 | } | ||
499 | |||
500 | /* | ||
501 | * This function deletes the BSS priority tables. | ||
502 | * | ||
503 | * The function traverses through all the allocated BSS priority nodes | ||
504 | * in every BSS priority table and frees them. | ||
505 | */ | ||
506 | static void mwifiex_delete_bss_prio_tbl(struct mwifiex_private *priv) | ||
507 | { | ||
508 | int i; | ||
509 | struct mwifiex_adapter *adapter = priv->adapter; | ||
510 | struct mwifiex_bss_prio_node *bssprio_node = NULL, *tmp_node = NULL, | ||
511 | **cur = NULL; | ||
512 | struct list_head *head; | ||
513 | spinlock_t *lock; | ||
514 | unsigned long flags; | ||
515 | |||
516 | for (i = 0; i < adapter->priv_num; ++i) { | ||
517 | head = &adapter->bss_prio_tbl[i].bss_prio_head; | ||
518 | cur = &adapter->bss_prio_tbl[i].bss_prio_cur; | ||
519 | lock = &adapter->bss_prio_tbl[i].bss_prio_lock; | ||
520 | dev_dbg(adapter->dev, "info: delete BSS priority table," | ||
521 | " index = %d, i = %d, head = %p, cur = %p\n", | ||
522 | priv->bss_index, i, head, *cur); | ||
523 | if (*cur) { | ||
524 | spin_lock_irqsave(lock, flags); | ||
525 | if (list_empty(head)) { | ||
526 | spin_unlock_irqrestore(lock, flags); | ||
527 | continue; | ||
528 | } | ||
529 | bssprio_node = list_first_entry(head, | ||
530 | struct mwifiex_bss_prio_node, list); | ||
531 | spin_unlock_irqrestore(lock, flags); | ||
532 | |||
533 | list_for_each_entry_safe(bssprio_node, tmp_node, head, | ||
534 | list) { | ||
535 | if (bssprio_node->priv == priv) { | ||
536 | dev_dbg(adapter->dev, "info: Delete " | ||
537 | "node %p, next = %p\n", | ||
538 | bssprio_node, tmp_node); | ||
539 | spin_lock_irqsave(lock, flags); | ||
540 | list_del(&bssprio_node->list); | ||
541 | spin_unlock_irqrestore(lock, flags); | ||
542 | kfree(bssprio_node); | ||
543 | } | ||
544 | } | ||
545 | *cur = (struct mwifiex_bss_prio_node *)head; | ||
546 | } | ||
547 | } | ||
548 | } | ||
549 | |||
550 | /* | ||
551 | * This function is used to shutdown the driver. | ||
552 | * | ||
553 | * The following operations are performed sequentially - | ||
554 | * - Check if already shut down | ||
555 | * - Make sure the main process has stopped | ||
556 | * - Clean up the Tx and Rx queues | ||
557 | * - Delete BSS priority tables | ||
558 | * - Free the adapter | ||
559 | * - Notify completion | ||
560 | */ | ||
561 | int | ||
562 | mwifiex_shutdown_drv(struct mwifiex_adapter *adapter) | ||
563 | { | ||
564 | int ret = -EINPROGRESS; | ||
565 | struct mwifiex_private *priv = NULL; | ||
566 | s32 i = 0; | ||
567 | unsigned long flags; | ||
568 | |||
569 | /* mwifiex already shutdown */ | ||
570 | if (adapter->hw_status == MWIFIEX_HW_STATUS_NOT_READY) | ||
571 | return 0; | ||
572 | |||
573 | adapter->hw_status = MWIFIEX_HW_STATUS_CLOSING; | ||
574 | /* wait for mwifiex_process to complete */ | ||
575 | if (adapter->mwifiex_processing) { | ||
576 | dev_warn(adapter->dev, "main process is still running\n"); | ||
577 | return ret; | ||
578 | } | ||
579 | |||
580 | /* shut down mwifiex */ | ||
581 | dev_dbg(adapter->dev, "info: shutdown mwifiex...\n"); | ||
582 | |||
583 | /* Clean up Tx/Rx queues and delete BSS priority table */ | ||
584 | for (i = 0; i < adapter->priv_num; i++) { | ||
585 | if (adapter->priv[i]) { | ||
586 | priv = adapter->priv[i]; | ||
587 | |||
588 | mwifiex_clean_txrx(priv); | ||
589 | mwifiex_delete_bss_prio_tbl(priv); | ||
590 | } | ||
591 | } | ||
592 | |||
593 | spin_lock_irqsave(&adapter->mwifiex_lock, flags); | ||
594 | |||
595 | /* Free adapter structure */ | ||
596 | mwifiex_free_adapter(adapter); | ||
597 | |||
598 | spin_unlock_irqrestore(&adapter->mwifiex_lock, flags); | ||
599 | |||
600 | /* Notify completion */ | ||
601 | ret = mwifiex_shutdown_fw_complete(adapter); | ||
602 | |||
603 | return ret; | ||
604 | } | ||
605 | |||
606 | /* | ||
607 | * This function downloads the firmware to the card. | ||
608 | * | ||
609 | * The actual download is preceded by two sanity checks - | ||
610 | * - Check if firmware is already running | ||
611 | * - Check if the interface is the winner to download the firmware | ||
612 | * | ||
613 | * ...and followed by another - | ||
614 | * - Check if the firmware is downloaded successfully | ||
615 | * | ||
616 | * After download is successfully completed, the host interrupts are enabled. | ||
617 | */ | ||
618 | int mwifiex_dnld_fw(struct mwifiex_adapter *adapter, | ||
619 | struct mwifiex_fw_image *pmfw) | ||
620 | { | ||
621 | int ret = 0; | ||
622 | u32 poll_num = 1; | ||
623 | int winner; | ||
624 | |||
625 | /* Check if firmware is already running */ | ||
626 | ret = adapter->if_ops.check_fw_status(adapter, poll_num, &winner); | ||
627 | if (!ret) { | ||
628 | dev_notice(adapter->dev, | ||
629 | "WLAN FW already running! Skip FW download\n"); | ||
630 | goto done; | ||
631 | } | ||
632 | poll_num = MAX_FIRMWARE_POLL_TRIES; | ||
633 | |||
634 | /* Check if we are the winner for downloading FW */ | ||
635 | if (!winner) { | ||
636 | dev_notice(adapter->dev, | ||
637 | "Other interface already running!" | ||
638 | " Skip FW download\n"); | ||
639 | poll_num = MAX_MULTI_INTERFACE_POLL_TRIES; | ||
640 | goto poll_fw; | ||
641 | } | ||
642 | if (pmfw) { | ||
643 | /* Download firmware with helper */ | ||
644 | ret = adapter->if_ops.prog_fw(adapter, pmfw); | ||
645 | if (ret) { | ||
646 | dev_err(adapter->dev, "prog_fw failed ret=%#x\n", ret); | ||
647 | return ret; | ||
648 | } | ||
649 | } | ||
650 | |||
651 | poll_fw: | ||
652 | /* Check if the firmware is downloaded successfully or not */ | ||
653 | ret = adapter->if_ops.check_fw_status(adapter, poll_num, NULL); | ||
654 | if (ret) { | ||
655 | dev_err(adapter->dev, "FW failed to be active in time\n"); | ||
656 | return -1; | ||
657 | } | ||
658 | done: | ||
659 | /* re-enable host interrupt for mwifiex after fw dnld is successful */ | ||
660 | adapter->if_ops.enable_int(adapter); | ||
661 | return ret; | ||
662 | } | ||
diff --git a/drivers/net/wireless/mwifiex/ioctl.h b/drivers/net/wireless/mwifiex/ioctl.h new file mode 100644 index 000000000000..703a6d12ebf3 --- /dev/null +++ b/drivers/net/wireless/mwifiex/ioctl.h | |||
@@ -0,0 +1,411 @@ | |||
1 | /* | ||
2 | * Marvell Wireless LAN device driver: ioctl data structures & APIs | ||
3 | * | ||
4 | * Copyright (C) 2011, Marvell International Ltd. | ||
5 | * | ||
6 | * This software file (the "File") is distributed by Marvell International | ||
7 | * Ltd. under the terms of the GNU General Public License Version 2, June 1991 | ||
8 | * (the "License"). You may use, redistribute and/or modify this File in | ||
9 | * accordance with the terms and conditions of the License, a copy of which | ||
10 | * is available by writing to the Free Software Foundation, Inc., | ||
11 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the | ||
12 | * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. | ||
13 | * | ||
14 | * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE | ||
15 | * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE | ||
16 | * ARE EXPRESSLY DISCLAIMED. The License provides additional details about | ||
17 | * this warranty disclaimer. | ||
18 | */ | ||
19 | |||
20 | #ifndef _MWIFIEX_IOCTL_H_ | ||
21 | #define _MWIFIEX_IOCTL_H_ | ||
22 | |||
23 | #include <net/mac80211.h> | ||
24 | |||
25 | enum { | ||
26 | MWIFIEX_SCAN_MODE_UNCHANGED = 0, | ||
27 | MWIFIEX_SCAN_MODE_BSS, | ||
28 | MWIFIEX_SCAN_MODE_IBSS, | ||
29 | MWIFIEX_SCAN_MODE_ANY | ||
30 | }; | ||
31 | |||
32 | enum { | ||
33 | MWIFIEX_SCAN_TYPE_UNCHANGED = 0, | ||
34 | MWIFIEX_SCAN_TYPE_ACTIVE, | ||
35 | MWIFIEX_SCAN_TYPE_PASSIVE | ||
36 | }; | ||
37 | |||
38 | struct mwifiex_get_scan_table_fixed { | ||
39 | u8 bssid[ETH_ALEN]; | ||
40 | u8 channel; | ||
41 | u8 rssi; | ||
42 | long long network_tsf; | ||
43 | }; | ||
44 | |||
45 | struct mwifiex_scan_time_params { | ||
46 | u32 specific_scan_time; | ||
47 | u32 active_scan_time; | ||
48 | u32 passive_scan_time; | ||
49 | }; | ||
50 | |||
51 | struct mwifiex_user_scan { | ||
52 | u32 scan_cfg_len; | ||
53 | u8 scan_cfg_buf[1]; | ||
54 | }; | ||
55 | |||
56 | struct mwifiex_scan_req { | ||
57 | u32 scan_mode; | ||
58 | u32 scan_type; | ||
59 | struct mwifiex_802_11_ssid scan_ssid; | ||
60 | struct mwifiex_scan_time_params scan_time; | ||
61 | struct mwifiex_user_scan user_scan; | ||
62 | }; | ||
63 | |||
64 | struct mwifiex_scan_resp { | ||
65 | u32 num_in_scan_table; | ||
66 | u8 *scan_table; | ||
67 | }; | ||
68 | |||
69 | #define MWIFIEX_PROMISC_MODE 1 | ||
70 | #define MWIFIEX_MULTICAST_MODE 2 | ||
71 | #define MWIFIEX_ALL_MULTI_MODE 4 | ||
72 | #define MWIFIEX_MAX_MULTICAST_LIST_SIZE 32 | ||
73 | |||
74 | struct mwifiex_multicast_list { | ||
75 | u32 mode; | ||
76 | u32 num_multicast_addr; | ||
77 | u8 mac_list[MWIFIEX_MAX_MULTICAST_LIST_SIZE][ETH_ALEN]; | ||
78 | }; | ||
79 | |||
80 | #define MWIFIEX_MAX_CHANNEL_NUM 128 | ||
81 | |||
82 | struct mwifiex_chan_freq { | ||
83 | u32 channel; | ||
84 | u32 freq; | ||
85 | }; | ||
86 | |||
87 | struct mwifiex_chan_list { | ||
88 | u32 num_of_chan; | ||
89 | struct mwifiex_chan_freq cf[MWIFIEX_MAX_CHANNEL_NUM]; | ||
90 | }; | ||
91 | |||
92 | struct mwifiex_ssid_bssid { | ||
93 | struct mwifiex_802_11_ssid ssid; | ||
94 | u8 bssid[ETH_ALEN]; | ||
95 | }; | ||
96 | |||
97 | enum { | ||
98 | BAND_B = 1, | ||
99 | BAND_G = 2, | ||
100 | BAND_A = 4, | ||
101 | BAND_GN = 8, | ||
102 | BAND_AN = 16, | ||
103 | }; | ||
104 | |||
105 | #define NO_SEC_CHANNEL 0 | ||
106 | #define SEC_CHANNEL_ABOVE 1 | ||
107 | #define SEC_CHANNEL_BELOW 3 | ||
108 | |||
109 | struct mwifiex_ds_band_cfg { | ||
110 | u32 config_bands; | ||
111 | u32 adhoc_start_band; | ||
112 | u32 adhoc_channel; | ||
113 | u32 sec_chan_offset; | ||
114 | }; | ||
115 | |||
116 | enum { | ||
117 | ADHOC_IDLE, | ||
118 | ADHOC_STARTED, | ||
119 | ADHOC_JOINED, | ||
120 | ADHOC_COALESCED | ||
121 | }; | ||
122 | |||
123 | struct mwifiex_ds_get_stats { | ||
124 | u32 mcast_tx_frame; | ||
125 | u32 failed; | ||
126 | u32 retry; | ||
127 | u32 multi_retry; | ||
128 | u32 frame_dup; | ||
129 | u32 rts_success; | ||
130 | u32 rts_failure; | ||
131 | u32 ack_failure; | ||
132 | u32 rx_frag; | ||
133 | u32 mcast_rx_frame; | ||
134 | u32 fcs_error; | ||
135 | u32 tx_frame; | ||
136 | u32 wep_icv_error[4]; | ||
137 | }; | ||
138 | |||
139 | #define BCN_RSSI_LAST_MASK 0x00000001 | ||
140 | #define BCN_RSSI_AVG_MASK 0x00000002 | ||
141 | #define DATA_RSSI_LAST_MASK 0x00000004 | ||
142 | #define DATA_RSSI_AVG_MASK 0x00000008 | ||
143 | #define BCN_SNR_LAST_MASK 0x00000010 | ||
144 | #define BCN_SNR_AVG_MASK 0x00000020 | ||
145 | #define DATA_SNR_LAST_MASK 0x00000040 | ||
146 | #define DATA_SNR_AVG_MASK 0x00000080 | ||
147 | #define BCN_NF_LAST_MASK 0x00000100 | ||
148 | #define BCN_NF_AVG_MASK 0x00000200 | ||
149 | #define DATA_NF_LAST_MASK 0x00000400 | ||
150 | #define DATA_NF_AVG_MASK 0x00000800 | ||
151 | #define ALL_RSSI_INFO_MASK 0x00000fff | ||
152 | |||
153 | struct mwifiex_ds_get_signal { | ||
154 | /* | ||
155 | * Bit0: Last Beacon RSSI, Bit1: Average Beacon RSSI, | ||
156 | * Bit2: Last Data RSSI, Bit3: Average Data RSSI, | ||
157 | * Bit4: Last Beacon SNR, Bit5: Average Beacon SNR, | ||
158 | * Bit6: Last Data SNR, Bit7: Average Data SNR, | ||
159 | * Bit8: Last Beacon NF, Bit9: Average Beacon NF, | ||
160 | * Bit10: Last Data NF, Bit11: Average Data NF | ||
161 | */ | ||
162 | u16 selector; | ||
163 | s16 bcn_rssi_last; | ||
164 | s16 bcn_rssi_avg; | ||
165 | s16 data_rssi_last; | ||
166 | s16 data_rssi_avg; | ||
167 | s16 bcn_snr_last; | ||
168 | s16 bcn_snr_avg; | ||
169 | s16 data_snr_last; | ||
170 | s16 data_snr_avg; | ||
171 | s16 bcn_nf_last; | ||
172 | s16 bcn_nf_avg; | ||
173 | s16 data_nf_last; | ||
174 | s16 data_nf_avg; | ||
175 | }; | ||
176 | |||
177 | struct mwifiex_fw_info { | ||
178 | u32 fw_ver; | ||
179 | u8 mac_addr[ETH_ALEN]; | ||
180 | }; | ||
181 | |||
182 | #define MWIFIEX_MAX_VER_STR_LEN 128 | ||
183 | |||
184 | struct mwifiex_ver_ext { | ||
185 | u32 version_str_sel; | ||
186 | char version_str[MWIFIEX_MAX_VER_STR_LEN]; | ||
187 | }; | ||
188 | |||
189 | struct mwifiex_bss_info { | ||
190 | u32 bss_mode; | ||
191 | struct mwifiex_802_11_ssid ssid; | ||
192 | u32 scan_table_idx; | ||
193 | u32 bss_chan; | ||
194 | u32 region_code; | ||
195 | u32 media_connected; | ||
196 | u32 max_power_level; | ||
197 | u32 min_power_level; | ||
198 | u32 adhoc_state; | ||
199 | signed int bcn_nf_last; | ||
200 | u32 wep_status; | ||
201 | u32 is_hs_configured; | ||
202 | u32 is_deep_sleep; | ||
203 | u8 bssid[ETH_ALEN]; | ||
204 | }; | ||
205 | |||
206 | #define MAX_NUM_TID 8 | ||
207 | |||
208 | #define MAX_RX_WINSIZE 64 | ||
209 | |||
210 | struct mwifiex_ds_rx_reorder_tbl { | ||
211 | u16 tid; | ||
212 | u8 ta[ETH_ALEN]; | ||
213 | u32 start_win; | ||
214 | u32 win_size; | ||
215 | u32 buffer[MAX_RX_WINSIZE]; | ||
216 | }; | ||
217 | |||
218 | struct mwifiex_ds_tx_ba_stream_tbl { | ||
219 | u16 tid; | ||
220 | u8 ra[ETH_ALEN]; | ||
221 | }; | ||
222 | |||
223 | #define DBG_CMD_NUM 5 | ||
224 | |||
225 | struct mwifiex_debug_info { | ||
226 | u32 int_counter; | ||
227 | u32 packets_out[MAX_NUM_TID]; | ||
228 | u32 max_tx_buf_size; | ||
229 | u32 tx_buf_size; | ||
230 | u32 curr_tx_buf_size; | ||
231 | u32 tx_tbl_num; | ||
232 | struct mwifiex_ds_tx_ba_stream_tbl | ||
233 | tx_tbl[MWIFIEX_MAX_TX_BASTREAM_SUPPORTED]; | ||
234 | u32 rx_tbl_num; | ||
235 | struct mwifiex_ds_rx_reorder_tbl rx_tbl | ||
236 | [MWIFIEX_MAX_RX_BASTREAM_SUPPORTED]; | ||
237 | u16 ps_mode; | ||
238 | u32 ps_state; | ||
239 | u8 is_deep_sleep; | ||
240 | u8 pm_wakeup_card_req; | ||
241 | u32 pm_wakeup_fw_try; | ||
242 | u8 is_hs_configured; | ||
243 | u8 hs_activated; | ||
244 | u32 num_cmd_host_to_card_failure; | ||
245 | u32 num_cmd_sleep_cfm_host_to_card_failure; | ||
246 | u32 num_tx_host_to_card_failure; | ||
247 | u32 num_event_deauth; | ||
248 | u32 num_event_disassoc; | ||
249 | u32 num_event_link_lost; | ||
250 | u32 num_cmd_deauth; | ||
251 | u32 num_cmd_assoc_success; | ||
252 | u32 num_cmd_assoc_failure; | ||
253 | u32 num_tx_timeout; | ||
254 | u32 num_cmd_timeout; | ||
255 | u16 timeout_cmd_id; | ||
256 | u16 timeout_cmd_act; | ||
257 | u16 last_cmd_id[DBG_CMD_NUM]; | ||
258 | u16 last_cmd_act[DBG_CMD_NUM]; | ||
259 | u16 last_cmd_index; | ||
260 | u16 last_cmd_resp_id[DBG_CMD_NUM]; | ||
261 | u16 last_cmd_resp_index; | ||
262 | u16 last_event[DBG_CMD_NUM]; | ||
263 | u16 last_event_index; | ||
264 | u8 data_sent; | ||
265 | u8 cmd_sent; | ||
266 | u8 cmd_resp_received; | ||
267 | u8 event_received; | ||
268 | }; | ||
269 | |||
270 | #define MWIFIEX_KEY_INDEX_UNICAST 0x40000000 | ||
271 | #define MWIFIEX_MAX_KEY_LENGTH 32 | ||
272 | #define WAPI_RXPN_LEN 16 | ||
273 | |||
274 | struct mwifiex_ds_encrypt_key { | ||
275 | u32 key_disable; | ||
276 | u32 key_index; | ||
277 | u32 key_len; | ||
278 | u8 key_material[MWIFIEX_MAX_KEY_LENGTH]; | ||
279 | u8 mac_addr[ETH_ALEN]; | ||
280 | u32 is_wapi_key; | ||
281 | u8 wapi_rxpn[WAPI_RXPN_LEN]; | ||
282 | }; | ||
283 | |||
284 | struct mwifiex_rate_cfg { | ||
285 | u32 action; | ||
286 | u32 is_rate_auto; | ||
287 | u32 rate; | ||
288 | }; | ||
289 | |||
290 | struct mwifiex_data_rate { | ||
291 | u32 tx_data_rate; | ||
292 | u32 rx_data_rate; | ||
293 | }; | ||
294 | |||
295 | struct mwifiex_power_cfg { | ||
296 | u32 is_power_auto; | ||
297 | u32 power_level; | ||
298 | }; | ||
299 | |||
300 | struct mwifiex_ds_hs_cfg { | ||
301 | u32 is_invoke_hostcmd; | ||
302 | /* Bit0: non-unicast data | ||
303 | * Bit1: unicast data | ||
304 | * Bit2: mac events | ||
305 | * Bit3: magic packet | ||
306 | */ | ||
307 | u32 conditions; | ||
308 | u32 gpio; | ||
309 | u32 gap; | ||
310 | }; | ||
311 | |||
312 | #define DEEP_SLEEP_ON 1 | ||
313 | #define DEEP_SLEEP_OFF 0 | ||
314 | |||
315 | #define DEEP_SLEEP_IDLE_TIME 100 | ||
316 | |||
317 | struct mwifiex_ds_auto_ds { | ||
318 | u16 auto_ds; | ||
319 | u16 idle_time; | ||
320 | }; | ||
321 | |||
322 | #define PS_MODE_UNCHANGED 0 | ||
323 | #define PS_MODE_AUTO 1 | ||
324 | #define PS_MODE_POLL 2 | ||
325 | #define PS_MODE_NULL 3 | ||
326 | |||
327 | |||
328 | struct mwifiex_ds_pm_cfg { | ||
329 | union { | ||
330 | u32 ps_mode; | ||
331 | struct mwifiex_ds_hs_cfg hs_cfg; | ||
332 | struct mwifiex_ds_auto_ds auto_deep_sleep; | ||
333 | u32 sleep_period; | ||
334 | } param; | ||
335 | }; | ||
336 | |||
337 | struct mwifiex_ioctl_wmm_queue_status_ac { | ||
338 | u8 wmm_acm; | ||
339 | u8 flow_required; | ||
340 | u8 flow_created; | ||
341 | u8 disabled; | ||
342 | }; | ||
343 | |||
344 | struct mwifiex_ds_wmm_queue_status { | ||
345 | struct mwifiex_ioctl_wmm_queue_status_ac | ||
346 | ac_status[IEEE80211_MAX_QUEUES]; | ||
347 | }; | ||
348 | |||
349 | struct mwifiex_ds_11n_tx_cfg { | ||
350 | u16 tx_htcap; | ||
351 | u16 tx_htinfo; | ||
352 | }; | ||
353 | |||
354 | struct mwifiex_ds_11n_amsdu_aggr_ctrl { | ||
355 | u16 enable; | ||
356 | u16 curr_buf_size; | ||
357 | }; | ||
358 | |||
359 | #define MWIFIEX_NUM_OF_CMD_BUFFER 20 | ||
360 | #define MWIFIEX_SIZE_OF_CMD_BUFFER 2048 | ||
361 | |||
362 | enum { | ||
363 | MWIFIEX_IE_TYPE_GEN_IE = 0, | ||
364 | MWIFIEX_IE_TYPE_ARP_FILTER, | ||
365 | }; | ||
366 | |||
367 | enum { | ||
368 | MWIFIEX_REG_MAC = 1, | ||
369 | MWIFIEX_REG_BBP, | ||
370 | MWIFIEX_REG_RF, | ||
371 | MWIFIEX_REG_PMIC, | ||
372 | MWIFIEX_REG_CAU, | ||
373 | }; | ||
374 | |||
375 | struct mwifiex_ds_reg_rw { | ||
376 | __le32 type; | ||
377 | __le32 offset; | ||
378 | __le32 value; | ||
379 | }; | ||
380 | |||
381 | #define MAX_EEPROM_DATA 256 | ||
382 | |||
383 | struct mwifiex_ds_read_eeprom { | ||
384 | __le16 offset; | ||
385 | __le16 byte_count; | ||
386 | u8 value[MAX_EEPROM_DATA]; | ||
387 | }; | ||
388 | |||
389 | struct mwifiex_ds_misc_gen_ie { | ||
390 | u32 type; | ||
391 | u32 len; | ||
392 | u8 ie_data[IW_CUSTOM_MAX]; | ||
393 | }; | ||
394 | |||
395 | struct mwifiex_ds_misc_cmd { | ||
396 | u32 len; | ||
397 | u8 cmd[MWIFIEX_SIZE_OF_CMD_BUFFER]; | ||
398 | }; | ||
399 | |||
400 | #define MWIFIEX_MAX_VSIE_LEN (256) | ||
401 | #define MWIFIEX_MAX_VSIE_NUM (8) | ||
402 | #define MWIFIEX_VSIE_MASK_SCAN 0x01 | ||
403 | #define MWIFIEX_VSIE_MASK_ASSOC 0x02 | ||
404 | #define MWIFIEX_VSIE_MASK_ADHOC 0x04 | ||
405 | |||
406 | enum { | ||
407 | MWIFIEX_FUNC_INIT = 1, | ||
408 | MWIFIEX_FUNC_SHUTDOWN, | ||
409 | }; | ||
410 | |||
411 | #endif /* !_MWIFIEX_IOCTL_H_ */ | ||
diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c new file mode 100644 index 000000000000..7a9e0b5962ed --- /dev/null +++ b/drivers/net/wireless/mwifiex/join.c | |||
@@ -0,0 +1,1462 @@ | |||
1 | /* | ||
2 | * Marvell Wireless LAN device driver: association and ad-hoc start/join | ||
3 | * | ||
4 | * Copyright (C) 2011, Marvell International Ltd. | ||
5 | * | ||
6 | * This software file (the "File") is distributed by Marvell International | ||
7 | * Ltd. under the terms of the GNU General Public License Version 2, June 1991 | ||
8 | * (the "License"). You may use, redistribute and/or modify this File in | ||
9 | * accordance with the terms and conditions of the License, a copy of which | ||
10 | * is available by writing to the Free Software Foundation, Inc., | ||
11 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the | ||
12 | * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. | ||
13 | * | ||
14 | * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE | ||
15 | * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE | ||
16 | * ARE EXPRESSLY DISCLAIMED. The License provides additional details about | ||
17 | * this warranty disclaimer. | ||
18 | */ | ||
19 | |||
20 | #include "decl.h" | ||
21 | #include "ioctl.h" | ||
22 | #include "util.h" | ||
23 | #include "fw.h" | ||
24 | #include "main.h" | ||
25 | #include "wmm.h" | ||
26 | #include "11n.h" | ||
27 | |||
28 | #define CAPINFO_MASK (~(BIT(15) | BIT(14) | BIT(12) | BIT(11) | BIT(9))) | ||
29 | |||
30 | /* | ||
31 | * Append a generic IE as a pass through TLV to a TLV buffer. | ||
32 | * | ||
33 | * This function is called from the network join command preparation routine. | ||
34 | * | ||
35 | * If the IE buffer has been setup by the application, this routine appends | ||
36 | * the buffer as a pass through TLV type to the request. | ||
37 | */ | ||
38 | static int | ||
39 | mwifiex_cmd_append_generic_ie(struct mwifiex_private *priv, u8 **buffer) | ||
40 | { | ||
41 | int ret_len = 0; | ||
42 | struct mwifiex_ie_types_header ie_header; | ||
43 | |||
44 | /* Null Checks */ | ||
45 | if (!buffer) | ||
46 | return 0; | ||
47 | if (!(*buffer)) | ||
48 | return 0; | ||
49 | |||
50 | /* | ||
51 | * If there is a generic ie buffer setup, append it to the return | ||
52 | * parameter buffer pointer. | ||
53 | */ | ||
54 | if (priv->gen_ie_buf_len) { | ||
55 | dev_dbg(priv->adapter->dev, "info: %s: append generic %d to %p\n", | ||
56 | __func__, priv->gen_ie_buf_len, *buffer); | ||
57 | |||
58 | /* Wrap the generic IE buffer with a pass through TLV type */ | ||
59 | ie_header.type = cpu_to_le16(TLV_TYPE_PASSTHROUGH); | ||
60 | ie_header.len = cpu_to_le16(priv->gen_ie_buf_len); | ||
61 | memcpy(*buffer, &ie_header, sizeof(ie_header)); | ||
62 | |||
63 | /* Increment the return size and the return buffer pointer | ||
64 | param */ | ||
65 | *buffer += sizeof(ie_header); | ||
66 | ret_len += sizeof(ie_header); | ||
67 | |||
68 | /* Copy the generic IE buffer to the output buffer, advance | ||
69 | pointer */ | ||
70 | memcpy(*buffer, priv->gen_ie_buf, priv->gen_ie_buf_len); | ||
71 | |||
72 | /* Increment the return size and the return buffer pointer | ||
73 | param */ | ||
74 | *buffer += priv->gen_ie_buf_len; | ||
75 | ret_len += priv->gen_ie_buf_len; | ||
76 | |||
77 | /* Reset the generic IE buffer */ | ||
78 | priv->gen_ie_buf_len = 0; | ||
79 | } | ||
80 | |||
81 | /* return the length appended to the buffer */ | ||
82 | return ret_len; | ||
83 | } | ||
84 | |||
85 | /* | ||
86 | * Append TSF tracking info from the scan table for the target AP. | ||
87 | * | ||
88 | * This function is called from the network join command preparation routine. | ||
89 | * | ||
90 | * The TSF table TSF sent to the firmware contains two TSF values: | ||
91 | * - The TSF of the target AP from its previous beacon/probe response | ||
92 | * - The TSF timestamp of our local MAC at the time we observed the | ||
93 | * beacon/probe response. | ||
94 | * | ||
95 | * The firmware uses the timestamp values to set an initial TSF value | ||
96 | * in the MAC for the new association after a reassociation attempt. | ||
97 | */ | ||
98 | static int | ||
99 | mwifiex_cmd_append_tsf_tlv(struct mwifiex_private *priv, u8 **buffer, | ||
100 | struct mwifiex_bssdescriptor *bss_desc) | ||
101 | { | ||
102 | struct mwifiex_ie_types_tsf_timestamp tsf_tlv; | ||
103 | long long tsf_val; | ||
104 | |||
105 | /* Null Checks */ | ||
106 | if (buffer == NULL) | ||
107 | return 0; | ||
108 | if (*buffer == NULL) | ||
109 | return 0; | ||
110 | |||
111 | memset(&tsf_tlv, 0x00, sizeof(struct mwifiex_ie_types_tsf_timestamp)); | ||
112 | |||
113 | tsf_tlv.header.type = cpu_to_le16(TLV_TYPE_TSFTIMESTAMP); | ||
114 | tsf_tlv.header.len = cpu_to_le16(2 * sizeof(tsf_val)); | ||
115 | |||
116 | memcpy(*buffer, &tsf_tlv, sizeof(tsf_tlv.header)); | ||
117 | *buffer += sizeof(tsf_tlv.header); | ||
118 | |||
119 | memcpy(*buffer, &tsf_val, sizeof(tsf_val)); | ||
120 | *buffer += sizeof(tsf_val); | ||
121 | |||
122 | memcpy(&tsf_val, bss_desc->time_stamp, sizeof(tsf_val)); | ||
123 | |||
124 | dev_dbg(priv->adapter->dev, "info: %s: TSF offset calc: %016llx - " | ||
125 | "%016llx\n", __func__, tsf_val, bss_desc->network_tsf); | ||
126 | |||
127 | memcpy(*buffer, &tsf_val, sizeof(tsf_val)); | ||
128 | *buffer += sizeof(tsf_val); | ||
129 | |||
130 | return sizeof(tsf_tlv.header) + (2 * sizeof(tsf_val)); | ||
131 | } | ||
132 | |||
133 | /* | ||
134 | * This function finds out the common rates between rate1 and rate2. | ||
135 | * | ||
136 | * It will fill common rates in rate1 as output if found. | ||
137 | * | ||
138 | * NOTE: Setting the MSB of the basic rates needs to be taken | ||
139 | * care of, either before or after calling this function. | ||
140 | */ | ||
141 | static int mwifiex_get_common_rates(struct mwifiex_private *priv, u8 *rate1, | ||
142 | u32 rate1_size, u8 *rate2, u32 rate2_size) | ||
143 | { | ||
144 | int ret = 0; | ||
145 | u8 *ptr = rate1; | ||
146 | u8 *tmp = NULL; | ||
147 | u32 i, j; | ||
148 | |||
149 | tmp = kmalloc(rate1_size, GFP_KERNEL); | ||
150 | if (!tmp) { | ||
151 | dev_err(priv->adapter->dev, "failed to alloc tmp buf\n"); | ||
152 | return -ENOMEM; | ||
153 | } | ||
154 | |||
155 | memcpy(tmp, rate1, rate1_size); | ||
156 | memset(rate1, 0, rate1_size); | ||
157 | |||
158 | for (i = 0; rate2[i] && i < rate2_size; i++) { | ||
159 | for (j = 0; tmp[j] && j < rate1_size; j++) { | ||
160 | /* Check common rate, excluding the bit for | ||
161 | basic rate */ | ||
162 | if ((rate2[i] & 0x7F) == (tmp[j] & 0x7F)) { | ||
163 | *rate1++ = tmp[j]; | ||
164 | break; | ||
165 | } | ||
166 | } | ||
167 | } | ||
168 | |||
169 | dev_dbg(priv->adapter->dev, "info: Tx data rate set to %#x\n", | ||
170 | priv->data_rate); | ||
171 | |||
172 | if (!priv->is_data_rate_auto) { | ||
173 | while (*ptr) { | ||
174 | if ((*ptr & 0x7f) == priv->data_rate) { | ||
175 | ret = 0; | ||
176 | goto done; | ||
177 | } | ||
178 | ptr++; | ||
179 | } | ||
180 | dev_err(priv->adapter->dev, "previously set fixed data rate %#x" | ||
181 | " is not compatible with the network\n", | ||
182 | priv->data_rate); | ||
183 | |||
184 | ret = -1; | ||
185 | goto done; | ||
186 | } | ||
187 | |||
188 | ret = 0; | ||
189 | done: | ||
190 | kfree(tmp); | ||
191 | return ret; | ||
192 | } | ||
193 | |||
194 | /* | ||
195 | * This function creates the intersection of the rates supported by a | ||
196 | * target BSS and our adapter settings for use in an assoc/join command. | ||
197 | */ | ||
198 | static int | ||
199 | mwifiex_setup_rates_from_bssdesc(struct mwifiex_private *priv, | ||
200 | struct mwifiex_bssdescriptor *bss_desc, | ||
201 | u8 *out_rates, u32 *out_rates_size) | ||
202 | { | ||
203 | u8 card_rates[MWIFIEX_SUPPORTED_RATES]; | ||
204 | u32 card_rates_size = 0; | ||
205 | |||
206 | /* Copy AP supported rates */ | ||
207 | memcpy(out_rates, bss_desc->supported_rates, MWIFIEX_SUPPORTED_RATES); | ||
208 | /* Get the STA supported rates */ | ||
209 | card_rates_size = mwifiex_get_active_data_rates(priv, card_rates); | ||
210 | /* Get the common rates between AP and STA supported rates */ | ||
211 | if (mwifiex_get_common_rates(priv, out_rates, MWIFIEX_SUPPORTED_RATES, | ||
212 | card_rates, card_rates_size)) { | ||
213 | *out_rates_size = 0; | ||
214 | dev_err(priv->adapter->dev, "%s: cannot get common rates\n", | ||
215 | __func__); | ||
216 | return -1; | ||
217 | } | ||
218 | |||
219 | *out_rates_size = | ||
220 | min_t(size_t, strlen(out_rates), MWIFIEX_SUPPORTED_RATES); | ||
221 | |||
222 | return 0; | ||
223 | } | ||
224 | |||
225 | /* | ||
226 | * This function updates the scan entry TSF timestamps to reflect | ||
227 | * a new association. | ||
228 | */ | ||
229 | static void | ||
230 | mwifiex_update_tsf_timestamps(struct mwifiex_private *priv, | ||
231 | struct mwifiex_bssdescriptor *new_bss_desc) | ||
232 | { | ||
233 | struct mwifiex_adapter *adapter = priv->adapter; | ||
234 | u32 table_idx; | ||
235 | long long new_tsf_base; | ||
236 | signed long long tsf_delta; | ||
237 | |||
238 | memcpy(&new_tsf_base, new_bss_desc->time_stamp, sizeof(new_tsf_base)); | ||
239 | |||
240 | tsf_delta = new_tsf_base - new_bss_desc->network_tsf; | ||
241 | |||
242 | dev_dbg(adapter->dev, "info: TSF: update TSF timestamps, " | ||
243 | "0x%016llx -> 0x%016llx\n", | ||
244 | new_bss_desc->network_tsf, new_tsf_base); | ||
245 | |||
246 | for (table_idx = 0; table_idx < adapter->num_in_scan_table; | ||
247 | table_idx++) | ||
248 | adapter->scan_table[table_idx].network_tsf += tsf_delta; | ||
249 | } | ||
250 | |||
251 | /* | ||
252 | * This function appends a WAPI IE. | ||
253 | * | ||
254 | * This function is called from the network join command preparation routine. | ||
255 | * | ||
256 | * If the IE buffer has been setup by the application, this routine appends | ||
257 | * the buffer as a WAPI TLV type to the request. | ||
258 | */ | ||
259 | static int | ||
260 | mwifiex_cmd_append_wapi_ie(struct mwifiex_private *priv, u8 **buffer) | ||
261 | { | ||
262 | int retLen = 0; | ||
263 | struct mwifiex_ie_types_header ie_header; | ||
264 | |||
265 | /* Null Checks */ | ||
266 | if (buffer == NULL) | ||
267 | return 0; | ||
268 | if (*buffer == NULL) | ||
269 | return 0; | ||
270 | |||
271 | /* | ||
272 | * If there is a wapi ie buffer setup, append it to the return | ||
273 | * parameter buffer pointer. | ||
274 | */ | ||
275 | if (priv->wapi_ie_len) { | ||
276 | dev_dbg(priv->adapter->dev, "cmd: append wapi ie %d to %p\n", | ||
277 | priv->wapi_ie_len, *buffer); | ||
278 | |||
279 | /* Wrap the generic IE buffer with a pass through TLV type */ | ||
280 | ie_header.type = cpu_to_le16(TLV_TYPE_WAPI_IE); | ||
281 | ie_header.len = cpu_to_le16(priv->wapi_ie_len); | ||
282 | memcpy(*buffer, &ie_header, sizeof(ie_header)); | ||
283 | |||
284 | /* Increment the return size and the return buffer pointer | ||
285 | param */ | ||
286 | *buffer += sizeof(ie_header); | ||
287 | retLen += sizeof(ie_header); | ||
288 | |||
289 | /* Copy the wapi IE buffer to the output buffer, advance | ||
290 | pointer */ | ||
291 | memcpy(*buffer, priv->wapi_ie, priv->wapi_ie_len); | ||
292 | |||
293 | /* Increment the return size and the return buffer pointer | ||
294 | param */ | ||
295 | *buffer += priv->wapi_ie_len; | ||
296 | retLen += priv->wapi_ie_len; | ||
297 | |||
298 | } | ||
299 | /* return the length appended to the buffer */ | ||
300 | return retLen; | ||
301 | } | ||
302 | |||
303 | /* | ||
304 | * This function appends rsn ie tlv for wpa/wpa2 security modes. | ||
305 | * It is called from the network join command preparation routine. | ||
306 | */ | ||
307 | static int mwifiex_append_rsn_ie_wpa_wpa2(struct mwifiex_private *priv, | ||
308 | u8 **buffer) | ||
309 | { | ||
310 | struct mwifiex_ie_types_rsn_param_set *rsn_ie_tlv; | ||
311 | int rsn_ie_len; | ||
312 | |||
313 | if (!buffer || !(*buffer)) | ||
314 | return 0; | ||
315 | |||
316 | rsn_ie_tlv = (struct mwifiex_ie_types_rsn_param_set *) (*buffer); | ||
317 | rsn_ie_tlv->header.type = cpu_to_le16((u16) priv->wpa_ie[0]); | ||
318 | rsn_ie_tlv->header.type = cpu_to_le16( | ||
319 | le16_to_cpu(rsn_ie_tlv->header.type) & 0x00FF); | ||
320 | rsn_ie_tlv->header.len = cpu_to_le16((u16) priv->wpa_ie[1]); | ||
321 | rsn_ie_tlv->header.len = cpu_to_le16(le16_to_cpu(rsn_ie_tlv->header.len) | ||
322 | & 0x00FF); | ||
323 | if (le16_to_cpu(rsn_ie_tlv->header.len) <= (sizeof(priv->wpa_ie) - 2)) | ||
324 | memcpy(rsn_ie_tlv->rsn_ie, &priv->wpa_ie[2], | ||
325 | le16_to_cpu(rsn_ie_tlv->header.len)); | ||
326 | else | ||
327 | return -1; | ||
328 | |||
329 | rsn_ie_len = sizeof(rsn_ie_tlv->header) + | ||
330 | le16_to_cpu(rsn_ie_tlv->header.len); | ||
331 | *buffer += rsn_ie_len; | ||
332 | |||
333 | return rsn_ie_len; | ||
334 | } | ||
335 | |||
336 | /* | ||
337 | * This function prepares command for association. | ||
338 | * | ||
339 | * This sets the following parameters - | ||
340 | * - Peer MAC address | ||
341 | * - Listen interval | ||
342 | * - Beacon interval | ||
343 | * - Capability information | ||
344 | * | ||
345 | * ...and the following TLVs, as required - | ||
346 | * - SSID TLV | ||
347 | * - PHY TLV | ||
348 | * - SS TLV | ||
349 | * - Rates TLV | ||
350 | * - Authentication TLV | ||
351 | * - Channel TLV | ||
352 | * - WPA/WPA2 IE | ||
353 | * - 11n TLV | ||
354 | * - Vendor specific TLV | ||
355 | * - WMM TLV | ||
356 | * - WAPI IE | ||
357 | * - Generic IE | ||
358 | * - TSF TLV | ||
359 | * | ||
360 | * Preparation also includes - | ||
361 | * - Setting command ID and proper size | ||
362 | * - Ensuring correct endian-ness | ||
363 | */ | ||
364 | int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv, | ||
365 | struct host_cmd_ds_command *cmd, | ||
366 | void *data_buf) | ||
367 | { | ||
368 | struct host_cmd_ds_802_11_associate *assoc = &cmd->params.associate; | ||
369 | struct mwifiex_bssdescriptor *bss_desc; | ||
370 | struct mwifiex_ie_types_ssid_param_set *ssid_tlv; | ||
371 | struct mwifiex_ie_types_phy_param_set *phy_tlv; | ||
372 | struct mwifiex_ie_types_ss_param_set *ss_tlv; | ||
373 | struct mwifiex_ie_types_rates_param_set *rates_tlv; | ||
374 | struct mwifiex_ie_types_auth_type *auth_tlv; | ||
375 | struct mwifiex_ie_types_chan_list_param_set *chan_tlv; | ||
376 | u8 rates[MWIFIEX_SUPPORTED_RATES]; | ||
377 | u32 rates_size; | ||
378 | u16 tmp_cap; | ||
379 | u8 *pos; | ||
380 | int rsn_ie_len = 0; | ||
381 | |||
382 | bss_desc = (struct mwifiex_bssdescriptor *) data_buf; | ||
383 | pos = (u8 *) assoc; | ||
384 | |||
385 | mwifiex_cfg_tx_buf(priv, bss_desc); | ||
386 | |||
387 | cmd->command = cpu_to_le16(HostCmd_CMD_802_11_ASSOCIATE); | ||
388 | |||
389 | /* Save so we know which BSS Desc to use in the response handler */ | ||
390 | priv->attempted_bss_desc = bss_desc; | ||
391 | |||
392 | memcpy(assoc->peer_sta_addr, | ||
393 | bss_desc->mac_address, sizeof(assoc->peer_sta_addr)); | ||
394 | pos += sizeof(assoc->peer_sta_addr); | ||
395 | |||
396 | /* Set the listen interval */ | ||
397 | assoc->listen_interval = cpu_to_le16(priv->listen_interval); | ||
398 | /* Set the beacon period */ | ||
399 | assoc->beacon_period = cpu_to_le16(bss_desc->beacon_period); | ||
400 | |||
401 | pos += sizeof(assoc->cap_info_bitmap); | ||
402 | pos += sizeof(assoc->listen_interval); | ||
403 | pos += sizeof(assoc->beacon_period); | ||
404 | pos += sizeof(assoc->dtim_period); | ||
405 | |||
406 | ssid_tlv = (struct mwifiex_ie_types_ssid_param_set *) pos; | ||
407 | ssid_tlv->header.type = cpu_to_le16(WLAN_EID_SSID); | ||
408 | ssid_tlv->header.len = cpu_to_le16((u16) bss_desc->ssid.ssid_len); | ||
409 | memcpy(ssid_tlv->ssid, bss_desc->ssid.ssid, | ||
410 | le16_to_cpu(ssid_tlv->header.len)); | ||
411 | pos += sizeof(ssid_tlv->header) + le16_to_cpu(ssid_tlv->header.len); | ||
412 | |||
413 | phy_tlv = (struct mwifiex_ie_types_phy_param_set *) pos; | ||
414 | phy_tlv->header.type = cpu_to_le16(WLAN_EID_DS_PARAMS); | ||
415 | phy_tlv->header.len = cpu_to_le16(sizeof(phy_tlv->fh_ds.ds_param_set)); | ||
416 | memcpy(&phy_tlv->fh_ds.ds_param_set, | ||
417 | &bss_desc->phy_param_set.ds_param_set.current_chan, | ||
418 | sizeof(phy_tlv->fh_ds.ds_param_set)); | ||
419 | pos += sizeof(phy_tlv->header) + le16_to_cpu(phy_tlv->header.len); | ||
420 | |||
421 | ss_tlv = (struct mwifiex_ie_types_ss_param_set *) pos; | ||
422 | ss_tlv->header.type = cpu_to_le16(WLAN_EID_CF_PARAMS); | ||
423 | ss_tlv->header.len = cpu_to_le16(sizeof(ss_tlv->cf_ibss.cf_param_set)); | ||
424 | pos += sizeof(ss_tlv->header) + le16_to_cpu(ss_tlv->header.len); | ||
425 | |||
426 | /* Get the common rates supported between the driver and the BSS Desc */ | ||
427 | if (mwifiex_setup_rates_from_bssdesc | ||
428 | (priv, bss_desc, rates, &rates_size)) | ||
429 | return -1; | ||
430 | |||
431 | /* Save the data rates into Current BSS state structure */ | ||
432 | priv->curr_bss_params.num_of_rates = rates_size; | ||
433 | memcpy(&priv->curr_bss_params.data_rates, rates, rates_size); | ||
434 | |||
435 | /* Setup the Rates TLV in the association command */ | ||
436 | rates_tlv = (struct mwifiex_ie_types_rates_param_set *) pos; | ||
437 | rates_tlv->header.type = cpu_to_le16(WLAN_EID_SUPP_RATES); | ||
438 | rates_tlv->header.len = cpu_to_le16((u16) rates_size); | ||
439 | memcpy(rates_tlv->rates, rates, rates_size); | ||
440 | pos += sizeof(rates_tlv->header) + rates_size; | ||
441 | dev_dbg(priv->adapter->dev, "info: ASSOC_CMD: rates size = %d\n", | ||
442 | rates_size); | ||
443 | |||
444 | /* Add the Authentication type to be used for Auth frames */ | ||
445 | auth_tlv = (struct mwifiex_ie_types_auth_type *) pos; | ||
446 | auth_tlv->header.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE); | ||
447 | auth_tlv->header.len = cpu_to_le16(sizeof(auth_tlv->auth_type)); | ||
448 | if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_ENABLED) | ||
449 | auth_tlv->auth_type = cpu_to_le16( | ||
450 | (u16) priv->sec_info.authentication_mode); | ||
451 | else | ||
452 | auth_tlv->auth_type = cpu_to_le16(NL80211_AUTHTYPE_OPEN_SYSTEM); | ||
453 | |||
454 | pos += sizeof(auth_tlv->header) + le16_to_cpu(auth_tlv->header.len); | ||
455 | |||
456 | if (IS_SUPPORT_MULTI_BANDS(priv->adapter) | ||
457 | && !(ISSUPP_11NENABLED(priv->adapter->fw_cap_info) | ||
458 | && (!bss_desc->disable_11n) | ||
459 | && (priv->adapter->config_bands & BAND_GN | ||
460 | || priv->adapter->config_bands & BAND_AN) | ||
461 | && (bss_desc->bcn_ht_cap) | ||
462 | ) | ||
463 | ) { | ||
464 | /* Append a channel TLV for the channel the attempted AP was | ||
465 | found on */ | ||
466 | chan_tlv = (struct mwifiex_ie_types_chan_list_param_set *) pos; | ||
467 | chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); | ||
468 | chan_tlv->header.len = | ||
469 | cpu_to_le16(sizeof(struct mwifiex_chan_scan_param_set)); | ||
470 | |||
471 | memset(chan_tlv->chan_scan_param, 0x00, | ||
472 | sizeof(struct mwifiex_chan_scan_param_set)); | ||
473 | chan_tlv->chan_scan_param[0].chan_number = | ||
474 | (bss_desc->phy_param_set.ds_param_set.current_chan); | ||
475 | dev_dbg(priv->adapter->dev, "info: Assoc: TLV Chan = %d\n", | ||
476 | chan_tlv->chan_scan_param[0].chan_number); | ||
477 | |||
478 | chan_tlv->chan_scan_param[0].radio_type = | ||
479 | mwifiex_band_to_radio_type((u8) bss_desc->bss_band); | ||
480 | |||
481 | dev_dbg(priv->adapter->dev, "info: Assoc: TLV Band = %d\n", | ||
482 | chan_tlv->chan_scan_param[0].radio_type); | ||
483 | pos += sizeof(chan_tlv->header) + | ||
484 | sizeof(struct mwifiex_chan_scan_param_set); | ||
485 | } | ||
486 | |||
487 | if (!priv->wps.session_enable) { | ||
488 | if (priv->sec_info.wpa_enabled || priv->sec_info.wpa2_enabled) | ||
489 | rsn_ie_len = mwifiex_append_rsn_ie_wpa_wpa2(priv, &pos); | ||
490 | |||
491 | if (rsn_ie_len == -1) | ||
492 | return -1; | ||
493 | } | ||
494 | |||
495 | if (ISSUPP_11NENABLED(priv->adapter->fw_cap_info) | ||
496 | && (!bss_desc->disable_11n) | ||
497 | && (priv->adapter->config_bands & BAND_GN | ||
498 | || priv->adapter->config_bands & BAND_AN)) | ||
499 | mwifiex_cmd_append_11n_tlv(priv, bss_desc, &pos); | ||
500 | |||
501 | /* Append vendor specific IE TLV */ | ||
502 | mwifiex_cmd_append_vsie_tlv(priv, MWIFIEX_VSIE_MASK_ASSOC, &pos); | ||
503 | |||
504 | mwifiex_wmm_process_association_req(priv, &pos, &bss_desc->wmm_ie, | ||
505 | bss_desc->bcn_ht_cap); | ||
506 | if (priv->sec_info.wapi_enabled && priv->wapi_ie_len) | ||
507 | mwifiex_cmd_append_wapi_ie(priv, &pos); | ||
508 | |||
509 | |||
510 | mwifiex_cmd_append_generic_ie(priv, &pos); | ||
511 | |||
512 | mwifiex_cmd_append_tsf_tlv(priv, &pos, bss_desc); | ||
513 | |||
514 | cmd->size = cpu_to_le16((u16) (pos - (u8 *) assoc) + S_DS_GEN); | ||
515 | |||
516 | /* Set the Capability info at last */ | ||
517 | tmp_cap = bss_desc->cap_info_bitmap; | ||
518 | |||
519 | if (priv->adapter->config_bands == BAND_B) | ||
520 | tmp_cap &= ~WLAN_CAPABILITY_SHORT_SLOT_TIME; | ||
521 | |||
522 | tmp_cap &= CAPINFO_MASK; | ||
523 | dev_dbg(priv->adapter->dev, "info: ASSOC_CMD: tmp_cap=%4X CAPINFO_MASK=%4lX\n", | ||
524 | tmp_cap, CAPINFO_MASK); | ||
525 | assoc->cap_info_bitmap = cpu_to_le16(tmp_cap); | ||
526 | |||
527 | return 0; | ||
528 | } | ||
529 | |||
530 | /* | ||
531 | * Association firmware command response handler | ||
532 | * | ||
533 | * The response buffer for the association command has the following | ||
534 | * memory layout. | ||
535 | * | ||
536 | * For cases where an association response was not received (indicated | ||
537 | * by the CapInfo and AId field): | ||
538 | * | ||
539 | * .------------------------------------------------------------. | ||
540 | * | Header(4 * sizeof(t_u16)): Standard command response hdr | | ||
541 | * .------------------------------------------------------------. | ||
542 | * | cap_info/Error Return(t_u16): | | ||
543 | * | 0xFFFF(-1): Internal error | | ||
544 | * | 0xFFFE(-2): Authentication unhandled message | | ||
545 | * | 0xFFFD(-3): Authentication refused | | ||
546 | * | 0xFFFC(-4): Timeout waiting for AP response | | ||
547 | * .------------------------------------------------------------. | ||
548 | * | status_code(t_u16): | | ||
549 | * | If cap_info is -1: | | ||
550 | * | An internal firmware failure prevented the | | ||
551 | * | command from being processed. The status_code | | ||
552 | * | will be set to 1. | | ||
553 | * | | | ||
554 | * | If cap_info is -2: | | ||
555 | * | An authentication frame was received but was | | ||
556 | * | not handled by the firmware. IEEE Status | | ||
557 | * | code for the failure is returned. | | ||
558 | * | | | ||
559 | * | If cap_info is -3: | | ||
560 | * | An authentication frame was received and the | | ||
561 | * | status_code is the IEEE Status reported in the | | ||
562 | * | response. | | ||
563 | * | | | ||
564 | * | If cap_info is -4: | | ||
565 | * | (1) Association response timeout | | ||
566 | * | (2) Authentication response timeout | | ||
567 | * .------------------------------------------------------------. | ||
568 | * | a_id(t_u16): 0xFFFF | | ||
569 | * .------------------------------------------------------------. | ||
570 | * | ||
571 | * | ||
572 | * For cases where an association response was received, the IEEE | ||
573 | * standard association response frame is returned: | ||
574 | * | ||
575 | * .------------------------------------------------------------. | ||
576 | * | Header(4 * sizeof(t_u16)): Standard command response hdr | | ||
577 | * .------------------------------------------------------------. | ||
578 | * | cap_info(t_u16): IEEE Capability | | ||
579 | * .------------------------------------------------------------. | ||
580 | * | status_code(t_u16): IEEE Status Code | | ||
581 | * .------------------------------------------------------------. | ||
582 | * | a_id(t_u16): IEEE Association ID | | ||
583 | * .------------------------------------------------------------. | ||
584 | * | IEEE IEs(variable): Any received IEs comprising the | | ||
585 | * | remaining portion of a received | | ||
586 | * | association response frame. | | ||
587 | * .------------------------------------------------------------. | ||
588 | * | ||
589 | * For simplistic handling, the status_code field can be used to determine | ||
590 | * an association success (0) or failure (non-zero). | ||
591 | */ | ||
592 | int mwifiex_ret_802_11_associate(struct mwifiex_private *priv, | ||
593 | struct host_cmd_ds_command *resp, void *wq_buf) | ||
594 | { | ||
595 | int ret = 0; | ||
596 | struct mwifiex_wait_queue *wait_queue = | ||
597 | (struct mwifiex_wait_queue *) wq_buf; | ||
598 | struct ieee_types_assoc_rsp *assoc_rsp; | ||
599 | struct mwifiex_bssdescriptor *bss_desc; | ||
600 | u8 enable_data = true; | ||
601 | |||
602 | assoc_rsp = (struct ieee_types_assoc_rsp *) &resp->params; | ||
603 | |||
604 | priv->assoc_rsp_size = min(le16_to_cpu(resp->size) - S_DS_GEN, | ||
605 | sizeof(priv->assoc_rsp_buf)); | ||
606 | |||
607 | memcpy(priv->assoc_rsp_buf, &resp->params, priv->assoc_rsp_size); | ||
608 | |||
609 | if (le16_to_cpu(assoc_rsp->status_code)) { | ||
610 | priv->adapter->dbg.num_cmd_assoc_failure++; | ||
611 | dev_err(priv->adapter->dev, "ASSOC_RESP: association failed, " | ||
612 | "status code = %d, error = 0x%x, a_id = 0x%x\n", | ||
613 | le16_to_cpu(assoc_rsp->status_code), | ||
614 | le16_to_cpu(assoc_rsp->cap_info_bitmap), | ||
615 | le16_to_cpu(assoc_rsp->a_id)); | ||
616 | |||
617 | ret = -1; | ||
618 | goto done; | ||
619 | } | ||
620 | |||
621 | /* Send a Media Connected event, according to the Spec */ | ||
622 | priv->media_connected = true; | ||
623 | |||
624 | priv->adapter->ps_state = PS_STATE_AWAKE; | ||
625 | priv->adapter->pps_uapsd_mode = false; | ||
626 | priv->adapter->tx_lock_flag = false; | ||
627 | |||
628 | /* Set the attempted BSSID Index to current */ | ||
629 | bss_desc = priv->attempted_bss_desc; | ||
630 | |||
631 | dev_dbg(priv->adapter->dev, "info: ASSOC_RESP: %s\n", | ||
632 | bss_desc->ssid.ssid); | ||
633 | |||
634 | /* Make a copy of current BSSID descriptor */ | ||
635 | memcpy(&priv->curr_bss_params.bss_descriptor, | ||
636 | bss_desc, sizeof(struct mwifiex_bssdescriptor)); | ||
637 | |||
638 | /* Update curr_bss_params */ | ||
639 | priv->curr_bss_params.bss_descriptor.channel | ||
640 | = bss_desc->phy_param_set.ds_param_set.current_chan; | ||
641 | |||
642 | priv->curr_bss_params.band = (u8) bss_desc->bss_band; | ||
643 | |||
644 | /* | ||
645 | * Adjust the timestamps in the scan table to be relative to the newly | ||
646 | * associated AP's TSF | ||
647 | */ | ||
648 | mwifiex_update_tsf_timestamps(priv, bss_desc); | ||
649 | |||
650 | if (bss_desc->wmm_ie.vend_hdr.element_id == WLAN_EID_VENDOR_SPECIFIC) | ||
651 | priv->curr_bss_params.wmm_enabled = true; | ||
652 | else | ||
653 | priv->curr_bss_params.wmm_enabled = false; | ||
654 | |||
655 | if ((priv->wmm_required || bss_desc->bcn_ht_cap) | ||
656 | && priv->curr_bss_params.wmm_enabled) | ||
657 | priv->wmm_enabled = true; | ||
658 | else | ||
659 | priv->wmm_enabled = false; | ||
660 | |||
661 | priv->curr_bss_params.wmm_uapsd_enabled = false; | ||
662 | |||
663 | if (priv->wmm_enabled) | ||
664 | priv->curr_bss_params.wmm_uapsd_enabled | ||
665 | = ((bss_desc->wmm_ie.qos_info_bitmap & | ||
666 | IEEE80211_WMM_IE_AP_QOSINFO_UAPSD) ? 1 : 0); | ||
667 | |||
668 | dev_dbg(priv->adapter->dev, "info: ASSOC_RESP: curr_pkt_filter is %#x\n", | ||
669 | priv->curr_pkt_filter); | ||
670 | if (priv->sec_info.wpa_enabled || priv->sec_info.wpa2_enabled) | ||
671 | priv->wpa_is_gtk_set = false; | ||
672 | |||
673 | if (priv->wmm_enabled) { | ||
674 | /* Don't re-enable carrier until we get the WMM_GET_STATUS | ||
675 | event */ | ||
676 | enable_data = false; | ||
677 | } else { | ||
678 | /* Since WMM is not enabled, setup the queues with the | ||
679 | defaults */ | ||
680 | mwifiex_wmm_setup_queue_priorities(priv, NULL); | ||
681 | mwifiex_wmm_setup_ac_downgrade(priv); | ||
682 | } | ||
683 | |||
684 | if (enable_data) | ||
685 | dev_dbg(priv->adapter->dev, | ||
686 | "info: post association, re-enabling data flow\n"); | ||
687 | |||
688 | /* Reset SNR/NF/RSSI values */ | ||
689 | priv->data_rssi_last = 0; | ||
690 | priv->data_nf_last = 0; | ||
691 | priv->data_rssi_avg = 0; | ||
692 | priv->data_nf_avg = 0; | ||
693 | priv->bcn_rssi_last = 0; | ||
694 | priv->bcn_nf_last = 0; | ||
695 | priv->bcn_rssi_avg = 0; | ||
696 | priv->bcn_nf_avg = 0; | ||
697 | priv->rxpd_rate = 0; | ||
698 | priv->rxpd_htinfo = 0; | ||
699 | |||
700 | mwifiex_save_curr_bcn(priv); | ||
701 | |||
702 | priv->adapter->dbg.num_cmd_assoc_success++; | ||
703 | |||
704 | dev_dbg(priv->adapter->dev, "info: ASSOC_RESP: associated\n"); | ||
705 | |||
706 | /* Add the ra_list here for infra mode as there will be only 1 ra | ||
707 | always */ | ||
708 | mwifiex_ralist_add(priv, | ||
709 | priv->curr_bss_params.bss_descriptor.mac_address); | ||
710 | |||
711 | if (!netif_carrier_ok(priv->netdev)) | ||
712 | netif_carrier_on(priv->netdev); | ||
713 | if (netif_queue_stopped(priv->netdev)) | ||
714 | netif_wake_queue(priv->netdev); | ||
715 | |||
716 | if (priv->sec_info.wpa_enabled || priv->sec_info.wpa2_enabled) | ||
717 | priv->scan_block = true; | ||
718 | |||
719 | done: | ||
720 | /* Need to indicate IOCTL complete */ | ||
721 | if (wait_queue) { | ||
722 | if (ret) { | ||
723 | if (assoc_rsp->status_code) | ||
724 | wait_queue->status = | ||
725 | le16_to_cpu(assoc_rsp->status_code); | ||
726 | else | ||
727 | wait_queue->status = MWIFIEX_ERROR_ASSOC_FAIL; | ||
728 | } else { | ||
729 | wait_queue->status = MWIFIEX_ERROR_NO_ERROR; | ||
730 | } | ||
731 | } | ||
732 | |||
733 | return ret; | ||
734 | } | ||
735 | |||
736 | /* | ||
737 | * This function prepares command for ad-hoc start. | ||
738 | * | ||
739 | * Driver will fill up SSID, BSS mode, IBSS parameters, physical | ||
740 | * parameters, probe delay, and capability information. Firmware | ||
741 | * will fill up beacon period, basic rates and operational rates. | ||
742 | * | ||
743 | * In addition, the following TLVs are added - | ||
744 | * - Channel TLV | ||
745 | * - Vendor specific IE | ||
746 | * - WPA/WPA2 IE | ||
747 | * - HT Capabilities IE | ||
748 | * - HT Information IE | ||
749 | * | ||
750 | * Preparation also includes - | ||
751 | * - Setting command ID and proper size | ||
752 | * - Ensuring correct endian-ness | ||
753 | */ | ||
754 | int | ||
755 | mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv, | ||
756 | struct host_cmd_ds_command *cmd, void *data_buf) | ||
757 | { | ||
758 | int ret = 0, rsn_ie_len = 0; | ||
759 | struct mwifiex_adapter *adapter = priv->adapter; | ||
760 | struct host_cmd_ds_802_11_ad_hoc_start *adhoc_start = | ||
761 | &cmd->params.adhoc_start; | ||
762 | struct mwifiex_bssdescriptor *bss_desc; | ||
763 | u32 cmd_append_size = 0; | ||
764 | u32 i; | ||
765 | u16 tmp_cap; | ||
766 | uint16_t ht_cap_info; | ||
767 | struct mwifiex_ie_types_chan_list_param_set *chan_tlv; | ||
768 | |||
769 | struct mwifiex_ie_types_htcap *ht_cap; | ||
770 | struct mwifiex_ie_types_htinfo *ht_info; | ||
771 | u8 *pos = (u8 *) adhoc_start + | ||
772 | sizeof(struct host_cmd_ds_802_11_ad_hoc_start); | ||
773 | |||
774 | if (!adapter) | ||
775 | return -1; | ||
776 | |||
777 | cmd->command = cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_START); | ||
778 | |||
779 | bss_desc = &priv->curr_bss_params.bss_descriptor; | ||
780 | priv->attempted_bss_desc = bss_desc; | ||
781 | |||
782 | /* | ||
783 | * Fill in the parameters for 2 data structures: | ||
784 | * 1. struct host_cmd_ds_802_11_ad_hoc_start command | ||
785 | * 2. bss_desc | ||
786 | * Driver will fill up SSID, bss_mode,IBSS param, Physical Param, | ||
787 | * probe delay, and Cap info. | ||
788 | * Firmware will fill up beacon period, Basic rates | ||
789 | * and operational rates. | ||
790 | */ | ||
791 | |||
792 | memset(adhoc_start->ssid, 0, IEEE80211_MAX_SSID_LEN); | ||
793 | |||
794 | memcpy(adhoc_start->ssid, | ||
795 | ((struct mwifiex_802_11_ssid *) data_buf)->ssid, | ||
796 | ((struct mwifiex_802_11_ssid *) data_buf)->ssid_len); | ||
797 | |||
798 | dev_dbg(adapter->dev, "info: ADHOC_S_CMD: SSID = %s\n", | ||
799 | adhoc_start->ssid); | ||
800 | |||
801 | memset(bss_desc->ssid.ssid, 0, IEEE80211_MAX_SSID_LEN); | ||
802 | memcpy(bss_desc->ssid.ssid, | ||
803 | ((struct mwifiex_802_11_ssid *) data_buf)->ssid, | ||
804 | ((struct mwifiex_802_11_ssid *) data_buf)->ssid_len); | ||
805 | |||
806 | bss_desc->ssid.ssid_len = | ||
807 | ((struct mwifiex_802_11_ssid *) data_buf)->ssid_len; | ||
808 | |||
809 | /* Set the BSS mode */ | ||
810 | adhoc_start->bss_mode = HostCmd_BSS_MODE_IBSS; | ||
811 | bss_desc->bss_mode = NL80211_IFTYPE_ADHOC; | ||
812 | adhoc_start->beacon_period = cpu_to_le16(priv->beacon_period); | ||
813 | bss_desc->beacon_period = priv->beacon_period; | ||
814 | |||
815 | /* Set Physical param set */ | ||
816 | /* Parameter IE Id */ | ||
817 | #define DS_PARA_IE_ID 3 | ||
818 | /* Parameter IE length */ | ||
819 | #define DS_PARA_IE_LEN 1 | ||
820 | |||
821 | adhoc_start->phy_param_set.ds_param_set.element_id = DS_PARA_IE_ID; | ||
822 | adhoc_start->phy_param_set.ds_param_set.len = DS_PARA_IE_LEN; | ||
823 | |||
824 | if (!mwifiex_get_cfp_by_band_and_channel_from_cfg80211 | ||
825 | (priv, adapter->adhoc_start_band, (u16) | ||
826 | priv->adhoc_channel)) { | ||
827 | struct mwifiex_chan_freq_power *cfp; | ||
828 | cfp = mwifiex_get_cfp_by_band_and_channel_from_cfg80211(priv, | ||
829 | adapter->adhoc_start_band, FIRST_VALID_CHANNEL); | ||
830 | if (cfp) | ||
831 | priv->adhoc_channel = (u8) cfp->channel; | ||
832 | } | ||
833 | |||
834 | if (!priv->adhoc_channel) { | ||
835 | dev_err(adapter->dev, "ADHOC_S_CMD: adhoc_channel cannot be 0\n"); | ||
836 | return -1; | ||
837 | } | ||
838 | |||
839 | dev_dbg(adapter->dev, "info: ADHOC_S_CMD: creating ADHOC on channel %d\n", | ||
840 | priv->adhoc_channel); | ||
841 | |||
842 | priv->curr_bss_params.bss_descriptor.channel = priv->adhoc_channel; | ||
843 | priv->curr_bss_params.band = adapter->adhoc_start_band; | ||
844 | |||
845 | bss_desc->channel = priv->adhoc_channel; | ||
846 | adhoc_start->phy_param_set.ds_param_set.current_chan = | ||
847 | priv->adhoc_channel; | ||
848 | |||
849 | memcpy(&bss_desc->phy_param_set, &adhoc_start->phy_param_set, | ||
850 | sizeof(union ieee_types_phy_param_set)); | ||
851 | |||
852 | /* Set IBSS param set */ | ||
853 | /* IBSS parameter IE Id */ | ||
854 | #define IBSS_PARA_IE_ID 6 | ||
855 | /* IBSS parameter IE length */ | ||
856 | #define IBSS_PARA_IE_LEN 2 | ||
857 | |||
858 | adhoc_start->ss_param_set.ibss_param_set.element_id = IBSS_PARA_IE_ID; | ||
859 | adhoc_start->ss_param_set.ibss_param_set.len = IBSS_PARA_IE_LEN; | ||
860 | adhoc_start->ss_param_set.ibss_param_set.atim_window | ||
861 | = cpu_to_le16(priv->atim_window); | ||
862 | memcpy(&bss_desc->ss_param_set, &adhoc_start->ss_param_set, | ||
863 | sizeof(union ieee_types_ss_param_set)); | ||
864 | |||
865 | /* Set Capability info */ | ||
866 | bss_desc->cap_info_bitmap |= WLAN_CAPABILITY_IBSS; | ||
867 | tmp_cap = le16_to_cpu(adhoc_start->cap_info_bitmap); | ||
868 | tmp_cap &= ~WLAN_CAPABILITY_ESS; | ||
869 | tmp_cap |= WLAN_CAPABILITY_IBSS; | ||
870 | |||
871 | /* Set up privacy in bss_desc */ | ||
872 | if (priv->sec_info.encryption_mode) { | ||
873 | /* Ad-Hoc capability privacy on */ | ||
874 | dev_dbg(adapter->dev, | ||
875 | "info: ADHOC_S_CMD: wep_status set privacy to WEP\n"); | ||
876 | bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_8021X_WEP; | ||
877 | tmp_cap |= WLAN_CAPABILITY_PRIVACY; | ||
878 | } else { | ||
879 | dev_dbg(adapter->dev, "info: ADHOC_S_CMD: wep_status NOT set," | ||
880 | " setting privacy to ACCEPT ALL\n"); | ||
881 | bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL; | ||
882 | } | ||
883 | |||
884 | memset(adhoc_start->DataRate, 0, sizeof(adhoc_start->DataRate)); | ||
885 | mwifiex_get_active_data_rates(priv, adhoc_start->DataRate); | ||
886 | if ((adapter->adhoc_start_band & BAND_G) && | ||
887 | (priv->curr_pkt_filter & HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON)) { | ||
888 | ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_MAC_CONTROL, | ||
889 | HostCmd_ACT_GEN_SET, | ||
890 | 0, NULL, &priv->curr_pkt_filter); | ||
891 | |||
892 | if (ret) { | ||
893 | dev_err(adapter->dev, | ||
894 | "ADHOC_S_CMD: G Protection config failed\n"); | ||
895 | return -1; | ||
896 | } | ||
897 | } | ||
898 | /* Find the last non zero */ | ||
899 | for (i = 0; i < sizeof(adhoc_start->DataRate) && | ||
900 | adhoc_start->DataRate[i]; | ||
901 | i++) | ||
902 | ; | ||
903 | |||
904 | priv->curr_bss_params.num_of_rates = i; | ||
905 | |||
906 | /* Copy the ad-hoc creating rates into Current BSS rate structure */ | ||
907 | memcpy(&priv->curr_bss_params.data_rates, | ||
908 | &adhoc_start->DataRate, priv->curr_bss_params.num_of_rates); | ||
909 | |||
910 | dev_dbg(adapter->dev, "info: ADHOC_S_CMD: rates=%02x %02x %02x %02x\n", | ||
911 | adhoc_start->DataRate[0], adhoc_start->DataRate[1], | ||
912 | adhoc_start->DataRate[2], adhoc_start->DataRate[3]); | ||
913 | |||
914 | dev_dbg(adapter->dev, "info: ADHOC_S_CMD: AD-HOC Start command is ready\n"); | ||
915 | |||
916 | if (IS_SUPPORT_MULTI_BANDS(adapter)) { | ||
917 | /* Append a channel TLV */ | ||
918 | chan_tlv = (struct mwifiex_ie_types_chan_list_param_set *) pos; | ||
919 | chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); | ||
920 | chan_tlv->header.len = | ||
921 | cpu_to_le16(sizeof(struct mwifiex_chan_scan_param_set)); | ||
922 | |||
923 | memset(chan_tlv->chan_scan_param, 0x00, | ||
924 | sizeof(struct mwifiex_chan_scan_param_set)); | ||
925 | chan_tlv->chan_scan_param[0].chan_number = | ||
926 | (u8) priv->curr_bss_params.bss_descriptor.channel; | ||
927 | |||
928 | dev_dbg(adapter->dev, "info: ADHOC_S_CMD: TLV Chan = %d\n", | ||
929 | chan_tlv->chan_scan_param[0].chan_number); | ||
930 | |||
931 | chan_tlv->chan_scan_param[0].radio_type | ||
932 | = mwifiex_band_to_radio_type(priv->curr_bss_params.band); | ||
933 | if (adapter->adhoc_start_band & BAND_GN | ||
934 | || adapter->adhoc_start_band & BAND_AN) { | ||
935 | if (adapter->chan_offset == SEC_CHANNEL_ABOVE) | ||
936 | chan_tlv->chan_scan_param[0].radio_type |= | ||
937 | SECOND_CHANNEL_ABOVE; | ||
938 | else if (adapter->chan_offset == SEC_CHANNEL_BELOW) | ||
939 | chan_tlv->chan_scan_param[0].radio_type |= | ||
940 | SECOND_CHANNEL_BELOW; | ||
941 | } | ||
942 | dev_dbg(adapter->dev, "info: ADHOC_S_CMD: TLV Band = %d\n", | ||
943 | chan_tlv->chan_scan_param[0].radio_type); | ||
944 | pos += sizeof(chan_tlv->header) + | ||
945 | sizeof(struct mwifiex_chan_scan_param_set); | ||
946 | cmd_append_size += | ||
947 | sizeof(chan_tlv->header) + | ||
948 | sizeof(struct mwifiex_chan_scan_param_set); | ||
949 | } | ||
950 | |||
951 | /* Append vendor specific IE TLV */ | ||
952 | cmd_append_size += mwifiex_cmd_append_vsie_tlv(priv, | ||
953 | MWIFIEX_VSIE_MASK_ADHOC, &pos); | ||
954 | |||
955 | if (priv->sec_info.wpa_enabled) { | ||
956 | rsn_ie_len = mwifiex_append_rsn_ie_wpa_wpa2(priv, &pos); | ||
957 | if (rsn_ie_len == -1) | ||
958 | return -1; | ||
959 | cmd_append_size += rsn_ie_len; | ||
960 | } | ||
961 | |||
962 | if (adapter->adhoc_11n_enabled) { | ||
963 | { | ||
964 | ht_cap = (struct mwifiex_ie_types_htcap *) pos; | ||
965 | memset(ht_cap, 0, | ||
966 | sizeof(struct mwifiex_ie_types_htcap)); | ||
967 | ht_cap->header.type = | ||
968 | cpu_to_le16(WLAN_EID_HT_CAPABILITY); | ||
969 | ht_cap->header.len = | ||
970 | cpu_to_le16(sizeof(struct ieee80211_ht_cap)); | ||
971 | ht_cap_info = le16_to_cpu(ht_cap->ht_cap.cap_info); | ||
972 | |||
973 | ht_cap_info |= IEEE80211_HT_CAP_SGI_20; | ||
974 | if (adapter->chan_offset) { | ||
975 | ht_cap_info |= IEEE80211_HT_CAP_SGI_40; | ||
976 | ht_cap_info |= IEEE80211_HT_CAP_DSSSCCK40; | ||
977 | ht_cap_info |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||
978 | SETHT_MCS32(ht_cap->ht_cap.mcs.rx_mask); | ||
979 | } | ||
980 | |||
981 | ht_cap->ht_cap.ampdu_params_info | ||
982 | = IEEE80211_HT_MAX_AMPDU_64K; | ||
983 | ht_cap->ht_cap.mcs.rx_mask[0] = 0xff; | ||
984 | pos += sizeof(struct mwifiex_ie_types_htcap); | ||
985 | cmd_append_size += | ||
986 | sizeof(struct mwifiex_ie_types_htcap); | ||
987 | } | ||
988 | { | ||
989 | ht_info = (struct mwifiex_ie_types_htinfo *) pos; | ||
990 | memset(ht_info, 0, | ||
991 | sizeof(struct mwifiex_ie_types_htinfo)); | ||
992 | ht_info->header.type = | ||
993 | cpu_to_le16(WLAN_EID_HT_INFORMATION); | ||
994 | ht_info->header.len = | ||
995 | cpu_to_le16(sizeof(struct ieee80211_ht_info)); | ||
996 | ht_info->ht_info.control_chan = | ||
997 | (u8) priv->curr_bss_params.bss_descriptor. | ||
998 | channel; | ||
999 | if (adapter->chan_offset) { | ||
1000 | ht_info->ht_info.ht_param = | ||
1001 | adapter->chan_offset; | ||
1002 | ht_info->ht_info.ht_param |= | ||
1003 | IEEE80211_HT_PARAM_CHAN_WIDTH_ANY; | ||
1004 | } | ||
1005 | ht_info->ht_info.operation_mode = | ||
1006 | cpu_to_le16(NON_GREENFIELD_STAS); | ||
1007 | ht_info->ht_info.basic_set[0] = 0xff; | ||
1008 | pos += sizeof(struct mwifiex_ie_types_htinfo); | ||
1009 | cmd_append_size += | ||
1010 | sizeof(struct mwifiex_ie_types_htinfo); | ||
1011 | } | ||
1012 | } | ||
1013 | |||
1014 | cmd->size = cpu_to_le16((u16) | ||
1015 | (sizeof(struct host_cmd_ds_802_11_ad_hoc_start) | ||
1016 | + S_DS_GEN + cmd_append_size)); | ||
1017 | |||
1018 | if (adapter->adhoc_start_band == BAND_B) | ||
1019 | tmp_cap &= ~WLAN_CAPABILITY_SHORT_SLOT_TIME; | ||
1020 | else | ||
1021 | tmp_cap |= WLAN_CAPABILITY_SHORT_SLOT_TIME; | ||
1022 | |||
1023 | adhoc_start->cap_info_bitmap = cpu_to_le16(tmp_cap); | ||
1024 | |||
1025 | return 0; | ||
1026 | } | ||
1027 | |||
1028 | /* | ||
1029 | * This function prepares command for ad-hoc join. | ||
1030 | * | ||
1031 | * Most of the parameters are set up by copying from the target BSS descriptor | ||
1032 | * from the scan response. | ||
1033 | * | ||
1034 | * In addition, the following TLVs are added - | ||
1035 | * - Channel TLV | ||
1036 | * - Vendor specific IE | ||
1037 | * - WPA/WPA2 IE | ||
1038 | * - 11n IE | ||
1039 | * | ||
1040 | * Preparation also includes - | ||
1041 | * - Setting command ID and proper size | ||
1042 | * - Ensuring correct endian-ness | ||
1043 | */ | ||
1044 | int | ||
1045 | mwifiex_cmd_802_11_ad_hoc_join(struct mwifiex_private *priv, | ||
1046 | struct host_cmd_ds_command *cmd, void *data_buf) | ||
1047 | { | ||
1048 | int ret = 0, rsn_ie_len = 0; | ||
1049 | struct host_cmd_ds_802_11_ad_hoc_join *adhoc_join = | ||
1050 | &cmd->params.adhoc_join; | ||
1051 | struct mwifiex_bssdescriptor *bss_desc = | ||
1052 | (struct mwifiex_bssdescriptor *) data_buf; | ||
1053 | struct mwifiex_ie_types_chan_list_param_set *chan_tlv; | ||
1054 | u32 cmd_append_size = 0; | ||
1055 | u16 tmp_cap; | ||
1056 | u32 i, rates_size = 0; | ||
1057 | u16 curr_pkt_filter; | ||
1058 | u8 *pos = | ||
1059 | (u8 *) adhoc_join + | ||
1060 | sizeof(struct host_cmd_ds_802_11_ad_hoc_join); | ||
1061 | |||
1062 | /* Use G protection */ | ||
1063 | #define USE_G_PROTECTION 0x02 | ||
1064 | if (bss_desc->erp_flags & USE_G_PROTECTION) { | ||
1065 | curr_pkt_filter = | ||
1066 | priv-> | ||
1067 | curr_pkt_filter | HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON; | ||
1068 | |||
1069 | ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_MAC_CONTROL, | ||
1070 | HostCmd_ACT_GEN_SET, 0, NULL, | ||
1071 | &curr_pkt_filter); | ||
1072 | if (ret) { | ||
1073 | dev_err(priv->adapter->dev, | ||
1074 | "ADHOC_J_CMD: G Protection config failed\n"); | ||
1075 | return -1; | ||
1076 | } | ||
1077 | } | ||
1078 | |||
1079 | priv->attempted_bss_desc = bss_desc; | ||
1080 | |||
1081 | cmd->command = cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_JOIN); | ||
1082 | |||
1083 | adhoc_join->bss_descriptor.bss_mode = HostCmd_BSS_MODE_IBSS; | ||
1084 | |||
1085 | adhoc_join->bss_descriptor.beacon_period | ||
1086 | = cpu_to_le16(bss_desc->beacon_period); | ||
1087 | |||
1088 | memcpy(&adhoc_join->bss_descriptor.bssid, | ||
1089 | &bss_desc->mac_address, ETH_ALEN); | ||
1090 | |||
1091 | memcpy(&adhoc_join->bss_descriptor.ssid, | ||
1092 | &bss_desc->ssid.ssid, bss_desc->ssid.ssid_len); | ||
1093 | |||
1094 | memcpy(&adhoc_join->bss_descriptor.phy_param_set, | ||
1095 | &bss_desc->phy_param_set, | ||
1096 | sizeof(union ieee_types_phy_param_set)); | ||
1097 | |||
1098 | memcpy(&adhoc_join->bss_descriptor.ss_param_set, | ||
1099 | &bss_desc->ss_param_set, sizeof(union ieee_types_ss_param_set)); | ||
1100 | |||
1101 | tmp_cap = bss_desc->cap_info_bitmap; | ||
1102 | |||
1103 | tmp_cap &= CAPINFO_MASK; | ||
1104 | |||
1105 | dev_dbg(priv->adapter->dev, "info: ADHOC_J_CMD: tmp_cap=%4X" | ||
1106 | " CAPINFO_MASK=%4lX\n", tmp_cap, CAPINFO_MASK); | ||
1107 | |||
1108 | /* Information on BSSID descriptor passed to FW */ | ||
1109 | dev_dbg(priv->adapter->dev, "info: ADHOC_J_CMD: BSSID = %pM, SSID = %s\n", | ||
1110 | adhoc_join->bss_descriptor.bssid, | ||
1111 | adhoc_join->bss_descriptor.ssid); | ||
1112 | |||
1113 | for (i = 0; bss_desc->supported_rates[i] && | ||
1114 | i < MWIFIEX_SUPPORTED_RATES; | ||
1115 | i++) | ||
1116 | ; | ||
1117 | rates_size = i; | ||
1118 | |||
1119 | /* Copy Data Rates from the Rates recorded in scan response */ | ||
1120 | memset(adhoc_join->bss_descriptor.data_rates, 0, | ||
1121 | sizeof(adhoc_join->bss_descriptor.data_rates)); | ||
1122 | memcpy(adhoc_join->bss_descriptor.data_rates, | ||
1123 | bss_desc->supported_rates, rates_size); | ||
1124 | |||
1125 | /* Copy the adhoc join rates into Current BSS state structure */ | ||
1126 | priv->curr_bss_params.num_of_rates = rates_size; | ||
1127 | memcpy(&priv->curr_bss_params.data_rates, bss_desc->supported_rates, | ||
1128 | rates_size); | ||
1129 | |||
1130 | /* Copy the channel information */ | ||
1131 | priv->curr_bss_params.bss_descriptor.channel = bss_desc->channel; | ||
1132 | priv->curr_bss_params.band = (u8) bss_desc->bss_band; | ||
1133 | |||
1134 | if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_ENABLED | ||
1135 | || priv->sec_info.wpa_enabled) | ||
1136 | tmp_cap |= WLAN_CAPABILITY_PRIVACY; | ||
1137 | |||
1138 | if (IS_SUPPORT_MULTI_BANDS(priv->adapter)) { | ||
1139 | /* Append a channel TLV */ | ||
1140 | chan_tlv = (struct mwifiex_ie_types_chan_list_param_set *) pos; | ||
1141 | chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); | ||
1142 | chan_tlv->header.len = | ||
1143 | cpu_to_le16(sizeof(struct mwifiex_chan_scan_param_set)); | ||
1144 | |||
1145 | memset(chan_tlv->chan_scan_param, 0x00, | ||
1146 | sizeof(struct mwifiex_chan_scan_param_set)); | ||
1147 | chan_tlv->chan_scan_param[0].chan_number = | ||
1148 | (bss_desc->phy_param_set.ds_param_set.current_chan); | ||
1149 | dev_dbg(priv->adapter->dev, "info: ADHOC_J_CMD: TLV Chan = %d\n", | ||
1150 | chan_tlv->chan_scan_param[0].chan_number); | ||
1151 | |||
1152 | chan_tlv->chan_scan_param[0].radio_type = | ||
1153 | mwifiex_band_to_radio_type((u8) bss_desc->bss_band); | ||
1154 | |||
1155 | dev_dbg(priv->adapter->dev, "info: ADHOC_J_CMD: TLV Band = %d\n", | ||
1156 | chan_tlv->chan_scan_param[0].radio_type); | ||
1157 | pos += sizeof(chan_tlv->header) + | ||
1158 | sizeof(struct mwifiex_chan_scan_param_set); | ||
1159 | cmd_append_size += sizeof(chan_tlv->header) + | ||
1160 | sizeof(struct mwifiex_chan_scan_param_set); | ||
1161 | } | ||
1162 | |||
1163 | if (priv->sec_info.wpa_enabled) | ||
1164 | rsn_ie_len = mwifiex_append_rsn_ie_wpa_wpa2(priv, &pos); | ||
1165 | if (rsn_ie_len == -1) | ||
1166 | return -1; | ||
1167 | cmd_append_size += rsn_ie_len; | ||
1168 | |||
1169 | if (ISSUPP_11NENABLED(priv->adapter->fw_cap_info)) | ||
1170 | cmd_append_size += mwifiex_cmd_append_11n_tlv(priv, | ||
1171 | bss_desc, &pos); | ||
1172 | |||
1173 | /* Append vendor specific IE TLV */ | ||
1174 | cmd_append_size += mwifiex_cmd_append_vsie_tlv(priv, | ||
1175 | MWIFIEX_VSIE_MASK_ADHOC, &pos); | ||
1176 | |||
1177 | cmd->size = cpu_to_le16((u16) | ||
1178 | (sizeof(struct host_cmd_ds_802_11_ad_hoc_join) | ||
1179 | + S_DS_GEN + cmd_append_size)); | ||
1180 | |||
1181 | adhoc_join->bss_descriptor.cap_info_bitmap = cpu_to_le16(tmp_cap); | ||
1182 | |||
1183 | return ret; | ||
1184 | } | ||
1185 | |||
1186 | /* | ||
1187 | * This function handles the command response of ad-hoc start and | ||
1188 | * ad-hoc join. | ||
1189 | * | ||
1190 | * The function generates a device-connected event to notify | ||
1191 | * the applications, in case of successful ad-hoc start/join, and | ||
1192 | * saves the beacon buffer. | ||
1193 | */ | ||
1194 | int mwifiex_ret_802_11_ad_hoc(struct mwifiex_private *priv, | ||
1195 | struct host_cmd_ds_command *resp, void *wq_buf) | ||
1196 | { | ||
1197 | int ret = 0; | ||
1198 | struct mwifiex_wait_queue *wait_queue = | ||
1199 | (struct mwifiex_wait_queue *) wq_buf; | ||
1200 | struct host_cmd_ds_802_11_ad_hoc_result *adhoc_result; | ||
1201 | struct mwifiex_bssdescriptor *bss_desc; | ||
1202 | u16 command = le16_to_cpu(resp->command); | ||
1203 | u16 result = le16_to_cpu(resp->result); | ||
1204 | |||
1205 | adhoc_result = &resp->params.adhoc_result; | ||
1206 | |||
1207 | bss_desc = priv->attempted_bss_desc; | ||
1208 | |||
1209 | /* Join result code 0 --> SUCCESS */ | ||
1210 | if (result) { | ||
1211 | dev_err(priv->adapter->dev, "ADHOC_RESP: failed\n"); | ||
1212 | if (priv->media_connected) | ||
1213 | mwifiex_reset_connect_state(priv); | ||
1214 | |||
1215 | memset(&priv->curr_bss_params.bss_descriptor, | ||
1216 | 0x00, sizeof(struct mwifiex_bssdescriptor)); | ||
1217 | |||
1218 | ret = -1; | ||
1219 | goto done; | ||
1220 | } | ||
1221 | |||
1222 | /* Send a Media Connected event, according to the Spec */ | ||
1223 | priv->media_connected = true; | ||
1224 | |||
1225 | if (command == HostCmd_CMD_802_11_AD_HOC_START) { | ||
1226 | dev_dbg(priv->adapter->dev, "info: ADHOC_S_RESP %s\n", | ||
1227 | bss_desc->ssid.ssid); | ||
1228 | |||
1229 | /* Update the created network descriptor with the new BSSID */ | ||
1230 | memcpy(bss_desc->mac_address, | ||
1231 | adhoc_result->bssid, ETH_ALEN); | ||
1232 | |||
1233 | priv->adhoc_state = ADHOC_STARTED; | ||
1234 | } else { | ||
1235 | /* | ||
1236 | * Now the join cmd should be successful. | ||
1237 | * If BSSID has changed use SSID to compare instead of BSSID | ||
1238 | */ | ||
1239 | dev_dbg(priv->adapter->dev, "info: ADHOC_J_RESP %s\n", | ||
1240 | bss_desc->ssid.ssid); | ||
1241 | |||
1242 | /* | ||
1243 | * Make a copy of current BSSID descriptor, only needed for | ||
1244 | * join since the current descriptor is already being used | ||
1245 | * for adhoc start | ||
1246 | */ | ||
1247 | memcpy(&priv->curr_bss_params.bss_descriptor, | ||
1248 | bss_desc, sizeof(struct mwifiex_bssdescriptor)); | ||
1249 | |||
1250 | priv->adhoc_state = ADHOC_JOINED; | ||
1251 | } | ||
1252 | |||
1253 | dev_dbg(priv->adapter->dev, "info: ADHOC_RESP: channel = %d\n", | ||
1254 | priv->adhoc_channel); | ||
1255 | dev_dbg(priv->adapter->dev, "info: ADHOC_RESP: BSSID = %pM\n", | ||
1256 | priv->curr_bss_params.bss_descriptor.mac_address); | ||
1257 | |||
1258 | if (!netif_carrier_ok(priv->netdev)) | ||
1259 | netif_carrier_on(priv->netdev); | ||
1260 | if (netif_queue_stopped(priv->netdev)) | ||
1261 | netif_wake_queue(priv->netdev); | ||
1262 | |||
1263 | mwifiex_save_curr_bcn(priv); | ||
1264 | |||
1265 | done: | ||
1266 | /* Need to indicate IOCTL complete */ | ||
1267 | if (wait_queue) { | ||
1268 | if (ret) | ||
1269 | wait_queue->status = MWIFIEX_ERROR_ASSOC_FAIL; | ||
1270 | else | ||
1271 | wait_queue->status = MWIFIEX_ERROR_NO_ERROR; | ||
1272 | |||
1273 | } | ||
1274 | |||
1275 | return ret; | ||
1276 | } | ||
1277 | |||
1278 | /* | ||
1279 | * This function associates to a specific BSS discovered in a scan. | ||
1280 | * | ||
1281 | * It clears any past association response stored for application | ||
1282 | * retrieval and calls the command preparation routine to send the | ||
1283 | * command to firmware. | ||
1284 | */ | ||
1285 | int mwifiex_associate(struct mwifiex_private *priv, | ||
1286 | void *wait_queue, struct mwifiex_bssdescriptor *bss_desc) | ||
1287 | { | ||
1288 | int ret = 0; | ||
1289 | u8 current_bssid[ETH_ALEN]; | ||
1290 | |||
1291 | /* Return error if the adapter or table entry is not marked as infra */ | ||
1292 | if ((priv->bss_mode != NL80211_IFTYPE_STATION) || | ||
1293 | (bss_desc->bss_mode != NL80211_IFTYPE_STATION)) | ||
1294 | return -1; | ||
1295 | |||
1296 | memcpy(¤t_bssid, | ||
1297 | &priv->curr_bss_params.bss_descriptor.mac_address, | ||
1298 | sizeof(current_bssid)); | ||
1299 | |||
1300 | /* Clear any past association response stored for application | ||
1301 | retrieval */ | ||
1302 | priv->assoc_rsp_size = 0; | ||
1303 | |||
1304 | ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_ASSOCIATE, | ||
1305 | HostCmd_ACT_GEN_SET, 0, wait_queue, | ||
1306 | bss_desc); | ||
1307 | |||
1308 | return ret; | ||
1309 | } | ||
1310 | |||
1311 | /* | ||
1312 | * This function starts an ad-hoc network. | ||
1313 | * | ||
1314 | * It calls the command preparation routine to send the command to firmware. | ||
1315 | */ | ||
1316 | int | ||
1317 | mwifiex_adhoc_start(struct mwifiex_private *priv, | ||
1318 | void *wait_queue, struct mwifiex_802_11_ssid *adhoc_ssid) | ||
1319 | { | ||
1320 | int ret = 0; | ||
1321 | |||
1322 | dev_dbg(priv->adapter->dev, "info: Adhoc Channel = %d\n", | ||
1323 | priv->adhoc_channel); | ||
1324 | dev_dbg(priv->adapter->dev, "info: curr_bss_params.channel = %d\n", | ||
1325 | priv->curr_bss_params.bss_descriptor.channel); | ||
1326 | dev_dbg(priv->adapter->dev, "info: curr_bss_params.band = %d\n", | ||
1327 | priv->curr_bss_params.band); | ||
1328 | |||
1329 | ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_AD_HOC_START, | ||
1330 | HostCmd_ACT_GEN_SET, 0, wait_queue, | ||
1331 | adhoc_ssid); | ||
1332 | |||
1333 | return ret; | ||
1334 | } | ||
1335 | |||
1336 | /* | ||
1337 | * This function joins an ad-hoc network found in a previous scan. | ||
1338 | * | ||
1339 | * It calls the command preparation routine to send the command to firmware, | ||
1340 | * if already not connected to the requested SSID. | ||
1341 | */ | ||
1342 | int mwifiex_adhoc_join(struct mwifiex_private *priv, | ||
1343 | void *wait_queue, struct mwifiex_bssdescriptor *bss_desc) | ||
1344 | { | ||
1345 | int ret = 0; | ||
1346 | |||
1347 | dev_dbg(priv->adapter->dev, "info: adhoc join: curr_bss ssid =%s\n", | ||
1348 | priv->curr_bss_params.bss_descriptor.ssid.ssid); | ||
1349 | dev_dbg(priv->adapter->dev, "info: adhoc join: curr_bss ssid_len =%u\n", | ||
1350 | priv->curr_bss_params.bss_descriptor.ssid.ssid_len); | ||
1351 | dev_dbg(priv->adapter->dev, "info: adhoc join: ssid =%s\n", | ||
1352 | bss_desc->ssid.ssid); | ||
1353 | dev_dbg(priv->adapter->dev, "info: adhoc join: ssid_len =%u\n", | ||
1354 | bss_desc->ssid.ssid_len); | ||
1355 | |||
1356 | /* Check if the requested SSID is already joined */ | ||
1357 | if (priv->curr_bss_params.bss_descriptor.ssid.ssid_len && | ||
1358 | !mwifiex_ssid_cmp(&bss_desc->ssid, | ||
1359 | &priv->curr_bss_params.bss_descriptor.ssid) && | ||
1360 | (priv->curr_bss_params.bss_descriptor.bss_mode == | ||
1361 | NL80211_IFTYPE_ADHOC)) { | ||
1362 | dev_dbg(priv->adapter->dev, "info: ADHOC_J_CMD: new ad-hoc SSID" | ||
1363 | " is the same as current; not attempting to re-join\n"); | ||
1364 | return -1; | ||
1365 | } | ||
1366 | |||
1367 | dev_dbg(priv->adapter->dev, "info: curr_bss_params.channel = %d\n", | ||
1368 | priv->curr_bss_params.bss_descriptor.channel); | ||
1369 | dev_dbg(priv->adapter->dev, "info: curr_bss_params.band = %c\n", | ||
1370 | priv->curr_bss_params.band); | ||
1371 | |||
1372 | ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_AD_HOC_JOIN, | ||
1373 | HostCmd_ACT_GEN_SET, 0, wait_queue, | ||
1374 | bss_desc); | ||
1375 | |||
1376 | return ret; | ||
1377 | } | ||
1378 | |||
1379 | /* | ||
1380 | * This function deauthenticates/disconnects from infra network by sending | ||
1381 | * deauthentication request. | ||
1382 | */ | ||
1383 | static int mwifiex_deauthenticate_infra(struct mwifiex_private *priv, | ||
1384 | struct mwifiex_wait_queue *wait, | ||
1385 | u8 *mac) | ||
1386 | { | ||
1387 | u8 mac_address[ETH_ALEN]; | ||
1388 | int ret = 0; | ||
1389 | u8 zero_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 }; | ||
1390 | |||
1391 | if (mac) { | ||
1392 | if (!memcmp(mac, zero_mac, sizeof(zero_mac))) | ||
1393 | memcpy((u8 *) &mac_address, | ||
1394 | (u8 *) &priv->curr_bss_params.bss_descriptor. | ||
1395 | mac_address, ETH_ALEN); | ||
1396 | else | ||
1397 | memcpy((u8 *) &mac_address, (u8 *) mac, ETH_ALEN); | ||
1398 | } else { | ||
1399 | memcpy((u8 *) &mac_address, (u8 *) &priv->curr_bss_params. | ||
1400 | bss_descriptor.mac_address, ETH_ALEN); | ||
1401 | } | ||
1402 | |||
1403 | ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_DEAUTHENTICATE, | ||
1404 | HostCmd_ACT_GEN_SET, 0, wait, &mac_address); | ||
1405 | |||
1406 | if (!ret && wait) | ||
1407 | ret = -EINPROGRESS; | ||
1408 | |||
1409 | return ret; | ||
1410 | } | ||
1411 | |||
1412 | /* | ||
1413 | * This function deauthenticates/disconnects from a BSS. | ||
1414 | * | ||
1415 | * In case of infra made, it sends deauthentication request, and | ||
1416 | * in case of ad-hoc mode, a stop network request is sent to the firmware. | ||
1417 | */ | ||
1418 | int mwifiex_deauthenticate(struct mwifiex_private *priv, | ||
1419 | struct mwifiex_wait_queue *wait, u8 *mac) | ||
1420 | { | ||
1421 | int ret = 0; | ||
1422 | |||
1423 | if (priv->media_connected) { | ||
1424 | if (priv->bss_mode == NL80211_IFTYPE_STATION) { | ||
1425 | ret = mwifiex_deauthenticate_infra(priv, wait, mac); | ||
1426 | } else if (priv->bss_mode == NL80211_IFTYPE_ADHOC) { | ||
1427 | ret = mwifiex_prepare_cmd(priv, | ||
1428 | HostCmd_CMD_802_11_AD_HOC_STOP, | ||
1429 | HostCmd_ACT_GEN_SET, 0, wait, NULL); | ||
1430 | |||
1431 | if (!ret && wait) | ||
1432 | ret = -EINPROGRESS; | ||
1433 | } | ||
1434 | } | ||
1435 | |||
1436 | return ret; | ||
1437 | } | ||
1438 | |||
1439 | /* | ||
1440 | * This function converts band to radio type used in channel TLV. | ||
1441 | */ | ||
1442 | u8 | ||
1443 | mwifiex_band_to_radio_type(u8 band) | ||
1444 | { | ||
1445 | u8 ret_radio_type; | ||
1446 | |||
1447 | switch (band) { | ||
1448 | case BAND_A: | ||
1449 | case BAND_AN: | ||
1450 | case BAND_A | BAND_AN: | ||
1451 | ret_radio_type = HostCmd_SCAN_RADIO_TYPE_A; | ||
1452 | break; | ||
1453 | case BAND_B: | ||
1454 | case BAND_G: | ||
1455 | case BAND_B | BAND_G: | ||
1456 | default: | ||
1457 | ret_radio_type = HostCmd_SCAN_RADIO_TYPE_BG; | ||
1458 | break; | ||
1459 | } | ||
1460 | |||
1461 | return ret_radio_type; | ||
1462 | } | ||
diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c new file mode 100644 index 000000000000..ed89ca41a902 --- /dev/null +++ b/drivers/net/wireless/mwifiex/main.c | |||
@@ -0,0 +1,1102 @@ | |||
1 | /* | ||
2 | * Marvell Wireless LAN device driver: major functions | ||
3 | * | ||
4 | * Copyright (C) 2011, Marvell International Ltd. | ||
5 | * | ||
6 | * This software file (the "File") is distributed by Marvell International | ||
7 | * Ltd. under the terms of the GNU General Public License Version 2, June 1991 | ||
8 | * (the "License"). You may use, redistribute and/or modify this File in | ||
9 | * accordance with the terms and conditions of the License, a copy of which | ||
10 | * is available by writing to the Free Software Foundation, Inc., | ||
11 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the | ||
12 | * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. | ||
13 | * | ||
14 | * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE | ||
15 | * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE | ||
16 | * ARE EXPRESSLY DISCLAIMED. The License provides additional details about | ||
17 | * this warranty disclaimer. | ||
18 | */ | ||
19 | |||
20 | #include "main.h" | ||
21 | #include "wmm.h" | ||
22 | #include "cfg80211.h" | ||
23 | #include "11n.h" | ||
24 | |||
25 | #define VERSION "1.0" | ||
26 | |||
27 | const char driver_version[] = "mwifiex " VERSION " (%s) "; | ||
28 | |||
29 | struct mwifiex_adapter *g_adapter; | ||
30 | EXPORT_SYMBOL_GPL(g_adapter); | ||
31 | |||
32 | static struct mwifiex_bss_attr mwifiex_bss_sta[] = { | ||
33 | {MWIFIEX_BSS_TYPE_STA, MWIFIEX_DATA_FRAME_TYPE_ETH_II, true, 0, 0}, | ||
34 | }; | ||
35 | |||
36 | static int drv_mode = DRV_MODE_STA; | ||
37 | |||
38 | static char fw_name[32] = DEFAULT_FW_NAME; | ||
39 | |||
40 | /* Supported drv_mode table */ | ||
41 | static struct mwifiex_drv_mode mwifiex_drv_mode_tbl[] = { | ||
42 | { | ||
43 | /* drv_mode */ | ||
44 | .drv_mode = DRV_MODE_STA, | ||
45 | /* intf number */ | ||
46 | .intf_num = ARRAY_SIZE(mwifiex_bss_sta), | ||
47 | /* bss_attr */ | ||
48 | .bss_attr = mwifiex_bss_sta, | ||
49 | } | ||
50 | , | ||
51 | }; | ||
52 | |||
53 | /* | ||
54 | * This function registers the device and performs all the necessary | ||
55 | * initializations. | ||
56 | * | ||
57 | * The following initialization operations are performed - | ||
58 | * - Allocate adapter structure | ||
59 | * - Save interface specific operations table in adapter | ||
60 | * - Call interface specific initialization routine | ||
61 | * - Allocate private structures | ||
62 | * - Set default adapter structure parameters | ||
63 | * - Initialize locks | ||
64 | * | ||
65 | * In case of any errors during inittialization, this function also ensures | ||
66 | * proper cleanup before exiting. | ||
67 | */ | ||
68 | static int mwifiex_register(void *card, struct mwifiex_if_ops *if_ops, | ||
69 | struct mwifiex_device *mdevice, void **padapter) | ||
70 | { | ||
71 | int ret = 0; | ||
72 | struct mwifiex_adapter *adapter = NULL; | ||
73 | u8 i = 0; | ||
74 | |||
75 | adapter = kzalloc(sizeof(struct mwifiex_adapter), GFP_KERNEL); | ||
76 | /* Allocate memory for adapter structure */ | ||
77 | if (!adapter) | ||
78 | return -1; | ||
79 | |||
80 | g_adapter = adapter; | ||
81 | adapter->card = card; | ||
82 | |||
83 | /* Save interface specific operations in adapter */ | ||
84 | memmove(&adapter->if_ops, if_ops, sizeof(struct mwifiex_if_ops)); | ||
85 | |||
86 | /* card specific initialization has been deferred until now .. */ | ||
87 | ret = adapter->if_ops.init_if(adapter); | ||
88 | if (ret) | ||
89 | goto error; | ||
90 | |||
91 | adapter->priv_num = 0; | ||
92 | for (i = 0; i < MWIFIEX_MAX_BSS_NUM; i++) { | ||
93 | adapter->priv[i] = NULL; | ||
94 | |||
95 | if (!mdevice->bss_attr[i].active) | ||
96 | continue; | ||
97 | |||
98 | /* For valid bss_attr, | ||
99 | allocate memory for private structure */ | ||
100 | adapter->priv[i] = kzalloc(sizeof(struct mwifiex_private), | ||
101 | GFP_KERNEL); | ||
102 | if (!adapter->priv[i]) { | ||
103 | dev_err(adapter->dev, "%s: failed to alloc priv[%d]\n", | ||
104 | __func__, i); | ||
105 | goto error; | ||
106 | } | ||
107 | |||
108 | adapter->priv_num++; | ||
109 | memset(adapter->priv[i], 0, | ||
110 | sizeof(struct mwifiex_private)); | ||
111 | adapter->priv[i]->adapter = adapter; | ||
112 | /* Save bss_type, frame_type & bss_priority */ | ||
113 | adapter->priv[i]->bss_type = (u8) mdevice->bss_attr[i].bss_type; | ||
114 | adapter->priv[i]->frame_type = | ||
115 | (u8) mdevice->bss_attr[i].frame_type; | ||
116 | adapter->priv[i]->bss_priority = | ||
117 | (u8) mdevice->bss_attr[i].bss_priority; | ||
118 | if (mdevice->bss_attr[i].bss_type == MWIFIEX_BSS_TYPE_STA) | ||
119 | adapter->priv[i]->bss_role = MWIFIEX_BSS_ROLE_STA; | ||
120 | else if (mdevice->bss_attr[i].bss_type == MWIFIEX_BSS_TYPE_UAP) | ||
121 | adapter->priv[i]->bss_role = MWIFIEX_BSS_ROLE_UAP; | ||
122 | |||
123 | /* Save bss_index & bss_num */ | ||
124 | adapter->priv[i]->bss_index = i; | ||
125 | adapter->priv[i]->bss_num = mdevice->bss_attr[i].bss_num; | ||
126 | } | ||
127 | |||
128 | /* Initialize lock variables */ | ||
129 | if (mwifiex_init_lock_list(adapter)) | ||
130 | goto error; | ||
131 | |||
132 | init_timer(&adapter->cmd_timer); | ||
133 | adapter->cmd_timer.function = mwifiex_cmd_timeout_func; | ||
134 | adapter->cmd_timer.data = (unsigned long) adapter; | ||
135 | |||
136 | /* Return pointer of struct mwifiex_adapter */ | ||
137 | *padapter = adapter; | ||
138 | return 0; | ||
139 | |||
140 | error: | ||
141 | dev_dbg(adapter->dev, "info: leave mwifiex_register with error\n"); | ||
142 | |||
143 | /* Free lock variables */ | ||
144 | mwifiex_free_lock_list(adapter); | ||
145 | for (i = 0; i < MWIFIEX_MAX_BSS_NUM; i++) | ||
146 | kfree(adapter->priv[i]); | ||
147 | kfree(adapter); | ||
148 | |||
149 | return -1; | ||
150 | } | ||
151 | |||
152 | /* | ||
153 | * This function unregisters the device and performs all the necessary | ||
154 | * cleanups. | ||
155 | * | ||
156 | * The following cleanup operations are performed - | ||
157 | * - Free the timers | ||
158 | * - Free beacon buffers | ||
159 | * - Free private structures | ||
160 | * - Free adapter structure | ||
161 | */ | ||
162 | static int mwifiex_unregister(struct mwifiex_adapter *adapter) | ||
163 | { | ||
164 | s32 i = 0; | ||
165 | |||
166 | del_timer(&adapter->cmd_timer); | ||
167 | |||
168 | /* Free private structures */ | ||
169 | for (i = 0; i < adapter->priv_num; i++) { | ||
170 | if (adapter->priv[i]) { | ||
171 | mwifiex_free_curr_bcn(adapter->priv[i]); | ||
172 | kfree(adapter->priv[i]); | ||
173 | } | ||
174 | } | ||
175 | |||
176 | kfree(adapter); | ||
177 | return 0; | ||
178 | } | ||
179 | |||
180 | /* | ||
181 | * The main process. | ||
182 | * | ||
183 | * This function is the main procedure of the driver and handles various driver | ||
184 | * operations. It runs in a loop and provides the core functionalities. | ||
185 | * | ||
186 | * The main responsibilities of this function are - | ||
187 | * - Ensure concurrency control | ||
188 | * - Handle pending interrupts and call interrupt handlers | ||
189 | * - Wake up the card if required | ||
190 | * - Handle command responses and call response handlers | ||
191 | * - Handle events and call event handlers | ||
192 | * - Execute pending commands | ||
193 | * - Transmit pending data packets | ||
194 | */ | ||
195 | int mwifiex_main_process(struct mwifiex_adapter *adapter) | ||
196 | { | ||
197 | int ret = 0; | ||
198 | unsigned long flags; | ||
199 | |||
200 | spin_lock_irqsave(&adapter->main_proc_lock, flags); | ||
201 | |||
202 | /* Check if already processing */ | ||
203 | if (adapter->mwifiex_processing) { | ||
204 | spin_unlock_irqrestore(&adapter->main_proc_lock, flags); | ||
205 | goto exit_main_proc; | ||
206 | } else { | ||
207 | adapter->mwifiex_processing = true; | ||
208 | spin_unlock_irqrestore(&adapter->main_proc_lock, flags); | ||
209 | } | ||
210 | process_start: | ||
211 | do { | ||
212 | if ((adapter->hw_status == MWIFIEX_HW_STATUS_CLOSING) || | ||
213 | (adapter->hw_status == MWIFIEX_HW_STATUS_NOT_READY)) | ||
214 | break; | ||
215 | |||
216 | /* Handle pending interrupt if any */ | ||
217 | if (adapter->int_status) { | ||
218 | if (adapter->hs_activated) | ||
219 | mwifiex_process_hs_config(adapter); | ||
220 | adapter->if_ops.process_int_status(adapter); | ||
221 | } | ||
222 | |||
223 | /* Need to wake up the card ? */ | ||
224 | if ((adapter->ps_state == PS_STATE_SLEEP) && | ||
225 | (adapter->pm_wakeup_card_req && | ||
226 | !adapter->pm_wakeup_fw_try) && | ||
227 | (is_command_pending(adapter) | ||
228 | || !mwifiex_wmm_lists_empty(adapter))) { | ||
229 | adapter->pm_wakeup_fw_try = true; | ||
230 | adapter->if_ops.wakeup(adapter); | ||
231 | continue; | ||
232 | } | ||
233 | if (IS_CARD_RX_RCVD(adapter)) { | ||
234 | adapter->pm_wakeup_fw_try = false; | ||
235 | if (adapter->ps_state == PS_STATE_SLEEP) | ||
236 | adapter->ps_state = PS_STATE_AWAKE; | ||
237 | } else { | ||
238 | /* We have tried to wakeup the card already */ | ||
239 | if (adapter->pm_wakeup_fw_try) | ||
240 | break; | ||
241 | if (adapter->ps_state != PS_STATE_AWAKE || | ||
242 | adapter->tx_lock_flag) | ||
243 | break; | ||
244 | |||
245 | if (adapter->scan_processing || adapter->data_sent | ||
246 | || mwifiex_wmm_lists_empty(adapter)) { | ||
247 | if (adapter->cmd_sent || adapter->curr_cmd | ||
248 | || (!is_command_pending(adapter))) | ||
249 | break; | ||
250 | } | ||
251 | } | ||
252 | |||
253 | /* Check for Cmd Resp */ | ||
254 | if (adapter->cmd_resp_received) { | ||
255 | adapter->cmd_resp_received = false; | ||
256 | mwifiex_process_cmdresp(adapter); | ||
257 | |||
258 | /* call mwifiex back when init_fw is done */ | ||
259 | if (adapter->hw_status == MWIFIEX_HW_STATUS_INIT_DONE) { | ||
260 | adapter->hw_status = MWIFIEX_HW_STATUS_READY; | ||
261 | mwifiex_init_fw_complete(adapter); | ||
262 | } | ||
263 | } | ||
264 | |||
265 | /* Check for event */ | ||
266 | if (adapter->event_received) { | ||
267 | adapter->event_received = false; | ||
268 | mwifiex_process_event(adapter); | ||
269 | } | ||
270 | |||
271 | /* Check if we need to confirm Sleep Request | ||
272 | received previously */ | ||
273 | if (adapter->ps_state == PS_STATE_PRE_SLEEP) { | ||
274 | if (!adapter->cmd_sent && !adapter->curr_cmd) | ||
275 | mwifiex_check_ps_cond(adapter); | ||
276 | } | ||
277 | |||
278 | /* * The ps_state may have been changed during processing of | ||
279 | * Sleep Request event. | ||
280 | */ | ||
281 | if ((adapter->ps_state == PS_STATE_SLEEP) | ||
282 | || (adapter->ps_state == PS_STATE_PRE_SLEEP) | ||
283 | || (adapter->ps_state == PS_STATE_SLEEP_CFM) | ||
284 | || adapter->tx_lock_flag) | ||
285 | continue; | ||
286 | |||
287 | if (!adapter->cmd_sent && !adapter->curr_cmd) { | ||
288 | if (mwifiex_exec_next_cmd(adapter) == -1) { | ||
289 | ret = -1; | ||
290 | break; | ||
291 | } | ||
292 | } | ||
293 | |||
294 | if (!adapter->scan_processing && !adapter->data_sent && | ||
295 | !mwifiex_wmm_lists_empty(adapter)) { | ||
296 | mwifiex_wmm_process_tx(adapter); | ||
297 | if (adapter->hs_activated) { | ||
298 | adapter->is_hs_configured = false; | ||
299 | mwifiex_hs_activated_event | ||
300 | (mwifiex_get_priv | ||
301 | (adapter, MWIFIEX_BSS_ROLE_ANY), | ||
302 | false); | ||
303 | } | ||
304 | } | ||
305 | |||
306 | if (adapter->delay_null_pkt && !adapter->cmd_sent && | ||
307 | !adapter->curr_cmd && !is_command_pending(adapter) | ||
308 | && mwifiex_wmm_lists_empty(adapter)) { | ||
309 | if (!mwifiex_send_null_packet | ||
310 | (mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA), | ||
311 | MWIFIEX_TxPD_POWER_MGMT_NULL_PACKET | | ||
312 | MWIFIEX_TxPD_POWER_MGMT_LAST_PACKET)) { | ||
313 | adapter->delay_null_pkt = false; | ||
314 | adapter->ps_state = PS_STATE_SLEEP; | ||
315 | } | ||
316 | break; | ||
317 | } | ||
318 | } while (true); | ||
319 | |||
320 | if ((adapter->int_status) || IS_CARD_RX_RCVD(adapter)) | ||
321 | goto process_start; | ||
322 | |||
323 | spin_lock_irqsave(&adapter->main_proc_lock, flags); | ||
324 | adapter->mwifiex_processing = false; | ||
325 | spin_unlock_irqrestore(&adapter->main_proc_lock, flags); | ||
326 | |||
327 | exit_main_proc: | ||
328 | if (adapter->hw_status == MWIFIEX_HW_STATUS_CLOSING) | ||
329 | mwifiex_shutdown_drv(adapter); | ||
330 | return ret; | ||
331 | } | ||
332 | |||
333 | /* | ||
334 | * This function initializes the software. | ||
335 | * | ||
336 | * The main work includes allocating and initializing the adapter structure | ||
337 | * and initializing the private structures. | ||
338 | */ | ||
339 | static int | ||
340 | mwifiex_init_sw(void *card, struct mwifiex_if_ops *if_ops, void **pmwifiex) | ||
341 | { | ||
342 | int i; | ||
343 | struct mwifiex_device device; | ||
344 | struct mwifiex_drv_mode *drv_mode_ptr; | ||
345 | |||
346 | /* find mwifiex_drv_mode entry from mwifiex_drv_mode_tbl */ | ||
347 | drv_mode_ptr = NULL; | ||
348 | for (i = 0; i < ARRAY_SIZE(mwifiex_drv_mode_tbl); i++) { | ||
349 | if (mwifiex_drv_mode_tbl[i].drv_mode == drv_mode) { | ||
350 | drv_mode_ptr = &mwifiex_drv_mode_tbl[i]; | ||
351 | break; | ||
352 | } | ||
353 | } | ||
354 | |||
355 | if (!drv_mode_ptr) { | ||
356 | pr_err("invalid drv_mode=%d\n", drv_mode); | ||
357 | return -1; | ||
358 | } | ||
359 | |||
360 | memset(&device, 0, sizeof(struct mwifiex_device)); | ||
361 | |||
362 | for (i = 0; i < drv_mode_ptr->intf_num; i++) { | ||
363 | device.bss_attr[i].bss_type = | ||
364 | drv_mode_ptr->bss_attr[i].bss_type; | ||
365 | device.bss_attr[i].frame_type = | ||
366 | drv_mode_ptr->bss_attr[i].frame_type; | ||
367 | device.bss_attr[i].active = drv_mode_ptr->bss_attr[i].active; | ||
368 | device.bss_attr[i].bss_priority = | ||
369 | drv_mode_ptr->bss_attr[i].bss_priority; | ||
370 | device.bss_attr[i].bss_num = drv_mode_ptr->bss_attr[i].bss_num; | ||
371 | } | ||
372 | |||
373 | if (mwifiex_register(card, if_ops, &device, pmwifiex)) | ||
374 | return -1; | ||
375 | |||
376 | return 0; | ||
377 | } | ||
378 | |||
379 | /* | ||
380 | * This function frees the adapter structure. | ||
381 | * | ||
382 | * Additionally, this closes the netlink socket, frees the timers | ||
383 | * and private structures. | ||
384 | */ | ||
385 | static void mwifiex_free_adapter(struct mwifiex_adapter *adapter) | ||
386 | { | ||
387 | if (!adapter) { | ||
388 | pr_err("%s: adapter is NULL\n", __func__); | ||
389 | return; | ||
390 | } | ||
391 | |||
392 | mwifiex_unregister(adapter); | ||
393 | pr_debug("info: %s: free adapter\n", __func__); | ||
394 | } | ||
395 | |||
396 | /* | ||
397 | * This function initializes the hardware and firmware. | ||
398 | * | ||
399 | * The main initialization steps followed are - | ||
400 | * - Download the correct firmware to card | ||
401 | * - Allocate and initialize the adapter structure | ||
402 | * - Initialize the private structures | ||
403 | * - Issue the init commands to firmware | ||
404 | */ | ||
405 | static int mwifiex_init_hw_fw(struct mwifiex_adapter *adapter) | ||
406 | { | ||
407 | int ret = 0; | ||
408 | int err; | ||
409 | struct mwifiex_fw_image fw; | ||
410 | |||
411 | memset(&fw, 0, sizeof(struct mwifiex_fw_image)); | ||
412 | |||
413 | switch (adapter->revision_id) { | ||
414 | case SD8787_W0: | ||
415 | case SD8787_W1: | ||
416 | strcpy(fw_name, SD8787_W1_FW_NAME); | ||
417 | break; | ||
418 | case SD8787_A0: | ||
419 | case SD8787_A1: | ||
420 | strcpy(fw_name, SD8787_AX_FW_NAME); | ||
421 | break; | ||
422 | default: | ||
423 | break; | ||
424 | } | ||
425 | |||
426 | err = request_firmware(&adapter->firmware, fw_name, adapter->dev); | ||
427 | if (err < 0) { | ||
428 | dev_err(adapter->dev, "request_firmware() returned" | ||
429 | " error code %#x\n", err); | ||
430 | ret = -1; | ||
431 | goto done; | ||
432 | } | ||
433 | fw.fw_buf = (u8 *) adapter->firmware->data; | ||
434 | fw.fw_len = adapter->firmware->size; | ||
435 | |||
436 | ret = mwifiex_dnld_fw(adapter, &fw); | ||
437 | if (ret == -1) | ||
438 | goto done; | ||
439 | |||
440 | dev_notice(adapter->dev, "WLAN FW is active\n"); | ||
441 | |||
442 | adapter->init_wait_q_woken = false; | ||
443 | ret = mwifiex_init_fw(adapter); | ||
444 | if (ret == -1) { | ||
445 | goto done; | ||
446 | } else if (!ret) { | ||
447 | adapter->hw_status = MWIFIEX_HW_STATUS_READY; | ||
448 | goto done; | ||
449 | } | ||
450 | /* Wait for mwifiex_init to complete */ | ||
451 | wait_event_interruptible(adapter->init_wait_q, | ||
452 | adapter->init_wait_q_woken); | ||
453 | if (adapter->hw_status != MWIFIEX_HW_STATUS_READY) { | ||
454 | ret = -1; | ||
455 | goto done; | ||
456 | } | ||
457 | ret = 0; | ||
458 | |||
459 | done: | ||
460 | if (adapter->firmware) | ||
461 | release_firmware(adapter->firmware); | ||
462 | if (ret) | ||
463 | ret = -1; | ||
464 | return ret; | ||
465 | } | ||
466 | |||
467 | /* | ||
468 | * This function fills a driver buffer. | ||
469 | * | ||
470 | * The function associates a given SKB with the provided driver buffer | ||
471 | * and also updates some of the SKB parameters, including IP header, | ||
472 | * priority and timestamp. | ||
473 | */ | ||
474 | static void | ||
475 | mwifiex_fill_buffer(struct sk_buff *skb) | ||
476 | { | ||
477 | struct ethhdr *eth = NULL; | ||
478 | struct iphdr *iph; | ||
479 | struct timeval tv; | ||
480 | u8 tid = 0; | ||
481 | |||
482 | eth = (struct ethhdr *) skb->data; | ||
483 | switch (eth->h_proto) { | ||
484 | case __constant_htons(ETH_P_IP): | ||
485 | iph = ip_hdr(skb); | ||
486 | tid = IPTOS_PREC(iph->tos); | ||
487 | pr_debug("data: packet type ETH_P_IP: %04x, tid=%#x prio=%#x\n", | ||
488 | eth->h_proto, tid, skb->priority); | ||
489 | break; | ||
490 | case __constant_htons(ETH_P_ARP): | ||
491 | pr_debug("data: ARP packet: %04x\n", eth->h_proto); | ||
492 | default: | ||
493 | break; | ||
494 | } | ||
495 | /* Offset for TOS field in the IP header */ | ||
496 | #define IPTOS_OFFSET 5 | ||
497 | tid = (tid >> IPTOS_OFFSET); | ||
498 | skb->priority = tid; | ||
499 | /* Record the current time the packet was queued; used to | ||
500 | determine the amount of time the packet was queued in | ||
501 | the driver before it was sent to the firmware. | ||
502 | The delay is then sent along with the packet to the | ||
503 | firmware for aggregate delay calculation for stats and | ||
504 | MSDU lifetime expiry. | ||
505 | */ | ||
506 | do_gettimeofday(&tv); | ||
507 | skb->tstamp = timeval_to_ktime(tv); | ||
508 | return; | ||
509 | } | ||
510 | |||
511 | /* | ||
512 | * CFG802.11 network device handler for open. | ||
513 | * | ||
514 | * Starts the data queue. | ||
515 | */ | ||
516 | static int | ||
517 | mwifiex_open(struct net_device *dev) | ||
518 | { | ||
519 | netif_start_queue(dev); | ||
520 | return 0; | ||
521 | } | ||
522 | |||
523 | /* | ||
524 | * CFG802.11 network device handler for close. | ||
525 | */ | ||
526 | static int | ||
527 | mwifiex_close(struct net_device *dev) | ||
528 | { | ||
529 | return 0; | ||
530 | } | ||
531 | |||
532 | /* | ||
533 | * CFG802.11 network device handler for data transmission. | ||
534 | */ | ||
535 | static int | ||
536 | mwifiex_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | ||
537 | { | ||
538 | struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); | ||
539 | struct sk_buff *new_skb = NULL; | ||
540 | struct mwifiex_txinfo *tx_info; | ||
541 | |||
542 | dev_dbg(priv->adapter->dev, "data: %lu BSS(%d): Data <= kernel\n", | ||
543 | jiffies, priv->bss_index); | ||
544 | |||
545 | if (priv->adapter->surprise_removed) { | ||
546 | kfree(skb); | ||
547 | priv->stats.tx_dropped++; | ||
548 | return 0; | ||
549 | } | ||
550 | if (!skb->len || (skb->len > ETH_FRAME_LEN)) { | ||
551 | dev_err(priv->adapter->dev, "Tx: bad skb len %d\n", skb->len); | ||
552 | kfree(skb); | ||
553 | priv->stats.tx_dropped++; | ||
554 | return 0; | ||
555 | } | ||
556 | if (skb_headroom(skb) < MWIFIEX_MIN_DATA_HEADER_LEN) { | ||
557 | dev_dbg(priv->adapter->dev, | ||
558 | "data: Tx: insufficient skb headroom %d\n", | ||
559 | skb_headroom(skb)); | ||
560 | /* Insufficient skb headroom - allocate a new skb */ | ||
561 | new_skb = | ||
562 | skb_realloc_headroom(skb, MWIFIEX_MIN_DATA_HEADER_LEN); | ||
563 | if (unlikely(!new_skb)) { | ||
564 | dev_err(priv->adapter->dev, "Tx: cannot alloca new_skb\n"); | ||
565 | kfree(skb); | ||
566 | priv->stats.tx_dropped++; | ||
567 | return 0; | ||
568 | } | ||
569 | kfree_skb(skb); | ||
570 | skb = new_skb; | ||
571 | dev_dbg(priv->adapter->dev, "info: new skb headroomd %d\n", | ||
572 | skb_headroom(skb)); | ||
573 | } | ||
574 | |||
575 | tx_info = MWIFIEX_SKB_TXCB(skb); | ||
576 | tx_info->bss_index = priv->bss_index; | ||
577 | mwifiex_fill_buffer(skb); | ||
578 | |||
579 | mwifiex_wmm_add_buf_txqueue(priv->adapter, skb); | ||
580 | atomic_inc(&priv->adapter->tx_pending); | ||
581 | |||
582 | if (atomic_read(&priv->adapter->tx_pending) >= MAX_TX_PENDING) { | ||
583 | netif_stop_queue(priv->netdev); | ||
584 | dev->trans_start = jiffies; | ||
585 | } | ||
586 | |||
587 | queue_work(priv->adapter->workqueue, &priv->adapter->main_work); | ||
588 | |||
589 | return 0; | ||
590 | } | ||
591 | |||
592 | /* | ||
593 | * CFG802.11 network device handler for setting MAC address. | ||
594 | */ | ||
595 | static int | ||
596 | mwifiex_set_mac_address(struct net_device *dev, void *addr) | ||
597 | { | ||
598 | struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); | ||
599 | struct sockaddr *hw_addr = (struct sockaddr *) addr; | ||
600 | |||
601 | memcpy(priv->curr_addr, hw_addr->sa_data, ETH_ALEN); | ||
602 | |||
603 | if (mwifiex_request_set_mac_address(priv)) { | ||
604 | dev_err(priv->adapter->dev, "set MAC address failed\n"); | ||
605 | return -EFAULT; | ||
606 | } | ||
607 | memcpy(dev->dev_addr, priv->curr_addr, ETH_ALEN); | ||
608 | |||
609 | return 0; | ||
610 | } | ||
611 | |||
612 | /* | ||
613 | * CFG802.11 network device handler for setting multicast list. | ||
614 | */ | ||
615 | static void mwifiex_set_multicast_list(struct net_device *dev) | ||
616 | { | ||
617 | struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); | ||
618 | mwifiex_request_set_multicast_list(priv, dev); | ||
619 | } | ||
620 | |||
621 | /* | ||
622 | * CFG802.11 network device handler for transmission timeout. | ||
623 | */ | ||
624 | static void | ||
625 | mwifiex_tx_timeout(struct net_device *dev) | ||
626 | { | ||
627 | struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); | ||
628 | |||
629 | dev_err(priv->adapter->dev, "%lu : Tx timeout, bss_index=%d\n", | ||
630 | jiffies, priv->bss_index); | ||
631 | dev->trans_start = jiffies; | ||
632 | priv->num_tx_timeout++; | ||
633 | } | ||
634 | |||
635 | /* | ||
636 | * CFG802.11 network device handler for statistics retrieval. | ||
637 | */ | ||
638 | static struct net_device_stats *mwifiex_get_stats(struct net_device *dev) | ||
639 | { | ||
640 | struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); | ||
641 | |||
642 | return &priv->stats; | ||
643 | } | ||
644 | |||
645 | /* Network device handlers */ | ||
646 | static const struct net_device_ops mwifiex_netdev_ops = { | ||
647 | .ndo_open = mwifiex_open, | ||
648 | .ndo_stop = mwifiex_close, | ||
649 | .ndo_start_xmit = mwifiex_hard_start_xmit, | ||
650 | .ndo_set_mac_address = mwifiex_set_mac_address, | ||
651 | .ndo_tx_timeout = mwifiex_tx_timeout, | ||
652 | .ndo_get_stats = mwifiex_get_stats, | ||
653 | .ndo_set_multicast_list = mwifiex_set_multicast_list, | ||
654 | }; | ||
655 | |||
656 | /* | ||
657 | * This function initializes the private structure parameters. | ||
658 | * | ||
659 | * The following wait queues are initialized - | ||
660 | * - IOCTL wait queue | ||
661 | * - Command wait queue | ||
662 | * - Statistics wait queue | ||
663 | * | ||
664 | * ...and the following default parameters are set - | ||
665 | * - Current key index : Set to 0 | ||
666 | * - Rate index : Set to auto | ||
667 | * - Media connected : Set to disconnected | ||
668 | * - Adhoc link sensed : Set to false | ||
669 | * - Nick name : Set to null | ||
670 | * - Number of Tx timeout : Set to 0 | ||
671 | * - Device address : Set to current address | ||
672 | * | ||
673 | * In addition, the CFG80211 work queue is also created. | ||
674 | */ | ||
675 | static void | ||
676 | mwifiex_init_priv_params(struct mwifiex_private *priv, struct net_device *dev) | ||
677 | { | ||
678 | dev->netdev_ops = &mwifiex_netdev_ops; | ||
679 | /* Initialize private structure */ | ||
680 | init_waitqueue_head(&priv->ioctl_wait_q); | ||
681 | init_waitqueue_head(&priv->cmd_wait_q); | ||
682 | init_waitqueue_head(&priv->w_stats_wait_q); | ||
683 | priv->current_key_index = 0; | ||
684 | priv->media_connected = false; | ||
685 | memset(&priv->nick_name, 0, sizeof(priv->nick_name)); | ||
686 | priv->num_tx_timeout = 0; | ||
687 | priv->workqueue = create_singlethread_workqueue("cfg80211_wq"); | ||
688 | INIT_WORK(&priv->cfg_workqueue, mwifiex_cfg80211_results); | ||
689 | memcpy(dev->dev_addr, priv->curr_addr, ETH_ALEN); | ||
690 | } | ||
691 | |||
692 | /* | ||
693 | * This function adds a new logical interface. | ||
694 | * | ||
695 | * It allocates, initializes and registers the interface by performing | ||
696 | * the following opearations - | ||
697 | * - Allocate a new net device structure | ||
698 | * - Assign device name | ||
699 | * - Register the new device with CFG80211 subsystem | ||
700 | * - Initialize semaphore and private structure | ||
701 | * - Register the new device with kernel | ||
702 | * - Create the complete debug FS structure if configured | ||
703 | */ | ||
704 | static struct mwifiex_private *mwifiex_add_interface( | ||
705 | struct mwifiex_adapter *adapter, | ||
706 | u8 bss_index, u8 bss_type) | ||
707 | { | ||
708 | struct net_device *dev = NULL; | ||
709 | struct mwifiex_private *priv = NULL; | ||
710 | void *mdev_priv = NULL; | ||
711 | |||
712 | dev = alloc_netdev_mq(sizeof(struct mwifiex_private *), "mlan%d", | ||
713 | ether_setup, 1); | ||
714 | if (!dev) { | ||
715 | dev_err(adapter->dev, "no memory available for netdevice\n"); | ||
716 | goto error; | ||
717 | } | ||
718 | if (dev_alloc_name(dev, dev->name)) { | ||
719 | dev_err(adapter->dev, "unable to alloc name for netdevice\n"); | ||
720 | goto error; | ||
721 | } | ||
722 | |||
723 | if (mwifiex_register_cfg80211(dev, adapter->priv[bss_index]->curr_addr, | ||
724 | adapter->priv[bss_index]) != 0) { | ||
725 | dev_err(adapter->dev, "cannot register netdevice with cfg80211\n"); | ||
726 | goto error; | ||
727 | } | ||
728 | /* Save the priv pointer in netdev */ | ||
729 | priv = adapter->priv[bss_index]; | ||
730 | mdev_priv = netdev_priv(dev); | ||
731 | *((unsigned long *) mdev_priv) = (unsigned long) priv; | ||
732 | |||
733 | priv->netdev = dev; | ||
734 | |||
735 | sema_init(&priv->async_sem, 1); | ||
736 | priv->scan_pending_on_block = false; | ||
737 | |||
738 | mwifiex_init_priv_params(priv, dev); | ||
739 | |||
740 | SET_NETDEV_DEV(dev, adapter->dev); | ||
741 | |||
742 | /* Register network device */ | ||
743 | if (register_netdev(dev)) { | ||
744 | dev_err(adapter->dev, "cannot register virtual network device\n"); | ||
745 | goto error; | ||
746 | } | ||
747 | |||
748 | dev_dbg(adapter->dev, "info: %s: Marvell 802.11 Adapter\n", dev->name); | ||
749 | #ifdef CONFIG_DEBUG_FS | ||
750 | mwifiex_dev_debugfs_init(priv); | ||
751 | #endif | ||
752 | return priv; | ||
753 | error: | ||
754 | if (dev) | ||
755 | free_netdev(dev); | ||
756 | return NULL; | ||
757 | } | ||
758 | |||
759 | /* | ||
760 | * This function removes a logical interface. | ||
761 | * | ||
762 | * It deregisters, resets and frees the interface by performing | ||
763 | * the following operations - | ||
764 | * - Disconnect the device if connected, send wireless event to | ||
765 | * notify applications. | ||
766 | * - Remove the debug FS structure if configured | ||
767 | * - Unregister the device from kernel | ||
768 | * - Free the net device structure | ||
769 | * - Cancel all works and destroy work queue | ||
770 | * - Unregister and free the wireless device from CFG80211 subsystem | ||
771 | */ | ||
772 | static void | ||
773 | mwifiex_remove_interface(struct mwifiex_adapter *adapter, u8 bss_index) | ||
774 | { | ||
775 | struct net_device *dev = NULL; | ||
776 | struct mwifiex_private *priv = adapter->priv[bss_index]; | ||
777 | |||
778 | if (!priv) | ||
779 | return; | ||
780 | dev = priv->netdev; | ||
781 | |||
782 | if (priv->media_connected) | ||
783 | priv->media_connected = false; | ||
784 | |||
785 | #ifdef CONFIG_DEBUG_FS | ||
786 | mwifiex_dev_debugfs_remove(priv); | ||
787 | #endif | ||
788 | /* Last reference is our one */ | ||
789 | dev_dbg(adapter->dev, "info: %s: refcnt = %d\n", | ||
790 | dev->name, netdev_refcnt_read(dev)); | ||
791 | |||
792 | if (dev->reg_state == NETREG_REGISTERED) | ||
793 | unregister_netdev(dev); | ||
794 | |||
795 | /* Clear the priv in adapter */ | ||
796 | priv->netdev = NULL; | ||
797 | if (dev) | ||
798 | free_netdev(dev); | ||
799 | |||
800 | cancel_work_sync(&priv->cfg_workqueue); | ||
801 | flush_workqueue(priv->workqueue); | ||
802 | destroy_workqueue(priv->workqueue); | ||
803 | wiphy_unregister(priv->wdev->wiphy); | ||
804 | wiphy_free(priv->wdev->wiphy); | ||
805 | kfree(priv->wdev); | ||
806 | |||
807 | return; | ||
808 | } | ||
809 | |||
810 | /* | ||
811 | * Sends IOCTL request to shutdown firmware. | ||
812 | * | ||
813 | * This function allocates the IOCTL request buffer, fills it | ||
814 | * with requisite parameters and calls the IOCTL handler. | ||
815 | */ | ||
816 | int mwifiex_shutdown_fw(struct mwifiex_private *priv, u8 wait_option) | ||
817 | { | ||
818 | struct mwifiex_wait_queue *wait = NULL; | ||
819 | int status = 0; | ||
820 | |||
821 | /* Allocate an IOCTL request buffer */ | ||
822 | wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); | ||
823 | if (!wait) | ||
824 | return -ENOMEM; | ||
825 | |||
826 | status = mwifiex_misc_ioctl_init_shutdown(priv->adapter, wait, | ||
827 | MWIFIEX_FUNC_SHUTDOWN); | ||
828 | |||
829 | status = mwifiex_request_ioctl(priv, wait, status, wait_option); | ||
830 | |||
831 | kfree(wait); | ||
832 | return status; | ||
833 | } | ||
834 | EXPORT_SYMBOL_GPL(mwifiex_shutdown_fw); | ||
835 | |||
836 | /* | ||
837 | * This function check if command is pending. | ||
838 | */ | ||
839 | int is_command_pending(struct mwifiex_adapter *adapter) | ||
840 | { | ||
841 | unsigned long flags; | ||
842 | int is_cmd_pend_q_empty; | ||
843 | |||
844 | spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags); | ||
845 | is_cmd_pend_q_empty = list_empty(&adapter->cmd_pending_q); | ||
846 | spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags); | ||
847 | |||
848 | return !is_cmd_pend_q_empty; | ||
849 | } | ||
850 | |||
851 | /* | ||
852 | * This function returns the correct private structure pointer based | ||
853 | * upon the BSS number. | ||
854 | */ | ||
855 | struct mwifiex_private * | ||
856 | mwifiex_bss_index_to_priv(struct mwifiex_adapter *adapter, u8 bss_index) | ||
857 | { | ||
858 | if (!adapter || (bss_index >= adapter->priv_num)) | ||
859 | return NULL; | ||
860 | return adapter->priv[bss_index]; | ||
861 | } | ||
862 | |||
863 | /* | ||
864 | * This is the main work queue function. | ||
865 | * | ||
866 | * It handles the main process, which in turn handles the complete | ||
867 | * driver operations. | ||
868 | */ | ||
869 | static void mwifiex_main_work_queue(struct work_struct *work) | ||
870 | { | ||
871 | struct mwifiex_adapter *adapter = | ||
872 | container_of(work, struct mwifiex_adapter, main_work); | ||
873 | |||
874 | if (adapter->surprise_removed) | ||
875 | return; | ||
876 | mwifiex_main_process(adapter); | ||
877 | } | ||
878 | |||
879 | /* | ||
880 | * This function cancels all works in the queue and destroys | ||
881 | * the main workqueue. | ||
882 | */ | ||
883 | static void | ||
884 | mwifiex_terminate_workqueue(struct mwifiex_adapter *adapter) | ||
885 | { | ||
886 | flush_workqueue(adapter->workqueue); | ||
887 | destroy_workqueue(adapter->workqueue); | ||
888 | adapter->workqueue = NULL; | ||
889 | } | ||
890 | |||
891 | /* | ||
892 | * This function adds the card. | ||
893 | * | ||
894 | * This function follows the following major steps to set up the device - | ||
895 | * - Initialize software. This includes probing the card, registering | ||
896 | * the interface operations table, and allocating/initializing the | ||
897 | * adapter structure | ||
898 | * - Set up the netlink socket | ||
899 | * - Create and start the main work queue | ||
900 | * - Register the device | ||
901 | * - Initialize firmware and hardware | ||
902 | * - Add logical interfaces | ||
903 | */ | ||
904 | int | ||
905 | mwifiex_add_card(void *card, struct semaphore *sem, | ||
906 | struct mwifiex_if_ops *if_ops) | ||
907 | { | ||
908 | int status = 0; | ||
909 | int i; | ||
910 | struct mwifiex_adapter *adapter = NULL; | ||
911 | struct mwifiex_drv_mode *drv_mode_info = &mwifiex_drv_mode_tbl[0]; | ||
912 | |||
913 | if (down_interruptible(sem)) | ||
914 | goto exit_sem_err; | ||
915 | |||
916 | if (mwifiex_init_sw(card, if_ops, (void **) &adapter)) { | ||
917 | pr_err("%s: software init failed\n", __func__); | ||
918 | goto err_init_sw; | ||
919 | } | ||
920 | |||
921 | adapter->drv_mode = drv_mode_info; | ||
922 | |||
923 | adapter->hw_status = MWIFIEX_HW_STATUS_INITIALIZING; | ||
924 | /* PnP and power profile */ | ||
925 | adapter->surprise_removed = false; | ||
926 | init_waitqueue_head(&adapter->init_wait_q); | ||
927 | adapter->is_suspended = false; | ||
928 | adapter->hs_activated = false; | ||
929 | init_waitqueue_head(&adapter->hs_activate_wait_q); | ||
930 | |||
931 | /* Create workqueue */ | ||
932 | adapter->workqueue = create_workqueue("MWIFIEX_WORK_QUEUE"); | ||
933 | if (!adapter->workqueue) | ||
934 | goto err_kmalloc; | ||
935 | |||
936 | INIT_WORK(&adapter->main_work, mwifiex_main_work_queue); | ||
937 | |||
938 | /* Register the device. Fill up the private data structure with relevant | ||
939 | information from the card and request for the required IRQ. */ | ||
940 | if (adapter->if_ops.register_dev(adapter)) { | ||
941 | pr_err("%s: failed to register mwifiex device\n", __func__); | ||
942 | goto err_registerdev; | ||
943 | } | ||
944 | |||
945 | /* Init FW and HW */ | ||
946 | if (mwifiex_init_hw_fw(adapter)) { | ||
947 | pr_err("%s: firmware init failed\n", __func__); | ||
948 | goto err_init_fw; | ||
949 | } | ||
950 | /* Add interfaces */ | ||
951 | for (i = 0; i < drv_mode_info->intf_num; i++) { | ||
952 | if (!mwifiex_add_interface(adapter, i, | ||
953 | adapter->drv_mode->bss_attr[i].bss_type)) { | ||
954 | status = -1; | ||
955 | break; | ||
956 | } | ||
957 | } | ||
958 | if (status) | ||
959 | goto err_add_intf; | ||
960 | |||
961 | up(sem); | ||
962 | |||
963 | return 0; | ||
964 | |||
965 | err_add_intf: | ||
966 | for (i = 0; i < adapter->priv_num; i++) | ||
967 | mwifiex_remove_interface(adapter, i); | ||
968 | err_init_fw: | ||
969 | /* Unregister device */ | ||
970 | pr_debug("info: %s: unregister device\n", __func__); | ||
971 | adapter->if_ops.unregister_dev(adapter); | ||
972 | err_registerdev: | ||
973 | adapter->surprise_removed = true; | ||
974 | mwifiex_terminate_workqueue(adapter); | ||
975 | err_kmalloc: | ||
976 | if ((adapter->hw_status == MWIFIEX_HW_STATUS_FW_READY) || | ||
977 | (adapter->hw_status == MWIFIEX_HW_STATUS_READY)) { | ||
978 | pr_debug("info: %s: shutdown mwifiex\n", __func__); | ||
979 | adapter->init_wait_q_woken = false; | ||
980 | status = mwifiex_shutdown_drv(adapter); | ||
981 | if (status == -EINPROGRESS) | ||
982 | wait_event_interruptible(adapter->init_wait_q, | ||
983 | adapter->init_wait_q_woken); | ||
984 | } | ||
985 | |||
986 | mwifiex_free_adapter(adapter); | ||
987 | |||
988 | err_init_sw: | ||
989 | up(sem); | ||
990 | |||
991 | exit_sem_err: | ||
992 | return -1; | ||
993 | } | ||
994 | EXPORT_SYMBOL_GPL(mwifiex_add_card); | ||
995 | |||
996 | /* | ||
997 | * This function removes the card. | ||
998 | * | ||
999 | * This function follows the following major steps to remove the device - | ||
1000 | * - Stop data traffic | ||
1001 | * - Shutdown firmware | ||
1002 | * - Remove the logical interfaces | ||
1003 | * - Terminate the work queue | ||
1004 | * - Unregister the device | ||
1005 | * - Free the adapter structure | ||
1006 | */ | ||
1007 | int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem) | ||
1008 | { | ||
1009 | struct mwifiex_private *priv = NULL; | ||
1010 | int status; | ||
1011 | int i; | ||
1012 | |||
1013 | if (down_interruptible(sem)) | ||
1014 | goto exit_sem_err; | ||
1015 | |||
1016 | if (!adapter) | ||
1017 | goto exit_remove; | ||
1018 | |||
1019 | adapter->surprise_removed = true; | ||
1020 | |||
1021 | /* Stop data */ | ||
1022 | for (i = 0; i < adapter->priv_num; i++) { | ||
1023 | priv = adapter->priv[i]; | ||
1024 | if (priv) { | ||
1025 | if (!netif_queue_stopped(priv->netdev)) | ||
1026 | netif_stop_queue(priv->netdev); | ||
1027 | if (netif_carrier_ok(priv->netdev)) | ||
1028 | netif_carrier_off(priv->netdev); | ||
1029 | } | ||
1030 | } | ||
1031 | |||
1032 | dev_dbg(adapter->dev, "cmd: calling mwifiex_shutdown_drv...\n"); | ||
1033 | adapter->init_wait_q_woken = false; | ||
1034 | status = mwifiex_shutdown_drv(adapter); | ||
1035 | if (status == -EINPROGRESS) | ||
1036 | wait_event_interruptible(adapter->init_wait_q, | ||
1037 | adapter->init_wait_q_woken); | ||
1038 | dev_dbg(adapter->dev, "cmd: mwifiex_shutdown_drv done\n"); | ||
1039 | if (atomic_read(&adapter->rx_pending) || | ||
1040 | atomic_read(&adapter->tx_pending) || | ||
1041 | atomic_read(&adapter->ioctl_pending)) { | ||
1042 | dev_err(adapter->dev, "rx_pending=%d, tx_pending=%d, " | ||
1043 | "ioctl_pending=%d\n", | ||
1044 | atomic_read(&adapter->rx_pending), | ||
1045 | atomic_read(&adapter->tx_pending), | ||
1046 | atomic_read(&adapter->ioctl_pending)); | ||
1047 | } | ||
1048 | |||
1049 | /* Remove interface */ | ||
1050 | for (i = 0; i < adapter->priv_num; i++) | ||
1051 | mwifiex_remove_interface(adapter, i); | ||
1052 | |||
1053 | mwifiex_terminate_workqueue(adapter); | ||
1054 | |||
1055 | /* Unregister device */ | ||
1056 | dev_dbg(adapter->dev, "info: unregister device\n"); | ||
1057 | adapter->if_ops.unregister_dev(adapter); | ||
1058 | /* Free adapter structure */ | ||
1059 | dev_dbg(adapter->dev, "info: free adapter\n"); | ||
1060 | mwifiex_free_adapter(adapter); | ||
1061 | |||
1062 | exit_remove: | ||
1063 | up(sem); | ||
1064 | exit_sem_err: | ||
1065 | return 0; | ||
1066 | } | ||
1067 | EXPORT_SYMBOL_GPL(mwifiex_remove_card); | ||
1068 | |||
1069 | /* | ||
1070 | * This function initializes the module. | ||
1071 | * | ||
1072 | * The debug FS is also initialized if configured. | ||
1073 | */ | ||
1074 | static int | ||
1075 | mwifiex_init_module(void) | ||
1076 | { | ||
1077 | #ifdef CONFIG_DEBUG_FS | ||
1078 | mwifiex_debugfs_init(); | ||
1079 | #endif | ||
1080 | return 0; | ||
1081 | } | ||
1082 | |||
1083 | /* | ||
1084 | * This function cleans up the module. | ||
1085 | * | ||
1086 | * The debug FS is removed if available. | ||
1087 | */ | ||
1088 | static void | ||
1089 | mwifiex_cleanup_module(void) | ||
1090 | { | ||
1091 | #ifdef CONFIG_DEBUG_FS | ||
1092 | mwifiex_debugfs_remove(); | ||
1093 | #endif | ||
1094 | } | ||
1095 | |||
1096 | module_init(mwifiex_init_module); | ||
1097 | module_exit(mwifiex_cleanup_module); | ||
1098 | |||
1099 | MODULE_AUTHOR("Marvell International Ltd."); | ||
1100 | MODULE_DESCRIPTION("Marvell WiFi-Ex Driver version " VERSION); | ||
1101 | MODULE_VERSION(VERSION); | ||
1102 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h new file mode 100644 index 000000000000..43ff149de9db --- /dev/null +++ b/drivers/net/wireless/mwifiex/main.h | |||
@@ -0,0 +1,1058 @@ | |||
1 | /* | ||
2 | * Marvell Wireless LAN device driver: major data structures and prototypes | ||
3 | * | ||
4 | * Copyright (C) 2011, Marvell International Ltd. | ||
5 | * | ||
6 | * This software file (the "File") is distributed by Marvell International | ||
7 | * Ltd. under the terms of the GNU General Public License Version 2, June 1991 | ||
8 | * (the "License"). You may use, redistribute and/or modify this File in | ||
9 | * accordance with the terms and conditions of the License, a copy of which | ||
10 | * is available by writing to the Free Software Foundation, Inc., | ||
11 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the | ||
12 | * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. | ||
13 | * | ||
14 | * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE | ||
15 | * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE | ||
16 | * ARE EXPRESSLY DISCLAIMED. The License provides additional details about | ||
17 | * this warranty disclaimer. | ||
18 | */ | ||
19 | |||
20 | #ifndef _MWIFIEX_MAIN_H_ | ||
21 | #define _MWIFIEX_MAIN_H_ | ||
22 | |||
23 | #include <linux/kernel.h> | ||
24 | #include <linux/module.h> | ||
25 | #include <linux/sched.h> | ||
26 | #include <linux/semaphore.h> | ||
27 | #include <linux/ip.h> | ||
28 | #include <linux/skbuff.h> | ||
29 | #include <linux/if_arp.h> | ||
30 | #include <linux/etherdevice.h> | ||
31 | #include <net/sock.h> | ||
32 | #include <net/lib80211.h> | ||
33 | #include <linux/firmware.h> | ||
34 | #include <linux/ctype.h> | ||
35 | |||
36 | #include "decl.h" | ||
37 | #include "ioctl.h" | ||
38 | #include "util.h" | ||
39 | #include "fw.h" | ||
40 | |||
41 | extern const char driver_version[]; | ||
42 | extern struct mwifiex_adapter *g_adapter; | ||
43 | |||
44 | enum { | ||
45 | MWIFIEX_NO_WAIT, | ||
46 | MWIFIEX_IOCTL_WAIT, | ||
47 | MWIFIEX_CMD_WAIT, | ||
48 | MWIFIEX_PROC_WAIT, | ||
49 | MWIFIEX_WSTATS_WAIT | ||
50 | }; | ||
51 | |||
52 | #define DRV_MODE_STA 0x1 | ||
53 | |||
54 | #define SD8787_W0 0x30 | ||
55 | #define SD8787_W1 0x31 | ||
56 | #define SD8787_A0 0x40 | ||
57 | #define SD8787_A1 0x41 | ||
58 | |||
59 | #define DEFAULT_FW_NAME "mrvl/sd8787_uapsta.bin" | ||
60 | #define SD8787_W1_FW_NAME "mrvl/sd8787_uapsta_w1.bin" | ||
61 | #define SD8787_AX_FW_NAME "mrvl/sd8787_uapsta.bin" | ||
62 | |||
63 | struct mwifiex_drv_mode { | ||
64 | u16 drv_mode; | ||
65 | u16 intf_num; | ||
66 | struct mwifiex_bss_attr *bss_attr; | ||
67 | }; | ||
68 | |||
69 | |||
70 | #define MWIFIEX_DEFAULT_WATCHDOG_TIMEOUT (5 * HZ) | ||
71 | |||
72 | #define MWIFIEX_TIMER_10S 10000 | ||
73 | #define MWIFIEX_TIMER_1S 1000 | ||
74 | |||
75 | #define MAX_TX_PENDING 60 | ||
76 | |||
77 | #define MWIFIEX_UPLD_SIZE (2312) | ||
78 | |||
79 | #define MAX_EVENT_SIZE 1024 | ||
80 | |||
81 | #define ARP_FILTER_MAX_BUF_SIZE 68 | ||
82 | |||
83 | #define MWIFIEX_KEY_BUFFER_SIZE 16 | ||
84 | #define MWIFIEX_DEFAULT_LISTEN_INTERVAL 10 | ||
85 | #define MWIFIEX_MAX_REGION_CODE 7 | ||
86 | |||
87 | #define DEFAULT_BCN_AVG_FACTOR 8 | ||
88 | #define DEFAULT_DATA_AVG_FACTOR 8 | ||
89 | |||
90 | #define FIRST_VALID_CHANNEL 0xff | ||
91 | #define DEFAULT_AD_HOC_CHANNEL 6 | ||
92 | #define DEFAULT_AD_HOC_CHANNEL_A 36 | ||
93 | |||
94 | #define DEFAULT_BCN_MISS_TIMEOUT 5 | ||
95 | |||
96 | #define MAX_SCAN_BEACON_BUFFER 8000 | ||
97 | |||
98 | #define SCAN_BEACON_ENTRY_PAD 6 | ||
99 | |||
100 | #define MWIFIEX_PASSIVE_SCAN_CHAN_TIME 200 | ||
101 | #define MWIFIEX_ACTIVE_SCAN_CHAN_TIME 200 | ||
102 | #define MWIFIEX_SPECIFIC_SCAN_CHAN_TIME 110 | ||
103 | |||
104 | #define SCAN_RSSI(RSSI) (0x100 - ((u8)(RSSI))) | ||
105 | |||
106 | #define MWIFIEX_MAX_TOTAL_SCAN_TIME (MWIFIEX_TIMER_10S - MWIFIEX_TIMER_1S) | ||
107 | |||
108 | #define RSN_GTK_OUI_OFFSET 2 | ||
109 | |||
110 | #define MWIFIEX_OUI_NOT_PRESENT 0 | ||
111 | #define MWIFIEX_OUI_PRESENT 1 | ||
112 | |||
113 | #define IS_CARD_RX_RCVD(adapter) (adapter->cmd_resp_received || \ | ||
114 | adapter->event_received || \ | ||
115 | adapter->data_received) | ||
116 | |||
117 | #define MWIFIEX_TYPE_CMD 1 | ||
118 | #define MWIFIEX_TYPE_DATA 0 | ||
119 | #define MWIFIEX_TYPE_EVENT 3 | ||
120 | |||
121 | #define DBG_CMD_NUM 5 | ||
122 | |||
123 | #define MAX_BITMAP_RATES_SIZE 10 | ||
124 | |||
125 | #define MAX_CHANNEL_BAND_BG 14 | ||
126 | |||
127 | #define MAX_FREQUENCY_BAND_BG 2484 | ||
128 | |||
129 | struct mwifiex_dbg { | ||
130 | u32 num_cmd_host_to_card_failure; | ||
131 | u32 num_cmd_sleep_cfm_host_to_card_failure; | ||
132 | u32 num_tx_host_to_card_failure; | ||
133 | u32 num_event_deauth; | ||
134 | u32 num_event_disassoc; | ||
135 | u32 num_event_link_lost; | ||
136 | u32 num_cmd_deauth; | ||
137 | u32 num_cmd_assoc_success; | ||
138 | u32 num_cmd_assoc_failure; | ||
139 | u32 num_tx_timeout; | ||
140 | u32 num_cmd_timeout; | ||
141 | u16 timeout_cmd_id; | ||
142 | u16 timeout_cmd_act; | ||
143 | u16 last_cmd_id[DBG_CMD_NUM]; | ||
144 | u16 last_cmd_act[DBG_CMD_NUM]; | ||
145 | u16 last_cmd_index; | ||
146 | u16 last_cmd_resp_id[DBG_CMD_NUM]; | ||
147 | u16 last_cmd_resp_index; | ||
148 | u16 last_event[DBG_CMD_NUM]; | ||
149 | u16 last_event_index; | ||
150 | }; | ||
151 | |||
152 | enum MWIFIEX_HARDWARE_STATUS { | ||
153 | MWIFIEX_HW_STATUS_READY, | ||
154 | MWIFIEX_HW_STATUS_INITIALIZING, | ||
155 | MWIFIEX_HW_STATUS_FW_READY, | ||
156 | MWIFIEX_HW_STATUS_INIT_DONE, | ||
157 | MWIFIEX_HW_STATUS_RESET, | ||
158 | MWIFIEX_HW_STATUS_CLOSING, | ||
159 | MWIFIEX_HW_STATUS_NOT_READY | ||
160 | }; | ||
161 | |||
162 | enum MWIFIEX_802_11_POWER_MODE { | ||
163 | MWIFIEX_802_11_POWER_MODE_CAM, | ||
164 | MWIFIEX_802_11_POWER_MODE_PSP | ||
165 | }; | ||
166 | |||
167 | struct mwifiex_tx_param { | ||
168 | u32 next_pkt_len; | ||
169 | }; | ||
170 | |||
171 | enum MWIFIEX_PS_STATE { | ||
172 | PS_STATE_AWAKE, | ||
173 | PS_STATE_PRE_SLEEP, | ||
174 | PS_STATE_SLEEP_CFM, | ||
175 | PS_STATE_SLEEP | ||
176 | }; | ||
177 | |||
178 | struct mwifiex_add_ba_param { | ||
179 | u32 tx_win_size; | ||
180 | u32 rx_win_size; | ||
181 | u32 timeout; | ||
182 | }; | ||
183 | |||
184 | struct mwifiex_tx_aggr { | ||
185 | u8 ampdu_user; | ||
186 | u8 ampdu_ap; | ||
187 | u8 amsdu; | ||
188 | }; | ||
189 | |||
190 | struct mwifiex_ra_list_tbl { | ||
191 | struct list_head list; | ||
192 | struct sk_buff_head skb_head; | ||
193 | u8 ra[ETH_ALEN]; | ||
194 | u32 total_pkts_size; | ||
195 | u32 is_11n_enabled; | ||
196 | }; | ||
197 | |||
198 | struct mwifiex_tid_tbl { | ||
199 | struct list_head ra_list; | ||
200 | /* spin lock for tid table */ | ||
201 | spinlock_t tid_tbl_lock; | ||
202 | struct mwifiex_ra_list_tbl *ra_list_curr; | ||
203 | }; | ||
204 | |||
205 | #define WMM_HIGHEST_PRIORITY 7 | ||
206 | #define HIGH_PRIO_TID 7 | ||
207 | #define LOW_PRIO_TID 0 | ||
208 | |||
209 | struct mwifiex_wmm_desc { | ||
210 | struct mwifiex_tid_tbl tid_tbl_ptr[MAX_NUM_TID]; | ||
211 | u32 packets_out[MAX_NUM_TID]; | ||
212 | /* spin lock to protect ra_list */ | ||
213 | spinlock_t ra_list_spinlock; | ||
214 | struct mwifiex_wmm_ac_status ac_status[IEEE80211_MAX_QUEUES]; | ||
215 | enum mwifiex_wmm_ac_e ac_down_graded_vals[IEEE80211_MAX_QUEUES]; | ||
216 | u32 drv_pkt_delay_max; | ||
217 | u8 queue_priority[IEEE80211_MAX_QUEUES]; | ||
218 | u32 user_pri_pkt_tx_ctrl[WMM_HIGHEST_PRIORITY + 1]; /* UP: 0 to 7 */ | ||
219 | |||
220 | }; | ||
221 | |||
222 | struct mwifiex_802_11_security { | ||
223 | u8 wpa_enabled; | ||
224 | u8 wpa2_enabled; | ||
225 | u8 wapi_enabled; | ||
226 | u8 wapi_key_on; | ||
227 | enum MWIFIEX_802_11_WEP_STATUS wep_status; | ||
228 | u32 authentication_mode; | ||
229 | u32 encryption_mode; | ||
230 | }; | ||
231 | |||
232 | struct ieee_types_header { | ||
233 | u8 element_id; | ||
234 | u8 len; | ||
235 | } __packed; | ||
236 | |||
237 | struct ieee_obss_scan_param { | ||
238 | u16 obss_scan_passive_dwell; | ||
239 | u16 obss_scan_active_dwell; | ||
240 | u16 bss_chan_width_trigger_scan_int; | ||
241 | u16 obss_scan_passive_total; | ||
242 | u16 obss_scan_active_total; | ||
243 | u16 bss_width_chan_trans_delay; | ||
244 | u16 obss_scan_active_threshold; | ||
245 | } __packed; | ||
246 | |||
247 | struct ieee_types_obss_scan_param { | ||
248 | struct ieee_types_header ieee_hdr; | ||
249 | struct ieee_obss_scan_param obss_scan; | ||
250 | } __packed; | ||
251 | |||
252 | #define MWIFIEX_SUPPORTED_RATES 14 | ||
253 | |||
254 | #define MWIFIEX_SUPPORTED_RATES_EXT 32 | ||
255 | |||
256 | #define IEEE_MAX_IE_SIZE 256 | ||
257 | |||
258 | struct ieee_types_vendor_specific { | ||
259 | struct ieee_types_vendor_header vend_hdr; | ||
260 | u8 data[IEEE_MAX_IE_SIZE - sizeof(struct ieee_types_vendor_header)]; | ||
261 | } __packed; | ||
262 | |||
263 | struct ieee_types_generic { | ||
264 | struct ieee_types_header ieee_hdr; | ||
265 | u8 data[IEEE_MAX_IE_SIZE - sizeof(struct ieee_types_header)]; | ||
266 | } __packed; | ||
267 | |||
268 | struct mwifiex_bssdescriptor { | ||
269 | u8 mac_address[ETH_ALEN]; | ||
270 | struct mwifiex_802_11_ssid ssid; | ||
271 | u32 privacy; | ||
272 | s32 rssi; | ||
273 | u32 channel; | ||
274 | u32 freq; | ||
275 | u16 beacon_period; | ||
276 | u8 erp_flags; | ||
277 | u32 bss_mode; | ||
278 | u8 supported_rates[MWIFIEX_SUPPORTED_RATES]; | ||
279 | u8 data_rates[MWIFIEX_SUPPORTED_RATES]; | ||
280 | /* Network band. | ||
281 | * BAND_B(0x01): 'b' band | ||
282 | * BAND_G(0x02): 'g' band | ||
283 | * BAND_A(0X04): 'a' band | ||
284 | */ | ||
285 | u16 bss_band; | ||
286 | long long network_tsf; | ||
287 | u8 time_stamp[8]; | ||
288 | union ieee_types_phy_param_set phy_param_set; | ||
289 | union ieee_types_ss_param_set ss_param_set; | ||
290 | u16 cap_info_bitmap; | ||
291 | struct ieee_types_wmm_parameter wmm_ie; | ||
292 | u8 disable_11n; | ||
293 | struct ieee80211_ht_cap *bcn_ht_cap; | ||
294 | u16 ht_cap_offset; | ||
295 | struct ieee80211_ht_info *bcn_ht_info; | ||
296 | u16 ht_info_offset; | ||
297 | u8 *bcn_bss_co_2040; | ||
298 | u16 bss_co_2040_offset; | ||
299 | u8 *bcn_ext_cap; | ||
300 | u16 ext_cap_offset; | ||
301 | struct ieee_types_obss_scan_param *bcn_obss_scan; | ||
302 | u16 overlap_bss_offset; | ||
303 | struct ieee_types_vendor_specific *bcn_wpa_ie; | ||
304 | u16 wpa_offset; | ||
305 | struct ieee_types_generic *bcn_rsn_ie; | ||
306 | u16 rsn_offset; | ||
307 | struct ieee_types_generic *bcn_wapi_ie; | ||
308 | u16 wapi_offset; | ||
309 | u8 *beacon_buf; | ||
310 | u32 beacon_buf_size; | ||
311 | u32 beacon_buf_size_max; | ||
312 | |||
313 | }; | ||
314 | |||
315 | struct mwifiex_current_bss_params { | ||
316 | struct mwifiex_bssdescriptor bss_descriptor; | ||
317 | u8 wmm_enabled; | ||
318 | u8 wmm_uapsd_enabled; | ||
319 | u8 band; | ||
320 | u32 num_of_rates; | ||
321 | u8 data_rates[MWIFIEX_SUPPORTED_RATES]; | ||
322 | }; | ||
323 | |||
324 | struct mwifiex_sleep_params { | ||
325 | u16 sp_error; | ||
326 | u16 sp_offset; | ||
327 | u16 sp_stable_time; | ||
328 | u8 sp_cal_control; | ||
329 | u8 sp_ext_sleep_clk; | ||
330 | u16 sp_reserved; | ||
331 | }; | ||
332 | |||
333 | struct mwifiex_sleep_period { | ||
334 | u16 period; | ||
335 | u16 reserved; | ||
336 | }; | ||
337 | |||
338 | struct mwifiex_wep_key { | ||
339 | u32 length; | ||
340 | u32 key_index; | ||
341 | u32 key_length; | ||
342 | u8 key_material[MWIFIEX_KEY_BUFFER_SIZE]; | ||
343 | }; | ||
344 | |||
345 | #define MAX_REGION_CHANNEL_NUM 2 | ||
346 | |||
347 | struct mwifiex_chan_freq_power { | ||
348 | u16 channel; | ||
349 | u32 freq; | ||
350 | u16 max_tx_power; | ||
351 | u8 unsupported; | ||
352 | }; | ||
353 | |||
354 | enum state_11d_t { | ||
355 | DISABLE_11D = 0, | ||
356 | ENABLE_11D = 1, | ||
357 | }; | ||
358 | |||
359 | #define MWIFIEX_MAX_TRIPLET_802_11D 83 | ||
360 | |||
361 | struct mwifiex_802_11d_domain_reg { | ||
362 | u8 country_code[IEEE80211_COUNTRY_STRING_LEN]; | ||
363 | u8 no_of_triplet; | ||
364 | struct ieee80211_country_ie_triplet | ||
365 | triplet[MWIFIEX_MAX_TRIPLET_802_11D]; | ||
366 | }; | ||
367 | |||
368 | struct mwifiex_vendor_spec_cfg_ie { | ||
369 | u16 mask; | ||
370 | u16 flag; | ||
371 | u8 ie[MWIFIEX_MAX_VSIE_LEN]; | ||
372 | }; | ||
373 | |||
374 | struct wps { | ||
375 | u8 session_enable; | ||
376 | }; | ||
377 | |||
378 | struct mwifiex_adapter; | ||
379 | struct mwifiex_private; | ||
380 | |||
381 | struct mwifiex_private { | ||
382 | struct mwifiex_adapter *adapter; | ||
383 | u8 bss_index; | ||
384 | u8 bss_type; | ||
385 | u8 bss_role; | ||
386 | u8 bss_priority; | ||
387 | u8 bss_num; | ||
388 | u8 frame_type; | ||
389 | u8 curr_addr[ETH_ALEN]; | ||
390 | u8 media_connected; | ||
391 | u32 num_tx_timeout; | ||
392 | struct net_device *netdev; | ||
393 | struct net_device_stats stats; | ||
394 | u16 curr_pkt_filter; | ||
395 | u32 bss_mode; | ||
396 | u32 pkt_tx_ctrl; | ||
397 | u16 tx_power_level; | ||
398 | u8 max_tx_power_level; | ||
399 | u8 min_tx_power_level; | ||
400 | u8 tx_rate; | ||
401 | u8 tx_htinfo; | ||
402 | u8 rxpd_htinfo; | ||
403 | u8 rxpd_rate; | ||
404 | u16 rate_bitmap; | ||
405 | u16 bitmap_rates[MAX_BITMAP_RATES_SIZE]; | ||
406 | u32 data_rate; | ||
407 | u8 is_data_rate_auto; | ||
408 | u16 bcn_avg_factor; | ||
409 | u16 data_avg_factor; | ||
410 | s16 data_rssi_last; | ||
411 | s16 data_nf_last; | ||
412 | s16 data_rssi_avg; | ||
413 | s16 data_nf_avg; | ||
414 | s16 bcn_rssi_last; | ||
415 | s16 bcn_nf_last; | ||
416 | s16 bcn_rssi_avg; | ||
417 | s16 bcn_nf_avg; | ||
418 | struct mwifiex_bssdescriptor *attempted_bss_desc; | ||
419 | struct mwifiex_802_11_ssid prev_ssid; | ||
420 | u8 prev_bssid[ETH_ALEN]; | ||
421 | struct mwifiex_current_bss_params curr_bss_params; | ||
422 | u16 beacon_period; | ||
423 | u16 listen_interval; | ||
424 | u16 atim_window; | ||
425 | u8 adhoc_channel; | ||
426 | u8 adhoc_is_link_sensed; | ||
427 | u8 adhoc_state; | ||
428 | struct mwifiex_802_11_security sec_info; | ||
429 | struct mwifiex_wep_key wep_key[NUM_WEP_KEYS]; | ||
430 | u16 wep_key_curr_index; | ||
431 | u8 wpa_ie[256]; | ||
432 | u8 wpa_ie_len; | ||
433 | u8 wpa_is_gtk_set; | ||
434 | struct host_cmd_ds_802_11_key_material aes_key; | ||
435 | u8 wapi_ie[256]; | ||
436 | u8 wapi_ie_len; | ||
437 | u8 wmm_required; | ||
438 | u8 wmm_enabled; | ||
439 | u8 wmm_qosinfo; | ||
440 | struct mwifiex_wmm_desc wmm; | ||
441 | struct list_head tx_ba_stream_tbl_ptr; | ||
442 | /* spin lock for tx_ba_stream_tbl_ptr queue */ | ||
443 | spinlock_t tx_ba_stream_tbl_lock; | ||
444 | struct mwifiex_tx_aggr aggr_prio_tbl[MAX_NUM_TID]; | ||
445 | struct mwifiex_add_ba_param add_ba_param; | ||
446 | u16 rx_seq[MAX_NUM_TID]; | ||
447 | struct list_head rx_reorder_tbl_ptr; | ||
448 | /* spin lock for rx_reorder_tbl_ptr queue */ | ||
449 | spinlock_t rx_reorder_tbl_lock; | ||
450 | /* spin lock for Rx packets */ | ||
451 | spinlock_t rx_pkt_lock; | ||
452 | |||
453 | #define MWIFIEX_ASSOC_RSP_BUF_SIZE 500 | ||
454 | u8 assoc_rsp_buf[MWIFIEX_ASSOC_RSP_BUF_SIZE]; | ||
455 | u32 assoc_rsp_size; | ||
456 | |||
457 | #define MWIFIEX_GENIE_BUF_SIZE 256 | ||
458 | u8 gen_ie_buf[MWIFIEX_GENIE_BUF_SIZE]; | ||
459 | u8 gen_ie_buf_len; | ||
460 | |||
461 | struct mwifiex_vendor_spec_cfg_ie vs_ie[MWIFIEX_MAX_VSIE_NUM]; | ||
462 | |||
463 | #define MWIFIEX_ASSOC_TLV_BUF_SIZE 256 | ||
464 | u8 assoc_tlv_buf[MWIFIEX_ASSOC_TLV_BUF_SIZE]; | ||
465 | u8 assoc_tlv_buf_len; | ||
466 | |||
467 | u8 *curr_bcn_buf; | ||
468 | u32 curr_bcn_size; | ||
469 | /* spin lock for beacon buffer */ | ||
470 | spinlock_t curr_bcn_buf_lock; | ||
471 | u16 ioctl_wait_q_woken; | ||
472 | wait_queue_head_t ioctl_wait_q; | ||
473 | u16 cmd_wait_q_woken; | ||
474 | wait_queue_head_t cmd_wait_q; | ||
475 | struct wireless_dev *wdev; | ||
476 | struct mwifiex_chan_freq_power cfp; | ||
477 | char version_str[128]; | ||
478 | #ifdef CONFIG_DEBUG_FS | ||
479 | struct dentry *dfs_dev_dir; | ||
480 | #endif | ||
481 | u8 nick_name[16]; | ||
482 | struct iw_statistics w_stats; | ||
483 | u16 w_stats_wait_q_woken; | ||
484 | wait_queue_head_t w_stats_wait_q; | ||
485 | u16 current_key_index; | ||
486 | struct semaphore async_sem; | ||
487 | u8 scan_pending_on_block; | ||
488 | u8 report_scan_result; | ||
489 | struct cfg80211_scan_request *scan_request; | ||
490 | int scan_result_status; | ||
491 | bool assoc_request; | ||
492 | u16 assoc_result; | ||
493 | bool ibss_join_request; | ||
494 | u16 ibss_join_result; | ||
495 | bool disconnect; | ||
496 | u8 cfg_bssid[6]; | ||
497 | struct workqueue_struct *workqueue; | ||
498 | struct work_struct cfg_workqueue; | ||
499 | u8 country_code[IEEE80211_COUNTRY_STRING_LEN]; | ||
500 | struct wps wps; | ||
501 | u8 scan_block; | ||
502 | }; | ||
503 | |||
504 | enum mwifiex_ba_status { | ||
505 | BA_STREAM_NOT_SETUP = 0, | ||
506 | BA_STREAM_SETUP_INPROGRESS, | ||
507 | BA_STREAM_SETUP_COMPLETE | ||
508 | }; | ||
509 | |||
510 | struct mwifiex_tx_ba_stream_tbl { | ||
511 | struct list_head list; | ||
512 | int tid; | ||
513 | u8 ra[ETH_ALEN]; | ||
514 | enum mwifiex_ba_status ba_status; | ||
515 | }; | ||
516 | |||
517 | struct mwifiex_rx_reorder_tbl; | ||
518 | |||
519 | struct reorder_tmr_cnxt { | ||
520 | struct timer_list timer; | ||
521 | struct mwifiex_rx_reorder_tbl *ptr; | ||
522 | struct mwifiex_private *priv; | ||
523 | }; | ||
524 | |||
525 | struct mwifiex_rx_reorder_tbl { | ||
526 | struct list_head list; | ||
527 | int tid; | ||
528 | u8 ta[ETH_ALEN]; | ||
529 | int start_win; | ||
530 | int win_size; | ||
531 | void **rx_reorder_ptr; | ||
532 | struct reorder_tmr_cnxt timer_context; | ||
533 | }; | ||
534 | |||
535 | struct mwifiex_bss_prio_node { | ||
536 | struct list_head list; | ||
537 | struct mwifiex_private *priv; | ||
538 | }; | ||
539 | |||
540 | struct mwifiex_bss_prio_tbl { | ||
541 | struct list_head bss_prio_head; | ||
542 | /* spin lock for bss priority */ | ||
543 | spinlock_t bss_prio_lock; | ||
544 | struct mwifiex_bss_prio_node *bss_prio_cur; | ||
545 | }; | ||
546 | |||
547 | struct cmd_ctrl_node { | ||
548 | struct list_head list; | ||
549 | struct mwifiex_private *priv; | ||
550 | u32 cmd_oid; | ||
551 | u32 cmd_flag; | ||
552 | struct sk_buff *cmd_skb; | ||
553 | struct sk_buff *resp_skb; | ||
554 | void *data_buf; | ||
555 | void *wq_buf; | ||
556 | struct sk_buff *skb; | ||
557 | }; | ||
558 | |||
559 | struct mwifiex_if_ops { | ||
560 | int (*init_if) (struct mwifiex_adapter *); | ||
561 | void (*cleanup_if) (struct mwifiex_adapter *); | ||
562 | int (*check_fw_status) (struct mwifiex_adapter *, u32, int *); | ||
563 | int (*prog_fw) (struct mwifiex_adapter *, struct mwifiex_fw_image *); | ||
564 | int (*register_dev) (struct mwifiex_adapter *); | ||
565 | void (*unregister_dev) (struct mwifiex_adapter *); | ||
566 | int (*enable_int) (struct mwifiex_adapter *); | ||
567 | int (*process_int_status) (struct mwifiex_adapter *); | ||
568 | int (*host_to_card) (struct mwifiex_adapter *, u8, | ||
569 | u8 *payload, u32 pkt_len, | ||
570 | struct mwifiex_tx_param *); | ||
571 | int (*wakeup) (struct mwifiex_adapter *); | ||
572 | int (*wakeup_complete) (struct mwifiex_adapter *); | ||
573 | |||
574 | void (*update_mp_end_port) (struct mwifiex_adapter *, u16); | ||
575 | void (*cleanup_mpa_buf) (struct mwifiex_adapter *); | ||
576 | }; | ||
577 | |||
578 | struct mwifiex_adapter { | ||
579 | struct mwifiex_private *priv[MWIFIEX_MAX_BSS_NUM]; | ||
580 | u8 priv_num; | ||
581 | struct mwifiex_drv_mode *drv_mode; | ||
582 | const struct firmware *firmware; | ||
583 | struct device *dev; | ||
584 | bool surprise_removed; | ||
585 | u32 fw_release_number; | ||
586 | u32 revision_id; | ||
587 | u16 init_wait_q_woken; | ||
588 | wait_queue_head_t init_wait_q; | ||
589 | void *card; | ||
590 | struct mwifiex_if_ops if_ops; | ||
591 | atomic_t rx_pending; | ||
592 | atomic_t tx_pending; | ||
593 | atomic_t ioctl_pending; | ||
594 | struct workqueue_struct *workqueue; | ||
595 | struct work_struct main_work; | ||
596 | struct mwifiex_bss_prio_tbl bss_prio_tbl[MWIFIEX_MAX_BSS_NUM]; | ||
597 | /* spin lock for init/shutdown */ | ||
598 | spinlock_t mwifiex_lock; | ||
599 | /* spin lock for main process */ | ||
600 | spinlock_t main_proc_lock; | ||
601 | u32 mwifiex_processing; | ||
602 | u16 max_tx_buf_size; | ||
603 | u16 tx_buf_size; | ||
604 | u16 curr_tx_buf_size; | ||
605 | u32 ioport; | ||
606 | enum MWIFIEX_HARDWARE_STATUS hw_status; | ||
607 | u16 number_of_antenna; | ||
608 | u32 fw_cap_info; | ||
609 | /* spin lock for interrupt handling */ | ||
610 | spinlock_t int_lock; | ||
611 | u8 int_status; | ||
612 | u32 event_cause; | ||
613 | struct sk_buff *event_skb; | ||
614 | u8 upld_buf[MWIFIEX_UPLD_SIZE]; | ||
615 | u8 data_sent; | ||
616 | u8 cmd_sent; | ||
617 | u8 cmd_resp_received; | ||
618 | u8 event_received; | ||
619 | u8 data_received; | ||
620 | u16 seq_num; | ||
621 | struct cmd_ctrl_node *cmd_pool; | ||
622 | struct cmd_ctrl_node *curr_cmd; | ||
623 | /* spin lock for command */ | ||
624 | spinlock_t mwifiex_cmd_lock; | ||
625 | u32 num_cmd_timeout; | ||
626 | u16 last_init_cmd; | ||
627 | struct timer_list cmd_timer; | ||
628 | struct list_head cmd_free_q; | ||
629 | /* spin lock for cmd_free_q */ | ||
630 | spinlock_t cmd_free_q_lock; | ||
631 | struct list_head cmd_pending_q; | ||
632 | /* spin lock for cmd_pending_q */ | ||
633 | spinlock_t cmd_pending_q_lock; | ||
634 | struct list_head scan_pending_q; | ||
635 | /* spin lock for scan_pending_q */ | ||
636 | spinlock_t scan_pending_q_lock; | ||
637 | u32 scan_processing; | ||
638 | u16 region_code; | ||
639 | struct mwifiex_802_11d_domain_reg domain_reg; | ||
640 | struct mwifiex_bssdescriptor *scan_table; | ||
641 | u32 num_in_scan_table; | ||
642 | u16 scan_probes; | ||
643 | u32 scan_mode; | ||
644 | u16 specific_scan_time; | ||
645 | u16 active_scan_time; | ||
646 | u16 passive_scan_time; | ||
647 | u8 bcn_buf[MAX_SCAN_BEACON_BUFFER]; | ||
648 | u8 *bcn_buf_end; | ||
649 | u8 fw_bands; | ||
650 | u8 adhoc_start_band; | ||
651 | u8 config_bands; | ||
652 | struct mwifiex_chan_scan_param_set *scan_channels; | ||
653 | u8 tx_lock_flag; | ||
654 | struct mwifiex_sleep_params sleep_params; | ||
655 | struct mwifiex_sleep_period sleep_period; | ||
656 | u16 ps_mode; | ||
657 | u32 ps_state; | ||
658 | u8 need_to_wakeup; | ||
659 | u16 multiple_dtim; | ||
660 | u16 local_listen_interval; | ||
661 | u16 null_pkt_interval; | ||
662 | struct sk_buff *sleep_cfm; | ||
663 | u16 bcn_miss_time_out; | ||
664 | u16 adhoc_awake_period; | ||
665 | u8 is_deep_sleep; | ||
666 | u8 delay_null_pkt; | ||
667 | u16 delay_to_ps; | ||
668 | u16 enhanced_ps_mode; | ||
669 | u8 pm_wakeup_card_req; | ||
670 | u16 gen_null_pkt; | ||
671 | u16 pps_uapsd_mode; | ||
672 | u32 pm_wakeup_fw_try; | ||
673 | u8 is_hs_configured; | ||
674 | struct mwifiex_hs_config_param hs_cfg; | ||
675 | u8 hs_activated; | ||
676 | u16 hs_activate_wait_q_woken; | ||
677 | wait_queue_head_t hs_activate_wait_q; | ||
678 | bool is_suspended; | ||
679 | u8 event_body[MAX_EVENT_SIZE]; | ||
680 | u32 hw_dot_11n_dev_cap; | ||
681 | u8 hw_dev_mcs_support; | ||
682 | u8 adhoc_11n_enabled; | ||
683 | u8 chan_offset; | ||
684 | struct mwifiex_dbg dbg; | ||
685 | u8 arp_filter[ARP_FILTER_MAX_BUF_SIZE]; | ||
686 | u32 arp_filter_size; | ||
687 | }; | ||
688 | |||
689 | int mwifiex_init_lock_list(struct mwifiex_adapter *adapter); | ||
690 | void mwifiex_free_lock_list(struct mwifiex_adapter *adapter); | ||
691 | |||
692 | int mwifiex_init_fw(struct mwifiex_adapter *adapter); | ||
693 | |||
694 | int mwifiex_init_fw_complete(struct mwifiex_adapter *adapter); | ||
695 | |||
696 | int mwifiex_shutdown_drv(struct mwifiex_adapter *adapter); | ||
697 | |||
698 | int mwifiex_shutdown_fw_complete(struct mwifiex_adapter *adapter); | ||
699 | |||
700 | int mwifiex_dnld_fw(struct mwifiex_adapter *, struct mwifiex_fw_image *); | ||
701 | |||
702 | int mwifiex_recv_complete(struct mwifiex_adapter *, | ||
703 | struct sk_buff *skb, | ||
704 | int status); | ||
705 | |||
706 | int mwifiex_recv_packet(struct mwifiex_adapter *, struct sk_buff *skb); | ||
707 | |||
708 | int mwifiex_process_event(struct mwifiex_adapter *adapter); | ||
709 | |||
710 | int mwifiex_ioctl_complete(struct mwifiex_adapter *adapter, | ||
711 | struct mwifiex_wait_queue *ioctl_wq, | ||
712 | int status); | ||
713 | |||
714 | int mwifiex_prepare_cmd(struct mwifiex_private *priv, | ||
715 | uint16_t cmd_no, | ||
716 | u16 cmd_action, | ||
717 | u32 cmd_oid, | ||
718 | void *wait_queue, void *data_buf); | ||
719 | |||
720 | void mwifiex_cmd_timeout_func(unsigned long function_context); | ||
721 | |||
722 | int mwifiex_misc_ioctl_init_shutdown(struct mwifiex_adapter *adapter, | ||
723 | struct mwifiex_wait_queue *wait_queue, | ||
724 | u32 func_init_shutdown); | ||
725 | int mwifiex_get_debug_info(struct mwifiex_private *, | ||
726 | struct mwifiex_debug_info *); | ||
727 | |||
728 | int mwifiex_alloc_cmd_buffer(struct mwifiex_adapter *adapter); | ||
729 | int mwifiex_free_cmd_buffer(struct mwifiex_adapter *adapter); | ||
730 | void mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter); | ||
731 | void mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter, | ||
732 | struct mwifiex_wait_queue *ioctl_wq); | ||
733 | |||
734 | void mwifiex_insert_cmd_to_free_q(struct mwifiex_adapter *adapter, | ||
735 | struct cmd_ctrl_node *cmd_node); | ||
736 | |||
737 | void mwifiex_insert_cmd_to_pending_q(struct mwifiex_adapter *adapter, | ||
738 | struct cmd_ctrl_node *cmd_node, | ||
739 | u32 addtail); | ||
740 | |||
741 | int mwifiex_exec_next_cmd(struct mwifiex_adapter *adapter); | ||
742 | int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter); | ||
743 | int mwifiex_handle_rx_packet(struct mwifiex_adapter *adapter, | ||
744 | struct sk_buff *skb); | ||
745 | int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb, | ||
746 | struct mwifiex_tx_param *tx_param); | ||
747 | int mwifiex_send_null_packet(struct mwifiex_private *priv, u8 flags); | ||
748 | int mwifiex_write_data_complete(struct mwifiex_adapter *adapter, | ||
749 | struct sk_buff *skb, int status); | ||
750 | int mwifiex_recv_packet_complete(struct mwifiex_adapter *, | ||
751 | struct sk_buff *skb, int status); | ||
752 | void mwifiex_clean_txrx(struct mwifiex_private *priv); | ||
753 | u8 mwifiex_check_last_packet_indication(struct mwifiex_private *priv); | ||
754 | void mwifiex_check_ps_cond(struct mwifiex_adapter *adapter); | ||
755 | void mwifiex_process_sleep_confirm_resp(struct mwifiex_adapter *, u8 *, | ||
756 | u32); | ||
757 | int mwifiex_cmd_enh_power_mode(struct mwifiex_private *priv, | ||
758 | struct host_cmd_ds_command *cmd, | ||
759 | u16 cmd_action, uint16_t ps_bitmap, | ||
760 | void *data_buf); | ||
761 | int mwifiex_ret_enh_power_mode(struct mwifiex_private *priv, | ||
762 | struct host_cmd_ds_command *resp, | ||
763 | void *data_buf); | ||
764 | void mwifiex_process_hs_config(struct mwifiex_adapter *adapter); | ||
765 | void mwifiex_hs_activated_event(struct mwifiex_private *priv, | ||
766 | u8 activated); | ||
767 | int mwifiex_ret_802_11_hs_cfg(struct mwifiex_private *priv, | ||
768 | struct host_cmd_ds_command *resp); | ||
769 | int mwifiex_process_rx_packet(struct mwifiex_adapter *adapter, | ||
770 | struct sk_buff *skb); | ||
771 | int mwifiex_sta_prepare_cmd(struct mwifiex_private *, uint16_t cmd_no, | ||
772 | u16 cmd_action, u32 cmd_oid, | ||
773 | void *data_buf, void *cmd_buf); | ||
774 | int mwifiex_process_sta_cmdresp(struct mwifiex_private *, u16 cmdresp_no, | ||
775 | void *cmd_buf, void *ioctl); | ||
776 | int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *, | ||
777 | struct sk_buff *skb); | ||
778 | int mwifiex_process_sta_event(struct mwifiex_private *); | ||
779 | void *mwifiex_process_sta_txpd(struct mwifiex_private *, struct sk_buff *skb); | ||
780 | int mwifiex_sta_init_cmd(struct mwifiex_private *, u8 first_sta); | ||
781 | int mwifiex_scan_networks(struct mwifiex_private *priv, void *wait_queue, | ||
782 | u16 action, | ||
783 | const struct mwifiex_user_scan_cfg | ||
784 | *user_scan_in, struct mwifiex_scan_resp *); | ||
785 | int mwifiex_cmd_802_11_scan(struct mwifiex_private *priv, | ||
786 | struct host_cmd_ds_command *cmd, | ||
787 | void *data_buf); | ||
788 | void mwifiex_queue_scan_cmd(struct mwifiex_private *priv, | ||
789 | struct cmd_ctrl_node *cmd_node); | ||
790 | int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, | ||
791 | struct host_cmd_ds_command *resp, | ||
792 | void *wait_queue); | ||
793 | s32 mwifiex_find_ssid_in_list(struct mwifiex_private *priv, | ||
794 | struct mwifiex_802_11_ssid *ssid, u8 *bssid, | ||
795 | u32 mode); | ||
796 | s32 mwifiex_find_bssid_in_list(struct mwifiex_private *priv, u8 *bssid, | ||
797 | u32 mode); | ||
798 | int mwifiex_find_best_network(struct mwifiex_private *priv, | ||
799 | struct mwifiex_ssid_bssid *req_ssid_bssid); | ||
800 | s32 mwifiex_ssid_cmp(struct mwifiex_802_11_ssid *ssid1, | ||
801 | struct mwifiex_802_11_ssid *ssid2); | ||
802 | int mwifiex_associate(struct mwifiex_private *priv, void *wait_queue, | ||
803 | struct mwifiex_bssdescriptor *bss_desc); | ||
804 | int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv, | ||
805 | struct host_cmd_ds_command | ||
806 | *cmd, void *data_buf); | ||
807 | int mwifiex_ret_802_11_associate(struct mwifiex_private *priv, | ||
808 | struct host_cmd_ds_command *resp, | ||
809 | void *wait_queue); | ||
810 | void mwifiex_reset_connect_state(struct mwifiex_private *priv); | ||
811 | void mwifiex_2040_coex_event(struct mwifiex_private *priv); | ||
812 | u8 mwifiex_band_to_radio_type(u8 band); | ||
813 | int mwifiex_deauthenticate(struct mwifiex_private *priv, | ||
814 | struct mwifiex_wait_queue *wait_queue, | ||
815 | u8 *mac); | ||
816 | int mwifiex_adhoc_start(struct mwifiex_private *priv, void *wait_queue, | ||
817 | struct mwifiex_802_11_ssid *adhoc_ssid); | ||
818 | int mwifiex_adhoc_join(struct mwifiex_private *priv, void *wait_queue, | ||
819 | struct mwifiex_bssdescriptor *bss_desc); | ||
820 | int mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv, | ||
821 | struct host_cmd_ds_command *cmd, | ||
822 | void *data_buf); | ||
823 | int mwifiex_cmd_802_11_ad_hoc_join(struct mwifiex_private *priv, | ||
824 | struct host_cmd_ds_command *cmd, | ||
825 | void *data_buf); | ||
826 | int mwifiex_ret_802_11_ad_hoc(struct mwifiex_private *priv, | ||
827 | struct host_cmd_ds_command *resp, | ||
828 | void *wait_queue); | ||
829 | int mwifiex_cmd_802_11_bg_scan_query(struct mwifiex_private *priv, | ||
830 | struct host_cmd_ds_command *cmd, | ||
831 | void *data_buf); | ||
832 | struct mwifiex_chan_freq_power * | ||
833 | mwifiex_get_cfp_by_band_and_channel_from_cfg80211( | ||
834 | struct mwifiex_private *priv, | ||
835 | u8 band, u16 channel); | ||
836 | struct mwifiex_chan_freq_power *mwifiex_get_cfp_by_band_and_freq_from_cfg80211( | ||
837 | struct mwifiex_private *priv, | ||
838 | u8 band, u32 freq); | ||
839 | u32 mwifiex_index_to_data_rate(struct mwifiex_adapter *adapter, u8 index, | ||
840 | u8 ht_info); | ||
841 | u32 mwifiex_find_freq_from_band_chan(u8, u8); | ||
842 | int mwifiex_cmd_append_vsie_tlv(struct mwifiex_private *priv, u16 vsie_mask, | ||
843 | u8 **buffer); | ||
844 | u32 mwifiex_index_to_data_rate(struct mwifiex_adapter *adapter, u8 index, | ||
845 | u8 ht_info); | ||
846 | u32 mwifiex_get_active_data_rates(struct mwifiex_private *priv, | ||
847 | u8 *rates); | ||
848 | u32 mwifiex_get_supported_rates(struct mwifiex_private *priv, u8 *rates); | ||
849 | u8 mwifiex_data_rate_to_index(struct mwifiex_adapter *adapter, u32 rate); | ||
850 | u8 mwifiex_is_rate_auto(struct mwifiex_private *priv); | ||
851 | int mwifiex_get_rate_index(struct mwifiex_adapter *adapter, | ||
852 | u16 *rateBitmap, int size); | ||
853 | extern u16 region_code_index[MWIFIEX_MAX_REGION_CODE]; | ||
854 | void mwifiex_save_curr_bcn(struct mwifiex_private *priv); | ||
855 | void mwifiex_free_curr_bcn(struct mwifiex_private *priv); | ||
856 | int mwifiex_cmd_get_hw_spec(struct mwifiex_private *priv, | ||
857 | struct host_cmd_ds_command *cmd); | ||
858 | int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv, | ||
859 | struct host_cmd_ds_command *resp); | ||
860 | int is_command_pending(struct mwifiex_adapter *adapter); | ||
861 | |||
862 | /* | ||
863 | * This function checks if the queuing is RA based or not. | ||
864 | */ | ||
865 | static inline u8 | ||
866 | mwifiex_queuing_ra_based(struct mwifiex_private *priv) | ||
867 | { | ||
868 | /* | ||
869 | * Currently we assume if we are in Infra, then DA=RA. This might not be | ||
870 | * true in the future | ||
871 | */ | ||
872 | if ((priv->bss_mode == NL80211_IFTYPE_STATION) && | ||
873 | (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA)) | ||
874 | return false; | ||
875 | |||
876 | return true; | ||
877 | } | ||
878 | |||
879 | /* | ||
880 | * This function copies rates. | ||
881 | */ | ||
882 | static inline u32 | ||
883 | mwifiex_copy_rates(u8 *dest, u32 pos, u8 *src, int len) | ||
884 | { | ||
885 | int i; | ||
886 | |||
887 | for (i = 0; i < len && src[i]; i++, pos++) { | ||
888 | if (pos >= MWIFIEX_SUPPORTED_RATES) | ||
889 | break; | ||
890 | dest[pos] = src[i]; | ||
891 | } | ||
892 | |||
893 | return pos; | ||
894 | } | ||
895 | |||
896 | /* | ||
897 | * This function returns the correct private structure pointer based | ||
898 | * upon the BSS type and BSS number. | ||
899 | */ | ||
900 | static inline struct mwifiex_private * | ||
901 | mwifiex_get_priv_by_id(struct mwifiex_adapter *adapter, | ||
902 | u32 bss_num, u32 bss_type) | ||
903 | { | ||
904 | int i; | ||
905 | |||
906 | for (i = 0; i < adapter->priv_num; i++) { | ||
907 | if (adapter->priv[i]) { | ||
908 | if ((adapter->priv[i]->bss_num == bss_num) | ||
909 | && (adapter->priv[i]->bss_type == bss_type)) | ||
910 | break; | ||
911 | } | ||
912 | } | ||
913 | return ((i < adapter->priv_num) ? adapter->priv[i] : NULL); | ||
914 | } | ||
915 | |||
916 | /* | ||
917 | * This function returns the first available private structure pointer | ||
918 | * based upon the BSS role. | ||
919 | */ | ||
920 | static inline struct mwifiex_private * | ||
921 | mwifiex_get_priv(struct mwifiex_adapter *adapter, | ||
922 | enum mwifiex_bss_role bss_role) | ||
923 | { | ||
924 | int i; | ||
925 | |||
926 | for (i = 0; i < adapter->priv_num; i++) { | ||
927 | if (adapter->priv[i]) { | ||
928 | if (bss_role == MWIFIEX_BSS_ROLE_ANY || | ||
929 | GET_BSS_ROLE(adapter->priv[i]) == bss_role) | ||
930 | break; | ||
931 | } | ||
932 | } | ||
933 | |||
934 | return ((i < adapter->priv_num) ? adapter->priv[i] : NULL); | ||
935 | } | ||
936 | |||
937 | /* | ||
938 | * This function returns the driver private structure of a network device. | ||
939 | */ | ||
940 | static inline struct mwifiex_private * | ||
941 | mwifiex_netdev_get_priv(struct net_device *dev) | ||
942 | { | ||
943 | return (struct mwifiex_private *) (*(unsigned long *) netdev_priv(dev)); | ||
944 | } | ||
945 | |||
946 | struct mwifiex_wait_queue *mwifiex_alloc_fill_wait_queue( | ||
947 | struct mwifiex_private *, | ||
948 | u8 wait_option); | ||
949 | struct mwifiex_private *mwifiex_bss_index_to_priv(struct mwifiex_adapter | ||
950 | *adapter, u8 bss_index); | ||
951 | int mwifiex_shutdown_fw(struct mwifiex_private *, u8); | ||
952 | |||
953 | int mwifiex_add_card(void *, struct semaphore *, struct mwifiex_if_ops *); | ||
954 | int mwifiex_remove_card(struct mwifiex_adapter *, struct semaphore *); | ||
955 | |||
956 | void mwifiex_get_version(struct mwifiex_adapter *adapter, char *version, | ||
957 | int maxlen); | ||
958 | int mwifiex_request_set_mac_address(struct mwifiex_private *priv); | ||
959 | void mwifiex_request_set_multicast_list(struct mwifiex_private *priv, | ||
960 | struct net_device *dev); | ||
961 | int mwifiex_request_ioctl(struct mwifiex_private *priv, | ||
962 | struct mwifiex_wait_queue *req, | ||
963 | int, u8 wait_option); | ||
964 | int mwifiex_disconnect(struct mwifiex_private *, u8, u8 *); | ||
965 | int mwifiex_bss_start(struct mwifiex_private *priv, | ||
966 | u8 wait_option, | ||
967 | struct mwifiex_ssid_bssid *ssid_bssid); | ||
968 | int mwifiex_set_hs_params(struct mwifiex_private *priv, | ||
969 | u16 action, u8 wait_option, | ||
970 | struct mwifiex_ds_hs_cfg *hscfg); | ||
971 | int mwifiex_cancel_hs(struct mwifiex_private *priv, u8 wait_option); | ||
972 | int mwifiex_enable_hs(struct mwifiex_adapter *adapter); | ||
973 | void mwifiex_process_ioctl_resp(struct mwifiex_private *priv, | ||
974 | struct mwifiex_wait_queue *req); | ||
975 | u32 mwifiex_get_mode(struct mwifiex_private *priv, u8 wait_option); | ||
976 | int mwifiex_get_signal_info(struct mwifiex_private *priv, | ||
977 | u8 wait_option, | ||
978 | struct mwifiex_ds_get_signal *signal); | ||
979 | int mwifiex_drv_get_data_rate(struct mwifiex_private *priv, | ||
980 | struct mwifiex_rate_cfg *rate); | ||
981 | int mwifiex_get_channel_list(struct mwifiex_private *priv, | ||
982 | u8 wait_option, | ||
983 | struct mwifiex_chan_list *chanlist); | ||
984 | int mwifiex_get_scan_table(struct mwifiex_private *priv, | ||
985 | u8 wait_option, | ||
986 | struct mwifiex_scan_resp *scanresp); | ||
987 | int mwifiex_enable_wep_key(struct mwifiex_private *priv, u8 wait_option); | ||
988 | int mwifiex_find_best_bss(struct mwifiex_private *priv, u8 wait_option, | ||
989 | struct mwifiex_ssid_bssid *ssid_bssid); | ||
990 | int mwifiex_request_scan(struct mwifiex_private *priv, | ||
991 | u8 wait_option, | ||
992 | struct mwifiex_802_11_ssid *req_ssid); | ||
993 | int mwifiex_set_user_scan_ioctl(struct mwifiex_private *priv, | ||
994 | struct mwifiex_user_scan_cfg *scan_req); | ||
995 | int mwifiex_change_adhoc_chan(struct mwifiex_private *priv, int channel); | ||
996 | int mwifiex_set_radio(struct mwifiex_private *priv, u8 option); | ||
997 | |||
998 | int mwifiex_drv_change_adhoc_chan(struct mwifiex_private *priv, int channel); | ||
999 | |||
1000 | int mwifiex_set_encode(struct mwifiex_private *priv, const u8 *key, | ||
1001 | int key_len, u8 key_index, int disable); | ||
1002 | |||
1003 | int mwifiex_set_gen_ie(struct mwifiex_private *priv, u8 *ie, int ie_len); | ||
1004 | |||
1005 | int mwifiex_get_ver_ext(struct mwifiex_private *priv); | ||
1006 | |||
1007 | int mwifiex_get_stats_info(struct mwifiex_private *priv, | ||
1008 | struct mwifiex_ds_get_stats *log); | ||
1009 | |||
1010 | int mwifiex_reg_write(struct mwifiex_private *priv, u32 reg_type, | ||
1011 | u32 reg_offset, u32 reg_value); | ||
1012 | |||
1013 | int mwifiex_reg_read(struct mwifiex_private *priv, u32 reg_type, | ||
1014 | u32 reg_offset, u32 *value); | ||
1015 | |||
1016 | int mwifiex_eeprom_read(struct mwifiex_private *priv, u16 offset, u16 bytes, | ||
1017 | u8 *value); | ||
1018 | |||
1019 | int mwifiex_set_11n_httx_cfg(struct mwifiex_private *priv, int data); | ||
1020 | |||
1021 | int mwifiex_get_11n_httx_cfg(struct mwifiex_private *priv, int *data); | ||
1022 | |||
1023 | int mwifiex_set_tx_rate_cfg(struct mwifiex_private *priv, int tx_rate_index); | ||
1024 | |||
1025 | int mwifiex_get_tx_rate_cfg(struct mwifiex_private *priv, int *tx_rate_index); | ||
1026 | |||
1027 | int mwifiex_drv_set_power(struct mwifiex_private *priv, bool power_on); | ||
1028 | |||
1029 | int mwifiex_drv_get_driver_version(struct mwifiex_adapter *adapter, | ||
1030 | char *version, int max_len); | ||
1031 | |||
1032 | int mwifiex_set_tx_power(struct mwifiex_private *priv, int type, int dbm); | ||
1033 | |||
1034 | int mwifiex_main_process(struct mwifiex_adapter *); | ||
1035 | |||
1036 | int mwifiex_bss_ioctl_channel(struct mwifiex_private *, | ||
1037 | u16 action, | ||
1038 | struct mwifiex_chan_freq_power *cfp); | ||
1039 | int mwifiex_bss_ioctl_find_bss(struct mwifiex_private *, | ||
1040 | struct mwifiex_wait_queue *, | ||
1041 | struct mwifiex_ssid_bssid *); | ||
1042 | int mwifiex_radio_ioctl_band_cfg(struct mwifiex_private *, | ||
1043 | u16 action, | ||
1044 | struct mwifiex_ds_band_cfg *); | ||
1045 | int mwifiex_snmp_mib_ioctl(struct mwifiex_private *, | ||
1046 | struct mwifiex_wait_queue *, | ||
1047 | u32 cmd_oid, u16 action, u32 *value); | ||
1048 | int mwifiex_get_bss_info(struct mwifiex_private *, | ||
1049 | struct mwifiex_bss_info *); | ||
1050 | |||
1051 | #ifdef CONFIG_DEBUG_FS | ||
1052 | void mwifiex_debugfs_init(void); | ||
1053 | void mwifiex_debugfs_remove(void); | ||
1054 | |||
1055 | void mwifiex_dev_debugfs_init(struct mwifiex_private *priv); | ||
1056 | void mwifiex_dev_debugfs_remove(struct mwifiex_private *priv); | ||
1057 | #endif | ||
1058 | #endif /* !_MWIFIEX_MAIN_H_ */ | ||
diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c new file mode 100644 index 000000000000..6bb52d0e6cfa --- /dev/null +++ b/drivers/net/wireless/mwifiex/scan.c | |||
@@ -0,0 +1,3097 @@ | |||
1 | /* | ||
2 | * Marvell Wireless LAN device driver: scan ioctl and command handling | ||
3 | * | ||
4 | * Copyright (C) 2011, Marvell International Ltd. | ||
5 | * | ||
6 | * This software file (the "File") is distributed by Marvell International | ||
7 | * Ltd. under the terms of the GNU General Public License Version 2, June 1991 | ||
8 | * (the "License"). You may use, redistribute and/or modify this File in | ||
9 | * accordance with the terms and conditions of the License, a copy of which | ||
10 | * is available by writing to the Free Software Foundation, Inc., | ||
11 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the | ||
12 | * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. | ||
13 | * | ||
14 | * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE | ||
15 | * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE | ||
16 | * ARE EXPRESSLY DISCLAIMED. The License provides additional details about | ||
17 | * this warranty disclaimer. | ||
18 | */ | ||
19 | |||
20 | #include "decl.h" | ||
21 | #include "ioctl.h" | ||
22 | #include "util.h" | ||
23 | #include "fw.h" | ||
24 | #include "main.h" | ||
25 | #include "11n.h" | ||
26 | #include "cfg80211.h" | ||
27 | |||
28 | /* The maximum number of channels the firmware can scan per command */ | ||
29 | #define MWIFIEX_MAX_CHANNELS_PER_SPECIFIC_SCAN 14 | ||
30 | |||
31 | #define MWIFIEX_CHANNELS_PER_SCAN_CMD 4 | ||
32 | |||
33 | /* Memory needed to store a max sized Channel List TLV for a firmware scan */ | ||
34 | #define CHAN_TLV_MAX_SIZE (sizeof(struct mwifiex_ie_types_header) \ | ||
35 | + (MWIFIEX_MAX_CHANNELS_PER_SPECIFIC_SCAN \ | ||
36 | *sizeof(struct mwifiex_chan_scan_param_set))) | ||
37 | |||
38 | /* Memory needed to store supported rate */ | ||
39 | #define RATE_TLV_MAX_SIZE (sizeof(struct mwifiex_ie_types_rates_param_set) \ | ||
40 | + HOSTCMD_SUPPORTED_RATES) | ||
41 | |||
42 | /* Memory needed to store a max number/size WildCard SSID TLV for a firmware | ||
43 | scan */ | ||
44 | #define WILDCARD_SSID_TLV_MAX_SIZE \ | ||
45 | (MWIFIEX_MAX_SSID_LIST_LENGTH * \ | ||
46 | (sizeof(struct mwifiex_ie_types_wildcard_ssid_params) \ | ||
47 | + IEEE80211_MAX_SSID_LEN)) | ||
48 | |||
49 | /* Maximum memory needed for a mwifiex_scan_cmd_config with all TLVs at max */ | ||
50 | #define MAX_SCAN_CFG_ALLOC (sizeof(struct mwifiex_scan_cmd_config) \ | ||
51 | + sizeof(struct mwifiex_ie_types_num_probes) \ | ||
52 | + sizeof(struct mwifiex_ie_types_htcap) \ | ||
53 | + CHAN_TLV_MAX_SIZE \ | ||
54 | + RATE_TLV_MAX_SIZE \ | ||
55 | + WILDCARD_SSID_TLV_MAX_SIZE) | ||
56 | |||
57 | |||
58 | union mwifiex_scan_cmd_config_tlv { | ||
59 | /* Scan configuration (variable length) */ | ||
60 | struct mwifiex_scan_cmd_config config; | ||
61 | /* Max allocated block */ | ||
62 | u8 config_alloc_buf[MAX_SCAN_CFG_ALLOC]; | ||
63 | }; | ||
64 | |||
65 | enum cipher_suite { | ||
66 | CIPHER_SUITE_TKIP, | ||
67 | CIPHER_SUITE_CCMP, | ||
68 | CIPHER_SUITE_MAX | ||
69 | }; | ||
70 | static u8 mwifiex_wpa_oui[CIPHER_SUITE_MAX][4] = { | ||
71 | { 0x00, 0x50, 0xf2, 0x02 }, /* TKIP */ | ||
72 | { 0x00, 0x50, 0xf2, 0x04 }, /* AES */ | ||
73 | }; | ||
74 | static u8 mwifiex_rsn_oui[CIPHER_SUITE_MAX][4] = { | ||
75 | { 0x00, 0x0f, 0xac, 0x02 }, /* TKIP */ | ||
76 | { 0x00, 0x0f, 0xac, 0x04 }, /* AES */ | ||
77 | }; | ||
78 | |||
79 | /* | ||
80 | * This function parses a given IE for a given OUI. | ||
81 | * | ||
82 | * This is used to parse a WPA/RSN IE to find if it has | ||
83 | * a given oui in PTK. | ||
84 | */ | ||
85 | static u8 | ||
86 | mwifiex_search_oui_in_ie(struct ie_body *iebody, u8 *oui) | ||
87 | { | ||
88 | u8 count; | ||
89 | |||
90 | count = iebody->ptk_cnt[0]; | ||
91 | |||
92 | /* There could be multiple OUIs for PTK hence | ||
93 | 1) Take the length. | ||
94 | 2) Check all the OUIs for AES. | ||
95 | 3) If one of them is AES then pass success. */ | ||
96 | while (count) { | ||
97 | if (!memcmp(iebody->ptk_body, oui, sizeof(iebody->ptk_body))) | ||
98 | return MWIFIEX_OUI_PRESENT; | ||
99 | |||
100 | --count; | ||
101 | if (count) | ||
102 | iebody = (struct ie_body *) ((u8 *) iebody + | ||
103 | sizeof(iebody->ptk_body)); | ||
104 | } | ||
105 | |||
106 | pr_debug("info: %s: OUI is not found in PTK\n", __func__); | ||
107 | return MWIFIEX_OUI_NOT_PRESENT; | ||
108 | } | ||
109 | |||
110 | /* | ||
111 | * This function checks if a given OUI is present in a RSN IE. | ||
112 | * | ||
113 | * The function first checks if a RSN IE is present or not in the | ||
114 | * BSS descriptor. It tries to locate the OUI only if such an IE is | ||
115 | * present. | ||
116 | */ | ||
117 | static u8 | ||
118 | mwifiex_is_rsn_oui_present(struct mwifiex_bssdescriptor *bss_desc, u32 cipher) | ||
119 | { | ||
120 | u8 *oui = NULL; | ||
121 | struct ie_body *iebody = NULL; | ||
122 | u8 ret = MWIFIEX_OUI_NOT_PRESENT; | ||
123 | |||
124 | if (((bss_desc->bcn_rsn_ie) && ((*(bss_desc->bcn_rsn_ie)). | ||
125 | ieee_hdr.element_id == WLAN_EID_RSN))) { | ||
126 | iebody = (struct ie_body *) | ||
127 | (((u8 *) bss_desc->bcn_rsn_ie->data) + | ||
128 | RSN_GTK_OUI_OFFSET); | ||
129 | oui = &mwifiex_rsn_oui[cipher][0]; | ||
130 | ret = mwifiex_search_oui_in_ie(iebody, oui); | ||
131 | if (ret) | ||
132 | return ret; | ||
133 | } | ||
134 | return ret; | ||
135 | } | ||
136 | |||
137 | /* | ||
138 | * This function checks if a given OUI is present in a WPA IE. | ||
139 | * | ||
140 | * The function first checks if a WPA IE is present or not in the | ||
141 | * BSS descriptor. It tries to locate the OUI only if such an IE is | ||
142 | * present. | ||
143 | */ | ||
144 | static u8 | ||
145 | mwifiex_is_wpa_oui_present(struct mwifiex_bssdescriptor *bss_desc, u32 cipher) | ||
146 | { | ||
147 | u8 *oui = NULL; | ||
148 | struct ie_body *iebody = NULL; | ||
149 | u8 ret = MWIFIEX_OUI_NOT_PRESENT; | ||
150 | |||
151 | if (((bss_desc->bcn_wpa_ie) && ((*(bss_desc->bcn_wpa_ie)). | ||
152 | vend_hdr.element_id == WLAN_EID_WPA))) { | ||
153 | iebody = (struct ie_body *) bss_desc->bcn_wpa_ie->data; | ||
154 | oui = &mwifiex_wpa_oui[cipher][0]; | ||
155 | ret = mwifiex_search_oui_in_ie(iebody, oui); | ||
156 | if (ret) | ||
157 | return ret; | ||
158 | } | ||
159 | return ret; | ||
160 | } | ||
161 | |||
162 | /* | ||
163 | * This function compares two SSIDs and checks if they match. | ||
164 | */ | ||
165 | s32 | ||
166 | mwifiex_ssid_cmp(struct mwifiex_802_11_ssid *ssid1, | ||
167 | struct mwifiex_802_11_ssid *ssid2) | ||
168 | { | ||
169 | if (!ssid1 || !ssid2 || (ssid1->ssid_len != ssid2->ssid_len)) | ||
170 | return -1; | ||
171 | return memcmp(ssid1->ssid, ssid2->ssid, ssid1->ssid_len); | ||
172 | } | ||
173 | |||
174 | /* | ||
175 | * Sends IOCTL request to get the best BSS. | ||
176 | * | ||
177 | * This function allocates the IOCTL request buffer, fills it | ||
178 | * with requisite parameters and calls the IOCTL handler. | ||
179 | */ | ||
180 | int mwifiex_find_best_bss(struct mwifiex_private *priv, | ||
181 | u8 wait_option, struct mwifiex_ssid_bssid *ssid_bssid) | ||
182 | { | ||
183 | struct mwifiex_wait_queue *wait = NULL; | ||
184 | struct mwifiex_ssid_bssid tmp_ssid_bssid; | ||
185 | int ret = 0; | ||
186 | u8 *mac = NULL; | ||
187 | |||
188 | if (!ssid_bssid) | ||
189 | return -1; | ||
190 | |||
191 | /* Allocate wait request buffer */ | ||
192 | wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); | ||
193 | if (!wait) | ||
194 | return -ENOMEM; | ||
195 | |||
196 | memcpy(&tmp_ssid_bssid, ssid_bssid, | ||
197 | sizeof(struct mwifiex_ssid_bssid)); | ||
198 | ret = mwifiex_bss_ioctl_find_bss(priv, wait, &tmp_ssid_bssid); | ||
199 | |||
200 | if (!ret) { | ||
201 | memcpy(ssid_bssid, &tmp_ssid_bssid, | ||
202 | sizeof(struct mwifiex_ssid_bssid)); | ||
203 | mac = (u8 *) &ssid_bssid->bssid; | ||
204 | dev_dbg(priv->adapter->dev, "cmd: found network: ssid=%s," | ||
205 | " %pM\n", ssid_bssid->ssid.ssid, mac); | ||
206 | } | ||
207 | |||
208 | kfree(wait); | ||
209 | return ret; | ||
210 | } | ||
211 | |||
212 | /* | ||
213 | * Sends IOCTL request to start a scan with user configurations. | ||
214 | * | ||
215 | * This function allocates the IOCTL request buffer, fills it | ||
216 | * with requisite parameters and calls the IOCTL handler. | ||
217 | * | ||
218 | * Upon completion, it also generates a wireless event to notify | ||
219 | * applications. | ||
220 | */ | ||
221 | int mwifiex_set_user_scan_ioctl(struct mwifiex_private *priv, | ||
222 | struct mwifiex_user_scan_cfg *scan_req) | ||
223 | { | ||
224 | struct mwifiex_wait_queue *wait = NULL; | ||
225 | int status = 0; | ||
226 | u8 wait_option = MWIFIEX_IOCTL_WAIT; | ||
227 | |||
228 | /* Allocate an IOCTL request buffer */ | ||
229 | wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); | ||
230 | if (!wait) | ||
231 | return -ENOMEM; | ||
232 | |||
233 | status = mwifiex_scan_networks(priv, wait, HostCmd_ACT_GEN_SET, | ||
234 | scan_req, NULL); | ||
235 | |||
236 | status = mwifiex_request_ioctl(priv, wait, status, wait_option); | ||
237 | |||
238 | if (wait && (status != -EINPROGRESS)) | ||
239 | kfree(wait); | ||
240 | return status; | ||
241 | } | ||
242 | |||
243 | /* | ||
244 | * This function checks if wapi is enabled in driver and scanned network is | ||
245 | * compatible with it. | ||
246 | */ | ||
247 | static bool | ||
248 | mwifiex_is_network_compatible_for_wapi(struct mwifiex_private *priv, | ||
249 | struct mwifiex_bssdescriptor *bss_desc) | ||
250 | { | ||
251 | if (priv->sec_info.wapi_enabled && | ||
252 | (bss_desc->bcn_wapi_ie && | ||
253 | ((*(bss_desc->bcn_wapi_ie)).ieee_hdr.element_id == | ||
254 | WLAN_EID_BSS_AC_ACCESS_DELAY))) { | ||
255 | return true; | ||
256 | } | ||
257 | return false; | ||
258 | } | ||
259 | |||
260 | /* | ||
261 | * This function checks if driver is configured with no security mode and | ||
262 | * scanned network is compatible with it. | ||
263 | */ | ||
264 | static bool | ||
265 | mwifiex_is_network_compatible_for_no_sec(struct mwifiex_private *priv, | ||
266 | struct mwifiex_bssdescriptor *bss_desc) | ||
267 | { | ||
268 | if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED | ||
269 | && !priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled | ||
270 | && ((!bss_desc->bcn_wpa_ie) || | ||
271 | ((*(bss_desc->bcn_wpa_ie)).vend_hdr.element_id != | ||
272 | WLAN_EID_WPA)) | ||
273 | && ((!bss_desc->bcn_rsn_ie) || | ||
274 | ((*(bss_desc->bcn_rsn_ie)).ieee_hdr.element_id != | ||
275 | WLAN_EID_RSN)) | ||
276 | && !priv->sec_info.encryption_mode | ||
277 | && !bss_desc->privacy) { | ||
278 | return true; | ||
279 | } | ||
280 | return false; | ||
281 | } | ||
282 | |||
283 | /* | ||
284 | * This function checks if static WEP is enabled in driver and scanned network | ||
285 | * is compatible with it. | ||
286 | */ | ||
287 | static bool | ||
288 | mwifiex_is_network_compatible_for_static_wep(struct mwifiex_private *priv, | ||
289 | struct mwifiex_bssdescriptor *bss_desc) | ||
290 | { | ||
291 | if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_ENABLED | ||
292 | && !priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled | ||
293 | && bss_desc->privacy) { | ||
294 | return true; | ||
295 | } | ||
296 | return false; | ||
297 | } | ||
298 | |||
299 | /* | ||
300 | * This function checks if wpa is enabled in driver and scanned network is | ||
301 | * compatible with it. | ||
302 | */ | ||
303 | static bool | ||
304 | mwifiex_is_network_compatible_for_wpa(struct mwifiex_private *priv, | ||
305 | struct mwifiex_bssdescriptor *bss_desc, | ||
306 | int index) | ||
307 | { | ||
308 | if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED | ||
309 | && priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled | ||
310 | && ((bss_desc->bcn_wpa_ie) && ((*(bss_desc->bcn_wpa_ie)).vend_hdr. | ||
311 | element_id == WLAN_EID_WPA)) | ||
312 | /* | ||
313 | * Privacy bit may NOT be set in some APs like | ||
314 | * LinkSys WRT54G && bss_desc->privacy | ||
315 | */ | ||
316 | ) { | ||
317 | dev_dbg(priv->adapter->dev, "info: %s: WPA: index=%d" | ||
318 | " wpa_ie=%#x wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s " | ||
319 | "EncMode=%#x privacy=%#x\n", __func__, index, | ||
320 | (bss_desc->bcn_wpa_ie) ? | ||
321 | (*(bss_desc->bcn_wpa_ie)). | ||
322 | vend_hdr.element_id : 0, | ||
323 | (bss_desc->bcn_rsn_ie) ? | ||
324 | (*(bss_desc->bcn_rsn_ie)). | ||
325 | ieee_hdr.element_id : 0, | ||
326 | (priv->sec_info.wep_status == | ||
327 | MWIFIEX_802_11_WEP_ENABLED) ? "e" : "d", | ||
328 | (priv->sec_info.wpa_enabled) ? "e" : "d", | ||
329 | (priv->sec_info.wpa2_enabled) ? "e" : "d", | ||
330 | priv->sec_info.encryption_mode, | ||
331 | bss_desc->privacy); | ||
332 | return true; | ||
333 | } | ||
334 | return false; | ||
335 | } | ||
336 | |||
337 | /* | ||
338 | * This function checks if wpa2 is enabled in driver and scanned network is | ||
339 | * compatible with it. | ||
340 | */ | ||
341 | static bool | ||
342 | mwifiex_is_network_compatible_for_wpa2(struct mwifiex_private *priv, | ||
343 | struct mwifiex_bssdescriptor *bss_desc, | ||
344 | int index) | ||
345 | { | ||
346 | if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED | ||
347 | && !priv->sec_info.wpa_enabled && priv->sec_info.wpa2_enabled | ||
348 | && ((bss_desc->bcn_rsn_ie) && ((*(bss_desc->bcn_rsn_ie)).ieee_hdr. | ||
349 | element_id == WLAN_EID_RSN)) | ||
350 | /* | ||
351 | * Privacy bit may NOT be set in some APs like | ||
352 | * LinkSys WRT54G && bss_desc->privacy | ||
353 | */ | ||
354 | ) { | ||
355 | dev_dbg(priv->adapter->dev, "info: %s: WPA2: index=%d" | ||
356 | " wpa_ie=%#x wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s " | ||
357 | "EncMode=%#x privacy=%#x\n", __func__, index, | ||
358 | (bss_desc->bcn_wpa_ie) ? | ||
359 | (*(bss_desc->bcn_wpa_ie)). | ||
360 | vend_hdr.element_id : 0, | ||
361 | (bss_desc->bcn_rsn_ie) ? | ||
362 | (*(bss_desc->bcn_rsn_ie)). | ||
363 | ieee_hdr.element_id : 0, | ||
364 | (priv->sec_info.wep_status == | ||
365 | MWIFIEX_802_11_WEP_ENABLED) ? "e" : "d", | ||
366 | (priv->sec_info.wpa_enabled) ? "e" : "d", | ||
367 | (priv->sec_info.wpa2_enabled) ? "e" : "d", | ||
368 | priv->sec_info.encryption_mode, | ||
369 | bss_desc->privacy); | ||
370 | return true; | ||
371 | } | ||
372 | return false; | ||
373 | } | ||
374 | |||
375 | /* | ||
376 | * This function checks if adhoc AES is enabled in driver and scanned network is | ||
377 | * compatible with it. | ||
378 | */ | ||
379 | static bool | ||
380 | mwifiex_is_network_compatible_for_adhoc_aes(struct mwifiex_private *priv, | ||
381 | struct mwifiex_bssdescriptor *bss_desc) | ||
382 | { | ||
383 | if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED | ||
384 | && !priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled | ||
385 | && ((!bss_desc->bcn_wpa_ie) || ((*(bss_desc->bcn_wpa_ie)).vend_hdr. | ||
386 | element_id != WLAN_EID_WPA)) | ||
387 | && ((!bss_desc->bcn_rsn_ie) || ((*(bss_desc->bcn_rsn_ie)).ieee_hdr. | ||
388 | element_id != WLAN_EID_RSN)) | ||
389 | && !priv->sec_info.encryption_mode | ||
390 | && bss_desc->privacy) { | ||
391 | return true; | ||
392 | } | ||
393 | return false; | ||
394 | } | ||
395 | |||
396 | /* | ||
397 | * This function checks if dynamic WEP is enabled in driver and scanned network | ||
398 | * is compatible with it. | ||
399 | */ | ||
400 | static bool | ||
401 | mwifiex_is_network_compatible_for_dynamic_wep(struct mwifiex_private *priv, | ||
402 | struct mwifiex_bssdescriptor *bss_desc, | ||
403 | int index) | ||
404 | { | ||
405 | if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED | ||
406 | && !priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled | ||
407 | && ((!bss_desc->bcn_wpa_ie) || ((*(bss_desc->bcn_wpa_ie)).vend_hdr. | ||
408 | element_id != WLAN_EID_WPA)) | ||
409 | && ((!bss_desc->bcn_rsn_ie) || ((*(bss_desc->bcn_rsn_ie)).ieee_hdr. | ||
410 | element_id != WLAN_EID_RSN)) | ||
411 | && priv->sec_info.encryption_mode | ||
412 | && bss_desc->privacy) { | ||
413 | dev_dbg(priv->adapter->dev, "info: %s: dynamic " | ||
414 | "WEP: index=%d wpa_ie=%#x wpa2_ie=%#x " | ||
415 | "EncMode=%#x privacy=%#x\n", | ||
416 | __func__, index, | ||
417 | (bss_desc->bcn_wpa_ie) ? | ||
418 | (*(bss_desc->bcn_wpa_ie)). | ||
419 | vend_hdr.element_id : 0, | ||
420 | (bss_desc->bcn_rsn_ie) ? | ||
421 | (*(bss_desc->bcn_rsn_ie)). | ||
422 | ieee_hdr.element_id : 0, | ||
423 | priv->sec_info.encryption_mode, | ||
424 | bss_desc->privacy); | ||
425 | return true; | ||
426 | } | ||
427 | return false; | ||
428 | } | ||
429 | |||
430 | /* | ||
431 | * This function checks if a scanned network is compatible with the driver | ||
432 | * settings. | ||
433 | * | ||
434 | * WEP WPA WPA2 ad-hoc encrypt Network | ||
435 | * enabled enabled enabled AES mode Privacy WPA WPA2 Compatible | ||
436 | * 0 0 0 0 NONE 0 0 0 yes No security | ||
437 | * 0 1 0 0 x 1x 1 x yes WPA (disable | ||
438 | * HT if no AES) | ||
439 | * 0 0 1 0 x 1x x 1 yes WPA2 (disable | ||
440 | * HT if no AES) | ||
441 | * 0 0 0 1 NONE 1 0 0 yes Ad-hoc AES | ||
442 | * 1 0 0 0 NONE 1 0 0 yes Static WEP | ||
443 | * (disable HT) | ||
444 | * 0 0 0 0 !=NONE 1 0 0 yes Dynamic WEP | ||
445 | * | ||
446 | * Compatibility is not matched while roaming, except for mode. | ||
447 | */ | ||
448 | static s32 | ||
449 | mwifiex_is_network_compatible(struct mwifiex_private *priv, u32 index, u32 mode) | ||
450 | { | ||
451 | struct mwifiex_adapter *adapter = priv->adapter; | ||
452 | struct mwifiex_bssdescriptor *bss_desc; | ||
453 | |||
454 | bss_desc = &adapter->scan_table[index]; | ||
455 | bss_desc->disable_11n = false; | ||
456 | |||
457 | /* Don't check for compatibility if roaming */ | ||
458 | if (priv->media_connected && (priv->bss_mode == NL80211_IFTYPE_STATION) | ||
459 | && (bss_desc->bss_mode == NL80211_IFTYPE_STATION)) | ||
460 | return index; | ||
461 | |||
462 | if (priv->wps.session_enable) { | ||
463 | dev_dbg(adapter->dev, | ||
464 | "info: return success directly in WPS period\n"); | ||
465 | return index; | ||
466 | } | ||
467 | |||
468 | if (mwifiex_is_network_compatible_for_wapi(priv, bss_desc)) { | ||
469 | dev_dbg(adapter->dev, "info: return success for WAPI AP\n"); | ||
470 | return index; | ||
471 | } | ||
472 | |||
473 | if (bss_desc->bss_mode == mode) { | ||
474 | if (mwifiex_is_network_compatible_for_no_sec(priv, bss_desc)) { | ||
475 | /* No security */ | ||
476 | return index; | ||
477 | } else if (mwifiex_is_network_compatible_for_static_wep(priv, | ||
478 | bss_desc)) { | ||
479 | /* Static WEP enabled */ | ||
480 | dev_dbg(adapter->dev, "info: Disable 11n in WEP mode.\n"); | ||
481 | bss_desc->disable_11n = true; | ||
482 | return index; | ||
483 | } else if (mwifiex_is_network_compatible_for_wpa(priv, bss_desc, | ||
484 | index)) { | ||
485 | /* WPA enabled */ | ||
486 | if (((priv->adapter->config_bands & BAND_GN | ||
487 | || priv->adapter->config_bands & BAND_AN) | ||
488 | && bss_desc->bcn_ht_cap) | ||
489 | && !mwifiex_is_wpa_oui_present(bss_desc, | ||
490 | CIPHER_SUITE_CCMP)) { | ||
491 | |||
492 | if (mwifiex_is_wpa_oui_present(bss_desc, | ||
493 | CIPHER_SUITE_TKIP)) { | ||
494 | dev_dbg(adapter->dev, | ||
495 | "info: Disable 11n if AES " | ||
496 | "is not supported by AP\n"); | ||
497 | bss_desc->disable_11n = true; | ||
498 | } else { | ||
499 | return -1; | ||
500 | } | ||
501 | } | ||
502 | return index; | ||
503 | } else if (mwifiex_is_network_compatible_for_wpa2(priv, | ||
504 | bss_desc, index)) { | ||
505 | /* WPA2 enabled */ | ||
506 | if (((priv->adapter->config_bands & BAND_GN | ||
507 | || priv->adapter->config_bands & BAND_AN) | ||
508 | && bss_desc->bcn_ht_cap) | ||
509 | && !mwifiex_is_rsn_oui_present(bss_desc, | ||
510 | CIPHER_SUITE_CCMP)) { | ||
511 | |||
512 | if (mwifiex_is_rsn_oui_present(bss_desc, | ||
513 | CIPHER_SUITE_TKIP)) { | ||
514 | dev_dbg(adapter->dev, | ||
515 | "info: Disable 11n if AES " | ||
516 | "is not supported by AP\n"); | ||
517 | bss_desc->disable_11n = true; | ||
518 | } else { | ||
519 | return -1; | ||
520 | } | ||
521 | } | ||
522 | return index; | ||
523 | } else if (mwifiex_is_network_compatible_for_adhoc_aes(priv, | ||
524 | bss_desc)) { | ||
525 | /* Ad-hoc AES enabled */ | ||
526 | return index; | ||
527 | } else if (mwifiex_is_network_compatible_for_dynamic_wep(priv, | ||
528 | bss_desc, index)) { | ||
529 | /* Dynamic WEP enabled */ | ||
530 | return index; | ||
531 | } | ||
532 | |||
533 | /* Security doesn't match */ | ||
534 | dev_dbg(adapter->dev, "info: %s: failed: index=%d " | ||
535 | "wpa_ie=%#x wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s EncMode" | ||
536 | "=%#x privacy=%#x\n", | ||
537 | __func__, index, | ||
538 | (bss_desc->bcn_wpa_ie) ? | ||
539 | (*(bss_desc->bcn_wpa_ie)).vend_hdr. | ||
540 | element_id : 0, | ||
541 | (bss_desc->bcn_rsn_ie) ? | ||
542 | (*(bss_desc->bcn_rsn_ie)).ieee_hdr. | ||
543 | element_id : 0, | ||
544 | (priv->sec_info.wep_status == | ||
545 | MWIFIEX_802_11_WEP_ENABLED) ? "e" : "d", | ||
546 | (priv->sec_info.wpa_enabled) ? "e" : "d", | ||
547 | (priv->sec_info.wpa2_enabled) ? "e" : "d", | ||
548 | priv->sec_info.encryption_mode, bss_desc->privacy); | ||
549 | return -1; | ||
550 | } | ||
551 | |||
552 | /* Mode doesn't match */ | ||
553 | return -1; | ||
554 | } | ||
555 | |||
556 | /* | ||
557 | * This function finds the best SSID in the scan list. | ||
558 | * | ||
559 | * It searches the scan table for the best SSID that also matches the current | ||
560 | * adapter network preference (mode, security etc.). | ||
561 | */ | ||
562 | static s32 | ||
563 | mwifiex_find_best_network_in_list(struct mwifiex_private *priv) | ||
564 | { | ||
565 | struct mwifiex_adapter *adapter = priv->adapter; | ||
566 | u32 mode = priv->bss_mode; | ||
567 | s32 best_net = -1; | ||
568 | s32 best_rssi = 0; | ||
569 | u32 i; | ||
570 | |||
571 | dev_dbg(adapter->dev, "info: num of BSSIDs = %d\n", | ||
572 | adapter->num_in_scan_table); | ||
573 | |||
574 | for (i = 0; i < adapter->num_in_scan_table; i++) { | ||
575 | switch (mode) { | ||
576 | case NL80211_IFTYPE_STATION: | ||
577 | case NL80211_IFTYPE_ADHOC: | ||
578 | if (mwifiex_is_network_compatible(priv, i, mode) >= 0) { | ||
579 | if (SCAN_RSSI(adapter->scan_table[i].rssi) > | ||
580 | best_rssi) { | ||
581 | best_rssi = SCAN_RSSI(adapter-> | ||
582 | scan_table[i].rssi); | ||
583 | best_net = i; | ||
584 | } | ||
585 | } | ||
586 | break; | ||
587 | case NL80211_IFTYPE_UNSPECIFIED: | ||
588 | default: | ||
589 | if (SCAN_RSSI(adapter->scan_table[i].rssi) > | ||
590 | best_rssi) { | ||
591 | best_rssi = SCAN_RSSI(adapter->scan_table[i]. | ||
592 | rssi); | ||
593 | best_net = i; | ||
594 | } | ||
595 | break; | ||
596 | } | ||
597 | } | ||
598 | |||
599 | return best_net; | ||
600 | } | ||
601 | |||
602 | /* | ||
603 | * This function creates a channel list for the driver to scan, based | ||
604 | * on region/band information. | ||
605 | * | ||
606 | * This routine is used for any scan that is not provided with a | ||
607 | * specific channel list to scan. | ||
608 | */ | ||
609 | static void | ||
610 | mwifiex_scan_create_channel_list(struct mwifiex_private *priv, | ||
611 | const struct mwifiex_user_scan_cfg | ||
612 | *user_scan_in, | ||
613 | struct mwifiex_chan_scan_param_set | ||
614 | *scan_chan_list, | ||
615 | u8 filtered_scan) | ||
616 | { | ||
617 | enum ieee80211_band band; | ||
618 | struct ieee80211_supported_band *sband; | ||
619 | struct ieee80211_channel *ch; | ||
620 | struct mwifiex_adapter *adapter = priv->adapter; | ||
621 | int chan_idx = 0, i; | ||
622 | u8 scan_type; | ||
623 | |||
624 | for (band = 0; (band < IEEE80211_NUM_BANDS) ; band++) { | ||
625 | |||
626 | if (!priv->wdev->wiphy->bands[band]) | ||
627 | continue; | ||
628 | |||
629 | sband = priv->wdev->wiphy->bands[band]; | ||
630 | |||
631 | for (i = 0; (i < sband->n_channels) ; i++, chan_idx++) { | ||
632 | ch = &sband->channels[i]; | ||
633 | if (ch->flags & IEEE80211_CHAN_DISABLED) | ||
634 | continue; | ||
635 | scan_chan_list[chan_idx].radio_type = band; | ||
636 | scan_type = ch->flags & IEEE80211_CHAN_PASSIVE_SCAN; | ||
637 | if (user_scan_in && | ||
638 | user_scan_in->chan_list[0].scan_time) | ||
639 | scan_chan_list[chan_idx].max_scan_time = | ||
640 | cpu_to_le16((u16) user_scan_in-> | ||
641 | chan_list[0].scan_time); | ||
642 | else if (scan_type == MWIFIEX_SCAN_TYPE_PASSIVE) | ||
643 | scan_chan_list[chan_idx].max_scan_time = | ||
644 | cpu_to_le16(adapter->passive_scan_time); | ||
645 | else | ||
646 | scan_chan_list[chan_idx].max_scan_time = | ||
647 | cpu_to_le16(adapter->active_scan_time); | ||
648 | if (scan_type == MWIFIEX_SCAN_TYPE_PASSIVE) | ||
649 | scan_chan_list[chan_idx].chan_scan_mode_bitmap | ||
650 | |= MWIFIEX_PASSIVE_SCAN; | ||
651 | else | ||
652 | scan_chan_list[chan_idx].chan_scan_mode_bitmap | ||
653 | &= ~MWIFIEX_PASSIVE_SCAN; | ||
654 | scan_chan_list[chan_idx].chan_number = | ||
655 | (u32) ch->hw_value; | ||
656 | if (filtered_scan) { | ||
657 | scan_chan_list[chan_idx].max_scan_time = | ||
658 | cpu_to_le16(adapter->specific_scan_time); | ||
659 | scan_chan_list[chan_idx].chan_scan_mode_bitmap | ||
660 | |= MWIFIEX_DISABLE_CHAN_FILT; | ||
661 | } | ||
662 | } | ||
663 | |||
664 | } | ||
665 | } | ||
666 | |||
667 | /* | ||
668 | * This function constructs and sends multiple scan config commands to | ||
669 | * the firmware. | ||
670 | * | ||
671 | * Previous routines in the code flow have created a scan command configuration | ||
672 | * with any requested TLVs. This function splits the channel TLV into maximum | ||
673 | * channels supported per scan lists and sends the portion of the channel TLV, | ||
674 | * along with the other TLVs, to the firmware. | ||
675 | */ | ||
676 | static int | ||
677 | mwifiex_scan_channel_list(struct mwifiex_private *priv, void *wait_buf, | ||
678 | u32 max_chan_per_scan, u8 filtered_scan, | ||
679 | struct mwifiex_scan_cmd_config *scan_cfg_out, | ||
680 | struct mwifiex_ie_types_chan_list_param_set | ||
681 | *chan_tlv_out, | ||
682 | struct mwifiex_chan_scan_param_set *scan_chan_list) | ||
683 | { | ||
684 | int ret = 0; | ||
685 | struct mwifiex_chan_scan_param_set *tmp_chan_list; | ||
686 | struct mwifiex_chan_scan_param_set *start_chan; | ||
687 | |||
688 | u32 tlv_idx; | ||
689 | u32 total_scan_time; | ||
690 | u32 done_early; | ||
691 | |||
692 | if (!scan_cfg_out || !chan_tlv_out || !scan_chan_list) { | ||
693 | dev_dbg(priv->adapter->dev, | ||
694 | "info: Scan: Null detect: %p, %p, %p\n", | ||
695 | scan_cfg_out, chan_tlv_out, scan_chan_list); | ||
696 | return -1; | ||
697 | } | ||
698 | |||
699 | chan_tlv_out->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); | ||
700 | |||
701 | /* Set the temp channel struct pointer to the start of the desired | ||
702 | list */ | ||
703 | tmp_chan_list = scan_chan_list; | ||
704 | |||
705 | /* Loop through the desired channel list, sending a new firmware scan | ||
706 | commands for each max_chan_per_scan channels (or for 1,6,11 | ||
707 | individually if configured accordingly) */ | ||
708 | while (tmp_chan_list->chan_number) { | ||
709 | |||
710 | tlv_idx = 0; | ||
711 | total_scan_time = 0; | ||
712 | chan_tlv_out->header.len = 0; | ||
713 | start_chan = tmp_chan_list; | ||
714 | done_early = false; | ||
715 | |||
716 | /* | ||
717 | * Construct the Channel TLV for the scan command. Continue to | ||
718 | * insert channel TLVs until: | ||
719 | * - the tlv_idx hits the maximum configured per scan command | ||
720 | * - the next channel to insert is 0 (end of desired channel | ||
721 | * list) | ||
722 | * - done_early is set (controlling individual scanning of | ||
723 | * 1,6,11) | ||
724 | */ | ||
725 | while (tlv_idx < max_chan_per_scan | ||
726 | && tmp_chan_list->chan_number && !done_early) { | ||
727 | |||
728 | dev_dbg(priv->adapter->dev, | ||
729 | "info: Scan: Chan(%3d), Radio(%d)," | ||
730 | " Mode(%d, %d), Dur(%d)\n", | ||
731 | tmp_chan_list->chan_number, | ||
732 | tmp_chan_list->radio_type, | ||
733 | tmp_chan_list->chan_scan_mode_bitmap | ||
734 | & MWIFIEX_PASSIVE_SCAN, | ||
735 | (tmp_chan_list->chan_scan_mode_bitmap | ||
736 | & MWIFIEX_DISABLE_CHAN_FILT) >> 1, | ||
737 | le16_to_cpu(tmp_chan_list->max_scan_time)); | ||
738 | |||
739 | /* Copy the current channel TLV to the command being | ||
740 | prepared */ | ||
741 | memcpy(chan_tlv_out->chan_scan_param + tlv_idx, | ||
742 | tmp_chan_list, | ||
743 | sizeof(chan_tlv_out->chan_scan_param)); | ||
744 | |||
745 | /* Increment the TLV header length by the size | ||
746 | appended */ | ||
747 | chan_tlv_out->header.len = | ||
748 | cpu_to_le16(le16_to_cpu(chan_tlv_out->header.len) + | ||
749 | (sizeof(chan_tlv_out->chan_scan_param))); | ||
750 | |||
751 | /* | ||
752 | * The tlv buffer length is set to the number of bytes | ||
753 | * of the between the channel tlv pointer and the start | ||
754 | * of the tlv buffer. This compensates for any TLVs | ||
755 | * that were appended before the channel list. | ||
756 | */ | ||
757 | scan_cfg_out->tlv_buf_len = (u32) ((u8 *) chan_tlv_out - | ||
758 | scan_cfg_out->tlv_buf); | ||
759 | |||
760 | /* Add the size of the channel tlv header and the data | ||
761 | length */ | ||
762 | scan_cfg_out->tlv_buf_len += | ||
763 | (sizeof(chan_tlv_out->header) | ||
764 | + le16_to_cpu(chan_tlv_out->header.len)); | ||
765 | |||
766 | /* Increment the index to the channel tlv we are | ||
767 | constructing */ | ||
768 | tlv_idx++; | ||
769 | |||
770 | /* Count the total scan time per command */ | ||
771 | total_scan_time += | ||
772 | le16_to_cpu(tmp_chan_list->max_scan_time); | ||
773 | |||
774 | done_early = false; | ||
775 | |||
776 | /* Stop the loop if the *current* channel is in the | ||
777 | 1,6,11 set and we are not filtering on a BSSID | ||
778 | or SSID. */ | ||
779 | if (!filtered_scan && (tmp_chan_list->chan_number == 1 | ||
780 | || tmp_chan_list->chan_number == 6 | ||
781 | || tmp_chan_list->chan_number == 11)) | ||
782 | done_early = true; | ||
783 | |||
784 | /* Increment the tmp pointer to the next channel to | ||
785 | be scanned */ | ||
786 | tmp_chan_list++; | ||
787 | |||
788 | /* Stop the loop if the *next* channel is in the 1,6,11 | ||
789 | set. This will cause it to be the only channel | ||
790 | scanned on the next interation */ | ||
791 | if (!filtered_scan && (tmp_chan_list->chan_number == 1 | ||
792 | || tmp_chan_list->chan_number == 6 | ||
793 | || tmp_chan_list->chan_number == 11)) | ||
794 | done_early = true; | ||
795 | } | ||
796 | |||
797 | /* The total scan time should be less than scan command timeout | ||
798 | value */ | ||
799 | if (total_scan_time > MWIFIEX_MAX_TOTAL_SCAN_TIME) { | ||
800 | dev_err(priv->adapter->dev, "total scan time %dms" | ||
801 | " is over limit (%dms), scan skipped\n", | ||
802 | total_scan_time, MWIFIEX_MAX_TOTAL_SCAN_TIME); | ||
803 | ret = -1; | ||
804 | break; | ||
805 | } | ||
806 | |||
807 | priv->adapter->scan_channels = start_chan; | ||
808 | |||
809 | /* Send the scan command to the firmware with the specified | ||
810 | cfg */ | ||
811 | ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_SCAN, | ||
812 | HostCmd_ACT_GEN_SET, | ||
813 | 0, wait_buf, scan_cfg_out); | ||
814 | if (ret) | ||
815 | break; | ||
816 | } | ||
817 | |||
818 | if (ret) | ||
819 | return -1; | ||
820 | |||
821 | return 0; | ||
822 | } | ||
823 | |||
824 | /* | ||
825 | * This function constructs a scan command configuration structure to use | ||
826 | * in scan commands. | ||
827 | * | ||
828 | * Application layer or other functions can invoke network scanning | ||
829 | * with a scan configuration supplied in a user scan configuration structure. | ||
830 | * This structure is used as the basis of one or many scan command configuration | ||
831 | * commands that are sent to the command processing module and eventually to the | ||
832 | * firmware. | ||
833 | * | ||
834 | * This function creates a scan command configuration structure based on the | ||
835 | * following user supplied parameters (if present): | ||
836 | * - SSID filter | ||
837 | * - BSSID filter | ||
838 | * - Number of Probes to be sent | ||
839 | * - Channel list | ||
840 | * | ||
841 | * If the SSID or BSSID filter is not present, the filter is disabled/cleared. | ||
842 | * If the number of probes is not set, adapter default setting is used. | ||
843 | */ | ||
844 | static void | ||
845 | mwifiex_scan_setup_scan_config(struct mwifiex_private *priv, | ||
846 | const struct mwifiex_user_scan_cfg *user_scan_in, | ||
847 | struct mwifiex_scan_cmd_config *scan_cfg_out, | ||
848 | struct mwifiex_ie_types_chan_list_param_set | ||
849 | **chan_list_out, | ||
850 | struct mwifiex_chan_scan_param_set | ||
851 | *scan_chan_list, | ||
852 | u8 *max_chan_per_scan, u8 *filtered_scan, | ||
853 | u8 *scan_current_only) | ||
854 | { | ||
855 | struct mwifiex_adapter *adapter = priv->adapter; | ||
856 | struct mwifiex_ie_types_num_probes *num_probes_tlv; | ||
857 | struct mwifiex_ie_types_wildcard_ssid_params *wildcard_ssid_tlv; | ||
858 | struct mwifiex_ie_types_rates_param_set *rates_tlv; | ||
859 | const u8 zero_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 }; | ||
860 | u8 *tlv_pos; | ||
861 | u32 num_probes; | ||
862 | u32 ssid_len; | ||
863 | u32 chan_idx; | ||
864 | u32 scan_type; | ||
865 | u16 scan_dur; | ||
866 | u8 channel; | ||
867 | u8 radio_type; | ||
868 | u32 ssid_idx; | ||
869 | u8 ssid_filter; | ||
870 | u8 rates[MWIFIEX_SUPPORTED_RATES]; | ||
871 | u32 rates_size; | ||
872 | struct mwifiex_ie_types_htcap *ht_cap; | ||
873 | |||
874 | /* The tlv_buf_len is calculated for each scan command. The TLVs added | ||
875 | in this routine will be preserved since the routine that sends the | ||
876 | command will append channelTLVs at *chan_list_out. The difference | ||
877 | between the *chan_list_out and the tlv_buf start will be used to | ||
878 | calculate the size of anything we add in this routine. */ | ||
879 | scan_cfg_out->tlv_buf_len = 0; | ||
880 | |||
881 | /* Running tlv pointer. Assigned to chan_list_out at end of function | ||
882 | so later routines know where channels can be added to the command | ||
883 | buf */ | ||
884 | tlv_pos = scan_cfg_out->tlv_buf; | ||
885 | |||
886 | /* Initialize the scan as un-filtered; the flag is later set to TRUE | ||
887 | below if a SSID or BSSID filter is sent in the command */ | ||
888 | *filtered_scan = false; | ||
889 | |||
890 | /* Initialize the scan as not being only on the current channel. If | ||
891 | the channel list is customized, only contains one channel, and is | ||
892 | the active channel, this is set true and data flow is not halted. */ | ||
893 | *scan_current_only = false; | ||
894 | |||
895 | if (user_scan_in) { | ||
896 | |||
897 | /* Default the ssid_filter flag to TRUE, set false under | ||
898 | certain wildcard conditions and qualified by the existence | ||
899 | of an SSID list before marking the scan as filtered */ | ||
900 | ssid_filter = true; | ||
901 | |||
902 | /* Set the BSS type scan filter, use Adapter setting if | ||
903 | unset */ | ||
904 | scan_cfg_out->bss_mode = | ||
905 | (user_scan_in->bss_mode ? (u8) user_scan_in-> | ||
906 | bss_mode : (u8) adapter->scan_mode); | ||
907 | |||
908 | /* Set the number of probes to send, use Adapter setting | ||
909 | if unset */ | ||
910 | num_probes = | ||
911 | (user_scan_in->num_probes ? user_scan_in-> | ||
912 | num_probes : adapter->scan_probes); | ||
913 | |||
914 | /* | ||
915 | * Set the BSSID filter to the incoming configuration, | ||
916 | * if non-zero. If not set, it will remain disabled | ||
917 | * (all zeros). | ||
918 | */ | ||
919 | memcpy(scan_cfg_out->specific_bssid, | ||
920 | user_scan_in->specific_bssid, | ||
921 | sizeof(scan_cfg_out->specific_bssid)); | ||
922 | |||
923 | for (ssid_idx = 0; | ||
924 | ((ssid_idx < ARRAY_SIZE(user_scan_in->ssid_list)) | ||
925 | && (*user_scan_in->ssid_list[ssid_idx].ssid | ||
926 | || user_scan_in->ssid_list[ssid_idx].max_len)); | ||
927 | ssid_idx++) { | ||
928 | |||
929 | ssid_len = strlen(user_scan_in->ssid_list[ssid_idx]. | ||
930 | ssid) + 1; | ||
931 | |||
932 | wildcard_ssid_tlv = | ||
933 | (struct mwifiex_ie_types_wildcard_ssid_params *) | ||
934 | tlv_pos; | ||
935 | wildcard_ssid_tlv->header.type = | ||
936 | cpu_to_le16(TLV_TYPE_WILDCARDSSID); | ||
937 | wildcard_ssid_tlv->header.len = cpu_to_le16( | ||
938 | (u16) (ssid_len + sizeof(wildcard_ssid_tlv-> | ||
939 | max_ssid_length))); | ||
940 | wildcard_ssid_tlv->max_ssid_length = | ||
941 | user_scan_in->ssid_list[ssid_idx].max_len; | ||
942 | |||
943 | memcpy(wildcard_ssid_tlv->ssid, | ||
944 | user_scan_in->ssid_list[ssid_idx].ssid, | ||
945 | ssid_len); | ||
946 | |||
947 | tlv_pos += (sizeof(wildcard_ssid_tlv->header) | ||
948 | + le16_to_cpu(wildcard_ssid_tlv->header.len)); | ||
949 | |||
950 | dev_dbg(adapter->dev, "info: scan: ssid_list[%d]: %s, %d\n", | ||
951 | ssid_idx, wildcard_ssid_tlv->ssid, | ||
952 | wildcard_ssid_tlv->max_ssid_length); | ||
953 | |||
954 | /* Empty wildcard ssid with a maxlen will match many or | ||
955 | potentially all SSIDs (maxlen == 32), therefore do | ||
956 | not treat the scan as | ||
957 | filtered. */ | ||
958 | if (!ssid_len && wildcard_ssid_tlv->max_ssid_length) | ||
959 | ssid_filter = false; | ||
960 | |||
961 | } | ||
962 | |||
963 | /* | ||
964 | * The default number of channels sent in the command is low to | ||
965 | * ensure the response buffer from the firmware does not | ||
966 | * truncate scan results. That is not an issue with an SSID | ||
967 | * or BSSID filter applied to the scan results in the firmware. | ||
968 | */ | ||
969 | if ((ssid_idx && ssid_filter) | ||
970 | || memcmp(scan_cfg_out->specific_bssid, &zero_mac, | ||
971 | sizeof(zero_mac))) | ||
972 | *filtered_scan = true; | ||
973 | } else { | ||
974 | scan_cfg_out->bss_mode = (u8) adapter->scan_mode; | ||
975 | num_probes = adapter->scan_probes; | ||
976 | } | ||
977 | |||
978 | /* | ||
979 | * If a specific BSSID or SSID is used, the number of channels in the | ||
980 | * scan command will be increased to the absolute maximum. | ||
981 | */ | ||
982 | if (*filtered_scan) | ||
983 | *max_chan_per_scan = MWIFIEX_MAX_CHANNELS_PER_SPECIFIC_SCAN; | ||
984 | else | ||
985 | *max_chan_per_scan = MWIFIEX_CHANNELS_PER_SCAN_CMD; | ||
986 | |||
987 | /* If the input config or adapter has the number of Probes set, | ||
988 | add tlv */ | ||
989 | if (num_probes) { | ||
990 | |||
991 | dev_dbg(adapter->dev, "info: scan: num_probes = %d\n", | ||
992 | num_probes); | ||
993 | |||
994 | num_probes_tlv = (struct mwifiex_ie_types_num_probes *) tlv_pos; | ||
995 | num_probes_tlv->header.type = cpu_to_le16(TLV_TYPE_NUMPROBES); | ||
996 | num_probes_tlv->header.len = | ||
997 | cpu_to_le16(sizeof(num_probes_tlv->num_probes)); | ||
998 | num_probes_tlv->num_probes = cpu_to_le16((u16) num_probes); | ||
999 | |||
1000 | tlv_pos += sizeof(num_probes_tlv->header) + | ||
1001 | le16_to_cpu(num_probes_tlv->header.len); | ||
1002 | |||
1003 | } | ||
1004 | |||
1005 | /* Append rates tlv */ | ||
1006 | memset(rates, 0, sizeof(rates)); | ||
1007 | |||
1008 | rates_size = mwifiex_get_supported_rates(priv, rates); | ||
1009 | |||
1010 | rates_tlv = (struct mwifiex_ie_types_rates_param_set *) tlv_pos; | ||
1011 | rates_tlv->header.type = cpu_to_le16(WLAN_EID_SUPP_RATES); | ||
1012 | rates_tlv->header.len = cpu_to_le16((u16) rates_size); | ||
1013 | memcpy(rates_tlv->rates, rates, rates_size); | ||
1014 | tlv_pos += sizeof(rates_tlv->header) + rates_size; | ||
1015 | |||
1016 | dev_dbg(adapter->dev, "info: SCAN_CMD: Rates size = %d\n", rates_size); | ||
1017 | |||
1018 | if (ISSUPP_11NENABLED(priv->adapter->fw_cap_info) | ||
1019 | && (priv->adapter->config_bands & BAND_GN | ||
1020 | || priv->adapter->config_bands & BAND_AN)) { | ||
1021 | ht_cap = (struct mwifiex_ie_types_htcap *) tlv_pos; | ||
1022 | memset(ht_cap, 0, sizeof(struct mwifiex_ie_types_htcap)); | ||
1023 | ht_cap->header.type = cpu_to_le16(WLAN_EID_HT_CAPABILITY); | ||
1024 | ht_cap->header.len = | ||
1025 | cpu_to_le16(sizeof(struct ieee80211_ht_cap)); | ||
1026 | mwifiex_fill_cap_info(priv, ht_cap); | ||
1027 | tlv_pos += sizeof(struct mwifiex_ie_types_htcap); | ||
1028 | } | ||
1029 | |||
1030 | /* Append vendor specific IE TLV */ | ||
1031 | mwifiex_cmd_append_vsie_tlv(priv, MWIFIEX_VSIE_MASK_SCAN, &tlv_pos); | ||
1032 | |||
1033 | /* | ||
1034 | * Set the output for the channel TLV to the address in the tlv buffer | ||
1035 | * past any TLVs that were added in this function (SSID, num_probes). | ||
1036 | * Channel TLVs will be added past this for each scan command, | ||
1037 | * preserving the TLVs that were previously added. | ||
1038 | */ | ||
1039 | *chan_list_out = | ||
1040 | (struct mwifiex_ie_types_chan_list_param_set *) tlv_pos; | ||
1041 | |||
1042 | if (user_scan_in && user_scan_in->chan_list[0].chan_number) { | ||
1043 | |||
1044 | dev_dbg(adapter->dev, "info: Scan: Using supplied channel list\n"); | ||
1045 | |||
1046 | for (chan_idx = 0; | ||
1047 | chan_idx < MWIFIEX_USER_SCAN_CHAN_MAX | ||
1048 | && user_scan_in->chan_list[chan_idx].chan_number; | ||
1049 | chan_idx++) { | ||
1050 | |||
1051 | channel = user_scan_in->chan_list[chan_idx].chan_number; | ||
1052 | (scan_chan_list + chan_idx)->chan_number = channel; | ||
1053 | |||
1054 | radio_type = | ||
1055 | user_scan_in->chan_list[chan_idx].radio_type; | ||
1056 | (scan_chan_list + chan_idx)->radio_type = radio_type; | ||
1057 | |||
1058 | scan_type = user_scan_in->chan_list[chan_idx].scan_type; | ||
1059 | |||
1060 | if (scan_type == MWIFIEX_SCAN_TYPE_PASSIVE) | ||
1061 | (scan_chan_list + | ||
1062 | chan_idx)->chan_scan_mode_bitmap | ||
1063 | |= MWIFIEX_PASSIVE_SCAN; | ||
1064 | else | ||
1065 | (scan_chan_list + | ||
1066 | chan_idx)->chan_scan_mode_bitmap | ||
1067 | &= ~MWIFIEX_PASSIVE_SCAN; | ||
1068 | |||
1069 | if (user_scan_in->chan_list[chan_idx].scan_time) { | ||
1070 | scan_dur = (u16) user_scan_in-> | ||
1071 | chan_list[chan_idx].scan_time; | ||
1072 | } else { | ||
1073 | if (scan_type == MWIFIEX_SCAN_TYPE_PASSIVE) | ||
1074 | scan_dur = adapter->passive_scan_time; | ||
1075 | else if (*filtered_scan) | ||
1076 | scan_dur = adapter->specific_scan_time; | ||
1077 | else | ||
1078 | scan_dur = adapter->active_scan_time; | ||
1079 | } | ||
1080 | |||
1081 | (scan_chan_list + chan_idx)->min_scan_time = | ||
1082 | cpu_to_le16(scan_dur); | ||
1083 | (scan_chan_list + chan_idx)->max_scan_time = | ||
1084 | cpu_to_le16(scan_dur); | ||
1085 | } | ||
1086 | |||
1087 | /* Check if we are only scanning the current channel */ | ||
1088 | if ((chan_idx == 1) | ||
1089 | && (user_scan_in->chan_list[0].chan_number | ||
1090 | == priv->curr_bss_params.bss_descriptor.channel)) { | ||
1091 | *scan_current_only = true; | ||
1092 | dev_dbg(adapter->dev, | ||
1093 | "info: Scan: Scanning current channel only\n"); | ||
1094 | } | ||
1095 | |||
1096 | } else { | ||
1097 | dev_dbg(adapter->dev, | ||
1098 | "info: Scan: Creating full region channel list\n"); | ||
1099 | mwifiex_scan_create_channel_list(priv, user_scan_in, | ||
1100 | scan_chan_list, | ||
1101 | *filtered_scan); | ||
1102 | } | ||
1103 | } | ||
1104 | |||
1105 | /* | ||
1106 | * This function inspects the scan response buffer for pointers to | ||
1107 | * expected TLVs. | ||
1108 | * | ||
1109 | * TLVs can be included at the end of the scan response BSS information. | ||
1110 | * | ||
1111 | * Data in the buffer is parsed pointers to TLVs that can potentially | ||
1112 | * be passed back in the response. | ||
1113 | */ | ||
1114 | static void | ||
1115 | mwifiex_ret_802_11_scan_get_tlv_ptrs(struct mwifiex_adapter *adapter, | ||
1116 | struct mwifiex_ie_types_data *tlv, | ||
1117 | u32 tlv_buf_size, u32 req_tlv_type, | ||
1118 | struct mwifiex_ie_types_data **tlv_data) | ||
1119 | { | ||
1120 | struct mwifiex_ie_types_data *current_tlv; | ||
1121 | u32 tlv_buf_left; | ||
1122 | u32 tlv_type; | ||
1123 | u32 tlv_len; | ||
1124 | |||
1125 | current_tlv = tlv; | ||
1126 | tlv_buf_left = tlv_buf_size; | ||
1127 | *tlv_data = NULL; | ||
1128 | |||
1129 | dev_dbg(adapter->dev, "info: SCAN_RESP: tlv_buf_size = %d\n", | ||
1130 | tlv_buf_size); | ||
1131 | |||
1132 | while (tlv_buf_left >= sizeof(struct mwifiex_ie_types_header)) { | ||
1133 | |||
1134 | tlv_type = le16_to_cpu(current_tlv->header.type); | ||
1135 | tlv_len = le16_to_cpu(current_tlv->header.len); | ||
1136 | |||
1137 | if (sizeof(tlv->header) + tlv_len > tlv_buf_left) { | ||
1138 | dev_err(adapter->dev, "SCAN_RESP: TLV buffer corrupt\n"); | ||
1139 | break; | ||
1140 | } | ||
1141 | |||
1142 | if (req_tlv_type == tlv_type) { | ||
1143 | switch (tlv_type) { | ||
1144 | case TLV_TYPE_TSFTIMESTAMP: | ||
1145 | dev_dbg(adapter->dev, "info: SCAN_RESP: TSF " | ||
1146 | "timestamp TLV, len = %d\n", tlv_len); | ||
1147 | *tlv_data = (struct mwifiex_ie_types_data *) | ||
1148 | current_tlv; | ||
1149 | break; | ||
1150 | case TLV_TYPE_CHANNELBANDLIST: | ||
1151 | dev_dbg(adapter->dev, "info: SCAN_RESP: channel" | ||
1152 | " band list TLV, len = %d\n", tlv_len); | ||
1153 | *tlv_data = (struct mwifiex_ie_types_data *) | ||
1154 | current_tlv; | ||
1155 | break; | ||
1156 | default: | ||
1157 | dev_err(adapter->dev, | ||
1158 | "SCAN_RESP: unhandled TLV = %d\n", | ||
1159 | tlv_type); | ||
1160 | /* Give up, this seems corrupted */ | ||
1161 | return; | ||
1162 | } | ||
1163 | } | ||
1164 | |||
1165 | if (*tlv_data) | ||
1166 | break; | ||
1167 | |||
1168 | |||
1169 | tlv_buf_left -= (sizeof(tlv->header) + tlv_len); | ||
1170 | current_tlv = | ||
1171 | (struct mwifiex_ie_types_data *) (current_tlv->data + | ||
1172 | tlv_len); | ||
1173 | |||
1174 | } /* while */ | ||
1175 | } | ||
1176 | |||
1177 | /* | ||
1178 | * This function interprets a BSS scan response returned from the firmware. | ||
1179 | * | ||
1180 | * The various fixed fields and IEs are parsed and passed back for a BSS | ||
1181 | * probe response or beacon from scan command. Information is recorded as | ||
1182 | * needed in the scan table for that entry. | ||
1183 | * | ||
1184 | * The following IE types are recognized and parsed - | ||
1185 | * - SSID | ||
1186 | * - Supported rates | ||
1187 | * - FH parameters set | ||
1188 | * - DS parameters set | ||
1189 | * - CF parameters set | ||
1190 | * - IBSS parameters set | ||
1191 | * - ERP information | ||
1192 | * - Extended supported rates | ||
1193 | * - Vendor specific (221) | ||
1194 | * - RSN IE | ||
1195 | * - WAPI IE | ||
1196 | * - HT capability | ||
1197 | * - HT operation | ||
1198 | * - BSS Coexistence 20/40 | ||
1199 | * - Extended capability | ||
1200 | * - Overlapping BSS scan parameters | ||
1201 | */ | ||
1202 | static int | ||
1203 | mwifiex_interpret_bss_desc_with_ie(struct mwifiex_adapter *adapter, | ||
1204 | struct mwifiex_bssdescriptor *bss_entry, | ||
1205 | u8 **beacon_info, u32 *bytes_left) | ||
1206 | { | ||
1207 | int ret = 0; | ||
1208 | u8 element_id; | ||
1209 | struct ieee_types_fh_param_set *fh_param_set; | ||
1210 | struct ieee_types_ds_param_set *ds_param_set; | ||
1211 | struct ieee_types_cf_param_set *cf_param_set; | ||
1212 | struct ieee_types_ibss_param_set *ibss_param_set; | ||
1213 | __le16 beacon_interval; | ||
1214 | __le16 capabilities; | ||
1215 | u8 *current_ptr; | ||
1216 | u8 *rate; | ||
1217 | u8 element_len; | ||
1218 | u16 total_ie_len; | ||
1219 | u8 bytes_to_copy; | ||
1220 | u8 rate_size; | ||
1221 | u16 beacon_size; | ||
1222 | u8 found_data_rate_ie; | ||
1223 | u32 bytes_left_for_current_beacon; | ||
1224 | struct ieee_types_vendor_specific *vendor_ie; | ||
1225 | const u8 wpa_oui[4] = { 0x00, 0x50, 0xf2, 0x01 }; | ||
1226 | const u8 wmm_oui[4] = { 0x00, 0x50, 0xf2, 0x02 }; | ||
1227 | |||
1228 | found_data_rate_ie = false; | ||
1229 | rate_size = 0; | ||
1230 | beacon_size = 0; | ||
1231 | |||
1232 | if (*bytes_left >= sizeof(beacon_size)) { | ||
1233 | /* Extract & convert beacon size from the command buffer */ | ||
1234 | memcpy(&beacon_size, *beacon_info, sizeof(beacon_size)); | ||
1235 | *bytes_left -= sizeof(beacon_size); | ||
1236 | *beacon_info += sizeof(beacon_size); | ||
1237 | } | ||
1238 | |||
1239 | if (!beacon_size || beacon_size > *bytes_left) { | ||
1240 | *beacon_info += *bytes_left; | ||
1241 | *bytes_left = 0; | ||
1242 | return -1; | ||
1243 | } | ||
1244 | |||
1245 | /* Initialize the current working beacon pointer for this BSS | ||
1246 | iteration */ | ||
1247 | current_ptr = *beacon_info; | ||
1248 | |||
1249 | /* Advance the return beacon pointer past the current beacon */ | ||
1250 | *beacon_info += beacon_size; | ||
1251 | *bytes_left -= beacon_size; | ||
1252 | |||
1253 | bytes_left_for_current_beacon = beacon_size; | ||
1254 | |||
1255 | memcpy(bss_entry->mac_address, current_ptr, ETH_ALEN); | ||
1256 | dev_dbg(adapter->dev, "info: InterpretIE: AP MAC Addr: %pM\n", | ||
1257 | bss_entry->mac_address); | ||
1258 | |||
1259 | current_ptr += ETH_ALEN; | ||
1260 | bytes_left_for_current_beacon -= ETH_ALEN; | ||
1261 | |||
1262 | if (bytes_left_for_current_beacon < 12) { | ||
1263 | dev_err(adapter->dev, "InterpretIE: not enough bytes left\n"); | ||
1264 | return -1; | ||
1265 | } | ||
1266 | |||
1267 | /* | ||
1268 | * Next 4 fields are RSSI, time stamp, beacon interval, | ||
1269 | * and capability information | ||
1270 | */ | ||
1271 | |||
1272 | /* RSSI is 1 byte long */ | ||
1273 | bss_entry->rssi = (s32) (*current_ptr); | ||
1274 | dev_dbg(adapter->dev, "info: InterpretIE: RSSI=%02X\n", *current_ptr); | ||
1275 | current_ptr += 1; | ||
1276 | bytes_left_for_current_beacon -= 1; | ||
1277 | |||
1278 | /* | ||
1279 | * The RSSI is not part of the beacon/probe response. After we have | ||
1280 | * advanced current_ptr past the RSSI field, save the remaining | ||
1281 | * data for use at the application layer | ||
1282 | */ | ||
1283 | bss_entry->beacon_buf = current_ptr; | ||
1284 | bss_entry->beacon_buf_size = bytes_left_for_current_beacon; | ||
1285 | |||
1286 | /* Time stamp is 8 bytes long */ | ||
1287 | memcpy(bss_entry->time_stamp, current_ptr, 8); | ||
1288 | current_ptr += 8; | ||
1289 | bytes_left_for_current_beacon -= 8; | ||
1290 | |||
1291 | /* Beacon interval is 2 bytes long */ | ||
1292 | memcpy(&beacon_interval, current_ptr, 2); | ||
1293 | bss_entry->beacon_period = le16_to_cpu(beacon_interval); | ||
1294 | current_ptr += 2; | ||
1295 | bytes_left_for_current_beacon -= 2; | ||
1296 | |||
1297 | /* Capability information is 2 bytes long */ | ||
1298 | memcpy(&capabilities, current_ptr, 2); | ||
1299 | dev_dbg(adapter->dev, "info: InterpretIE: capabilities=0x%X\n", | ||
1300 | capabilities); | ||
1301 | bss_entry->cap_info_bitmap = le16_to_cpu(capabilities); | ||
1302 | current_ptr += 2; | ||
1303 | bytes_left_for_current_beacon -= 2; | ||
1304 | |||
1305 | /* Rest of the current buffer are IE's */ | ||
1306 | dev_dbg(adapter->dev, "info: InterpretIE: IELength for this AP = %d\n", | ||
1307 | bytes_left_for_current_beacon); | ||
1308 | |||
1309 | if (bss_entry->cap_info_bitmap & WLAN_CAPABILITY_PRIVACY) { | ||
1310 | dev_dbg(adapter->dev, "info: InterpretIE: AP WEP enabled\n"); | ||
1311 | bss_entry->privacy = MWIFIEX_802_11_PRIV_FILTER_8021X_WEP; | ||
1312 | } else { | ||
1313 | bss_entry->privacy = MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL; | ||
1314 | } | ||
1315 | |||
1316 | if (bss_entry->cap_info_bitmap & WLAN_CAPABILITY_IBSS) | ||
1317 | bss_entry->bss_mode = NL80211_IFTYPE_ADHOC; | ||
1318 | else | ||
1319 | bss_entry->bss_mode = NL80211_IFTYPE_STATION; | ||
1320 | |||
1321 | |||
1322 | /* Process variable IE */ | ||
1323 | while (bytes_left_for_current_beacon >= 2) { | ||
1324 | element_id = *current_ptr; | ||
1325 | element_len = *(current_ptr + 1); | ||
1326 | total_ie_len = element_len + sizeof(struct ieee_types_header); | ||
1327 | |||
1328 | if (bytes_left_for_current_beacon < total_ie_len) { | ||
1329 | dev_err(adapter->dev, "err: InterpretIE: in processing" | ||
1330 | " IE, bytes left < IE length\n"); | ||
1331 | bytes_left_for_current_beacon = 0; | ||
1332 | ret = -1; | ||
1333 | continue; | ||
1334 | } | ||
1335 | switch (element_id) { | ||
1336 | case WLAN_EID_SSID: | ||
1337 | bss_entry->ssid.ssid_len = element_len; | ||
1338 | memcpy(bss_entry->ssid.ssid, (current_ptr + 2), | ||
1339 | element_len); | ||
1340 | dev_dbg(adapter->dev, "info: InterpretIE: ssid: %-32s\n", | ||
1341 | bss_entry->ssid.ssid); | ||
1342 | break; | ||
1343 | |||
1344 | case WLAN_EID_SUPP_RATES: | ||
1345 | memcpy(bss_entry->data_rates, current_ptr + 2, | ||
1346 | element_len); | ||
1347 | memcpy(bss_entry->supported_rates, current_ptr + 2, | ||
1348 | element_len); | ||
1349 | rate_size = element_len; | ||
1350 | found_data_rate_ie = true; | ||
1351 | break; | ||
1352 | |||
1353 | case WLAN_EID_FH_PARAMS: | ||
1354 | fh_param_set = | ||
1355 | (struct ieee_types_fh_param_set *) current_ptr; | ||
1356 | memcpy(&bss_entry->phy_param_set.fh_param_set, | ||
1357 | fh_param_set, | ||
1358 | sizeof(struct ieee_types_fh_param_set)); | ||
1359 | break; | ||
1360 | |||
1361 | case WLAN_EID_DS_PARAMS: | ||
1362 | ds_param_set = | ||
1363 | (struct ieee_types_ds_param_set *) current_ptr; | ||
1364 | |||
1365 | bss_entry->channel = ds_param_set->current_chan; | ||
1366 | |||
1367 | memcpy(&bss_entry->phy_param_set.ds_param_set, | ||
1368 | ds_param_set, | ||
1369 | sizeof(struct ieee_types_ds_param_set)); | ||
1370 | break; | ||
1371 | |||
1372 | case WLAN_EID_CF_PARAMS: | ||
1373 | cf_param_set = | ||
1374 | (struct ieee_types_cf_param_set *) current_ptr; | ||
1375 | memcpy(&bss_entry->ss_param_set.cf_param_set, | ||
1376 | cf_param_set, | ||
1377 | sizeof(struct ieee_types_cf_param_set)); | ||
1378 | break; | ||
1379 | |||
1380 | case WLAN_EID_IBSS_PARAMS: | ||
1381 | ibss_param_set = | ||
1382 | (struct ieee_types_ibss_param_set *) | ||
1383 | current_ptr; | ||
1384 | memcpy(&bss_entry->ss_param_set.ibss_param_set, | ||
1385 | ibss_param_set, | ||
1386 | sizeof(struct ieee_types_ibss_param_set)); | ||
1387 | break; | ||
1388 | |||
1389 | case WLAN_EID_ERP_INFO: | ||
1390 | bss_entry->erp_flags = *(current_ptr + 2); | ||
1391 | break; | ||
1392 | |||
1393 | case WLAN_EID_EXT_SUPP_RATES: | ||
1394 | /* | ||
1395 | * Only process extended supported rate | ||
1396 | * if data rate is already found. | ||
1397 | * Data rate IE should come before | ||
1398 | * extended supported rate IE | ||
1399 | */ | ||
1400 | if (found_data_rate_ie) { | ||
1401 | if ((element_len + rate_size) > | ||
1402 | MWIFIEX_SUPPORTED_RATES) | ||
1403 | bytes_to_copy = | ||
1404 | (MWIFIEX_SUPPORTED_RATES - | ||
1405 | rate_size); | ||
1406 | else | ||
1407 | bytes_to_copy = element_len; | ||
1408 | |||
1409 | rate = (u8 *) bss_entry->data_rates; | ||
1410 | rate += rate_size; | ||
1411 | memcpy(rate, current_ptr + 2, bytes_to_copy); | ||
1412 | |||
1413 | rate = (u8 *) bss_entry->supported_rates; | ||
1414 | rate += rate_size; | ||
1415 | memcpy(rate, current_ptr + 2, bytes_to_copy); | ||
1416 | } | ||
1417 | break; | ||
1418 | |||
1419 | case WLAN_EID_VENDOR_SPECIFIC: | ||
1420 | vendor_ie = (struct ieee_types_vendor_specific *) | ||
1421 | current_ptr; | ||
1422 | |||
1423 | if (!memcmp | ||
1424 | (vendor_ie->vend_hdr.oui, wpa_oui, | ||
1425 | sizeof(wpa_oui))) { | ||
1426 | bss_entry->bcn_wpa_ie = | ||
1427 | (struct ieee_types_vendor_specific *) | ||
1428 | current_ptr; | ||
1429 | bss_entry->wpa_offset = (u16) (current_ptr - | ||
1430 | bss_entry->beacon_buf); | ||
1431 | } else if (!memcmp(vendor_ie->vend_hdr.oui, wmm_oui, | ||
1432 | sizeof(wmm_oui))) { | ||
1433 | if (total_ie_len == | ||
1434 | sizeof(struct ieee_types_wmm_parameter) | ||
1435 | || total_ie_len == | ||
1436 | sizeof(struct ieee_types_wmm_info)) | ||
1437 | /* | ||
1438 | * Only accept and copy the WMM IE if | ||
1439 | * it matches the size expected for the | ||
1440 | * WMM Info IE or the WMM Parameter IE. | ||
1441 | */ | ||
1442 | memcpy((u8 *) &bss_entry->wmm_ie, | ||
1443 | current_ptr, total_ie_len); | ||
1444 | } | ||
1445 | break; | ||
1446 | case WLAN_EID_RSN: | ||
1447 | bss_entry->bcn_rsn_ie = | ||
1448 | (struct ieee_types_generic *) current_ptr; | ||
1449 | bss_entry->rsn_offset = (u16) (current_ptr - | ||
1450 | bss_entry->beacon_buf); | ||
1451 | break; | ||
1452 | case WLAN_EID_BSS_AC_ACCESS_DELAY: | ||
1453 | bss_entry->bcn_wapi_ie = | ||
1454 | (struct ieee_types_generic *) current_ptr; | ||
1455 | bss_entry->wapi_offset = (u16) (current_ptr - | ||
1456 | bss_entry->beacon_buf); | ||
1457 | break; | ||
1458 | case WLAN_EID_HT_CAPABILITY: | ||
1459 | bss_entry->bcn_ht_cap = (struct ieee80211_ht_cap *) | ||
1460 | (current_ptr + | ||
1461 | sizeof(struct ieee_types_header)); | ||
1462 | bss_entry->ht_cap_offset = (u16) (current_ptr + | ||
1463 | sizeof(struct ieee_types_header) - | ||
1464 | bss_entry->beacon_buf); | ||
1465 | break; | ||
1466 | case WLAN_EID_HT_INFORMATION: | ||
1467 | bss_entry->bcn_ht_info = (struct ieee80211_ht_info *) | ||
1468 | (current_ptr + | ||
1469 | sizeof(struct ieee_types_header)); | ||
1470 | bss_entry->ht_info_offset = (u16) (current_ptr + | ||
1471 | sizeof(struct ieee_types_header) - | ||
1472 | bss_entry->beacon_buf); | ||
1473 | break; | ||
1474 | case WLAN_EID_BSS_COEX_2040: | ||
1475 | bss_entry->bcn_bss_co_2040 = (u8 *) (current_ptr + | ||
1476 | sizeof(struct ieee_types_header)); | ||
1477 | bss_entry->bss_co_2040_offset = (u16) (current_ptr + | ||
1478 | sizeof(struct ieee_types_header) - | ||
1479 | bss_entry->beacon_buf); | ||
1480 | break; | ||
1481 | case WLAN_EID_EXT_CAPABILITY: | ||
1482 | bss_entry->bcn_ext_cap = (u8 *) (current_ptr + | ||
1483 | sizeof(struct ieee_types_header)); | ||
1484 | bss_entry->ext_cap_offset = (u16) (current_ptr + | ||
1485 | sizeof(struct ieee_types_header) - | ||
1486 | bss_entry->beacon_buf); | ||
1487 | break; | ||
1488 | case WLAN_EID_OVERLAP_BSS_SCAN_PARAM: | ||
1489 | bss_entry->bcn_obss_scan = | ||
1490 | (struct ieee_types_obss_scan_param *) | ||
1491 | current_ptr; | ||
1492 | bss_entry->overlap_bss_offset = (u16) (current_ptr - | ||
1493 | bss_entry->beacon_buf); | ||
1494 | break; | ||
1495 | default: | ||
1496 | break; | ||
1497 | } | ||
1498 | |||
1499 | current_ptr += element_len + 2; | ||
1500 | |||
1501 | /* Need to account for IE ID and IE Len */ | ||
1502 | bytes_left_for_current_beacon -= (element_len + 2); | ||
1503 | |||
1504 | } /* while (bytes_left_for_current_beacon > 2) */ | ||
1505 | return ret; | ||
1506 | } | ||
1507 | |||
1508 | /* | ||
1509 | * This function adjusts the pointers used in beacon buffers to reflect | ||
1510 | * shifts. | ||
1511 | * | ||
1512 | * The memory allocated for beacon buffers is of fixed sizes where all the | ||
1513 | * saved beacons must be stored. New beacons are added in the free portion | ||
1514 | * of this memory, space permitting; while duplicate beacon buffers are | ||
1515 | * placed at the same start location. However, since duplicate beacon | ||
1516 | * buffers may not match the size of the old one, all the following buffers | ||
1517 | * in the memory must be shifted to either make space, or to fill up freed | ||
1518 | * up space. | ||
1519 | * | ||
1520 | * This function is used to update the beacon buffer pointers that are past | ||
1521 | * an existing beacon buffer that is updated with a new one of different | ||
1522 | * size. The pointers are shifted by a fixed amount, either forward or | ||
1523 | * backward. | ||
1524 | * | ||
1525 | * the following pointers in every affected beacon buffers are changed, if | ||
1526 | * present - | ||
1527 | * - WPA IE pointer | ||
1528 | * - RSN IE pointer | ||
1529 | * - WAPI IE pointer | ||
1530 | * - HT capability IE pointer | ||
1531 | * - HT information IE pointer | ||
1532 | * - BSS coexistence 20/40 IE pointer | ||
1533 | * - Extended capability IE pointer | ||
1534 | * - Overlapping BSS scan parameter IE pointer | ||
1535 | */ | ||
1536 | static void | ||
1537 | mwifiex_adjust_beacon_buffer_ptrs(struct mwifiex_private *priv, u8 advance, | ||
1538 | u8 *bcn_store, u32 rem_bcn_size, | ||
1539 | u32 num_of_ent) | ||
1540 | { | ||
1541 | struct mwifiex_adapter *adapter = priv->adapter; | ||
1542 | u32 adj_idx; | ||
1543 | for (adj_idx = 0; adj_idx < num_of_ent; adj_idx++) { | ||
1544 | if (adapter->scan_table[adj_idx].beacon_buf > bcn_store) { | ||
1545 | |||
1546 | if (advance) | ||
1547 | adapter->scan_table[adj_idx].beacon_buf += | ||
1548 | rem_bcn_size; | ||
1549 | else | ||
1550 | adapter->scan_table[adj_idx].beacon_buf -= | ||
1551 | rem_bcn_size; | ||
1552 | |||
1553 | if (adapter->scan_table[adj_idx].bcn_wpa_ie) | ||
1554 | adapter->scan_table[adj_idx].bcn_wpa_ie = | ||
1555 | (struct ieee_types_vendor_specific *) | ||
1556 | (adapter->scan_table[adj_idx].beacon_buf + | ||
1557 | adapter->scan_table[adj_idx].wpa_offset); | ||
1558 | if (adapter->scan_table[adj_idx].bcn_rsn_ie) | ||
1559 | adapter->scan_table[adj_idx].bcn_rsn_ie = | ||
1560 | (struct ieee_types_generic *) | ||
1561 | (adapter->scan_table[adj_idx].beacon_buf + | ||
1562 | adapter->scan_table[adj_idx].rsn_offset); | ||
1563 | if (adapter->scan_table[adj_idx].bcn_wapi_ie) | ||
1564 | adapter->scan_table[adj_idx].bcn_wapi_ie = | ||
1565 | (struct ieee_types_generic *) | ||
1566 | (adapter->scan_table[adj_idx].beacon_buf + | ||
1567 | adapter->scan_table[adj_idx].wapi_offset); | ||
1568 | if (adapter->scan_table[adj_idx].bcn_ht_cap) | ||
1569 | adapter->scan_table[adj_idx].bcn_ht_cap = | ||
1570 | (struct ieee80211_ht_cap *) | ||
1571 | (adapter->scan_table[adj_idx].beacon_buf + | ||
1572 | adapter->scan_table[adj_idx].ht_cap_offset); | ||
1573 | |||
1574 | if (adapter->scan_table[adj_idx].bcn_ht_info) | ||
1575 | adapter->scan_table[adj_idx].bcn_ht_info = | ||
1576 | (struct ieee80211_ht_info *) | ||
1577 | (adapter->scan_table[adj_idx].beacon_buf + | ||
1578 | adapter->scan_table[adj_idx].ht_info_offset); | ||
1579 | if (adapter->scan_table[adj_idx].bcn_bss_co_2040) | ||
1580 | adapter->scan_table[adj_idx].bcn_bss_co_2040 = | ||
1581 | (u8 *) | ||
1582 | (adapter->scan_table[adj_idx].beacon_buf + | ||
1583 | adapter->scan_table[adj_idx].bss_co_2040_offset); | ||
1584 | if (adapter->scan_table[adj_idx].bcn_ext_cap) | ||
1585 | adapter->scan_table[adj_idx].bcn_ext_cap = | ||
1586 | (u8 *) | ||
1587 | (adapter->scan_table[adj_idx].beacon_buf + | ||
1588 | adapter->scan_table[adj_idx].ext_cap_offset); | ||
1589 | if (adapter->scan_table[adj_idx].bcn_obss_scan) | ||
1590 | adapter->scan_table[adj_idx].bcn_obss_scan = | ||
1591 | (struct ieee_types_obss_scan_param *) | ||
1592 | (adapter->scan_table[adj_idx].beacon_buf + | ||
1593 | adapter->scan_table[adj_idx].overlap_bss_offset); | ||
1594 | } | ||
1595 | } | ||
1596 | } | ||
1597 | |||
1598 | /* | ||
1599 | * This function updates the pointers used in beacon buffer for given bss | ||
1600 | * descriptor to reflect shifts | ||
1601 | * | ||
1602 | * Following pointers are updated | ||
1603 | * - WPA IE pointer | ||
1604 | * - RSN IE pointer | ||
1605 | * - WAPI IE pointer | ||
1606 | * - HT capability IE pointer | ||
1607 | * - HT information IE pointer | ||
1608 | * - BSS coexistence 20/40 IE pointer | ||
1609 | * - Extended capability IE pointer | ||
1610 | * - Overlapping BSS scan parameter IE pointer | ||
1611 | */ | ||
1612 | static void | ||
1613 | mwifiex_update_beacon_buffer_ptrs(struct mwifiex_bssdescriptor *beacon) | ||
1614 | { | ||
1615 | if (beacon->bcn_wpa_ie) | ||
1616 | beacon->bcn_wpa_ie = (struct ieee_types_vendor_specific *) | ||
1617 | (beacon->beacon_buf + beacon->wpa_offset); | ||
1618 | if (beacon->bcn_rsn_ie) | ||
1619 | beacon->bcn_rsn_ie = (struct ieee_types_generic *) | ||
1620 | (beacon->beacon_buf + beacon->rsn_offset); | ||
1621 | if (beacon->bcn_wapi_ie) | ||
1622 | beacon->bcn_wapi_ie = (struct ieee_types_generic *) | ||
1623 | (beacon->beacon_buf + beacon->wapi_offset); | ||
1624 | if (beacon->bcn_ht_cap) | ||
1625 | beacon->bcn_ht_cap = (struct ieee80211_ht_cap *) | ||
1626 | (beacon->beacon_buf + beacon->ht_cap_offset); | ||
1627 | if (beacon->bcn_ht_info) | ||
1628 | beacon->bcn_ht_info = (struct ieee80211_ht_info *) | ||
1629 | (beacon->beacon_buf + beacon->ht_info_offset); | ||
1630 | if (beacon->bcn_bss_co_2040) | ||
1631 | beacon->bcn_bss_co_2040 = (u8 *) (beacon->beacon_buf + | ||
1632 | beacon->bss_co_2040_offset); | ||
1633 | if (beacon->bcn_ext_cap) | ||
1634 | beacon->bcn_ext_cap = (u8 *) (beacon->beacon_buf + | ||
1635 | beacon->ext_cap_offset); | ||
1636 | if (beacon->bcn_obss_scan) | ||
1637 | beacon->bcn_obss_scan = (struct ieee_types_obss_scan_param *) | ||
1638 | (beacon->beacon_buf + beacon->overlap_bss_offset); | ||
1639 | } | ||
1640 | |||
1641 | /* | ||
1642 | * This function stores a beacon or probe response for a BSS returned | ||
1643 | * in the scan. | ||
1644 | * | ||
1645 | * This stores a new scan response or an update for a previous scan response. | ||
1646 | * New entries need to verify that they do not exceed the total amount of | ||
1647 | * memory allocated for the table. | ||
1648 | * | ||
1649 | * Replacement entries need to take into consideration the amount of space | ||
1650 | * currently allocated for the beacon/probe response and adjust the entry | ||
1651 | * as needed. | ||
1652 | * | ||
1653 | * A small amount of extra pad (SCAN_BEACON_ENTRY_PAD) is generally reserved | ||
1654 | * for an entry in case it is a beacon since a probe response for the | ||
1655 | * network will by larger per the standard. This helps to reduce the | ||
1656 | * amount of memory copying to fit a new probe response into an entry | ||
1657 | * already occupied by a network's previously stored beacon. | ||
1658 | */ | ||
1659 | static void | ||
1660 | mwifiex_ret_802_11_scan_store_beacon(struct mwifiex_private *priv, | ||
1661 | u32 beacon_idx, u32 num_of_ent, | ||
1662 | struct mwifiex_bssdescriptor *new_beacon) | ||
1663 | { | ||
1664 | struct mwifiex_adapter *adapter = priv->adapter; | ||
1665 | u8 *bcn_store; | ||
1666 | u32 new_bcn_size; | ||
1667 | u32 old_bcn_size; | ||
1668 | u32 bcn_space; | ||
1669 | |||
1670 | if (adapter->scan_table[beacon_idx].beacon_buf) { | ||
1671 | |||
1672 | new_bcn_size = new_beacon->beacon_buf_size; | ||
1673 | old_bcn_size = adapter->scan_table[beacon_idx].beacon_buf_size; | ||
1674 | bcn_space = adapter->scan_table[beacon_idx].beacon_buf_size_max; | ||
1675 | bcn_store = adapter->scan_table[beacon_idx].beacon_buf; | ||
1676 | |||
1677 | /* Set the max to be the same as current entry unless changed | ||
1678 | below */ | ||
1679 | new_beacon->beacon_buf_size_max = bcn_space; | ||
1680 | if (new_bcn_size == old_bcn_size) { | ||
1681 | /* | ||
1682 | * Beacon is the same size as the previous entry. | ||
1683 | * Replace the previous contents with the scan result | ||
1684 | */ | ||
1685 | memcpy(bcn_store, new_beacon->beacon_buf, | ||
1686 | new_beacon->beacon_buf_size); | ||
1687 | |||
1688 | } else if (new_bcn_size <= bcn_space) { | ||
1689 | /* | ||
1690 | * New beacon size will fit in the amount of space | ||
1691 | * we have previously allocated for it | ||
1692 | */ | ||
1693 | |||
1694 | /* Copy the new beacon buffer entry over the old one */ | ||
1695 | memcpy(bcn_store, new_beacon->beacon_buf, new_bcn_size); | ||
1696 | |||
1697 | /* | ||
1698 | * If the old beacon size was less than the maximum | ||
1699 | * we had alloted for the entry, and the new entry | ||
1700 | * is even smaller, reset the max size to the old | ||
1701 | * beacon entry and compress the storage space | ||
1702 | * (leaving a new pad space of (old_bcn_size - | ||
1703 | * new_bcn_size). | ||
1704 | */ | ||
1705 | if (old_bcn_size < bcn_space | ||
1706 | && new_bcn_size <= old_bcn_size) { | ||
1707 | /* | ||
1708 | * Old Beacon size is smaller than the alloted | ||
1709 | * storage size. Shrink the alloted storage | ||
1710 | * space. | ||
1711 | */ | ||
1712 | dev_dbg(adapter->dev, "info: AppControl:" | ||
1713 | " smaller duplicate beacon " | ||
1714 | "(%d), old = %d, new = %d, space = %d," | ||
1715 | "left = %d\n", | ||
1716 | beacon_idx, old_bcn_size, new_bcn_size, | ||
1717 | bcn_space, | ||
1718 | (int)(sizeof(adapter->bcn_buf) - | ||
1719 | (adapter->bcn_buf_end - | ||
1720 | adapter->bcn_buf))); | ||
1721 | |||
1722 | /* | ||
1723 | * memmove (since the memory overlaps) the | ||
1724 | * data after the beacon we just stored to the | ||
1725 | * end of the current beacon. This cleans up | ||
1726 | * any unused space the old larger beacon was | ||
1727 | * using in the buffer | ||
1728 | */ | ||
1729 | memmove(bcn_store + old_bcn_size, | ||
1730 | bcn_store + bcn_space, | ||
1731 | adapter->bcn_buf_end - (bcn_store + | ||
1732 | bcn_space)); | ||
1733 | |||
1734 | /* | ||
1735 | * Decrement the end pointer by the difference | ||
1736 | * between the old larger size and the new | ||
1737 | * smaller size since we are using less space | ||
1738 | * due to the new beacon being smaller | ||
1739 | */ | ||
1740 | adapter->bcn_buf_end -= | ||
1741 | (bcn_space - old_bcn_size); | ||
1742 | |||
1743 | /* Set the maximum storage size to the old | ||
1744 | beacon size */ | ||
1745 | new_beacon->beacon_buf_size_max = old_bcn_size; | ||
1746 | |||
1747 | /* Adjust beacon buffer pointers that are past | ||
1748 | the current */ | ||
1749 | mwifiex_adjust_beacon_buffer_ptrs(priv, 0, | ||
1750 | bcn_store, (bcn_space - old_bcn_size), | ||
1751 | num_of_ent); | ||
1752 | } | ||
1753 | } else if (adapter->bcn_buf_end + (new_bcn_size - bcn_space) | ||
1754 | < (adapter->bcn_buf + sizeof(adapter->bcn_buf))) { | ||
1755 | /* | ||
1756 | * Beacon is larger than space previously allocated | ||
1757 | * (bcn_space) and there is enough space left in the | ||
1758 | * beaconBuffer to store the additional data | ||
1759 | */ | ||
1760 | dev_dbg(adapter->dev, "info: AppControl:" | ||
1761 | " larger duplicate beacon (%d), " | ||
1762 | "old = %d, new = %d, space = %d, left = %d\n", | ||
1763 | beacon_idx, old_bcn_size, new_bcn_size, | ||
1764 | bcn_space, | ||
1765 | (int)(sizeof(adapter->bcn_buf) - | ||
1766 | (adapter->bcn_buf_end - | ||
1767 | adapter->bcn_buf))); | ||
1768 | |||
1769 | /* | ||
1770 | * memmove (since the memory overlaps) the data | ||
1771 | * after the beacon we just stored to the end of | ||
1772 | * the current beacon. This moves the data for | ||
1773 | * the beacons after this further in memory to | ||
1774 | * make space for the new larger beacon we are | ||
1775 | * about to copy in. | ||
1776 | */ | ||
1777 | memmove(bcn_store + new_bcn_size, | ||
1778 | bcn_store + bcn_space, | ||
1779 | adapter->bcn_buf_end - (bcn_store + bcn_space)); | ||
1780 | |||
1781 | /* Copy the new beacon buffer entry over the old one */ | ||
1782 | memcpy(bcn_store, new_beacon->beacon_buf, new_bcn_size); | ||
1783 | |||
1784 | /* Move the beacon end pointer by the amount of new | ||
1785 | beacon data we are adding */ | ||
1786 | adapter->bcn_buf_end += (new_bcn_size - bcn_space); | ||
1787 | |||
1788 | /* | ||
1789 | * This entry is bigger than the alloted max space | ||
1790 | * previously reserved. Increase the max space to | ||
1791 | * be equal to the new beacon size | ||
1792 | */ | ||
1793 | new_beacon->beacon_buf_size_max = new_bcn_size; | ||
1794 | |||
1795 | /* Adjust beacon buffer pointers that are past the | ||
1796 | current */ | ||
1797 | mwifiex_adjust_beacon_buffer_ptrs(priv, 1, bcn_store, | ||
1798 | (new_bcn_size - bcn_space), | ||
1799 | num_of_ent); | ||
1800 | } else { | ||
1801 | /* | ||
1802 | * Beacon is larger than the previously allocated space, | ||
1803 | * but there is not enough free space to store the | ||
1804 | * additional data. | ||
1805 | */ | ||
1806 | dev_err(adapter->dev, "AppControl: larger duplicate " | ||
1807 | " beacon (%d), old = %d new = %d, space = %d," | ||
1808 | " left = %d\n", beacon_idx, old_bcn_size, | ||
1809 | new_bcn_size, bcn_space, | ||
1810 | (int)(sizeof(adapter->bcn_buf) - | ||
1811 | (adapter->bcn_buf_end - adapter->bcn_buf))); | ||
1812 | |||
1813 | /* Storage failure, keep old beacon intact */ | ||
1814 | new_beacon->beacon_buf_size = old_bcn_size; | ||
1815 | if (new_beacon->bcn_wpa_ie) | ||
1816 | new_beacon->wpa_offset = | ||
1817 | adapter->scan_table[beacon_idx]. | ||
1818 | wpa_offset; | ||
1819 | if (new_beacon->bcn_rsn_ie) | ||
1820 | new_beacon->rsn_offset = | ||
1821 | adapter->scan_table[beacon_idx]. | ||
1822 | rsn_offset; | ||
1823 | if (new_beacon->bcn_wapi_ie) | ||
1824 | new_beacon->wapi_offset = | ||
1825 | adapter->scan_table[beacon_idx]. | ||
1826 | wapi_offset; | ||
1827 | if (new_beacon->bcn_ht_cap) | ||
1828 | new_beacon->ht_cap_offset = | ||
1829 | adapter->scan_table[beacon_idx]. | ||
1830 | ht_cap_offset; | ||
1831 | if (new_beacon->bcn_ht_info) | ||
1832 | new_beacon->ht_info_offset = | ||
1833 | adapter->scan_table[beacon_idx]. | ||
1834 | ht_info_offset; | ||
1835 | if (new_beacon->bcn_bss_co_2040) | ||
1836 | new_beacon->bss_co_2040_offset = | ||
1837 | adapter->scan_table[beacon_idx]. | ||
1838 | bss_co_2040_offset; | ||
1839 | if (new_beacon->bcn_ext_cap) | ||
1840 | new_beacon->ext_cap_offset = | ||
1841 | adapter->scan_table[beacon_idx]. | ||
1842 | ext_cap_offset; | ||
1843 | if (new_beacon->bcn_obss_scan) | ||
1844 | new_beacon->overlap_bss_offset = | ||
1845 | adapter->scan_table[beacon_idx]. | ||
1846 | overlap_bss_offset; | ||
1847 | } | ||
1848 | /* Point the new entry to its permanent storage space */ | ||
1849 | new_beacon->beacon_buf = bcn_store; | ||
1850 | mwifiex_update_beacon_buffer_ptrs(new_beacon); | ||
1851 | } else { | ||
1852 | /* | ||
1853 | * No existing beacon data exists for this entry, check to see | ||
1854 | * if we can fit it in the remaining space | ||
1855 | */ | ||
1856 | if (adapter->bcn_buf_end + new_beacon->beacon_buf_size + | ||
1857 | SCAN_BEACON_ENTRY_PAD < (adapter->bcn_buf + | ||
1858 | sizeof(adapter->bcn_buf))) { | ||
1859 | |||
1860 | /* | ||
1861 | * Copy the beacon buffer data from the local entry to | ||
1862 | * the adapter dev struct buffer space used to store | ||
1863 | * the raw beacon data for each entry in the scan table | ||
1864 | */ | ||
1865 | memcpy(adapter->bcn_buf_end, new_beacon->beacon_buf, | ||
1866 | new_beacon->beacon_buf_size); | ||
1867 | |||
1868 | /* Update the beacon ptr to point to the table save | ||
1869 | area */ | ||
1870 | new_beacon->beacon_buf = adapter->bcn_buf_end; | ||
1871 | new_beacon->beacon_buf_size_max = | ||
1872 | (new_beacon->beacon_buf_size + | ||
1873 | SCAN_BEACON_ENTRY_PAD); | ||
1874 | |||
1875 | mwifiex_update_beacon_buffer_ptrs(new_beacon); | ||
1876 | |||
1877 | /* Increment the end pointer by the size reserved */ | ||
1878 | adapter->bcn_buf_end += new_beacon->beacon_buf_size_max; | ||
1879 | |||
1880 | dev_dbg(adapter->dev, "info: AppControl: beacon[%02d]" | ||
1881 | " sz=%03d, used = %04d, left = %04d\n", | ||
1882 | beacon_idx, | ||
1883 | new_beacon->beacon_buf_size, | ||
1884 | (int)(adapter->bcn_buf_end - adapter->bcn_buf), | ||
1885 | (int)(sizeof(adapter->bcn_buf) - | ||
1886 | (adapter->bcn_buf_end - | ||
1887 | adapter->bcn_buf))); | ||
1888 | } else { | ||
1889 | /* No space for new beacon */ | ||
1890 | dev_dbg(adapter->dev, "info: AppControl: no space for" | ||
1891 | " beacon (%d): %pM sz=%03d, left=%03d\n", | ||
1892 | beacon_idx, new_beacon->mac_address, | ||
1893 | new_beacon->beacon_buf_size, | ||
1894 | (int)(sizeof(adapter->bcn_buf) - | ||
1895 | (adapter->bcn_buf_end - | ||
1896 | adapter->bcn_buf))); | ||
1897 | |||
1898 | /* Storage failure; clear storage records for this | ||
1899 | bcn */ | ||
1900 | new_beacon->beacon_buf = NULL; | ||
1901 | new_beacon->beacon_buf_size = 0; | ||
1902 | new_beacon->beacon_buf_size_max = 0; | ||
1903 | new_beacon->bcn_wpa_ie = NULL; | ||
1904 | new_beacon->wpa_offset = 0; | ||
1905 | new_beacon->bcn_rsn_ie = NULL; | ||
1906 | new_beacon->rsn_offset = 0; | ||
1907 | new_beacon->bcn_wapi_ie = NULL; | ||
1908 | new_beacon->wapi_offset = 0; | ||
1909 | new_beacon->bcn_ht_cap = NULL; | ||
1910 | new_beacon->ht_cap_offset = 0; | ||
1911 | new_beacon->bcn_ht_info = NULL; | ||
1912 | new_beacon->ht_info_offset = 0; | ||
1913 | new_beacon->bcn_bss_co_2040 = NULL; | ||
1914 | new_beacon->bss_co_2040_offset = 0; | ||
1915 | new_beacon->bcn_ext_cap = NULL; | ||
1916 | new_beacon->ext_cap_offset = 0; | ||
1917 | new_beacon->bcn_obss_scan = NULL; | ||
1918 | new_beacon->overlap_bss_offset = 0; | ||
1919 | } | ||
1920 | } | ||
1921 | } | ||
1922 | |||
1923 | /* | ||
1924 | * This function restores a beacon buffer of the current BSS descriptor. | ||
1925 | */ | ||
1926 | static void mwifiex_restore_curr_bcn(struct mwifiex_private *priv) | ||
1927 | { | ||
1928 | struct mwifiex_adapter *adapter = priv->adapter; | ||
1929 | struct mwifiex_bssdescriptor *curr_bss = | ||
1930 | &priv->curr_bss_params.bss_descriptor; | ||
1931 | unsigned long flags; | ||
1932 | |||
1933 | if (priv->curr_bcn_buf && | ||
1934 | ((adapter->bcn_buf_end + priv->curr_bcn_size) < | ||
1935 | (adapter->bcn_buf + sizeof(adapter->bcn_buf)))) { | ||
1936 | spin_lock_irqsave(&priv->curr_bcn_buf_lock, flags); | ||
1937 | |||
1938 | /* restore the current beacon buffer */ | ||
1939 | memcpy(adapter->bcn_buf_end, priv->curr_bcn_buf, | ||
1940 | priv->curr_bcn_size); | ||
1941 | curr_bss->beacon_buf = adapter->bcn_buf_end; | ||
1942 | curr_bss->beacon_buf_size = priv->curr_bcn_size; | ||
1943 | adapter->bcn_buf_end += priv->curr_bcn_size; | ||
1944 | |||
1945 | /* adjust the pointers in the current BSS descriptor */ | ||
1946 | if (curr_bss->bcn_wpa_ie) | ||
1947 | curr_bss->bcn_wpa_ie = | ||
1948 | (struct ieee_types_vendor_specific *) | ||
1949 | (curr_bss->beacon_buf + | ||
1950 | curr_bss->wpa_offset); | ||
1951 | |||
1952 | if (curr_bss->bcn_rsn_ie) | ||
1953 | curr_bss->bcn_rsn_ie = (struct ieee_types_generic *) | ||
1954 | (curr_bss->beacon_buf + | ||
1955 | curr_bss->rsn_offset); | ||
1956 | |||
1957 | if (curr_bss->bcn_ht_cap) | ||
1958 | curr_bss->bcn_ht_cap = (struct ieee80211_ht_cap *) | ||
1959 | (curr_bss->beacon_buf + | ||
1960 | curr_bss->ht_cap_offset); | ||
1961 | |||
1962 | if (curr_bss->bcn_ht_info) | ||
1963 | curr_bss->bcn_ht_info = (struct ieee80211_ht_info *) | ||
1964 | (curr_bss->beacon_buf + | ||
1965 | curr_bss->ht_info_offset); | ||
1966 | |||
1967 | if (curr_bss->bcn_bss_co_2040) | ||
1968 | curr_bss->bcn_bss_co_2040 = | ||
1969 | (u8 *) (curr_bss->beacon_buf + | ||
1970 | curr_bss->bss_co_2040_offset); | ||
1971 | |||
1972 | if (curr_bss->bcn_ext_cap) | ||
1973 | curr_bss->bcn_ext_cap = (u8 *) (curr_bss->beacon_buf + | ||
1974 | curr_bss->ext_cap_offset); | ||
1975 | |||
1976 | if (curr_bss->bcn_obss_scan) | ||
1977 | curr_bss->bcn_obss_scan = | ||
1978 | (struct ieee_types_obss_scan_param *) | ||
1979 | (curr_bss->beacon_buf + | ||
1980 | curr_bss->overlap_bss_offset); | ||
1981 | |||
1982 | spin_unlock_irqrestore(&priv->curr_bcn_buf_lock, flags); | ||
1983 | |||
1984 | dev_dbg(adapter->dev, "info: current beacon restored %d\n", | ||
1985 | priv->curr_bcn_size); | ||
1986 | } else { | ||
1987 | dev_warn(adapter->dev, | ||
1988 | "curr_bcn_buf not saved or bcn_buf has no space\n"); | ||
1989 | } | ||
1990 | } | ||
1991 | |||
1992 | /* | ||
1993 | * This function post processes the scan table after a new scan command has | ||
1994 | * completed. | ||
1995 | * | ||
1996 | * It inspects each entry of the scan table and tries to find an entry that | ||
1997 | * matches with our current associated/joined network from the scan. If | ||
1998 | * one is found, the stored copy of the BSS descriptor of our current network | ||
1999 | * is updated. | ||
2000 | * | ||
2001 | * It also debug dumps the current scan table contents after processing is over. | ||
2002 | */ | ||
2003 | static void | ||
2004 | mwifiex_process_scan_results(struct mwifiex_private *priv) | ||
2005 | { | ||
2006 | struct mwifiex_adapter *adapter = priv->adapter; | ||
2007 | s32 j; | ||
2008 | u32 i; | ||
2009 | unsigned long flags; | ||
2010 | |||
2011 | if (priv->media_connected) { | ||
2012 | |||
2013 | j = mwifiex_find_ssid_in_list(priv, &priv->curr_bss_params. | ||
2014 | bss_descriptor.ssid, | ||
2015 | priv->curr_bss_params. | ||
2016 | bss_descriptor.mac_address, | ||
2017 | priv->bss_mode); | ||
2018 | |||
2019 | if (j >= 0) { | ||
2020 | spin_lock_irqsave(&priv->curr_bcn_buf_lock, flags); | ||
2021 | priv->curr_bss_params.bss_descriptor.bcn_wpa_ie = NULL; | ||
2022 | priv->curr_bss_params.bss_descriptor.wpa_offset = 0; | ||
2023 | priv->curr_bss_params.bss_descriptor.bcn_rsn_ie = NULL; | ||
2024 | priv->curr_bss_params.bss_descriptor.rsn_offset = 0; | ||
2025 | priv->curr_bss_params.bss_descriptor.bcn_wapi_ie = NULL; | ||
2026 | priv->curr_bss_params.bss_descriptor.wapi_offset = 0; | ||
2027 | priv->curr_bss_params.bss_descriptor.bcn_ht_cap = NULL; | ||
2028 | priv->curr_bss_params.bss_descriptor.ht_cap_offset = | ||
2029 | 0; | ||
2030 | priv->curr_bss_params.bss_descriptor.bcn_ht_info = NULL; | ||
2031 | priv->curr_bss_params.bss_descriptor.ht_info_offset = | ||
2032 | 0; | ||
2033 | priv->curr_bss_params.bss_descriptor.bcn_bss_co_2040 = | ||
2034 | NULL; | ||
2035 | priv->curr_bss_params.bss_descriptor. | ||
2036 | bss_co_2040_offset = 0; | ||
2037 | priv->curr_bss_params.bss_descriptor.bcn_ext_cap = NULL; | ||
2038 | priv->curr_bss_params.bss_descriptor.ext_cap_offset = 0; | ||
2039 | priv->curr_bss_params.bss_descriptor. | ||
2040 | bcn_obss_scan = NULL; | ||
2041 | priv->curr_bss_params.bss_descriptor. | ||
2042 | overlap_bss_offset = 0; | ||
2043 | priv->curr_bss_params.bss_descriptor.beacon_buf = NULL; | ||
2044 | priv->curr_bss_params.bss_descriptor.beacon_buf_size = | ||
2045 | 0; | ||
2046 | priv->curr_bss_params.bss_descriptor. | ||
2047 | beacon_buf_size_max = 0; | ||
2048 | |||
2049 | dev_dbg(adapter->dev, "info: Found current ssid/bssid" | ||
2050 | " in list @ index #%d\n", j); | ||
2051 | /* Make a copy of current BSSID descriptor */ | ||
2052 | memcpy(&priv->curr_bss_params.bss_descriptor, | ||
2053 | &adapter->scan_table[j], | ||
2054 | sizeof(priv->curr_bss_params.bss_descriptor)); | ||
2055 | |||
2056 | mwifiex_save_curr_bcn(priv); | ||
2057 | spin_unlock_irqrestore(&priv->curr_bcn_buf_lock, flags); | ||
2058 | |||
2059 | } else { | ||
2060 | mwifiex_restore_curr_bcn(priv); | ||
2061 | } | ||
2062 | } | ||
2063 | |||
2064 | for (i = 0; i < adapter->num_in_scan_table; i++) | ||
2065 | dev_dbg(adapter->dev, "info: scan:(%02d) %pM " | ||
2066 | "RSSI[%03d], SSID[%s]\n", | ||
2067 | i, adapter->scan_table[i].mac_address, | ||
2068 | (s32) adapter->scan_table[i].rssi, | ||
2069 | adapter->scan_table[i].ssid.ssid); | ||
2070 | } | ||
2071 | |||
2072 | /* | ||
2073 | * This function converts radio type scan parameter to a band configuration | ||
2074 | * to be used in join command. | ||
2075 | */ | ||
2076 | static u8 | ||
2077 | mwifiex_radio_type_to_band(u8 radio_type) | ||
2078 | { | ||
2079 | u8 ret_band; | ||
2080 | |||
2081 | switch (radio_type) { | ||
2082 | case HostCmd_SCAN_RADIO_TYPE_A: | ||
2083 | ret_band = BAND_A; | ||
2084 | break; | ||
2085 | case HostCmd_SCAN_RADIO_TYPE_BG: | ||
2086 | default: | ||
2087 | ret_band = BAND_G; | ||
2088 | break; | ||
2089 | } | ||
2090 | |||
2091 | return ret_band; | ||
2092 | } | ||
2093 | |||
2094 | /* | ||
2095 | * This function deletes a specific indexed entry from the scan table. | ||
2096 | * | ||
2097 | * This also compacts the remaining entries and adjusts any buffering | ||
2098 | * of beacon/probe response data if needed. | ||
2099 | */ | ||
2100 | static void | ||
2101 | mwifiex_scan_delete_table_entry(struct mwifiex_private *priv, s32 table_idx) | ||
2102 | { | ||
2103 | struct mwifiex_adapter *adapter = priv->adapter; | ||
2104 | u32 del_idx; | ||
2105 | u32 beacon_buf_adj; | ||
2106 | u8 *beacon_buf; | ||
2107 | |||
2108 | /* | ||
2109 | * Shift the saved beacon buffer data for the scan table back over the | ||
2110 | * entry being removed. Update the end of buffer pointer. Save the | ||
2111 | * deleted buffer allocation size for pointer adjustments for entries | ||
2112 | * compacted after the deleted index. | ||
2113 | */ | ||
2114 | beacon_buf_adj = adapter->scan_table[table_idx].beacon_buf_size_max; | ||
2115 | |||
2116 | dev_dbg(adapter->dev, "info: Scan: Delete Entry %d, beacon buffer " | ||
2117 | "removal = %d bytes\n", table_idx, beacon_buf_adj); | ||
2118 | |||
2119 | /* Check if the table entry had storage allocated for its beacon */ | ||
2120 | if (beacon_buf_adj) { | ||
2121 | beacon_buf = adapter->scan_table[table_idx].beacon_buf; | ||
2122 | |||
2123 | /* | ||
2124 | * Remove the entry's buffer space, decrement the table end | ||
2125 | * pointer by the amount we are removing | ||
2126 | */ | ||
2127 | adapter->bcn_buf_end -= beacon_buf_adj; | ||
2128 | |||
2129 | dev_dbg(adapter->dev, "info: scan: delete entry %d," | ||
2130 | " compact data: %p <- %p (sz = %d)\n", | ||
2131 | table_idx, beacon_buf, | ||
2132 | beacon_buf + beacon_buf_adj, | ||
2133 | (int)(adapter->bcn_buf_end - beacon_buf)); | ||
2134 | |||
2135 | /* | ||
2136 | * Compact data storage. Copy all data after the deleted | ||
2137 | * entry's end address (beacon_buf + beacon_buf_adj) back | ||
2138 | * to the original start address (beacon_buf). | ||
2139 | * | ||
2140 | * Scan table entries affected by the move will have their | ||
2141 | * entry pointer adjusted below. | ||
2142 | * | ||
2143 | * Use memmove since the dest/src memory regions overlap. | ||
2144 | */ | ||
2145 | memmove(beacon_buf, beacon_buf + beacon_buf_adj, | ||
2146 | adapter->bcn_buf_end - beacon_buf); | ||
2147 | } | ||
2148 | |||
2149 | dev_dbg(adapter->dev, | ||
2150 | "info: Scan: Delete Entry %d, num_in_scan_table = %d\n", | ||
2151 | table_idx, adapter->num_in_scan_table); | ||
2152 | |||
2153 | /* Shift all of the entries after the table_idx back by one, compacting | ||
2154 | the table and removing the requested entry */ | ||
2155 | for (del_idx = table_idx; (del_idx + 1) < adapter->num_in_scan_table; | ||
2156 | del_idx++) { | ||
2157 | /* Copy the next entry over this one */ | ||
2158 | memcpy(adapter->scan_table + del_idx, | ||
2159 | adapter->scan_table + del_idx + 1, | ||
2160 | sizeof(struct mwifiex_bssdescriptor)); | ||
2161 | |||
2162 | /* | ||
2163 | * Adjust this entry's pointer to its beacon buffer based on | ||
2164 | * the removed/compacted entry from the deleted index. Don't | ||
2165 | * decrement if the buffer pointer is NULL (no data stored for | ||
2166 | * this entry). | ||
2167 | */ | ||
2168 | if (adapter->scan_table[del_idx].beacon_buf) { | ||
2169 | adapter->scan_table[del_idx].beacon_buf -= | ||
2170 | beacon_buf_adj; | ||
2171 | if (adapter->scan_table[del_idx].bcn_wpa_ie) | ||
2172 | adapter->scan_table[del_idx].bcn_wpa_ie = | ||
2173 | (struct ieee_types_vendor_specific *) | ||
2174 | (adapter->scan_table[del_idx]. | ||
2175 | beacon_buf + | ||
2176 | adapter->scan_table[del_idx]. | ||
2177 | wpa_offset); | ||
2178 | if (adapter->scan_table[del_idx].bcn_rsn_ie) | ||
2179 | adapter->scan_table[del_idx].bcn_rsn_ie = | ||
2180 | (struct ieee_types_generic *) | ||
2181 | (adapter->scan_table[del_idx]. | ||
2182 | beacon_buf + | ||
2183 | adapter->scan_table[del_idx]. | ||
2184 | rsn_offset); | ||
2185 | if (adapter->scan_table[del_idx].bcn_wapi_ie) | ||
2186 | adapter->scan_table[del_idx].bcn_wapi_ie = | ||
2187 | (struct ieee_types_generic *) | ||
2188 | (adapter->scan_table[del_idx].beacon_buf | ||
2189 | + adapter->scan_table[del_idx]. | ||
2190 | wapi_offset); | ||
2191 | if (adapter->scan_table[del_idx].bcn_ht_cap) | ||
2192 | adapter->scan_table[del_idx].bcn_ht_cap = | ||
2193 | (struct ieee80211_ht_cap *) | ||
2194 | (adapter->scan_table[del_idx].beacon_buf | ||
2195 | + adapter->scan_table[del_idx]. | ||
2196 | ht_cap_offset); | ||
2197 | |||
2198 | if (adapter->scan_table[del_idx].bcn_ht_info) | ||
2199 | adapter->scan_table[del_idx].bcn_ht_info = | ||
2200 | (struct ieee80211_ht_info *) | ||
2201 | (adapter->scan_table[del_idx].beacon_buf | ||
2202 | + adapter->scan_table[del_idx]. | ||
2203 | ht_info_offset); | ||
2204 | if (adapter->scan_table[del_idx].bcn_bss_co_2040) | ||
2205 | adapter->scan_table[del_idx].bcn_bss_co_2040 = | ||
2206 | (u8 *) | ||
2207 | (adapter->scan_table[del_idx].beacon_buf | ||
2208 | + adapter->scan_table[del_idx]. | ||
2209 | bss_co_2040_offset); | ||
2210 | if (adapter->scan_table[del_idx].bcn_ext_cap) | ||
2211 | adapter->scan_table[del_idx].bcn_ext_cap = | ||
2212 | (u8 *) | ||
2213 | (adapter->scan_table[del_idx].beacon_buf | ||
2214 | + adapter->scan_table[del_idx]. | ||
2215 | ext_cap_offset); | ||
2216 | if (adapter->scan_table[del_idx].bcn_obss_scan) | ||
2217 | adapter->scan_table[del_idx]. | ||
2218 | bcn_obss_scan = | ||
2219 | (struct ieee_types_obss_scan_param *) | ||
2220 | (adapter->scan_table[del_idx].beacon_buf | ||
2221 | + adapter->scan_table[del_idx]. | ||
2222 | overlap_bss_offset); | ||
2223 | } | ||
2224 | } | ||
2225 | |||
2226 | /* The last entry is invalid now that it has been deleted or moved | ||
2227 | back */ | ||
2228 | memset(adapter->scan_table + adapter->num_in_scan_table - 1, | ||
2229 | 0x00, sizeof(struct mwifiex_bssdescriptor)); | ||
2230 | |||
2231 | adapter->num_in_scan_table--; | ||
2232 | } | ||
2233 | |||
2234 | /* | ||
2235 | * This function deletes all occurrences of a given SSID from the scan table. | ||
2236 | * | ||
2237 | * This iterates through the scan table and deletes all entries that match | ||
2238 | * the given SSID. It also compacts the remaining scan table entries. | ||
2239 | */ | ||
2240 | static int | ||
2241 | mwifiex_scan_delete_ssid_table_entry(struct mwifiex_private *priv, | ||
2242 | struct mwifiex_802_11_ssid *del_ssid) | ||
2243 | { | ||
2244 | int ret = -1; | ||
2245 | s32 table_idx; | ||
2246 | |||
2247 | dev_dbg(priv->adapter->dev, "info: scan: delete ssid entry: %-32s\n", | ||
2248 | del_ssid->ssid); | ||
2249 | |||
2250 | /* If the requested SSID is found in the table, delete it. Then keep | ||
2251 | searching the table for multiple entires for the SSID until no | ||
2252 | more are found */ | ||
2253 | while ((table_idx = mwifiex_find_ssid_in_list(priv, del_ssid, NULL, | ||
2254 | NL80211_IFTYPE_UNSPECIFIED)) >= 0) { | ||
2255 | dev_dbg(priv->adapter->dev, | ||
2256 | "info: Scan: Delete SSID Entry: Found Idx = %d\n", | ||
2257 | table_idx); | ||
2258 | ret = 0; | ||
2259 | mwifiex_scan_delete_table_entry(priv, table_idx); | ||
2260 | } | ||
2261 | |||
2262 | return ret; | ||
2263 | } | ||
2264 | |||
2265 | /* | ||
2266 | * This is an internal function used to start a scan based on an input | ||
2267 | * configuration. | ||
2268 | * | ||
2269 | * This uses the input user scan configuration information when provided in | ||
2270 | * order to send the appropriate scan commands to firmware to populate or | ||
2271 | * update the internal driver scan table. | ||
2272 | */ | ||
2273 | int mwifiex_scan_networks(struct mwifiex_private *priv, | ||
2274 | void *wait_buf, u16 action, | ||
2275 | const struct mwifiex_user_scan_cfg *user_scan_in, | ||
2276 | struct mwifiex_scan_resp *scan_resp) | ||
2277 | { | ||
2278 | int ret = 0; | ||
2279 | struct mwifiex_adapter *adapter = priv->adapter; | ||
2280 | struct cmd_ctrl_node *cmd_node = NULL; | ||
2281 | union mwifiex_scan_cmd_config_tlv *scan_cfg_out = NULL; | ||
2282 | struct mwifiex_ie_types_chan_list_param_set *chan_list_out; | ||
2283 | u32 buf_size; | ||
2284 | struct mwifiex_chan_scan_param_set *scan_chan_list; | ||
2285 | u8 keep_previous_scan; | ||
2286 | u8 filtered_scan; | ||
2287 | u8 scan_current_chan_only; | ||
2288 | u8 max_chan_per_scan; | ||
2289 | unsigned long flags; | ||
2290 | |||
2291 | if (action == HostCmd_ACT_GEN_GET) { | ||
2292 | if (scan_resp) { | ||
2293 | scan_resp->scan_table = (u8 *) adapter->scan_table; | ||
2294 | scan_resp->num_in_scan_table = | ||
2295 | adapter->num_in_scan_table; | ||
2296 | } else { | ||
2297 | ret = -1; | ||
2298 | } | ||
2299 | return ret; | ||
2300 | } | ||
2301 | |||
2302 | if (adapter->scan_processing && action == HostCmd_ACT_GEN_SET) { | ||
2303 | dev_dbg(adapter->dev, "cmd: Scan already in process...\n"); | ||
2304 | return ret; | ||
2305 | } | ||
2306 | |||
2307 | spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); | ||
2308 | adapter->scan_processing = true; | ||
2309 | spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); | ||
2310 | |||
2311 | if (priv->scan_block && action == HostCmd_ACT_GEN_SET) { | ||
2312 | dev_dbg(adapter->dev, | ||
2313 | "cmd: Scan is blocked during association...\n"); | ||
2314 | return ret; | ||
2315 | } | ||
2316 | |||
2317 | scan_cfg_out = kzalloc(sizeof(union mwifiex_scan_cmd_config_tlv), | ||
2318 | GFP_KERNEL); | ||
2319 | if (!scan_cfg_out) { | ||
2320 | dev_err(adapter->dev, "failed to alloc scan_cfg_out\n"); | ||
2321 | return -1; | ||
2322 | } | ||
2323 | |||
2324 | buf_size = sizeof(struct mwifiex_chan_scan_param_set) * | ||
2325 | MWIFIEX_USER_SCAN_CHAN_MAX; | ||
2326 | scan_chan_list = kzalloc(buf_size, GFP_KERNEL); | ||
2327 | if (!scan_chan_list) { | ||
2328 | dev_err(adapter->dev, "failed to alloc scan_chan_list\n"); | ||
2329 | kfree(scan_cfg_out); | ||
2330 | return -1; | ||
2331 | } | ||
2332 | |||
2333 | keep_previous_scan = false; | ||
2334 | |||
2335 | mwifiex_scan_setup_scan_config(priv, user_scan_in, | ||
2336 | &scan_cfg_out->config, &chan_list_out, | ||
2337 | scan_chan_list, &max_chan_per_scan, | ||
2338 | &filtered_scan, &scan_current_chan_only); | ||
2339 | |||
2340 | if (user_scan_in) | ||
2341 | keep_previous_scan = user_scan_in->keep_previous_scan; | ||
2342 | |||
2343 | |||
2344 | if (!keep_previous_scan) { | ||
2345 | memset(adapter->scan_table, 0x00, | ||
2346 | sizeof(struct mwifiex_bssdescriptor) * IW_MAX_AP); | ||
2347 | adapter->num_in_scan_table = 0; | ||
2348 | adapter->bcn_buf_end = adapter->bcn_buf; | ||
2349 | } | ||
2350 | |||
2351 | ret = mwifiex_scan_channel_list(priv, wait_buf, max_chan_per_scan, | ||
2352 | filtered_scan, &scan_cfg_out->config, | ||
2353 | chan_list_out, scan_chan_list); | ||
2354 | |||
2355 | /* Get scan command from scan_pending_q and put to cmd_pending_q */ | ||
2356 | if (!ret) { | ||
2357 | spin_lock_irqsave(&adapter->scan_pending_q_lock, flags); | ||
2358 | if (!list_empty(&adapter->scan_pending_q)) { | ||
2359 | cmd_node = list_first_entry(&adapter->scan_pending_q, | ||
2360 | struct cmd_ctrl_node, list); | ||
2361 | list_del(&cmd_node->list); | ||
2362 | spin_unlock_irqrestore(&adapter->scan_pending_q_lock, | ||
2363 | flags); | ||
2364 | mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, | ||
2365 | true); | ||
2366 | } else { | ||
2367 | spin_unlock_irqrestore(&adapter->scan_pending_q_lock, | ||
2368 | flags); | ||
2369 | } | ||
2370 | ret = -EINPROGRESS; | ||
2371 | } else { | ||
2372 | spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); | ||
2373 | adapter->scan_processing = true; | ||
2374 | spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); | ||
2375 | } | ||
2376 | |||
2377 | kfree(scan_cfg_out); | ||
2378 | kfree(scan_chan_list); | ||
2379 | return ret; | ||
2380 | } | ||
2381 | |||
2382 | /* | ||
2383 | * This function prepares a scan command to be sent to the firmware. | ||
2384 | * | ||
2385 | * This uses the scan command configuration sent to the command processing | ||
2386 | * module in command preparation stage to configure a scan command structure | ||
2387 | * to send to firmware. | ||
2388 | * | ||
2389 | * The fixed fields specifying the BSS type and BSSID filters as well as a | ||
2390 | * variable number/length of TLVs are sent in the command to firmware. | ||
2391 | * | ||
2392 | * Preparation also includes - | ||
2393 | * - Setting command ID, and proper size | ||
2394 | * - Ensuring correct endian-ness | ||
2395 | */ | ||
2396 | int mwifiex_cmd_802_11_scan(struct mwifiex_private *priv, | ||
2397 | struct host_cmd_ds_command *cmd, void *data_buf) | ||
2398 | { | ||
2399 | struct host_cmd_ds_802_11_scan *scan_cmd = &cmd->params.scan; | ||
2400 | struct mwifiex_scan_cmd_config *scan_cfg; | ||
2401 | |||
2402 | scan_cfg = (struct mwifiex_scan_cmd_config *) data_buf; | ||
2403 | |||
2404 | /* Set fixed field variables in scan command */ | ||
2405 | scan_cmd->bss_mode = scan_cfg->bss_mode; | ||
2406 | memcpy(scan_cmd->bssid, scan_cfg->specific_bssid, | ||
2407 | sizeof(scan_cmd->bssid)); | ||
2408 | memcpy(scan_cmd->tlv_buffer, scan_cfg->tlv_buf, scan_cfg->tlv_buf_len); | ||
2409 | |||
2410 | cmd->command = cpu_to_le16(HostCmd_CMD_802_11_SCAN); | ||
2411 | |||
2412 | /* Size is equal to the sizeof(fixed portions) + the TLV len + header */ | ||
2413 | cmd->size = cpu_to_le16((u16) (sizeof(scan_cmd->bss_mode) | ||
2414 | + sizeof(scan_cmd->bssid) | ||
2415 | + scan_cfg->tlv_buf_len + S_DS_GEN)); | ||
2416 | |||
2417 | return 0; | ||
2418 | } | ||
2419 | |||
2420 | /* | ||
2421 | * This function handles the command response of scan. | ||
2422 | * | ||
2423 | * The response buffer for the scan command has the following | ||
2424 | * memory layout: | ||
2425 | * | ||
2426 | * .-------------------------------------------------------------. | ||
2427 | * | Header (4 * sizeof(t_u16)): Standard command response hdr | | ||
2428 | * .-------------------------------------------------------------. | ||
2429 | * | BufSize (t_u16) : sizeof the BSS Description data | | ||
2430 | * .-------------------------------------------------------------. | ||
2431 | * | NumOfSet (t_u8) : Number of BSS Descs returned | | ||
2432 | * .-------------------------------------------------------------. | ||
2433 | * | BSSDescription data (variable, size given in BufSize) | | ||
2434 | * .-------------------------------------------------------------. | ||
2435 | * | TLV data (variable, size calculated using Header->Size, | | ||
2436 | * | BufSize and sizeof the fixed fields above) | | ||
2437 | * .-------------------------------------------------------------. | ||
2438 | */ | ||
2439 | int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, | ||
2440 | struct host_cmd_ds_command *resp, void *wq_buf) | ||
2441 | { | ||
2442 | int ret = 0; | ||
2443 | struct mwifiex_adapter *adapter = priv->adapter; | ||
2444 | struct mwifiex_wait_queue *wait_queue = NULL; | ||
2445 | struct cmd_ctrl_node *cmd_node = NULL; | ||
2446 | struct host_cmd_ds_802_11_scan_rsp *scan_rsp = NULL; | ||
2447 | struct mwifiex_bssdescriptor *bss_new_entry = NULL; | ||
2448 | struct mwifiex_ie_types_data *tlv_data; | ||
2449 | struct mwifiex_ie_types_tsf_timestamp *tsf_tlv; | ||
2450 | u8 *bss_info; | ||
2451 | u32 scan_resp_size; | ||
2452 | u32 bytes_left; | ||
2453 | u32 num_in_table; | ||
2454 | u32 bss_idx; | ||
2455 | u32 idx; | ||
2456 | u32 tlv_buf_size; | ||
2457 | long long tsf_val; | ||
2458 | struct mwifiex_chan_freq_power *cfp; | ||
2459 | struct mwifiex_ie_types_chan_band_list_param_set *chan_band_tlv; | ||
2460 | struct chan_band_param_set *chan_band; | ||
2461 | u8 band; | ||
2462 | u8 is_bgscan_resp; | ||
2463 | unsigned long flags; | ||
2464 | |||
2465 | is_bgscan_resp = (le16_to_cpu(resp->command) | ||
2466 | == HostCmd_CMD_802_11_BG_SCAN_QUERY); | ||
2467 | if (is_bgscan_resp) | ||
2468 | scan_rsp = &resp->params.bg_scan_query_resp.scan_resp; | ||
2469 | else | ||
2470 | scan_rsp = &resp->params.scan_resp; | ||
2471 | |||
2472 | |||
2473 | if (scan_rsp->number_of_sets > IW_MAX_AP) { | ||
2474 | dev_err(adapter->dev, "SCAN_RESP: too many AP returned (%d)\n", | ||
2475 | scan_rsp->number_of_sets); | ||
2476 | ret = -1; | ||
2477 | goto done; | ||
2478 | } | ||
2479 | |||
2480 | bytes_left = le16_to_cpu(scan_rsp->bss_descript_size); | ||
2481 | dev_dbg(adapter->dev, "info: SCAN_RESP: bss_descript_size %d\n", | ||
2482 | bytes_left); | ||
2483 | |||
2484 | scan_resp_size = le16_to_cpu(resp->size); | ||
2485 | |||
2486 | dev_dbg(adapter->dev, | ||
2487 | "info: SCAN_RESP: returned %d APs before parsing\n", | ||
2488 | scan_rsp->number_of_sets); | ||
2489 | |||
2490 | num_in_table = adapter->num_in_scan_table; | ||
2491 | bss_info = scan_rsp->bss_desc_and_tlv_buffer; | ||
2492 | |||
2493 | /* | ||
2494 | * The size of the TLV buffer is equal to the entire command response | ||
2495 | * size (scan_resp_size) minus the fixed fields (sizeof()'s), the | ||
2496 | * BSS Descriptions (bss_descript_size as bytesLef) and the command | ||
2497 | * response header (S_DS_GEN) | ||
2498 | */ | ||
2499 | tlv_buf_size = scan_resp_size - (bytes_left | ||
2500 | + sizeof(scan_rsp->bss_descript_size) | ||
2501 | + sizeof(scan_rsp->number_of_sets) | ||
2502 | + S_DS_GEN); | ||
2503 | |||
2504 | tlv_data = (struct mwifiex_ie_types_data *) (scan_rsp-> | ||
2505 | bss_desc_and_tlv_buffer + | ||
2506 | bytes_left); | ||
2507 | |||
2508 | /* Search the TLV buffer space in the scan response for any valid | ||
2509 | TLVs */ | ||
2510 | mwifiex_ret_802_11_scan_get_tlv_ptrs(adapter, tlv_data, tlv_buf_size, | ||
2511 | TLV_TYPE_TSFTIMESTAMP, | ||
2512 | (struct mwifiex_ie_types_data **) | ||
2513 | &tsf_tlv); | ||
2514 | |||
2515 | /* Search the TLV buffer space in the scan response for any valid | ||
2516 | TLVs */ | ||
2517 | mwifiex_ret_802_11_scan_get_tlv_ptrs(adapter, tlv_data, tlv_buf_size, | ||
2518 | TLV_TYPE_CHANNELBANDLIST, | ||
2519 | (struct mwifiex_ie_types_data **) | ||
2520 | &chan_band_tlv); | ||
2521 | |||
2522 | /* | ||
2523 | * Process each scan response returned (scan_rsp->number_of_sets). | ||
2524 | * Save the information in the bss_new_entry and then insert into the | ||
2525 | * driver scan table either as an update to an existing entry | ||
2526 | * or as an addition at the end of the table | ||
2527 | */ | ||
2528 | bss_new_entry = kzalloc(sizeof(struct mwifiex_bssdescriptor), | ||
2529 | GFP_KERNEL); | ||
2530 | if (!bss_new_entry) { | ||
2531 | dev_err(adapter->dev, " failed to alloc bss_new_entry\n"); | ||
2532 | return -1; | ||
2533 | } | ||
2534 | |||
2535 | for (idx = 0; idx < scan_rsp->number_of_sets && bytes_left; idx++) { | ||
2536 | /* Zero out the bss_new_entry we are about to store info in */ | ||
2537 | memset(bss_new_entry, 0x00, | ||
2538 | sizeof(struct mwifiex_bssdescriptor)); | ||
2539 | |||
2540 | if (mwifiex_interpret_bss_desc_with_ie(adapter, bss_new_entry, | ||
2541 | &bss_info, | ||
2542 | &bytes_left)) { | ||
2543 | /* Error parsing/interpreting scan response, skipped */ | ||
2544 | dev_err(adapter->dev, "SCAN_RESP: " | ||
2545 | "mwifiex_interpret_bss_desc_with_ie " | ||
2546 | "returned ERROR\n"); | ||
2547 | continue; | ||
2548 | } | ||
2549 | |||
2550 | /* Process the data fields and IEs returned for this BSS */ | ||
2551 | dev_dbg(adapter->dev, "info: SCAN_RESP: BSSID = %pM\n", | ||
2552 | bss_new_entry->mac_address); | ||
2553 | |||
2554 | /* Search the scan table for the same bssid */ | ||
2555 | for (bss_idx = 0; bss_idx < num_in_table; bss_idx++) { | ||
2556 | if (memcmp(bss_new_entry->mac_address, | ||
2557 | adapter->scan_table[bss_idx].mac_address, | ||
2558 | sizeof(bss_new_entry->mac_address))) { | ||
2559 | continue; | ||
2560 | } | ||
2561 | /* | ||
2562 | * If the SSID matches as well, it is a | ||
2563 | * duplicate of this entry. Keep the bss_idx | ||
2564 | * set to this entry so we replace the old | ||
2565 | * contents in the table | ||
2566 | */ | ||
2567 | if ((bss_new_entry->ssid.ssid_len | ||
2568 | == adapter->scan_table[bss_idx]. ssid.ssid_len) | ||
2569 | && (!memcmp(bss_new_entry->ssid.ssid, | ||
2570 | adapter->scan_table[bss_idx].ssid.ssid, | ||
2571 | bss_new_entry->ssid.ssid_len))) { | ||
2572 | dev_dbg(adapter->dev, "info: SCAN_RESP:" | ||
2573 | " duplicate of index: %d\n", bss_idx); | ||
2574 | break; | ||
2575 | } | ||
2576 | } | ||
2577 | /* | ||
2578 | * If the bss_idx is equal to the number of entries in | ||
2579 | * the table, the new entry was not a duplicate; append | ||
2580 | * it to the scan table | ||
2581 | */ | ||
2582 | if (bss_idx == num_in_table) { | ||
2583 | /* Range check the bss_idx, keep it limited to | ||
2584 | the last entry */ | ||
2585 | if (bss_idx == IW_MAX_AP) | ||
2586 | bss_idx--; | ||
2587 | else | ||
2588 | num_in_table++; | ||
2589 | } | ||
2590 | |||
2591 | /* | ||
2592 | * Save the beacon/probe response returned for later application | ||
2593 | * retrieval. Duplicate beacon/probe responses are updated if | ||
2594 | * possible | ||
2595 | */ | ||
2596 | mwifiex_ret_802_11_scan_store_beacon(priv, bss_idx, | ||
2597 | num_in_table, bss_new_entry); | ||
2598 | /* | ||
2599 | * If the TSF TLV was appended to the scan results, save this | ||
2600 | * entry's TSF value in the networkTSF field.The networkTSF is | ||
2601 | * the firmware's TSF value at the time the beacon or probe | ||
2602 | * response was received. | ||
2603 | */ | ||
2604 | if (tsf_tlv) { | ||
2605 | memcpy(&tsf_val, &tsf_tlv->tsf_data[idx * TSF_DATA_SIZE] | ||
2606 | , sizeof(tsf_val)); | ||
2607 | memcpy(&bss_new_entry->network_tsf, &tsf_val, | ||
2608 | sizeof(bss_new_entry->network_tsf)); | ||
2609 | } | ||
2610 | band = BAND_G; | ||
2611 | if (chan_band_tlv) { | ||
2612 | chan_band = &chan_band_tlv->chan_band_param[idx]; | ||
2613 | band = mwifiex_radio_type_to_band(chan_band->radio_type | ||
2614 | & (BIT(0) | BIT(1))); | ||
2615 | } | ||
2616 | |||
2617 | /* Save the band designation for this entry for use in join */ | ||
2618 | bss_new_entry->bss_band = band; | ||
2619 | cfp = mwifiex_get_cfp_by_band_and_channel_from_cfg80211(priv, | ||
2620 | (u8) bss_new_entry->bss_band, | ||
2621 | (u16)bss_new_entry->channel); | ||
2622 | |||
2623 | if (cfp) | ||
2624 | bss_new_entry->freq = cfp->freq; | ||
2625 | else | ||
2626 | bss_new_entry->freq = 0; | ||
2627 | |||
2628 | /* Copy the locally created bss_new_entry to the scan table */ | ||
2629 | memcpy(&adapter->scan_table[bss_idx], bss_new_entry, | ||
2630 | sizeof(adapter->scan_table[bss_idx])); | ||
2631 | |||
2632 | } | ||
2633 | |||
2634 | dev_dbg(adapter->dev, | ||
2635 | "info: SCAN_RESP: Scanned %2d APs, %d valid, %d total\n", | ||
2636 | scan_rsp->number_of_sets, | ||
2637 | num_in_table - adapter->num_in_scan_table, num_in_table); | ||
2638 | |||
2639 | /* Update the total number of BSSIDs in the scan table */ | ||
2640 | adapter->num_in_scan_table = num_in_table; | ||
2641 | |||
2642 | spin_lock_irqsave(&adapter->scan_pending_q_lock, flags); | ||
2643 | if (list_empty(&adapter->scan_pending_q)) { | ||
2644 | spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags); | ||
2645 | spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); | ||
2646 | adapter->scan_processing = false; | ||
2647 | spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); | ||
2648 | /* | ||
2649 | * Process the resulting scan table: | ||
2650 | * - Remove any bad ssids | ||
2651 | * - Update our current BSS information from scan data | ||
2652 | */ | ||
2653 | mwifiex_process_scan_results(priv); | ||
2654 | |||
2655 | /* Need to indicate IOCTL complete */ | ||
2656 | wait_queue = (struct mwifiex_wait_queue *) wq_buf; | ||
2657 | if (wait_queue) { | ||
2658 | wait_queue->status = MWIFIEX_ERROR_NO_ERROR; | ||
2659 | |||
2660 | /* Indicate ioctl complete */ | ||
2661 | mwifiex_ioctl_complete(adapter, | ||
2662 | (struct mwifiex_wait_queue *) wait_queue, 0); | ||
2663 | } | ||
2664 | if (priv->report_scan_result) | ||
2665 | priv->report_scan_result = false; | ||
2666 | if (priv->scan_pending_on_block) { | ||
2667 | priv->scan_pending_on_block = false; | ||
2668 | up(&priv->async_sem); | ||
2669 | } | ||
2670 | |||
2671 | } else { | ||
2672 | /* Get scan command from scan_pending_q and put to | ||
2673 | cmd_pending_q */ | ||
2674 | cmd_node = list_first_entry(&adapter->scan_pending_q, | ||
2675 | struct cmd_ctrl_node, list); | ||
2676 | list_del(&cmd_node->list); | ||
2677 | spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags); | ||
2678 | |||
2679 | mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, true); | ||
2680 | } | ||
2681 | |||
2682 | done: | ||
2683 | kfree((u8 *) bss_new_entry); | ||
2684 | return ret; | ||
2685 | } | ||
2686 | |||
2687 | /* | ||
2688 | * This function prepares command for background scan query. | ||
2689 | * | ||
2690 | * Preparation includes - | ||
2691 | * - Setting command ID and proper size | ||
2692 | * - Setting background scan flush parameter | ||
2693 | * - Ensuring correct endian-ness | ||
2694 | */ | ||
2695 | int mwifiex_cmd_802_11_bg_scan_query(struct mwifiex_private *priv, | ||
2696 | struct host_cmd_ds_command *cmd, | ||
2697 | void *data_buf) | ||
2698 | { | ||
2699 | struct host_cmd_ds_802_11_bg_scan_query *bg_query = | ||
2700 | &cmd->params.bg_scan_query; | ||
2701 | |||
2702 | cmd->command = cpu_to_le16(HostCmd_CMD_802_11_BG_SCAN_QUERY); | ||
2703 | cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_bg_scan_query) | ||
2704 | + S_DS_GEN); | ||
2705 | |||
2706 | bg_query->flush = 1; | ||
2707 | |||
2708 | return 0; | ||
2709 | } | ||
2710 | |||
2711 | /* | ||
2712 | * This function finds a SSID in the scan table. | ||
2713 | * | ||
2714 | * A BSSID may optionally be provided to qualify the SSID. | ||
2715 | * For non-Auto mode, further check is made to make sure the | ||
2716 | * BSS found in the scan table is compatible with the current | ||
2717 | * settings of the driver. | ||
2718 | */ | ||
2719 | s32 | ||
2720 | mwifiex_find_ssid_in_list(struct mwifiex_private *priv, | ||
2721 | struct mwifiex_802_11_ssid *ssid, u8 *bssid, | ||
2722 | u32 mode) | ||
2723 | { | ||
2724 | struct mwifiex_adapter *adapter = priv->adapter; | ||
2725 | s32 net = -1, j; | ||
2726 | u8 best_rssi = 0; | ||
2727 | u32 i; | ||
2728 | |||
2729 | dev_dbg(adapter->dev, "info: num of entries in table = %d\n", | ||
2730 | adapter->num_in_scan_table); | ||
2731 | |||
2732 | /* | ||
2733 | * Loop through the table until the maximum is reached or until a match | ||
2734 | * is found based on the bssid field comparison | ||
2735 | */ | ||
2736 | for (i = 0; | ||
2737 | i < adapter->num_in_scan_table && (!bssid || (bssid && net < 0)); | ||
2738 | i++) { | ||
2739 | if (!mwifiex_ssid_cmp(&adapter->scan_table[i].ssid, ssid) && | ||
2740 | (!bssid | ||
2741 | || !memcmp(adapter->scan_table[i].mac_address, bssid, | ||
2742 | ETH_ALEN)) | ||
2743 | && | ||
2744 | (mwifiex_get_cfp_by_band_and_channel_from_cfg80211 | ||
2745 | (priv, (u8) adapter->scan_table[i].bss_band, | ||
2746 | (u16) adapter->scan_table[i].channel))) { | ||
2747 | switch (mode) { | ||
2748 | case NL80211_IFTYPE_STATION: | ||
2749 | case NL80211_IFTYPE_ADHOC: | ||
2750 | j = mwifiex_is_network_compatible(priv, i, | ||
2751 | mode); | ||
2752 | |||
2753 | if (j >= 0) { | ||
2754 | if (SCAN_RSSI | ||
2755 | (adapter->scan_table[i].rssi) > | ||
2756 | best_rssi) { | ||
2757 | best_rssi = SCAN_RSSI(adapter-> | ||
2758 | scan_table | ||
2759 | [i].rssi); | ||
2760 | net = i; | ||
2761 | } | ||
2762 | } else { | ||
2763 | if (net == -1) | ||
2764 | net = j; | ||
2765 | } | ||
2766 | break; | ||
2767 | case NL80211_IFTYPE_UNSPECIFIED: | ||
2768 | default: | ||
2769 | /* | ||
2770 | * Do not check compatibility if the mode | ||
2771 | * requested is Auto/Unknown. Allows generic | ||
2772 | * find to work without verifying against the | ||
2773 | * Adapter security settings | ||
2774 | */ | ||
2775 | if (SCAN_RSSI(adapter->scan_table[i].rssi) > | ||
2776 | best_rssi) { | ||
2777 | best_rssi = SCAN_RSSI(adapter-> | ||
2778 | scan_table[i].rssi); | ||
2779 | net = i; | ||
2780 | } | ||
2781 | break; | ||
2782 | } | ||
2783 | } | ||
2784 | } | ||
2785 | |||
2786 | return net; | ||
2787 | } | ||
2788 | |||
2789 | /* | ||
2790 | * This function finds a specific compatible BSSID in the scan list. | ||
2791 | * | ||
2792 | * This function loops through the scan table looking for a compatible | ||
2793 | * match. If a BSSID matches, but the BSS is found to be not compatible | ||
2794 | * the function ignores it and continues to search through the rest of | ||
2795 | * the entries in case there is an AP with multiple SSIDs assigned to | ||
2796 | * the same BSSID. | ||
2797 | */ | ||
2798 | s32 | ||
2799 | mwifiex_find_bssid_in_list(struct mwifiex_private *priv, u8 *bssid, | ||
2800 | u32 mode) | ||
2801 | { | ||
2802 | struct mwifiex_adapter *adapter = priv->adapter; | ||
2803 | s32 net = -1; | ||
2804 | u32 i; | ||
2805 | |||
2806 | if (!bssid) | ||
2807 | return -1; | ||
2808 | |||
2809 | dev_dbg(adapter->dev, "info: FindBSSID: Num of BSSIDs = %d\n", | ||
2810 | adapter->num_in_scan_table); | ||
2811 | |||
2812 | /* | ||
2813 | * Look through the scan table for a compatible match. The ret return | ||
2814 | * variable will be equal to the index in the scan table (greater | ||
2815 | * than zero) if the network is compatible. The loop will continue | ||
2816 | * past a matched bssid that is not compatible in case there is an | ||
2817 | * AP with multiple SSIDs assigned to the same BSSID | ||
2818 | */ | ||
2819 | for (i = 0; net < 0 && i < adapter->num_in_scan_table; i++) { | ||
2820 | if (!memcmp | ||
2821 | (adapter->scan_table[i].mac_address, bssid, ETH_ALEN) | ||
2822 | && mwifiex_get_cfp_by_band_and_channel_from_cfg80211 | ||
2823 | (priv, | ||
2824 | (u8) adapter-> | ||
2825 | scan_table[i]. | ||
2826 | bss_band, | ||
2827 | (u16) adapter-> | ||
2828 | scan_table[i]. | ||
2829 | channel)) { | ||
2830 | switch (mode) { | ||
2831 | case NL80211_IFTYPE_STATION: | ||
2832 | case NL80211_IFTYPE_ADHOC: | ||
2833 | net = mwifiex_is_network_compatible(priv, i, | ||
2834 | mode); | ||
2835 | break; | ||
2836 | default: | ||
2837 | net = i; | ||
2838 | break; | ||
2839 | } | ||
2840 | } | ||
2841 | } | ||
2842 | |||
2843 | return net; | ||
2844 | } | ||
2845 | |||
2846 | /* | ||
2847 | * This function inserts scan command node to the scan pending queue. | ||
2848 | */ | ||
2849 | void | ||
2850 | mwifiex_queue_scan_cmd(struct mwifiex_private *priv, | ||
2851 | struct cmd_ctrl_node *cmd_node) | ||
2852 | { | ||
2853 | struct mwifiex_adapter *adapter = priv->adapter; | ||
2854 | unsigned long flags; | ||
2855 | |||
2856 | spin_lock_irqsave(&adapter->scan_pending_q_lock, flags); | ||
2857 | list_add_tail(&cmd_node->list, &adapter->scan_pending_q); | ||
2858 | spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags); | ||
2859 | } | ||
2860 | |||
2861 | /* | ||
2862 | * This function finds an AP with specific ssid in the scan list. | ||
2863 | */ | ||
2864 | int mwifiex_find_best_network(struct mwifiex_private *priv, | ||
2865 | struct mwifiex_ssid_bssid *req_ssid_bssid) | ||
2866 | { | ||
2867 | struct mwifiex_adapter *adapter = priv->adapter; | ||
2868 | struct mwifiex_bssdescriptor *req_bss; | ||
2869 | s32 i; | ||
2870 | |||
2871 | memset(req_ssid_bssid, 0, sizeof(struct mwifiex_ssid_bssid)); | ||
2872 | |||
2873 | i = mwifiex_find_best_network_in_list(priv); | ||
2874 | |||
2875 | if (i >= 0) { | ||
2876 | req_bss = &adapter->scan_table[i]; | ||
2877 | memcpy(&req_ssid_bssid->ssid, &req_bss->ssid, | ||
2878 | sizeof(struct mwifiex_802_11_ssid)); | ||
2879 | memcpy((u8 *) &req_ssid_bssid->bssid, | ||
2880 | (u8 *) &req_bss->mac_address, ETH_ALEN); | ||
2881 | |||
2882 | /* Make sure we are in the right mode */ | ||
2883 | if (priv->bss_mode == NL80211_IFTYPE_UNSPECIFIED) | ||
2884 | priv->bss_mode = req_bss->bss_mode; | ||
2885 | } | ||
2886 | |||
2887 | if (!req_ssid_bssid->ssid.ssid_len) | ||
2888 | return -1; | ||
2889 | |||
2890 | dev_dbg(adapter->dev, "info: Best network found = [%s], " | ||
2891 | "[%pM]\n", req_ssid_bssid->ssid.ssid, | ||
2892 | req_ssid_bssid->bssid); | ||
2893 | |||
2894 | return 0; | ||
2895 | } | ||
2896 | |||
2897 | /* | ||
2898 | * This function sends a scan command for all available channels to the | ||
2899 | * firmware, filtered on a specific SSID. | ||
2900 | */ | ||
2901 | static int mwifiex_scan_specific_ssid(struct mwifiex_private *priv, | ||
2902 | void *wait_buf, u16 action, | ||
2903 | struct mwifiex_802_11_ssid *req_ssid, | ||
2904 | struct mwifiex_scan_resp *scan_resp) | ||
2905 | { | ||
2906 | struct mwifiex_adapter *adapter = priv->adapter; | ||
2907 | int ret = 0; | ||
2908 | struct mwifiex_user_scan_cfg *scan_cfg; | ||
2909 | |||
2910 | if (!req_ssid) | ||
2911 | return -1; | ||
2912 | |||
2913 | if (action == HostCmd_ACT_GEN_GET) { | ||
2914 | if (scan_resp) { | ||
2915 | scan_resp->scan_table = | ||
2916 | (u8 *) &priv->curr_bss_params.bss_descriptor; | ||
2917 | scan_resp->num_in_scan_table = | ||
2918 | adapter->num_in_scan_table; | ||
2919 | } else { | ||
2920 | ret = -1; | ||
2921 | } | ||
2922 | return ret; | ||
2923 | } | ||
2924 | |||
2925 | if (adapter->scan_processing && action == HostCmd_ACT_GEN_SET) { | ||
2926 | dev_dbg(adapter->dev, "cmd: Scan already in process...\n"); | ||
2927 | return ret; | ||
2928 | } | ||
2929 | |||
2930 | if (priv->scan_block && action == HostCmd_ACT_GEN_SET) { | ||
2931 | dev_dbg(adapter->dev, | ||
2932 | "cmd: Scan is blocked during association...\n"); | ||
2933 | return ret; | ||
2934 | } | ||
2935 | |||
2936 | mwifiex_scan_delete_ssid_table_entry(priv, req_ssid); | ||
2937 | |||
2938 | scan_cfg = kzalloc(sizeof(struct mwifiex_user_scan_cfg), GFP_KERNEL); | ||
2939 | if (!scan_cfg) { | ||
2940 | dev_err(adapter->dev, "failed to alloc scan_cfg\n"); | ||
2941 | return -1; | ||
2942 | } | ||
2943 | |||
2944 | memcpy(scan_cfg->ssid_list[0].ssid, req_ssid->ssid, | ||
2945 | req_ssid->ssid_len); | ||
2946 | scan_cfg->keep_previous_scan = true; | ||
2947 | |||
2948 | ret = mwifiex_scan_networks(priv, wait_buf, action, scan_cfg, NULL); | ||
2949 | |||
2950 | kfree(scan_cfg); | ||
2951 | return ret; | ||
2952 | } | ||
2953 | |||
2954 | /* | ||
2955 | * Sends IOCTL request to start a scan. | ||
2956 | * | ||
2957 | * This function allocates the IOCTL request buffer, fills it | ||
2958 | * with requisite parameters and calls the IOCTL handler. | ||
2959 | * | ||
2960 | * Scan command can be issued for both normal scan and specific SSID | ||
2961 | * scan, depending upon whether an SSID is provided or not. | ||
2962 | */ | ||
2963 | int mwifiex_request_scan(struct mwifiex_private *priv, u8 wait_option, | ||
2964 | struct mwifiex_802_11_ssid *req_ssid) | ||
2965 | { | ||
2966 | int ret = 0; | ||
2967 | struct mwifiex_wait_queue *wait = NULL; | ||
2968 | int status = 0; | ||
2969 | |||
2970 | if (down_interruptible(&priv->async_sem)) { | ||
2971 | dev_err(priv->adapter->dev, "%s: acquire semaphore\n", | ||
2972 | __func__); | ||
2973 | return -1; | ||
2974 | } | ||
2975 | priv->scan_pending_on_block = true; | ||
2976 | |||
2977 | /* Allocate wait request buffer */ | ||
2978 | wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); | ||
2979 | if (!wait) { | ||
2980 | ret = -1; | ||
2981 | goto done; | ||
2982 | } | ||
2983 | |||
2984 | if (req_ssid && req_ssid->ssid_len != 0) | ||
2985 | /* Specific SSID scan */ | ||
2986 | status = mwifiex_scan_specific_ssid(priv, wait, | ||
2987 | HostCmd_ACT_GEN_SET, | ||
2988 | req_ssid, NULL); | ||
2989 | else | ||
2990 | /* Normal scan */ | ||
2991 | status = mwifiex_scan_networks(priv, wait, HostCmd_ACT_GEN_SET, | ||
2992 | NULL, NULL); | ||
2993 | status = mwifiex_request_ioctl(priv, wait, status, wait_option); | ||
2994 | if (status == -1) | ||
2995 | ret = -1; | ||
2996 | done: | ||
2997 | if ((wait) && (status != -EINPROGRESS)) | ||
2998 | kfree(wait); | ||
2999 | if (ret == -1) { | ||
3000 | priv->scan_pending_on_block = false; | ||
3001 | up(&priv->async_sem); | ||
3002 | } | ||
3003 | return ret; | ||
3004 | } | ||
3005 | |||
3006 | /* | ||
3007 | * This function appends the vendor specific IE TLV to a buffer. | ||
3008 | */ | ||
3009 | int | ||
3010 | mwifiex_cmd_append_vsie_tlv(struct mwifiex_private *priv, | ||
3011 | u16 vsie_mask, u8 **buffer) | ||
3012 | { | ||
3013 | int id, ret_len = 0; | ||
3014 | struct mwifiex_ie_types_vendor_param_set *vs_param_set; | ||
3015 | |||
3016 | if (!buffer) | ||
3017 | return 0; | ||
3018 | if (!(*buffer)) | ||
3019 | return 0; | ||
3020 | |||
3021 | /* | ||
3022 | * Traverse through the saved vendor specific IE array and append | ||
3023 | * the selected(scan/assoc/adhoc) IE as TLV to the command | ||
3024 | */ | ||
3025 | for (id = 0; id < MWIFIEX_MAX_VSIE_NUM; id++) { | ||
3026 | if (priv->vs_ie[id].mask & vsie_mask) { | ||
3027 | vs_param_set = | ||
3028 | (struct mwifiex_ie_types_vendor_param_set *) | ||
3029 | *buffer; | ||
3030 | vs_param_set->header.type = | ||
3031 | cpu_to_le16(TLV_TYPE_PASSTHROUGH); | ||
3032 | vs_param_set->header.len = | ||
3033 | cpu_to_le16((((u16) priv->vs_ie[id].ie[1]) | ||
3034 | & 0x00FF) + 2); | ||
3035 | memcpy(vs_param_set->ie, priv->vs_ie[id].ie, | ||
3036 | le16_to_cpu(vs_param_set->header.len)); | ||
3037 | *buffer += le16_to_cpu(vs_param_set->header.len) + | ||
3038 | sizeof(struct mwifiex_ie_types_header); | ||
3039 | ret_len += le16_to_cpu(vs_param_set->header.len) + | ||
3040 | sizeof(struct mwifiex_ie_types_header); | ||
3041 | } | ||
3042 | } | ||
3043 | return ret_len; | ||
3044 | } | ||
3045 | |||
3046 | /* | ||
3047 | * This function saves a beacon buffer of the current BSS descriptor. | ||
3048 | * | ||
3049 | * The current beacon buffer is saved so that it can be restored in the | ||
3050 | * following cases that makes the beacon buffer not to contain the current | ||
3051 | * ssid's beacon buffer. | ||
3052 | * - The current ssid was not found somehow in the last scan. | ||
3053 | * - The current ssid was the last entry of the scan table and overloaded. | ||
3054 | */ | ||
3055 | void | ||
3056 | mwifiex_save_curr_bcn(struct mwifiex_private *priv) | ||
3057 | { | ||
3058 | struct mwifiex_bssdescriptor *curr_bss = | ||
3059 | &priv->curr_bss_params.bss_descriptor; | ||
3060 | |||
3061 | /* save the beacon buffer if it is not saved or updated */ | ||
3062 | if ((priv->curr_bcn_buf == NULL) || | ||
3063 | (priv->curr_bcn_size != curr_bss->beacon_buf_size) || | ||
3064 | (memcmp(priv->curr_bcn_buf, curr_bss->beacon_buf, | ||
3065 | curr_bss->beacon_buf_size))) { | ||
3066 | |||
3067 | kfree(priv->curr_bcn_buf); | ||
3068 | priv->curr_bcn_buf = NULL; | ||
3069 | |||
3070 | priv->curr_bcn_size = curr_bss->beacon_buf_size; | ||
3071 | if (!priv->curr_bcn_size) | ||
3072 | return; | ||
3073 | |||
3074 | priv->curr_bcn_buf = kzalloc(curr_bss->beacon_buf_size, | ||
3075 | GFP_KERNEL); | ||
3076 | if (!priv->curr_bcn_buf) { | ||
3077 | dev_err(priv->adapter->dev, | ||
3078 | "failed to alloc curr_bcn_buf\n"); | ||
3079 | } else { | ||
3080 | memcpy(priv->curr_bcn_buf, curr_bss->beacon_buf, | ||
3081 | curr_bss->beacon_buf_size); | ||
3082 | dev_dbg(priv->adapter->dev, | ||
3083 | "info: current beacon saved %d\n", | ||
3084 | priv->curr_bcn_size); | ||
3085 | } | ||
3086 | } | ||
3087 | } | ||
3088 | |||
3089 | /* | ||
3090 | * This function frees the current BSS descriptor beacon buffer. | ||
3091 | */ | ||
3092 | void | ||
3093 | mwifiex_free_curr_bcn(struct mwifiex_private *priv) | ||
3094 | { | ||
3095 | kfree(priv->curr_bcn_buf); | ||
3096 | priv->curr_bcn_buf = NULL; | ||
3097 | } | ||
diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c new file mode 100644 index 000000000000..f21e5cd19839 --- /dev/null +++ b/drivers/net/wireless/mwifiex/sdio.c | |||
@@ -0,0 +1,1770 @@ | |||
1 | /* | ||
2 | * Marvell Wireless LAN device driver: SDIO specific handling | ||
3 | * | ||
4 | * Copyright (C) 2011, Marvell International Ltd. | ||
5 | * | ||
6 | * This software file (the "File") is distributed by Marvell International | ||
7 | * Ltd. under the terms of the GNU General Public License Version 2, June 1991 | ||
8 | * (the "License"). You may use, redistribute and/or modify this File in | ||
9 | * accordance with the terms and conditions of the License, a copy of which | ||
10 | * is available by writing to the Free Software Foundation, Inc., | ||
11 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the | ||
12 | * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. | ||
13 | * | ||
14 | * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE | ||
15 | * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE | ||
16 | * ARE EXPRESSLY DISCLAIMED. The License provides additional details about | ||
17 | * this warranty disclaimer. | ||
18 | */ | ||
19 | |||
20 | #include <linux/firmware.h> | ||
21 | |||
22 | #include "decl.h" | ||
23 | #include "ioctl.h" | ||
24 | #include "util.h" | ||
25 | #include "fw.h" | ||
26 | #include "main.h" | ||
27 | #include "wmm.h" | ||
28 | #include "11n.h" | ||
29 | #include "sdio.h" | ||
30 | |||
31 | |||
32 | #define SDIO_VERSION "1.0" | ||
33 | |||
34 | static struct mwifiex_if_ops sdio_ops; | ||
35 | |||
36 | static struct semaphore add_remove_card_sem; | ||
37 | |||
38 | /* | ||
39 | * SDIO probe. | ||
40 | * | ||
41 | * This function probes an mwifiex device and registers it. It allocates | ||
42 | * the card structure, enables SDIO function number and initiates the | ||
43 | * device registration and initialization procedure by adding a logical | ||
44 | * interface. | ||
45 | */ | ||
46 | static int | ||
47 | mwifiex_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id) | ||
48 | { | ||
49 | int ret = 0; | ||
50 | struct sdio_mmc_card *card = NULL; | ||
51 | |||
52 | pr_debug("info: vendor=0x%4.04X device=0x%4.04X class=%d function=%d\n", | ||
53 | func->vendor, func->device, func->class, func->num); | ||
54 | |||
55 | card = kzalloc(sizeof(struct sdio_mmc_card), GFP_KERNEL); | ||
56 | if (!card) { | ||
57 | pr_err("%s: failed to alloc memory\n", __func__); | ||
58 | return -ENOMEM; | ||
59 | } | ||
60 | |||
61 | card->func = func; | ||
62 | |||
63 | func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE; | ||
64 | |||
65 | sdio_claim_host(func); | ||
66 | ret = sdio_enable_func(func); | ||
67 | sdio_release_host(func); | ||
68 | |||
69 | if (ret) { | ||
70 | pr_err("%s: failed to enable function\n", __func__); | ||
71 | return -EIO; | ||
72 | } | ||
73 | |||
74 | if (mwifiex_add_card(card, &add_remove_card_sem, &sdio_ops)) { | ||
75 | pr_err("%s: add card failed\n", __func__); | ||
76 | kfree(card); | ||
77 | sdio_claim_host(func); | ||
78 | ret = sdio_disable_func(func); | ||
79 | sdio_release_host(func); | ||
80 | ret = -1; | ||
81 | } | ||
82 | |||
83 | return ret; | ||
84 | } | ||
85 | |||
86 | /* | ||
87 | * SDIO remove. | ||
88 | * | ||
89 | * This function removes the interface and frees up the card structure. | ||
90 | */ | ||
91 | static void | ||
92 | mwifiex_sdio_remove(struct sdio_func *func) | ||
93 | { | ||
94 | struct sdio_mmc_card *card; | ||
95 | |||
96 | pr_debug("info: SDIO func num=%d\n", func->num); | ||
97 | |||
98 | if (func) { | ||
99 | card = sdio_get_drvdata(func); | ||
100 | if (card) { | ||
101 | mwifiex_remove_card(card->adapter, | ||
102 | &add_remove_card_sem); | ||
103 | kfree(card); | ||
104 | } | ||
105 | } | ||
106 | } | ||
107 | |||
108 | /* | ||
109 | * SDIO suspend. | ||
110 | * | ||
111 | * Kernel needs to suspend all functions separately. Therefore all | ||
112 | * registered functions must have drivers with suspend and resume | ||
113 | * methods. Failing that the kernel simply removes the whole card. | ||
114 | * | ||
115 | * If already not suspended, this function allocates and sends a host | ||
116 | * sleep activate request to the firmware and turns off the traffic. | ||
117 | */ | ||
118 | static int mwifiex_sdio_suspend(struct device *dev) | ||
119 | { | ||
120 | struct sdio_func *func = dev_to_sdio_func(dev); | ||
121 | struct sdio_mmc_card *card; | ||
122 | struct mwifiex_adapter *adapter = NULL; | ||
123 | mmc_pm_flag_t pm_flag = 0; | ||
124 | int hs_actived = 0; | ||
125 | int i; | ||
126 | int ret = 0; | ||
127 | |||
128 | if (func) { | ||
129 | pm_flag = sdio_get_host_pm_caps(func); | ||
130 | pr_debug("cmd: %s: suspend: PM flag = 0x%x\n", | ||
131 | sdio_func_id(func), pm_flag); | ||
132 | if (!(pm_flag & MMC_PM_KEEP_POWER)) { | ||
133 | pr_err("%s: cannot remain alive while host is" | ||
134 | " suspended\n", sdio_func_id(func)); | ||
135 | return -ENOSYS; | ||
136 | } | ||
137 | |||
138 | card = sdio_get_drvdata(func); | ||
139 | if (!card || !card->adapter) { | ||
140 | pr_err("suspend: invalid card or adapter\n"); | ||
141 | return 0; | ||
142 | } | ||
143 | } else { | ||
144 | pr_err("suspend: sdio_func is not specified\n"); | ||
145 | return 0; | ||
146 | } | ||
147 | |||
148 | adapter = card->adapter; | ||
149 | |||
150 | /* Enable the Host Sleep */ | ||
151 | hs_actived = mwifiex_enable_hs(adapter); | ||
152 | if (hs_actived) { | ||
153 | pr_debug("cmd: suspend with MMC_PM_KEEP_POWER\n"); | ||
154 | ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); | ||
155 | } | ||
156 | |||
157 | /* Indicate device suspended */ | ||
158 | adapter->is_suspended = true; | ||
159 | |||
160 | for (i = 0; i < adapter->priv_num; i++) | ||
161 | netif_carrier_off(adapter->priv[i]->netdev); | ||
162 | |||
163 | return ret; | ||
164 | } | ||
165 | |||
166 | /* | ||
167 | * SDIO resume. | ||
168 | * | ||
169 | * Kernel needs to suspend all functions separately. Therefore all | ||
170 | * registered functions must have drivers with suspend and resume | ||
171 | * methods. Failing that the kernel simply removes the whole card. | ||
172 | * | ||
173 | * If already not resumed, this function turns on the traffic and | ||
174 | * sends a host sleep cancel request to the firmware. | ||
175 | */ | ||
176 | static int mwifiex_sdio_resume(struct device *dev) | ||
177 | { | ||
178 | struct sdio_func *func = dev_to_sdio_func(dev); | ||
179 | struct sdio_mmc_card *card; | ||
180 | struct mwifiex_adapter *adapter = NULL; | ||
181 | mmc_pm_flag_t pm_flag = 0; | ||
182 | int i; | ||
183 | |||
184 | if (func) { | ||
185 | pm_flag = sdio_get_host_pm_caps(func); | ||
186 | card = sdio_get_drvdata(func); | ||
187 | if (!card || !card->adapter) { | ||
188 | pr_err("resume: invalid card or adapter\n"); | ||
189 | return 0; | ||
190 | } | ||
191 | } else { | ||
192 | pr_err("resume: sdio_func is not specified\n"); | ||
193 | return 0; | ||
194 | } | ||
195 | |||
196 | adapter = card->adapter; | ||
197 | |||
198 | if (!adapter->is_suspended) { | ||
199 | dev_warn(adapter->dev, "device already resumed\n"); | ||
200 | return 0; | ||
201 | } | ||
202 | |||
203 | adapter->is_suspended = false; | ||
204 | |||
205 | for (i = 0; i < adapter->priv_num; i++) | ||
206 | if (adapter->priv[i]->media_connected) | ||
207 | netif_carrier_on(adapter->priv[i]->netdev); | ||
208 | |||
209 | /* Disable Host Sleep */ | ||
210 | mwifiex_cancel_hs(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA), | ||
211 | MWIFIEX_NO_WAIT); | ||
212 | |||
213 | return 0; | ||
214 | } | ||
215 | |||
216 | /* Device ID for SD8787 */ | ||
217 | #define SDIO_DEVICE_ID_MARVELL_8787 (0x9119) | ||
218 | |||
219 | /* WLAN IDs */ | ||
220 | static const struct sdio_device_id mwifiex_ids[] = { | ||
221 | {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8787)}, | ||
222 | {}, | ||
223 | }; | ||
224 | |||
225 | MODULE_DEVICE_TABLE(sdio, mwifiex_ids); | ||
226 | |||
227 | static const struct dev_pm_ops mwifiex_sdio_pm_ops = { | ||
228 | .suspend = mwifiex_sdio_suspend, | ||
229 | .resume = mwifiex_sdio_resume, | ||
230 | }; | ||
231 | |||
232 | static struct sdio_driver mwifiex_sdio = { | ||
233 | .name = "mwifiex_sdio", | ||
234 | .id_table = mwifiex_ids, | ||
235 | .probe = mwifiex_sdio_probe, | ||
236 | .remove = mwifiex_sdio_remove, | ||
237 | .drv = { | ||
238 | .owner = THIS_MODULE, | ||
239 | .pm = &mwifiex_sdio_pm_ops, | ||
240 | } | ||
241 | }; | ||
242 | |||
243 | /* | ||
244 | * This function writes data into SDIO card register. | ||
245 | */ | ||
246 | static int | ||
247 | mwifiex_write_reg(struct mwifiex_adapter *adapter, u32 reg, u32 data) | ||
248 | { | ||
249 | struct sdio_mmc_card *card = adapter->card; | ||
250 | int ret = -1; | ||
251 | |||
252 | sdio_claim_host(card->func); | ||
253 | sdio_writeb(card->func, (u8) data, reg, &ret); | ||
254 | sdio_release_host(card->func); | ||
255 | |||
256 | return ret; | ||
257 | } | ||
258 | |||
259 | /* | ||
260 | * This function reads data from SDIO card register. | ||
261 | */ | ||
262 | static int | ||
263 | mwifiex_read_reg(struct mwifiex_adapter *adapter, u32 reg, u32 *data) | ||
264 | { | ||
265 | struct sdio_mmc_card *card = adapter->card; | ||
266 | int ret = -1; | ||
267 | u8 val; | ||
268 | |||
269 | sdio_claim_host(card->func); | ||
270 | val = sdio_readb(card->func, reg, &ret); | ||
271 | sdio_release_host(card->func); | ||
272 | |||
273 | *data = val; | ||
274 | |||
275 | return ret; | ||
276 | } | ||
277 | |||
278 | /* | ||
279 | * This function writes multiple data into SDIO card memory. | ||
280 | * | ||
281 | * This does not work in suspended mode. | ||
282 | */ | ||
283 | static int | ||
284 | mwifiex_write_data_sync(struct mwifiex_adapter *adapter, | ||
285 | u8 *buffer, u32 pkt_len, u32 port, u32 timeout) | ||
286 | { | ||
287 | struct sdio_mmc_card *card = adapter->card; | ||
288 | int ret = -1; | ||
289 | u8 blk_mode = | ||
290 | (port & MWIFIEX_SDIO_BYTE_MODE_MASK) ? BYTE_MODE : BLOCK_MODE; | ||
291 | u32 blk_size = (blk_mode == BLOCK_MODE) ? MWIFIEX_SDIO_BLOCK_SIZE : 1; | ||
292 | u32 blk_cnt = | ||
293 | (blk_mode == | ||
294 | BLOCK_MODE) ? (pkt_len / | ||
295 | MWIFIEX_SDIO_BLOCK_SIZE) : pkt_len; | ||
296 | u32 ioport = (port & MWIFIEX_SDIO_IO_PORT_MASK); | ||
297 | |||
298 | if (adapter->is_suspended) { | ||
299 | dev_err(adapter->dev, | ||
300 | "%s: not allowed while suspended\n", __func__); | ||
301 | return -1; | ||
302 | } | ||
303 | |||
304 | sdio_claim_host(card->func); | ||
305 | |||
306 | if (!sdio_writesb(card->func, ioport, buffer, blk_cnt * blk_size)) | ||
307 | ret = 0; | ||
308 | |||
309 | sdio_release_host(card->func); | ||
310 | |||
311 | return ret; | ||
312 | } | ||
313 | |||
314 | /* | ||
315 | * This function reads multiple data from SDIO card memory. | ||
316 | */ | ||
317 | static int mwifiex_read_data_sync(struct mwifiex_adapter *adapter, | ||
318 | u8 *buffer, u32 len, | ||
319 | u32 port, u32 timeout, u8 claim) | ||
320 | { | ||
321 | struct sdio_mmc_card *card = adapter->card; | ||
322 | int ret = -1; | ||
323 | u8 blk_mode = | ||
324 | (port & MWIFIEX_SDIO_BYTE_MODE_MASK) ? BYTE_MODE : BLOCK_MODE; | ||
325 | u32 blk_size = (blk_mode == BLOCK_MODE) ? MWIFIEX_SDIO_BLOCK_SIZE : 1; | ||
326 | u32 blk_cnt = | ||
327 | (blk_mode == | ||
328 | BLOCK_MODE) ? (len / MWIFIEX_SDIO_BLOCK_SIZE) : len; | ||
329 | u32 ioport = (port & MWIFIEX_SDIO_IO_PORT_MASK); | ||
330 | |||
331 | if (claim) | ||
332 | sdio_claim_host(card->func); | ||
333 | |||
334 | if (!sdio_readsb(card->func, buffer, ioport, blk_cnt * blk_size)) | ||
335 | ret = 0; | ||
336 | |||
337 | if (claim) | ||
338 | sdio_release_host(card->func); | ||
339 | |||
340 | return ret; | ||
341 | } | ||
342 | |||
343 | /* | ||
344 | * This function wakes up the card. | ||
345 | * | ||
346 | * A host power up command is written to the card configuration | ||
347 | * register to wake up the card. | ||
348 | */ | ||
349 | static int mwifiex_pm_wakeup_card(struct mwifiex_adapter *adapter) | ||
350 | { | ||
351 | int ret; | ||
352 | |||
353 | dev_dbg(adapter->dev, "event: wakeup device...\n"); | ||
354 | ret = mwifiex_write_reg(adapter, CONFIGURATION_REG, HOST_POWER_UP); | ||
355 | |||
356 | return ret; | ||
357 | } | ||
358 | |||
359 | /* | ||
360 | * This function is called after the card has woken up. | ||
361 | * | ||
362 | * The card configuration register is reset. | ||
363 | */ | ||
364 | static int mwifiex_pm_wakeup_card_complete(struct mwifiex_adapter *adapter) | ||
365 | { | ||
366 | int ret; | ||
367 | |||
368 | dev_dbg(adapter->dev, "cmd: wakeup device completed\n"); | ||
369 | ret = mwifiex_write_reg(adapter, CONFIGURATION_REG, 0); | ||
370 | |||
371 | return ret; | ||
372 | } | ||
373 | |||
374 | /* | ||
375 | * This function initializes the IO ports. | ||
376 | * | ||
377 | * The following operations are performed - | ||
378 | * - Read the IO ports (0, 1 and 2) | ||
379 | * - Set host interrupt Reset-To-Read to clear | ||
380 | * - Set auto re-enable interrupt | ||
381 | */ | ||
382 | static int mwifiex_init_sdio_ioport(struct mwifiex_adapter *adapter) | ||
383 | { | ||
384 | u32 reg; | ||
385 | |||
386 | adapter->ioport = 0; | ||
387 | |||
388 | /* Read the IO port */ | ||
389 | if (!mwifiex_read_reg(adapter, IO_PORT_0_REG, ®)) | ||
390 | adapter->ioport |= (reg & 0xff); | ||
391 | else | ||
392 | return -1; | ||
393 | |||
394 | if (!mwifiex_read_reg(adapter, IO_PORT_1_REG, ®)) | ||
395 | adapter->ioport |= ((reg & 0xff) << 8); | ||
396 | else | ||
397 | return -1; | ||
398 | |||
399 | if (!mwifiex_read_reg(adapter, IO_PORT_2_REG, ®)) | ||
400 | adapter->ioport |= ((reg & 0xff) << 16); | ||
401 | else | ||
402 | return -1; | ||
403 | |||
404 | pr_debug("info: SDIO FUNC1 IO port: %#x\n", adapter->ioport); | ||
405 | |||
406 | /* Set Host interrupt reset to read to clear */ | ||
407 | if (!mwifiex_read_reg(adapter, HOST_INT_RSR_REG, ®)) | ||
408 | mwifiex_write_reg(adapter, HOST_INT_RSR_REG, | ||
409 | reg | SDIO_INT_MASK); | ||
410 | else | ||
411 | return -1; | ||
412 | |||
413 | /* Dnld/Upld ready set to auto reset */ | ||
414 | if (!mwifiex_read_reg(adapter, CARD_MISC_CFG_REG, ®)) | ||
415 | mwifiex_write_reg(adapter, CARD_MISC_CFG_REG, | ||
416 | reg | AUTO_RE_ENABLE_INT); | ||
417 | else | ||
418 | return -1; | ||
419 | |||
420 | return 0; | ||
421 | } | ||
422 | |||
423 | /* | ||
424 | * This function sends data to the card. | ||
425 | */ | ||
426 | static int mwifiex_write_data_to_card(struct mwifiex_adapter *adapter, | ||
427 | u8 *payload, u32 pkt_len, u32 port) | ||
428 | { | ||
429 | u32 i = 0; | ||
430 | int ret = 0; | ||
431 | |||
432 | do { | ||
433 | ret = mwifiex_write_data_sync(adapter, payload, pkt_len, | ||
434 | port, 0); | ||
435 | if (ret) { | ||
436 | i++; | ||
437 | dev_err(adapter->dev, "host_to_card, write iomem" | ||
438 | " (%d) failed: %d\n", i, ret); | ||
439 | if (mwifiex_write_reg(adapter, | ||
440 | CONFIGURATION_REG, 0x04)) | ||
441 | dev_err(adapter->dev, "write CFG reg failed\n"); | ||
442 | |||
443 | ret = -1; | ||
444 | if (i > MAX_WRITE_IOMEM_RETRY) | ||
445 | return ret; | ||
446 | } | ||
447 | } while (ret == -1); | ||
448 | |||
449 | return ret; | ||
450 | } | ||
451 | |||
452 | /* | ||
453 | * This function gets the read port. | ||
454 | * | ||
455 | * If control port bit is set in MP read bitmap, the control port | ||
456 | * is returned, otherwise the current read port is returned and | ||
457 | * the value is increased (provided it does not reach the maximum | ||
458 | * limit, in which case it is reset to 1) | ||
459 | */ | ||
460 | static int mwifiex_get_rd_port(struct mwifiex_adapter *adapter, u8 *port) | ||
461 | { | ||
462 | struct sdio_mmc_card *card = adapter->card; | ||
463 | u16 rd_bitmap = card->mp_rd_bitmap; | ||
464 | |||
465 | dev_dbg(adapter->dev, "data: mp_rd_bitmap=0x%04x\n", rd_bitmap); | ||
466 | |||
467 | if (!(rd_bitmap & (CTRL_PORT_MASK | DATA_PORT_MASK))) | ||
468 | return -1; | ||
469 | |||
470 | if (card->mp_rd_bitmap & CTRL_PORT_MASK) { | ||
471 | card->mp_rd_bitmap &= (u16) (~CTRL_PORT_MASK); | ||
472 | *port = CTRL_PORT; | ||
473 | dev_dbg(adapter->dev, "data: port=%d mp_rd_bitmap=0x%04x\n", | ||
474 | *port, card->mp_rd_bitmap); | ||
475 | } else { | ||
476 | if (card->mp_rd_bitmap & (1 << card->curr_rd_port)) { | ||
477 | card->mp_rd_bitmap &= | ||
478 | (u16) (~(1 << card->curr_rd_port)); | ||
479 | *port = card->curr_rd_port; | ||
480 | |||
481 | if (++card->curr_rd_port == MAX_PORT) | ||
482 | card->curr_rd_port = 1; | ||
483 | } else { | ||
484 | return -1; | ||
485 | } | ||
486 | |||
487 | dev_dbg(adapter->dev, | ||
488 | "data: port=%d mp_rd_bitmap=0x%04x -> 0x%04x\n", | ||
489 | *port, rd_bitmap, card->mp_rd_bitmap); | ||
490 | } | ||
491 | return 0; | ||
492 | } | ||
493 | |||
494 | /* | ||
495 | * This function gets the write port for data. | ||
496 | * | ||
497 | * The current write port is returned if available and the value is | ||
498 | * increased (provided it does not reach the maximum limit, in which | ||
499 | * case it is reset to 1) | ||
500 | */ | ||
501 | static int mwifiex_get_wr_port_data(struct mwifiex_adapter *adapter, u8 *port) | ||
502 | { | ||
503 | struct sdio_mmc_card *card = adapter->card; | ||
504 | u16 wr_bitmap = card->mp_wr_bitmap; | ||
505 | |||
506 | dev_dbg(adapter->dev, "data: mp_wr_bitmap=0x%04x\n", wr_bitmap); | ||
507 | |||
508 | if (!(wr_bitmap & card->mp_data_port_mask)) | ||
509 | return -1; | ||
510 | |||
511 | if (card->mp_wr_bitmap & (1 << card->curr_wr_port)) { | ||
512 | card->mp_wr_bitmap &= (u16) (~(1 << card->curr_wr_port)); | ||
513 | *port = card->curr_wr_port; | ||
514 | if (++card->curr_wr_port == card->mp_end_port) | ||
515 | card->curr_wr_port = 1; | ||
516 | } else { | ||
517 | adapter->data_sent = true; | ||
518 | return -EBUSY; | ||
519 | } | ||
520 | |||
521 | if (*port == CTRL_PORT) { | ||
522 | dev_err(adapter->dev, "invalid data port=%d cur port=%d" | ||
523 | " mp_wr_bitmap=0x%04x -> 0x%04x\n", | ||
524 | *port, card->curr_wr_port, wr_bitmap, | ||
525 | card->mp_wr_bitmap); | ||
526 | return -1; | ||
527 | } | ||
528 | |||
529 | dev_dbg(adapter->dev, "data: port=%d mp_wr_bitmap=0x%04x -> 0x%04x\n", | ||
530 | *port, wr_bitmap, card->mp_wr_bitmap); | ||
531 | |||
532 | return 0; | ||
533 | } | ||
534 | |||
535 | /* | ||
536 | * This function polls the card status. | ||
537 | */ | ||
538 | static int | ||
539 | mwifiex_sdio_poll_card_status(struct mwifiex_adapter *adapter, u8 bits) | ||
540 | { | ||
541 | u32 tries; | ||
542 | u32 cs = 0; | ||
543 | |||
544 | for (tries = 0; tries < MAX_POLL_TRIES; tries++) { | ||
545 | if (mwifiex_read_reg(adapter, CARD_STATUS_REG, &cs)) | ||
546 | break; | ||
547 | else if ((cs & bits) == bits) | ||
548 | return 0; | ||
549 | |||
550 | udelay(10); | ||
551 | } | ||
552 | |||
553 | dev_err(adapter->dev, "poll card status failed, tries = %d\n", | ||
554 | tries); | ||
555 | return -1; | ||
556 | } | ||
557 | |||
558 | /* | ||
559 | * This function reads the firmware status. | ||
560 | */ | ||
561 | static int | ||
562 | mwifiex_sdio_read_fw_status(struct mwifiex_adapter *adapter, u16 *dat) | ||
563 | { | ||
564 | u32 fws0 = 0, fws1 = 0; | ||
565 | |||
566 | if (mwifiex_read_reg(adapter, CARD_FW_STATUS0_REG, &fws0)) | ||
567 | return -1; | ||
568 | |||
569 | if (mwifiex_read_reg(adapter, CARD_FW_STATUS1_REG, &fws1)) | ||
570 | return -1; | ||
571 | |||
572 | *dat = (u16) ((fws1 << 8) | fws0); | ||
573 | |||
574 | return 0; | ||
575 | } | ||
576 | |||
577 | /* | ||
578 | * This function disables the host interrupt. | ||
579 | * | ||
580 | * The host interrupt mask is read, the disable bit is reset and | ||
581 | * written back to the card host interrupt mask register. | ||
582 | */ | ||
583 | static int mwifiex_sdio_disable_host_int(struct mwifiex_adapter *adapter) | ||
584 | { | ||
585 | u32 host_int_mask = 0; | ||
586 | |||
587 | /* Read back the host_int_mask register */ | ||
588 | if (mwifiex_read_reg(adapter, HOST_INT_MASK_REG, &host_int_mask)) | ||
589 | return -1; | ||
590 | |||
591 | /* Update with the mask and write back to the register */ | ||
592 | host_int_mask &= ~HOST_INT_DISABLE; | ||
593 | |||
594 | if (mwifiex_write_reg(adapter, HOST_INT_MASK_REG, host_int_mask)) { | ||
595 | dev_err(adapter->dev, "disable host interrupt failed\n"); | ||
596 | return -1; | ||
597 | } | ||
598 | |||
599 | return 0; | ||
600 | } | ||
601 | |||
602 | /* | ||
603 | * This function enables the host interrupt. | ||
604 | * | ||
605 | * The host interrupt enable mask is written to the card | ||
606 | * host interrupt mask register. | ||
607 | */ | ||
608 | static int mwifiex_sdio_enable_host_int(struct mwifiex_adapter *adapter) | ||
609 | { | ||
610 | /* Simply write the mask to the register */ | ||
611 | if (mwifiex_write_reg(adapter, HOST_INT_MASK_REG, HOST_INT_ENABLE)) { | ||
612 | dev_err(adapter->dev, "enable host interrupt failed\n"); | ||
613 | return -1; | ||
614 | } | ||
615 | return 0; | ||
616 | } | ||
617 | |||
618 | /* | ||
619 | * This function sends a data buffer to the card. | ||
620 | */ | ||
621 | static int mwifiex_sdio_card_to_host(struct mwifiex_adapter *adapter, | ||
622 | u32 *type, u8 *buffer, | ||
623 | u32 npayload, u32 ioport) | ||
624 | { | ||
625 | int ret = 0; | ||
626 | u32 nb; | ||
627 | |||
628 | if (!buffer) { | ||
629 | dev_err(adapter->dev, "%s: buffer is NULL\n", __func__); | ||
630 | return -1; | ||
631 | } | ||
632 | |||
633 | ret = mwifiex_read_data_sync(adapter, buffer, npayload, ioport, 0, 1); | ||
634 | |||
635 | if (ret) { | ||
636 | dev_err(adapter->dev, "%s: read iomem failed: %d\n", __func__, | ||
637 | ret); | ||
638 | return -1; | ||
639 | } | ||
640 | |||
641 | nb = le16_to_cpu(*(__le16 *) (buffer)); | ||
642 | if (nb > npayload) { | ||
643 | dev_err(adapter->dev, "%s: invalid packet, nb=%d, npayload=%d\n", | ||
644 | __func__, nb, npayload); | ||
645 | return -1; | ||
646 | } | ||
647 | |||
648 | *type = le16_to_cpu(*(__le16 *) (buffer + 2)); | ||
649 | |||
650 | return ret; | ||
651 | } | ||
652 | |||
653 | /* | ||
654 | * This function downloads the firmware to the card. | ||
655 | * | ||
656 | * Firmware is downloaded to the card in blocks. Every block download | ||
657 | * is tested for CRC errors, and retried a number of times before | ||
658 | * returning failure. | ||
659 | */ | ||
660 | static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter, | ||
661 | struct mwifiex_fw_image *fw) | ||
662 | { | ||
663 | int ret = 0; | ||
664 | u8 *firmware = fw->fw_buf; | ||
665 | u32 firmware_len = fw->fw_len; | ||
666 | u32 offset = 0; | ||
667 | u32 base0, base1; | ||
668 | u8 *fwbuf; | ||
669 | u16 len = 0; | ||
670 | u32 txlen = 0, tx_blocks = 0, tries = 0; | ||
671 | u32 i = 0; | ||
672 | |||
673 | if (!firmware_len) { | ||
674 | dev_err(adapter->dev, "firmware image not found!" | ||
675 | " Terminating download\n"); | ||
676 | return -1; | ||
677 | } | ||
678 | |||
679 | dev_dbg(adapter->dev, "info: downloading FW image (%d bytes)\n", | ||
680 | firmware_len); | ||
681 | |||
682 | /* Assume that the allocated buffer is 8-byte aligned */ | ||
683 | fwbuf = kzalloc(MWIFIEX_UPLD_SIZE, GFP_KERNEL); | ||
684 | if (!fwbuf) { | ||
685 | dev_err(adapter->dev, "unable to alloc buffer for firmware." | ||
686 | " Terminating download\n"); | ||
687 | return -1; | ||
688 | } | ||
689 | |||
690 | /* Perform firmware data transfer */ | ||
691 | do { | ||
692 | /* The host polls for the DN_LD_CARD_RDY and CARD_IO_READY | ||
693 | bits */ | ||
694 | ret = mwifiex_sdio_poll_card_status(adapter, CARD_IO_READY | | ||
695 | DN_LD_CARD_RDY); | ||
696 | if (ret) { | ||
697 | dev_err(adapter->dev, "FW download with helper:" | ||
698 | " poll status timeout @ %d\n", offset); | ||
699 | goto done; | ||
700 | } | ||
701 | |||
702 | /* More data? */ | ||
703 | if (offset >= firmware_len) | ||
704 | break; | ||
705 | |||
706 | for (tries = 0; tries < MAX_POLL_TRIES; tries++) { | ||
707 | ret = mwifiex_read_reg(adapter, HOST_F1_RD_BASE_0, | ||
708 | &base0); | ||
709 | if (ret) { | ||
710 | dev_err(adapter->dev, "dev BASE0 register read" | ||
711 | " failed: base0=0x%04X(%d). Terminating " | ||
712 | "download\n", base0, base0); | ||
713 | goto done; | ||
714 | } | ||
715 | ret = mwifiex_read_reg(adapter, HOST_F1_RD_BASE_1, | ||
716 | &base1); | ||
717 | if (ret) { | ||
718 | dev_err(adapter->dev, "dev BASE1 register read" | ||
719 | " failed: base1=0x%04X(%d). Terminating " | ||
720 | "download\n", base1, base1); | ||
721 | goto done; | ||
722 | } | ||
723 | len = (u16) (((base1 & 0xff) << 8) | (base0 & 0xff)); | ||
724 | |||
725 | if (len) | ||
726 | break; | ||
727 | |||
728 | udelay(10); | ||
729 | } | ||
730 | |||
731 | if (!len) { | ||
732 | break; | ||
733 | } else if (len > MWIFIEX_UPLD_SIZE) { | ||
734 | dev_err(adapter->dev, "FW download failed @ %d," | ||
735 | " invalid length %d\n", offset, len); | ||
736 | ret = -1; | ||
737 | goto done; | ||
738 | } | ||
739 | |||
740 | txlen = len; | ||
741 | |||
742 | if (len & BIT(0)) { | ||
743 | i++; | ||
744 | if (i > MAX_WRITE_IOMEM_RETRY) { | ||
745 | dev_err(adapter->dev, "FW download failed @" | ||
746 | " %d, over max retry count\n", offset); | ||
747 | ret = -1; | ||
748 | goto done; | ||
749 | } | ||
750 | dev_err(adapter->dev, "CRC indicated by the helper:" | ||
751 | " len = 0x%04X, txlen = %d\n", len, txlen); | ||
752 | len &= ~BIT(0); | ||
753 | /* Setting this to 0 to resend from same offset */ | ||
754 | txlen = 0; | ||
755 | } else { | ||
756 | i = 0; | ||
757 | |||
758 | /* Set blocksize to transfer - checking for last | ||
759 | block */ | ||
760 | if (firmware_len - offset < txlen) | ||
761 | txlen = firmware_len - offset; | ||
762 | |||
763 | tx_blocks = (txlen + MWIFIEX_SDIO_BLOCK_SIZE - | ||
764 | 1) / MWIFIEX_SDIO_BLOCK_SIZE; | ||
765 | |||
766 | /* Copy payload to buffer */ | ||
767 | memmove(fwbuf, &firmware[offset], txlen); | ||
768 | } | ||
769 | |||
770 | ret = mwifiex_write_data_sync(adapter, fwbuf, tx_blocks * | ||
771 | MWIFIEX_SDIO_BLOCK_SIZE, | ||
772 | adapter->ioport, 0); | ||
773 | if (ret) { | ||
774 | dev_err(adapter->dev, "FW download, write iomem (%d)" | ||
775 | " failed @ %d\n", i, offset); | ||
776 | if (mwifiex_write_reg(adapter, CONFIGURATION_REG, 0x04)) | ||
777 | dev_err(adapter->dev, "write CFG reg failed\n"); | ||
778 | |||
779 | ret = -1; | ||
780 | goto done; | ||
781 | } | ||
782 | |||
783 | offset += txlen; | ||
784 | } while (true); | ||
785 | |||
786 | dev_dbg(adapter->dev, "info: FW download over, size %d bytes\n", | ||
787 | offset); | ||
788 | |||
789 | ret = 0; | ||
790 | done: | ||
791 | kfree(fwbuf); | ||
792 | return ret; | ||
793 | } | ||
794 | |||
795 | /* | ||
796 | * This function checks the firmware status in card. | ||
797 | * | ||
798 | * The winner interface is also determined by this function. | ||
799 | */ | ||
800 | static int mwifiex_check_fw_status(struct mwifiex_adapter *adapter, | ||
801 | u32 poll_num, int *winner) | ||
802 | { | ||
803 | int ret = 0; | ||
804 | u16 firmware_stat; | ||
805 | u32 tries; | ||
806 | u32 winner_status; | ||
807 | |||
808 | /* Wait for firmware initialization event */ | ||
809 | for (tries = 0; tries < poll_num; tries++) { | ||
810 | ret = mwifiex_sdio_read_fw_status(adapter, &firmware_stat); | ||
811 | if (ret) | ||
812 | continue; | ||
813 | if (firmware_stat == FIRMWARE_READY) { | ||
814 | ret = 0; | ||
815 | break; | ||
816 | } else { | ||
817 | mdelay(100); | ||
818 | ret = -1; | ||
819 | } | ||
820 | } | ||
821 | |||
822 | if (winner && ret) { | ||
823 | if (mwifiex_read_reg | ||
824 | (adapter, CARD_FW_STATUS0_REG, &winner_status)) | ||
825 | winner_status = 0; | ||
826 | |||
827 | if (winner_status) | ||
828 | *winner = 0; | ||
829 | else | ||
830 | *winner = 1; | ||
831 | } | ||
832 | return ret; | ||
833 | } | ||
834 | |||
835 | /* | ||
836 | * This function reads the interrupt status from card. | ||
837 | */ | ||
838 | static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter) | ||
839 | { | ||
840 | struct sdio_mmc_card *card = adapter->card; | ||
841 | u32 sdio_ireg = 0; | ||
842 | unsigned long flags; | ||
843 | |||
844 | if (mwifiex_read_data_sync(adapter, card->mp_regs, MAX_MP_REGS, | ||
845 | REG_PORT | MWIFIEX_SDIO_BYTE_MODE_MASK, 0, | ||
846 | 0)) { | ||
847 | dev_err(adapter->dev, "read mp_regs failed\n"); | ||
848 | return; | ||
849 | } | ||
850 | |||
851 | sdio_ireg = card->mp_regs[HOST_INTSTATUS_REG]; | ||
852 | if (sdio_ireg) { | ||
853 | /* | ||
854 | * DN_LD_HOST_INT_STATUS and/or UP_LD_HOST_INT_STATUS | ||
855 | * Clear the interrupt status register | ||
856 | */ | ||
857 | dev_dbg(adapter->dev, "int: sdio_ireg = %#x\n", sdio_ireg); | ||
858 | spin_lock_irqsave(&adapter->int_lock, flags); | ||
859 | adapter->int_status |= sdio_ireg; | ||
860 | spin_unlock_irqrestore(&adapter->int_lock, flags); | ||
861 | } | ||
862 | |||
863 | return; | ||
864 | } | ||
865 | |||
866 | /* | ||
867 | * SDIO interrupt handler. | ||
868 | * | ||
869 | * This function reads the interrupt status from firmware and assigns | ||
870 | * the main process in workqueue which will handle the interrupt. | ||
871 | */ | ||
872 | static void | ||
873 | mwifiex_sdio_interrupt(struct sdio_func *func) | ||
874 | { | ||
875 | struct mwifiex_adapter *adapter; | ||
876 | struct sdio_mmc_card *card; | ||
877 | |||
878 | card = sdio_get_drvdata(func); | ||
879 | if (!card || !card->adapter) { | ||
880 | pr_debug("int: func=%p card=%p adapter=%p\n", | ||
881 | func, card, card ? card->adapter : NULL); | ||
882 | return; | ||
883 | } | ||
884 | adapter = card->adapter; | ||
885 | |||
886 | if (adapter->surprise_removed) | ||
887 | return; | ||
888 | |||
889 | if (!adapter->pps_uapsd_mode && adapter->ps_state == PS_STATE_SLEEP) | ||
890 | adapter->ps_state = PS_STATE_AWAKE; | ||
891 | |||
892 | mwifiex_interrupt_status(adapter); | ||
893 | queue_work(adapter->workqueue, &adapter->main_work); | ||
894 | |||
895 | return; | ||
896 | } | ||
897 | |||
898 | /* | ||
899 | * This function decodes a received packet. | ||
900 | * | ||
901 | * Based on the type, the packet is treated as either a data, or | ||
902 | * a command response, or an event, and the correct handler | ||
903 | * function is invoked. | ||
904 | */ | ||
905 | static int mwifiex_decode_rx_packet(struct mwifiex_adapter *adapter, | ||
906 | struct sk_buff *skb, u32 upld_typ) | ||
907 | { | ||
908 | u8 *cmd_buf; | ||
909 | |||
910 | skb_pull(skb, INTF_HEADER_LEN); | ||
911 | |||
912 | switch (upld_typ) { | ||
913 | case MWIFIEX_TYPE_DATA: | ||
914 | dev_dbg(adapter->dev, "info: --- Rx: Data packet ---\n"); | ||
915 | mwifiex_handle_rx_packet(adapter, skb); | ||
916 | break; | ||
917 | |||
918 | case MWIFIEX_TYPE_CMD: | ||
919 | dev_dbg(adapter->dev, "info: --- Rx: Cmd Response ---\n"); | ||
920 | /* take care of curr_cmd = NULL case */ | ||
921 | if (!adapter->curr_cmd) { | ||
922 | cmd_buf = adapter->upld_buf; | ||
923 | |||
924 | if (adapter->ps_state == PS_STATE_SLEEP_CFM) | ||
925 | mwifiex_process_sleep_confirm_resp(adapter, | ||
926 | skb->data, skb->len); | ||
927 | |||
928 | memcpy(cmd_buf, skb->data, min_t(u32, | ||
929 | MWIFIEX_SIZE_OF_CMD_BUFFER, skb->len)); | ||
930 | |||
931 | dev_kfree_skb_any(skb); | ||
932 | } else { | ||
933 | adapter->cmd_resp_received = true; | ||
934 | adapter->curr_cmd->resp_skb = skb; | ||
935 | } | ||
936 | break; | ||
937 | |||
938 | case MWIFIEX_TYPE_EVENT: | ||
939 | dev_dbg(adapter->dev, "info: --- Rx: Event ---\n"); | ||
940 | adapter->event_cause = *(u32 *) skb->data; | ||
941 | |||
942 | skb_pull(skb, MWIFIEX_EVENT_HEADER_LEN); | ||
943 | |||
944 | if ((skb->len > 0) && (skb->len < MAX_EVENT_SIZE)) | ||
945 | memcpy(adapter->event_body, skb->data, skb->len); | ||
946 | |||
947 | /* event cause has been saved to adapter->event_cause */ | ||
948 | adapter->event_received = true; | ||
949 | adapter->event_skb = skb; | ||
950 | |||
951 | break; | ||
952 | |||
953 | default: | ||
954 | dev_err(adapter->dev, "unknown upload type %#x\n", upld_typ); | ||
955 | dev_kfree_skb_any(skb); | ||
956 | break; | ||
957 | } | ||
958 | |||
959 | return 0; | ||
960 | } | ||
961 | |||
962 | /* | ||
963 | * This function transfers received packets from card to driver, performing | ||
964 | * aggregation if required. | ||
965 | * | ||
966 | * For data received on control port, or if aggregation is disabled, the | ||
967 | * received buffers are uploaded as separate packets. However, if aggregation | ||
968 | * is enabled and required, the buffers are copied onto an aggregation buffer, | ||
969 | * provided there is space left, processed and finally uploaded. | ||
970 | */ | ||
971 | static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter, | ||
972 | struct sk_buff *skb, u8 port) | ||
973 | { | ||
974 | struct sdio_mmc_card *card = adapter->card; | ||
975 | s32 f_do_rx_aggr = 0; | ||
976 | s32 f_do_rx_cur = 0; | ||
977 | s32 f_aggr_cur = 0; | ||
978 | struct sk_buff *skb_deaggr; | ||
979 | u32 pind = 0; | ||
980 | u32 pkt_len, pkt_type = 0; | ||
981 | u8 *curr_ptr; | ||
982 | u32 rx_len = skb->len; | ||
983 | |||
984 | if (port == CTRL_PORT) { | ||
985 | /* Read the command Resp without aggr */ | ||
986 | dev_dbg(adapter->dev, "info: %s: no aggregation for cmd " | ||
987 | "response\n", __func__); | ||
988 | |||
989 | f_do_rx_cur = 1; | ||
990 | goto rx_curr_single; | ||
991 | } | ||
992 | |||
993 | if (!card->mpa_rx.enabled) { | ||
994 | dev_dbg(adapter->dev, "info: %s: rx aggregation disabled\n", | ||
995 | __func__); | ||
996 | |||
997 | f_do_rx_cur = 1; | ||
998 | goto rx_curr_single; | ||
999 | } | ||
1000 | |||
1001 | if (card->mp_rd_bitmap & (~((u16) CTRL_PORT_MASK))) { | ||
1002 | /* Some more data RX pending */ | ||
1003 | dev_dbg(adapter->dev, "info: %s: not last packet\n", __func__); | ||
1004 | |||
1005 | if (MP_RX_AGGR_IN_PROGRESS(card)) { | ||
1006 | if (MP_RX_AGGR_BUF_HAS_ROOM(card, skb->len)) { | ||
1007 | f_aggr_cur = 1; | ||
1008 | } else { | ||
1009 | /* No room in Aggr buf, do rx aggr now */ | ||
1010 | f_do_rx_aggr = 1; | ||
1011 | f_do_rx_cur = 1; | ||
1012 | } | ||
1013 | } else { | ||
1014 | /* Rx aggr not in progress */ | ||
1015 | f_aggr_cur = 1; | ||
1016 | } | ||
1017 | |||
1018 | } else { | ||
1019 | /* No more data RX pending */ | ||
1020 | dev_dbg(adapter->dev, "info: %s: last packet\n", __func__); | ||
1021 | |||
1022 | if (MP_RX_AGGR_IN_PROGRESS(card)) { | ||
1023 | f_do_rx_aggr = 1; | ||
1024 | if (MP_RX_AGGR_BUF_HAS_ROOM(card, skb->len)) | ||
1025 | f_aggr_cur = 1; | ||
1026 | else | ||
1027 | /* No room in Aggr buf, do rx aggr now */ | ||
1028 | f_do_rx_cur = 1; | ||
1029 | } else { | ||
1030 | f_do_rx_cur = 1; | ||
1031 | } | ||
1032 | } | ||
1033 | |||
1034 | if (f_aggr_cur) { | ||
1035 | dev_dbg(adapter->dev, "info: current packet aggregation\n"); | ||
1036 | /* Curr pkt can be aggregated */ | ||
1037 | MP_RX_AGGR_SETUP(card, skb, port); | ||
1038 | |||
1039 | if (MP_RX_AGGR_PKT_LIMIT_REACHED(card) || | ||
1040 | MP_RX_AGGR_PORT_LIMIT_REACHED(card)) { | ||
1041 | dev_dbg(adapter->dev, "info: %s: aggregated packet " | ||
1042 | "limit reached\n", __func__); | ||
1043 | /* No more pkts allowed in Aggr buf, rx it */ | ||
1044 | f_do_rx_aggr = 1; | ||
1045 | } | ||
1046 | } | ||
1047 | |||
1048 | if (f_do_rx_aggr) { | ||
1049 | /* do aggr RX now */ | ||
1050 | dev_dbg(adapter->dev, "info: do_rx_aggr: num of packets: %d\n", | ||
1051 | card->mpa_rx.pkt_cnt); | ||
1052 | |||
1053 | if (mwifiex_read_data_sync(adapter, card->mpa_rx.buf, | ||
1054 | card->mpa_rx.buf_len, | ||
1055 | (adapter->ioport | 0x1000 | | ||
1056 | (card->mpa_rx.ports << 4)) + | ||
1057 | card->mpa_rx.start_port, 0, 1)) | ||
1058 | return -1; | ||
1059 | |||
1060 | curr_ptr = card->mpa_rx.buf; | ||
1061 | |||
1062 | for (pind = 0; pind < card->mpa_rx.pkt_cnt; pind++) { | ||
1063 | |||
1064 | /* get curr PKT len & type */ | ||
1065 | pkt_len = *(u16 *) &curr_ptr[0]; | ||
1066 | pkt_type = *(u16 *) &curr_ptr[2]; | ||
1067 | |||
1068 | /* copy pkt to deaggr buf */ | ||
1069 | skb_deaggr = card->mpa_rx.skb_arr[pind]; | ||
1070 | |||
1071 | if ((pkt_type == MWIFIEX_TYPE_DATA) && (pkt_len <= | ||
1072 | card->mpa_rx.len_arr[pind])) { | ||
1073 | |||
1074 | memcpy(skb_deaggr->data, curr_ptr, pkt_len); | ||
1075 | |||
1076 | skb_trim(skb_deaggr, pkt_len); | ||
1077 | |||
1078 | /* Process de-aggr packet */ | ||
1079 | mwifiex_decode_rx_packet(adapter, skb_deaggr, | ||
1080 | pkt_type); | ||
1081 | } else { | ||
1082 | dev_err(adapter->dev, "wrong aggr pkt:" | ||
1083 | " type=%d len=%d max_len=%d\n", | ||
1084 | pkt_type, pkt_len, | ||
1085 | card->mpa_rx.len_arr[pind]); | ||
1086 | dev_kfree_skb_any(skb_deaggr); | ||
1087 | } | ||
1088 | curr_ptr += card->mpa_rx.len_arr[pind]; | ||
1089 | } | ||
1090 | MP_RX_AGGR_BUF_RESET(card); | ||
1091 | } | ||
1092 | |||
1093 | rx_curr_single: | ||
1094 | if (f_do_rx_cur) { | ||
1095 | dev_dbg(adapter->dev, "info: RX: port: %d, rx_len: %d\n", | ||
1096 | port, rx_len); | ||
1097 | |||
1098 | if (mwifiex_sdio_card_to_host(adapter, &pkt_type, | ||
1099 | skb->data, skb->len, | ||
1100 | adapter->ioport + port)) | ||
1101 | return -1; | ||
1102 | |||
1103 | mwifiex_decode_rx_packet(adapter, skb, pkt_type); | ||
1104 | } | ||
1105 | |||
1106 | return 0; | ||
1107 | } | ||
1108 | |||
1109 | /* | ||
1110 | * This function checks the current interrupt status. | ||
1111 | * | ||
1112 | * The following interrupts are checked and handled by this function - | ||
1113 | * - Data sent | ||
1114 | * - Command sent | ||
1115 | * - Packets received | ||
1116 | * | ||
1117 | * Since the firmware does not generate download ready interrupt if the | ||
1118 | * port updated is command port only, command sent interrupt checking | ||
1119 | * should be done manually, and for every SDIO interrupt. | ||
1120 | * | ||
1121 | * In case of Rx packets received, the packets are uploaded from card to | ||
1122 | * host and processed accordingly. | ||
1123 | */ | ||
1124 | static int mwifiex_process_int_status(struct mwifiex_adapter *adapter) | ||
1125 | { | ||
1126 | struct sdio_mmc_card *card = adapter->card; | ||
1127 | int ret = 0; | ||
1128 | u8 sdio_ireg; | ||
1129 | struct sk_buff *skb = NULL; | ||
1130 | u8 port = CTRL_PORT; | ||
1131 | u32 len_reg_l, len_reg_u; | ||
1132 | u32 rx_blocks; | ||
1133 | u16 rx_len; | ||
1134 | unsigned long flags; | ||
1135 | |||
1136 | spin_lock_irqsave(&adapter->int_lock, flags); | ||
1137 | sdio_ireg = adapter->int_status; | ||
1138 | adapter->int_status = 0; | ||
1139 | spin_unlock_irqrestore(&adapter->int_lock, flags); | ||
1140 | |||
1141 | if (!sdio_ireg) | ||
1142 | return ret; | ||
1143 | |||
1144 | if (sdio_ireg & DN_LD_HOST_INT_STATUS) { | ||
1145 | card->mp_wr_bitmap = ((u16) card->mp_regs[WR_BITMAP_U]) << 8; | ||
1146 | card->mp_wr_bitmap |= (u16) card->mp_regs[WR_BITMAP_L]; | ||
1147 | dev_dbg(adapter->dev, "int: DNLD: wr_bitmap=0x%04x\n", | ||
1148 | card->mp_wr_bitmap); | ||
1149 | if (adapter->data_sent && | ||
1150 | (card->mp_wr_bitmap & card->mp_data_port_mask)) { | ||
1151 | dev_dbg(adapter->dev, | ||
1152 | "info: <--- Tx DONE Interrupt --->\n"); | ||
1153 | adapter->data_sent = false; | ||
1154 | } | ||
1155 | } | ||
1156 | |||
1157 | /* As firmware will not generate download ready interrupt if the port | ||
1158 | updated is command port only, cmd_sent should be done for any SDIO | ||
1159 | interrupt. */ | ||
1160 | if (adapter->cmd_sent) { | ||
1161 | /* Check if firmware has attach buffer at command port and | ||
1162 | update just that in wr_bit_map. */ | ||
1163 | card->mp_wr_bitmap |= | ||
1164 | (u16) card->mp_regs[WR_BITMAP_L] & CTRL_PORT_MASK; | ||
1165 | if (card->mp_wr_bitmap & CTRL_PORT_MASK) | ||
1166 | adapter->cmd_sent = false; | ||
1167 | } | ||
1168 | |||
1169 | dev_dbg(adapter->dev, "info: cmd_sent=%d data_sent=%d\n", | ||
1170 | adapter->cmd_sent, adapter->data_sent); | ||
1171 | if (sdio_ireg & UP_LD_HOST_INT_STATUS) { | ||
1172 | card->mp_rd_bitmap = ((u16) card->mp_regs[RD_BITMAP_U]) << 8; | ||
1173 | card->mp_rd_bitmap |= (u16) card->mp_regs[RD_BITMAP_L]; | ||
1174 | dev_dbg(adapter->dev, "int: UPLD: rd_bitmap=0x%04x\n", | ||
1175 | card->mp_rd_bitmap); | ||
1176 | |||
1177 | while (true) { | ||
1178 | ret = mwifiex_get_rd_port(adapter, &port); | ||
1179 | if (ret) { | ||
1180 | dev_dbg(adapter->dev, | ||
1181 | "info: no more rd_port available\n"); | ||
1182 | break; | ||
1183 | } | ||
1184 | len_reg_l = RD_LEN_P0_L + (port << 1); | ||
1185 | len_reg_u = RD_LEN_P0_U + (port << 1); | ||
1186 | rx_len = ((u16) card->mp_regs[len_reg_u]) << 8; | ||
1187 | rx_len |= (u16) card->mp_regs[len_reg_l]; | ||
1188 | dev_dbg(adapter->dev, "info: RX: port=%d rx_len=%u\n", | ||
1189 | port, rx_len); | ||
1190 | rx_blocks = | ||
1191 | (rx_len + MWIFIEX_SDIO_BLOCK_SIZE - | ||
1192 | 1) / MWIFIEX_SDIO_BLOCK_SIZE; | ||
1193 | if (rx_len <= INTF_HEADER_LEN | ||
1194 | || (rx_blocks * MWIFIEX_SDIO_BLOCK_SIZE) > | ||
1195 | MWIFIEX_RX_DATA_BUF_SIZE) { | ||
1196 | dev_err(adapter->dev, "invalid rx_len=%d\n", | ||
1197 | rx_len); | ||
1198 | return -1; | ||
1199 | } | ||
1200 | rx_len = (u16) (rx_blocks * MWIFIEX_SDIO_BLOCK_SIZE); | ||
1201 | |||
1202 | skb = dev_alloc_skb(rx_len); | ||
1203 | |||
1204 | if (!skb) { | ||
1205 | dev_err(adapter->dev, "%s: failed to alloc skb", | ||
1206 | __func__); | ||
1207 | return -1; | ||
1208 | } | ||
1209 | |||
1210 | skb_put(skb, rx_len); | ||
1211 | |||
1212 | dev_dbg(adapter->dev, "info: rx_len = %d skb->len = %d\n", | ||
1213 | rx_len, skb->len); | ||
1214 | |||
1215 | if (mwifiex_sdio_card_to_host_mp_aggr(adapter, skb, | ||
1216 | port)) { | ||
1217 | u32 cr = 0; | ||
1218 | |||
1219 | dev_err(adapter->dev, "card_to_host_mpa failed:" | ||
1220 | " int status=%#x\n", sdio_ireg); | ||
1221 | if (mwifiex_read_reg(adapter, | ||
1222 | CONFIGURATION_REG, &cr)) | ||
1223 | dev_err(adapter->dev, | ||
1224 | "read CFG reg failed\n"); | ||
1225 | |||
1226 | dev_dbg(adapter->dev, | ||
1227 | "info: CFG reg val = %d\n", cr); | ||
1228 | if (mwifiex_write_reg(adapter, | ||
1229 | CONFIGURATION_REG, | ||
1230 | (cr | 0x04))) | ||
1231 | dev_err(adapter->dev, | ||
1232 | "write CFG reg failed\n"); | ||
1233 | |||
1234 | dev_dbg(adapter->dev, "info: write success\n"); | ||
1235 | if (mwifiex_read_reg(adapter, | ||
1236 | CONFIGURATION_REG, &cr)) | ||
1237 | dev_err(adapter->dev, | ||
1238 | "read CFG reg failed\n"); | ||
1239 | |||
1240 | dev_dbg(adapter->dev, | ||
1241 | "info: CFG reg val =%x\n", cr); | ||
1242 | dev_kfree_skb_any(skb); | ||
1243 | return -1; | ||
1244 | } | ||
1245 | } | ||
1246 | } | ||
1247 | |||
1248 | return 0; | ||
1249 | } | ||
1250 | |||
1251 | /* | ||
1252 | * This function aggregates transmission buffers in driver and downloads | ||
1253 | * the aggregated packet to card. | ||
1254 | * | ||
1255 | * The individual packets are aggregated by copying into an aggregation | ||
1256 | * buffer and then downloaded to the card. Previous unsent packets in the | ||
1257 | * aggregation buffer are pre-copied first before new packets are added. | ||
1258 | * Aggregation is done till there is space left in the aggregation buffer, | ||
1259 | * or till new packets are available. | ||
1260 | * | ||
1261 | * The function will only download the packet to the card when aggregation | ||
1262 | * stops, otherwise it will just aggregate the packet in aggregation buffer | ||
1263 | * and return. | ||
1264 | */ | ||
1265 | static int mwifiex_host_to_card_mp_aggr(struct mwifiex_adapter *adapter, | ||
1266 | u8 *payload, u32 pkt_len, u8 port, | ||
1267 | u32 next_pkt_len) | ||
1268 | { | ||
1269 | struct sdio_mmc_card *card = adapter->card; | ||
1270 | int ret = 0; | ||
1271 | s32 f_send_aggr_buf = 0; | ||
1272 | s32 f_send_cur_buf = 0; | ||
1273 | s32 f_precopy_cur_buf = 0; | ||
1274 | s32 f_postcopy_cur_buf = 0; | ||
1275 | |||
1276 | if ((!card->mpa_tx.enabled) || (port == CTRL_PORT)) { | ||
1277 | dev_dbg(adapter->dev, "info: %s: tx aggregation disabled\n", | ||
1278 | __func__); | ||
1279 | |||
1280 | f_send_cur_buf = 1; | ||
1281 | goto tx_curr_single; | ||
1282 | } | ||
1283 | |||
1284 | if (next_pkt_len) { | ||
1285 | /* More pkt in TX queue */ | ||
1286 | dev_dbg(adapter->dev, "info: %s: more packets in queue.\n", | ||
1287 | __func__); | ||
1288 | |||
1289 | if (MP_TX_AGGR_IN_PROGRESS(card)) { | ||
1290 | if (!MP_TX_AGGR_PORT_LIMIT_REACHED(card) && | ||
1291 | MP_TX_AGGR_BUF_HAS_ROOM(card, pkt_len)) { | ||
1292 | f_precopy_cur_buf = 1; | ||
1293 | |||
1294 | if (!(card->mp_wr_bitmap & | ||
1295 | (1 << card->curr_wr_port)) | ||
1296 | || !MP_TX_AGGR_BUF_HAS_ROOM( | ||
1297 | card, next_pkt_len)) | ||
1298 | f_send_aggr_buf = 1; | ||
1299 | } else { | ||
1300 | /* No room in Aggr buf, send it */ | ||
1301 | f_send_aggr_buf = 1; | ||
1302 | |||
1303 | if (MP_TX_AGGR_PORT_LIMIT_REACHED(card) || | ||
1304 | !(card->mp_wr_bitmap & | ||
1305 | (1 << card->curr_wr_port))) | ||
1306 | f_send_cur_buf = 1; | ||
1307 | else | ||
1308 | f_postcopy_cur_buf = 1; | ||
1309 | } | ||
1310 | } else { | ||
1311 | if (MP_TX_AGGR_BUF_HAS_ROOM(card, pkt_len) | ||
1312 | && (card->mp_wr_bitmap & (1 << card->curr_wr_port))) | ||
1313 | f_precopy_cur_buf = 1; | ||
1314 | else | ||
1315 | f_send_cur_buf = 1; | ||
1316 | } | ||
1317 | } else { | ||
1318 | /* Last pkt in TX queue */ | ||
1319 | dev_dbg(adapter->dev, "info: %s: Last packet in Tx Queue.\n", | ||
1320 | __func__); | ||
1321 | |||
1322 | if (MP_TX_AGGR_IN_PROGRESS(card)) { | ||
1323 | /* some packs in Aggr buf already */ | ||
1324 | f_send_aggr_buf = 1; | ||
1325 | |||
1326 | if (MP_TX_AGGR_BUF_HAS_ROOM(card, pkt_len)) | ||
1327 | f_precopy_cur_buf = 1; | ||
1328 | else | ||
1329 | /* No room in Aggr buf, send it */ | ||
1330 | f_send_cur_buf = 1; | ||
1331 | } else { | ||
1332 | f_send_cur_buf = 1; | ||
1333 | } | ||
1334 | } | ||
1335 | |||
1336 | if (f_precopy_cur_buf) { | ||
1337 | dev_dbg(adapter->dev, "data: %s: precopy current buffer\n", | ||
1338 | __func__); | ||
1339 | MP_TX_AGGR_BUF_PUT(card, payload, pkt_len, port); | ||
1340 | |||
1341 | if (MP_TX_AGGR_PKT_LIMIT_REACHED(card) || | ||
1342 | MP_TX_AGGR_PORT_LIMIT_REACHED(card)) | ||
1343 | /* No more pkts allowed in Aggr buf, send it */ | ||
1344 | f_send_aggr_buf = 1; | ||
1345 | } | ||
1346 | |||
1347 | if (f_send_aggr_buf) { | ||
1348 | dev_dbg(adapter->dev, "data: %s: send aggr buffer: %d %d\n", | ||
1349 | __func__, | ||
1350 | card->mpa_tx.start_port, card->mpa_tx.ports); | ||
1351 | ret = mwifiex_write_data_to_card(adapter, card->mpa_tx.buf, | ||
1352 | card->mpa_tx.buf_len, | ||
1353 | (adapter->ioport | 0x1000 | | ||
1354 | (card->mpa_tx.ports << 4)) + | ||
1355 | card->mpa_tx.start_port); | ||
1356 | |||
1357 | MP_TX_AGGR_BUF_RESET(card); | ||
1358 | } | ||
1359 | |||
1360 | tx_curr_single: | ||
1361 | if (f_send_cur_buf) { | ||
1362 | dev_dbg(adapter->dev, "data: %s: send current buffer %d\n", | ||
1363 | __func__, port); | ||
1364 | ret = mwifiex_write_data_to_card(adapter, payload, pkt_len, | ||
1365 | adapter->ioport + port); | ||
1366 | } | ||
1367 | |||
1368 | if (f_postcopy_cur_buf) { | ||
1369 | dev_dbg(adapter->dev, "data: %s: postcopy current buffer\n", | ||
1370 | __func__); | ||
1371 | MP_TX_AGGR_BUF_PUT(card, payload, pkt_len, port); | ||
1372 | } | ||
1373 | |||
1374 | return ret; | ||
1375 | } | ||
1376 | |||
1377 | /* | ||
1378 | * This function downloads data from driver to card. | ||
1379 | * | ||
1380 | * Both commands and data packets are transferred to the card by this | ||
1381 | * function. | ||
1382 | * | ||
1383 | * This function adds the SDIO specific header to the front of the buffer | ||
1384 | * before transferring. The header contains the length of the packet and | ||
1385 | * the type. The firmware handles the packets based upon this set type. | ||
1386 | */ | ||
1387 | static int mwifiex_sdio_host_to_card(struct mwifiex_adapter *adapter, | ||
1388 | u8 type, u8 *payload, u32 pkt_len, | ||
1389 | struct mwifiex_tx_param *tx_param) | ||
1390 | { | ||
1391 | struct sdio_mmc_card *card = adapter->card; | ||
1392 | int ret = 0; | ||
1393 | u32 buf_block_len; | ||
1394 | u32 blk_size; | ||
1395 | u8 port = CTRL_PORT; | ||
1396 | |||
1397 | /* Allocate buffer and copy payload */ | ||
1398 | blk_size = MWIFIEX_SDIO_BLOCK_SIZE; | ||
1399 | buf_block_len = (pkt_len + blk_size - 1) / blk_size; | ||
1400 | *(u16 *) &payload[0] = (u16) pkt_len; | ||
1401 | *(u16 *) &payload[2] = type; | ||
1402 | |||
1403 | /* | ||
1404 | * This is SDIO specific header | ||
1405 | * u16 length, | ||
1406 | * u16 type (MWIFIEX_TYPE_DATA = 0, MWIFIEX_TYPE_CMD = 1, | ||
1407 | * MWIFIEX_TYPE_EVENT = 3) | ||
1408 | */ | ||
1409 | if (type == MWIFIEX_TYPE_DATA) { | ||
1410 | ret = mwifiex_get_wr_port_data(adapter, &port); | ||
1411 | if (ret) { | ||
1412 | dev_err(adapter->dev, "%s: no wr_port available\n", | ||
1413 | __func__); | ||
1414 | return ret; | ||
1415 | } | ||
1416 | } else { | ||
1417 | adapter->cmd_sent = true; | ||
1418 | /* Type must be MWIFIEX_TYPE_CMD */ | ||
1419 | |||
1420 | if (pkt_len <= INTF_HEADER_LEN || | ||
1421 | pkt_len > MWIFIEX_UPLD_SIZE) | ||
1422 | dev_err(adapter->dev, "%s: payload=%p, nb=%d\n", | ||
1423 | __func__, payload, pkt_len); | ||
1424 | } | ||
1425 | |||
1426 | /* Transfer data to card */ | ||
1427 | pkt_len = buf_block_len * blk_size; | ||
1428 | |||
1429 | if (tx_param) | ||
1430 | ret = mwifiex_host_to_card_mp_aggr(adapter, payload, pkt_len, | ||
1431 | port, tx_param->next_pkt_len); | ||
1432 | else | ||
1433 | ret = mwifiex_host_to_card_mp_aggr(adapter, payload, pkt_len, | ||
1434 | port, 0); | ||
1435 | |||
1436 | if (ret) { | ||
1437 | if (type == MWIFIEX_TYPE_CMD) | ||
1438 | adapter->cmd_sent = false; | ||
1439 | if (type == MWIFIEX_TYPE_DATA) | ||
1440 | adapter->data_sent = false; | ||
1441 | } else { | ||
1442 | if (type == MWIFIEX_TYPE_DATA) { | ||
1443 | if (!(card->mp_wr_bitmap & (1 << card->curr_wr_port))) | ||
1444 | adapter->data_sent = true; | ||
1445 | else | ||
1446 | adapter->data_sent = false; | ||
1447 | } | ||
1448 | } | ||
1449 | |||
1450 | return ret; | ||
1451 | } | ||
1452 | |||
1453 | /* | ||
1454 | * This function allocates the MPA Tx and Rx buffers. | ||
1455 | */ | ||
1456 | static int mwifiex_alloc_sdio_mpa_buffers(struct mwifiex_adapter *adapter, | ||
1457 | u32 mpa_tx_buf_size, u32 mpa_rx_buf_size) | ||
1458 | { | ||
1459 | struct sdio_mmc_card *card = adapter->card; | ||
1460 | int ret = 0; | ||
1461 | |||
1462 | card->mpa_tx.buf = kzalloc(mpa_tx_buf_size, GFP_KERNEL); | ||
1463 | if (!card->mpa_tx.buf) { | ||
1464 | dev_err(adapter->dev, "could not alloc buffer for MP-A TX\n"); | ||
1465 | ret = -1; | ||
1466 | goto error; | ||
1467 | } | ||
1468 | |||
1469 | card->mpa_tx.buf_size = mpa_tx_buf_size; | ||
1470 | |||
1471 | card->mpa_rx.buf = kzalloc(mpa_rx_buf_size, GFP_KERNEL); | ||
1472 | if (!card->mpa_rx.buf) { | ||
1473 | dev_err(adapter->dev, "could not alloc buffer for MP-A RX\n"); | ||
1474 | ret = -1; | ||
1475 | goto error; | ||
1476 | } | ||
1477 | |||
1478 | card->mpa_rx.buf_size = mpa_rx_buf_size; | ||
1479 | |||
1480 | error: | ||
1481 | if (ret) { | ||
1482 | kfree(card->mpa_tx.buf); | ||
1483 | kfree(card->mpa_rx.buf); | ||
1484 | } | ||
1485 | |||
1486 | return ret; | ||
1487 | } | ||
1488 | |||
1489 | /* | ||
1490 | * This function unregisters the SDIO device. | ||
1491 | * | ||
1492 | * The SDIO IRQ is released, the function is disabled and driver | ||
1493 | * data is set to null. | ||
1494 | */ | ||
1495 | static void | ||
1496 | mwifiex_unregister_dev(struct mwifiex_adapter *adapter) | ||
1497 | { | ||
1498 | struct sdio_mmc_card *card = adapter->card; | ||
1499 | |||
1500 | if (adapter->card) { | ||
1501 | /* Release the SDIO IRQ */ | ||
1502 | sdio_claim_host(card->func); | ||
1503 | sdio_release_irq(card->func); | ||
1504 | sdio_disable_func(card->func); | ||
1505 | sdio_release_host(card->func); | ||
1506 | sdio_set_drvdata(card->func, NULL); | ||
1507 | } | ||
1508 | } | ||
1509 | |||
1510 | /* | ||
1511 | * This function registers the SDIO device. | ||
1512 | * | ||
1513 | * SDIO IRQ is claimed, block size is set and driver data is initialized. | ||
1514 | */ | ||
1515 | static int mwifiex_register_dev(struct mwifiex_adapter *adapter) | ||
1516 | { | ||
1517 | int ret = 0; | ||
1518 | struct sdio_mmc_card *card = adapter->card; | ||
1519 | struct sdio_func *func = card->func; | ||
1520 | |||
1521 | /* save adapter pointer in card */ | ||
1522 | card->adapter = adapter; | ||
1523 | |||
1524 | sdio_claim_host(func); | ||
1525 | |||
1526 | /* Request the SDIO IRQ */ | ||
1527 | ret = sdio_claim_irq(func, mwifiex_sdio_interrupt); | ||
1528 | if (ret) { | ||
1529 | pr_err("claim irq failed: ret=%d\n", ret); | ||
1530 | goto disable_func; | ||
1531 | } | ||
1532 | |||
1533 | /* Set block size */ | ||
1534 | ret = sdio_set_block_size(card->func, MWIFIEX_SDIO_BLOCK_SIZE); | ||
1535 | if (ret) { | ||
1536 | pr_err("cannot set SDIO block size\n"); | ||
1537 | ret = -1; | ||
1538 | goto release_irq; | ||
1539 | } | ||
1540 | |||
1541 | sdio_release_host(func); | ||
1542 | sdio_set_drvdata(func, card); | ||
1543 | |||
1544 | adapter->dev = &func->dev; | ||
1545 | |||
1546 | return 0; | ||
1547 | |||
1548 | release_irq: | ||
1549 | sdio_release_irq(func); | ||
1550 | disable_func: | ||
1551 | sdio_disable_func(func); | ||
1552 | sdio_release_host(func); | ||
1553 | adapter->card = NULL; | ||
1554 | |||
1555 | return -1; | ||
1556 | } | ||
1557 | |||
1558 | /* | ||
1559 | * This function initializes the SDIO driver. | ||
1560 | * | ||
1561 | * The following initializations steps are followed - | ||
1562 | * - Read the Host interrupt status register to acknowledge | ||
1563 | * the first interrupt got from bootloader | ||
1564 | * - Disable host interrupt mask register | ||
1565 | * - Get SDIO port | ||
1566 | * - Get revision ID | ||
1567 | * - Initialize SDIO variables in card | ||
1568 | * - Allocate MP registers | ||
1569 | * - Allocate MPA Tx and Rx buffers | ||
1570 | */ | ||
1571 | static int mwifiex_init_sdio(struct mwifiex_adapter *adapter) | ||
1572 | { | ||
1573 | struct sdio_mmc_card *card = adapter->card; | ||
1574 | int ret; | ||
1575 | u32 sdio_ireg = 0; | ||
1576 | |||
1577 | /* | ||
1578 | * Read the HOST_INT_STATUS_REG for ACK the first interrupt got | ||
1579 | * from the bootloader. If we don't do this we get a interrupt | ||
1580 | * as soon as we register the irq. | ||
1581 | */ | ||
1582 | mwifiex_read_reg(adapter, HOST_INTSTATUS_REG, &sdio_ireg); | ||
1583 | |||
1584 | /* Disable host interrupt mask register for SDIO */ | ||
1585 | mwifiex_sdio_disable_host_int(adapter); | ||
1586 | |||
1587 | /* Get SDIO ioport */ | ||
1588 | mwifiex_init_sdio_ioport(adapter); | ||
1589 | |||
1590 | /* Get revision ID */ | ||
1591 | #define REV_ID_REG 0x5c | ||
1592 | mwifiex_read_reg(adapter, REV_ID_REG, &adapter->revision_id); | ||
1593 | |||
1594 | /* Initialize SDIO variables in card */ | ||
1595 | card->mp_rd_bitmap = 0; | ||
1596 | card->mp_wr_bitmap = 0; | ||
1597 | card->curr_rd_port = 1; | ||
1598 | card->curr_wr_port = 1; | ||
1599 | |||
1600 | card->mp_data_port_mask = DATA_PORT_MASK; | ||
1601 | |||
1602 | card->mpa_tx.buf_len = 0; | ||
1603 | card->mpa_tx.pkt_cnt = 0; | ||
1604 | card->mpa_tx.start_port = 0; | ||
1605 | |||
1606 | card->mpa_tx.enabled = 0; | ||
1607 | card->mpa_tx.pkt_aggr_limit = SDIO_MP_AGGR_DEF_PKT_LIMIT; | ||
1608 | |||
1609 | card->mpa_rx.buf_len = 0; | ||
1610 | card->mpa_rx.pkt_cnt = 0; | ||
1611 | card->mpa_rx.start_port = 0; | ||
1612 | |||
1613 | card->mpa_rx.enabled = 0; | ||
1614 | card->mpa_rx.pkt_aggr_limit = SDIO_MP_AGGR_DEF_PKT_LIMIT; | ||
1615 | |||
1616 | /* Allocate buffers for SDIO MP-A */ | ||
1617 | card->mp_regs = kzalloc(MAX_MP_REGS, GFP_KERNEL); | ||
1618 | if (!card->mp_regs) { | ||
1619 | dev_err(adapter->dev, "failed to alloc mp_regs\n"); | ||
1620 | return -1; | ||
1621 | } | ||
1622 | |||
1623 | ret = mwifiex_alloc_sdio_mpa_buffers(adapter, | ||
1624 | SDIO_MP_TX_AGGR_DEF_BUF_SIZE, | ||
1625 | SDIO_MP_RX_AGGR_DEF_BUF_SIZE); | ||
1626 | if (ret) { | ||
1627 | dev_err(adapter->dev, "failed to alloc sdio mp-a buffers\n"); | ||
1628 | kfree(card->mp_regs); | ||
1629 | return -1; | ||
1630 | } | ||
1631 | |||
1632 | return ret; | ||
1633 | } | ||
1634 | |||
1635 | /* | ||
1636 | * This function resets the MPA Tx and Rx buffers. | ||
1637 | */ | ||
1638 | static void mwifiex_cleanup_mpa_buf(struct mwifiex_adapter *adapter) | ||
1639 | { | ||
1640 | struct sdio_mmc_card *card = adapter->card; | ||
1641 | |||
1642 | MP_TX_AGGR_BUF_RESET(card); | ||
1643 | MP_RX_AGGR_BUF_RESET(card); | ||
1644 | } | ||
1645 | |||
1646 | /* | ||
1647 | * This function cleans up the allocated card buffers. | ||
1648 | * | ||
1649 | * The following are freed by this function - | ||
1650 | * - MP registers | ||
1651 | * - MPA Tx buffer | ||
1652 | * - MPA Rx buffer | ||
1653 | */ | ||
1654 | static void mwifiex_cleanup_sdio(struct mwifiex_adapter *adapter) | ||
1655 | { | ||
1656 | struct sdio_mmc_card *card = adapter->card; | ||
1657 | |||
1658 | kfree(card->mp_regs); | ||
1659 | kfree(card->mpa_tx.buf); | ||
1660 | kfree(card->mpa_rx.buf); | ||
1661 | } | ||
1662 | |||
1663 | /* | ||
1664 | * This function updates the MP end port in card. | ||
1665 | */ | ||
1666 | static void | ||
1667 | mwifiex_update_mp_end_port(struct mwifiex_adapter *adapter, u16 port) | ||
1668 | { | ||
1669 | struct sdio_mmc_card *card = adapter->card; | ||
1670 | int i; | ||
1671 | |||
1672 | card->mp_end_port = port; | ||
1673 | |||
1674 | card->mp_data_port_mask = DATA_PORT_MASK; | ||
1675 | |||
1676 | for (i = 1; i <= MAX_PORT - card->mp_end_port; i++) | ||
1677 | card->mp_data_port_mask &= ~(1 << (MAX_PORT - i)); | ||
1678 | |||
1679 | card->curr_wr_port = 1; | ||
1680 | |||
1681 | dev_dbg(adapter->dev, "cmd: mp_end_port %d, data port mask 0x%x\n", | ||
1682 | port, card->mp_data_port_mask); | ||
1683 | } | ||
1684 | |||
1685 | static struct mwifiex_if_ops sdio_ops = { | ||
1686 | .init_if = mwifiex_init_sdio, | ||
1687 | .cleanup_if = mwifiex_cleanup_sdio, | ||
1688 | .check_fw_status = mwifiex_check_fw_status, | ||
1689 | .prog_fw = mwifiex_prog_fw_w_helper, | ||
1690 | .register_dev = mwifiex_register_dev, | ||
1691 | .unregister_dev = mwifiex_unregister_dev, | ||
1692 | .enable_int = mwifiex_sdio_enable_host_int, | ||
1693 | .process_int_status = mwifiex_process_int_status, | ||
1694 | .host_to_card = mwifiex_sdio_host_to_card, | ||
1695 | .wakeup = mwifiex_pm_wakeup_card, | ||
1696 | .wakeup_complete = mwifiex_pm_wakeup_card_complete, | ||
1697 | |||
1698 | /* SDIO specific */ | ||
1699 | .update_mp_end_port = mwifiex_update_mp_end_port, | ||
1700 | .cleanup_mpa_buf = mwifiex_cleanup_mpa_buf, | ||
1701 | }; | ||
1702 | |||
1703 | /* | ||
1704 | * This function initializes the SDIO driver. | ||
1705 | * | ||
1706 | * This initiates the semaphore and registers the device with | ||
1707 | * SDIO bus. | ||
1708 | */ | ||
1709 | static int | ||
1710 | mwifiex_sdio_init_module(void) | ||
1711 | { | ||
1712 | int ret; | ||
1713 | |||
1714 | sema_init(&add_remove_card_sem, 1); | ||
1715 | |||
1716 | ret = sdio_register_driver(&mwifiex_sdio); | ||
1717 | |||
1718 | return ret; | ||
1719 | } | ||
1720 | |||
1721 | /* | ||
1722 | * This function cleans up the SDIO driver. | ||
1723 | * | ||
1724 | * The following major steps are followed for cleanup - | ||
1725 | * - Resume the device if its suspended | ||
1726 | * - Disconnect the device if connected | ||
1727 | * - Shutdown the firmware | ||
1728 | * - Unregister the device from SDIO bus. | ||
1729 | */ | ||
1730 | static void | ||
1731 | mwifiex_sdio_cleanup_module(void) | ||
1732 | { | ||
1733 | struct mwifiex_adapter *adapter = g_adapter; | ||
1734 | int i; | ||
1735 | |||
1736 | if (down_interruptible(&add_remove_card_sem)) | ||
1737 | goto exit_sem_err; | ||
1738 | |||
1739 | if (!adapter || !adapter->priv_num) | ||
1740 | goto exit; | ||
1741 | |||
1742 | if (adapter->is_suspended) | ||
1743 | mwifiex_sdio_resume(adapter->dev); | ||
1744 | |||
1745 | for (i = 0; i < adapter->priv_num; i++) | ||
1746 | if ((GET_BSS_ROLE(adapter->priv[i]) == MWIFIEX_BSS_ROLE_STA) && | ||
1747 | adapter->priv[i]->media_connected) | ||
1748 | mwifiex_disconnect(adapter->priv[i], MWIFIEX_CMD_WAIT, | ||
1749 | NULL); | ||
1750 | |||
1751 | if (!adapter->surprise_removed) | ||
1752 | mwifiex_shutdown_fw(mwifiex_get_priv | ||
1753 | (adapter, MWIFIEX_BSS_ROLE_ANY), | ||
1754 | MWIFIEX_CMD_WAIT); | ||
1755 | |||
1756 | exit: | ||
1757 | up(&add_remove_card_sem); | ||
1758 | |||
1759 | exit_sem_err: | ||
1760 | sdio_unregister_driver(&mwifiex_sdio); | ||
1761 | } | ||
1762 | |||
1763 | module_init(mwifiex_sdio_init_module); | ||
1764 | module_exit(mwifiex_sdio_cleanup_module); | ||
1765 | |||
1766 | MODULE_AUTHOR("Marvell International Ltd."); | ||
1767 | MODULE_DESCRIPTION("Marvell WiFi-Ex SDIO Driver version " SDIO_VERSION); | ||
1768 | MODULE_VERSION(SDIO_VERSION); | ||
1769 | MODULE_LICENSE("GPL v2"); | ||
1770 | MODULE_FIRMWARE("sd8787.bin"); | ||
diff --git a/drivers/net/wireless/mwifiex/sdio.h b/drivers/net/wireless/mwifiex/sdio.h new file mode 100644 index 000000000000..a0e9bc5253e0 --- /dev/null +++ b/drivers/net/wireless/mwifiex/sdio.h | |||
@@ -0,0 +1,305 @@ | |||
1 | /* | ||
2 | * Marvell Wireless LAN device driver: SDIO specific definitions | ||
3 | * | ||
4 | * Copyright (C) 2011, Marvell International Ltd. | ||
5 | * | ||
6 | * This software file (the "File") is distributed by Marvell International | ||
7 | * Ltd. under the terms of the GNU General Public License Version 2, June 1991 | ||
8 | * (the "License"). You may use, redistribute and/or modify this File in | ||
9 | * accordance with the terms and conditions of the License, a copy of which | ||
10 | * is available by writing to the Free Software Foundation, Inc., | ||
11 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the | ||
12 | * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. | ||
13 | * | ||
14 | * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE | ||
15 | * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE | ||
16 | * ARE EXPRESSLY DISCLAIMED. The License provides additional details about | ||
17 | * this warranty disclaimer. | ||
18 | */ | ||
19 | |||
20 | #ifndef _MWIFIEX_SDIO_H | ||
21 | #define _MWIFIEX_SDIO_H | ||
22 | |||
23 | |||
24 | #include <linux/mmc/sdio.h> | ||
25 | #include <linux/mmc/sdio_ids.h> | ||
26 | #include <linux/mmc/sdio_func.h> | ||
27 | #include <linux/mmc/card.h> | ||
28 | |||
29 | #include "main.h" | ||
30 | |||
31 | #define BLOCK_MODE 1 | ||
32 | #define BYTE_MODE 0 | ||
33 | |||
34 | #define REG_PORT 0 | ||
35 | #define RD_BITMAP_L 0x04 | ||
36 | #define RD_BITMAP_U 0x05 | ||
37 | #define WR_BITMAP_L 0x06 | ||
38 | #define WR_BITMAP_U 0x07 | ||
39 | #define RD_LEN_P0_L 0x08 | ||
40 | #define RD_LEN_P0_U 0x09 | ||
41 | |||
42 | #define MWIFIEX_SDIO_IO_PORT_MASK 0xfffff | ||
43 | |||
44 | #define MWIFIEX_SDIO_BYTE_MODE_MASK 0x80000000 | ||
45 | |||
46 | #define CTRL_PORT 0 | ||
47 | #define CTRL_PORT_MASK 0x0001 | ||
48 | #define DATA_PORT_MASK 0xfffe | ||
49 | |||
50 | #define MAX_MP_REGS 64 | ||
51 | #define MAX_PORT 16 | ||
52 | |||
53 | #define SDIO_MP_AGGR_DEF_PKT_LIMIT 8 | ||
54 | |||
55 | #define SDIO_MP_TX_AGGR_DEF_BUF_SIZE (4096) /* 4K */ | ||
56 | |||
57 | /* Multi port RX aggregation buffer size */ | ||
58 | #define SDIO_MP_RX_AGGR_DEF_BUF_SIZE (4096) /* 4K */ | ||
59 | |||
60 | /* Misc. Config Register : Auto Re-enable interrupts */ | ||
61 | #define AUTO_RE_ENABLE_INT BIT(4) | ||
62 | |||
63 | /* Host Control Registers */ | ||
64 | /* Host Control Registers : I/O port 0 */ | ||
65 | #define IO_PORT_0_REG 0x78 | ||
66 | /* Host Control Registers : I/O port 1 */ | ||
67 | #define IO_PORT_1_REG 0x79 | ||
68 | /* Host Control Registers : I/O port 2 */ | ||
69 | #define IO_PORT_2_REG 0x7A | ||
70 | |||
71 | /* Host Control Registers : Configuration */ | ||
72 | #define CONFIGURATION_REG 0x00 | ||
73 | /* Host Control Registers : Host without Command 53 finish host*/ | ||
74 | #define HOST_TO_CARD_EVENT (0x1U << 3) | ||
75 | /* Host Control Registers : Host without Command 53 finish host */ | ||
76 | #define HOST_WO_CMD53_FINISH_HOST (0x1U << 2) | ||
77 | /* Host Control Registers : Host power up */ | ||
78 | #define HOST_POWER_UP (0x1U << 1) | ||
79 | /* Host Control Registers : Host power down */ | ||
80 | #define HOST_POWER_DOWN (0x1U << 0) | ||
81 | |||
82 | /* Host Control Registers : Host interrupt mask */ | ||
83 | #define HOST_INT_MASK_REG 0x02 | ||
84 | /* Host Control Registers : Upload host interrupt mask */ | ||
85 | #define UP_LD_HOST_INT_MASK (0x1U) | ||
86 | /* Host Control Registers : Download host interrupt mask */ | ||
87 | #define DN_LD_HOST_INT_MASK (0x2U) | ||
88 | /* Enable Host interrupt mask */ | ||
89 | #define HOST_INT_ENABLE (UP_LD_HOST_INT_MASK | DN_LD_HOST_INT_MASK) | ||
90 | /* Disable Host interrupt mask */ | ||
91 | #define HOST_INT_DISABLE 0xff | ||
92 | |||
93 | /* Host Control Registers : Host interrupt status */ | ||
94 | #define HOST_INTSTATUS_REG 0x03 | ||
95 | /* Host Control Registers : Upload host interrupt status */ | ||
96 | #define UP_LD_HOST_INT_STATUS (0x1U) | ||
97 | /* Host Control Registers : Download host interrupt status */ | ||
98 | #define DN_LD_HOST_INT_STATUS (0x2U) | ||
99 | |||
100 | /* Host Control Registers : Host interrupt RSR */ | ||
101 | #define HOST_INT_RSR_REG 0x01 | ||
102 | /* Host Control Registers : Upload host interrupt RSR */ | ||
103 | #define UP_LD_HOST_INT_RSR (0x1U) | ||
104 | #define SDIO_INT_MASK 0x3F | ||
105 | |||
106 | /* Host Control Registers : Host interrupt status */ | ||
107 | #define HOST_INT_STATUS_REG 0x28 | ||
108 | /* Host Control Registers : Upload CRC error */ | ||
109 | #define UP_LD_CRC_ERR (0x1U << 2) | ||
110 | /* Host Control Registers : Upload restart */ | ||
111 | #define UP_LD_RESTART (0x1U << 1) | ||
112 | /* Host Control Registers : Download restart */ | ||
113 | #define DN_LD_RESTART (0x1U << 0) | ||
114 | |||
115 | /* Card Control Registers : Card status register */ | ||
116 | #define CARD_STATUS_REG 0x30 | ||
117 | /* Card Control Registers : Card I/O ready */ | ||
118 | #define CARD_IO_READY (0x1U << 3) | ||
119 | /* Card Control Registers : CIS card ready */ | ||
120 | #define CIS_CARD_RDY (0x1U << 2) | ||
121 | /* Card Control Registers : Upload card ready */ | ||
122 | #define UP_LD_CARD_RDY (0x1U << 1) | ||
123 | /* Card Control Registers : Download card ready */ | ||
124 | #define DN_LD_CARD_RDY (0x1U << 0) | ||
125 | |||
126 | /* Card Control Registers : Host interrupt mask register */ | ||
127 | #define HOST_INTERRUPT_MASK_REG 0x34 | ||
128 | /* Card Control Registers : Host power interrupt mask */ | ||
129 | #define HOST_POWER_INT_MASK (0x1U << 3) | ||
130 | /* Card Control Registers : Abort card interrupt mask */ | ||
131 | #define ABORT_CARD_INT_MASK (0x1U << 2) | ||
132 | /* Card Control Registers : Upload card interrupt mask */ | ||
133 | #define UP_LD_CARD_INT_MASK (0x1U << 1) | ||
134 | /* Card Control Registers : Download card interrupt mask */ | ||
135 | #define DN_LD_CARD_INT_MASK (0x1U << 0) | ||
136 | |||
137 | /* Card Control Registers : Card interrupt status register */ | ||
138 | #define CARD_INTERRUPT_STATUS_REG 0x38 | ||
139 | /* Card Control Registers : Power up interrupt */ | ||
140 | #define POWER_UP_INT (0x1U << 4) | ||
141 | /* Card Control Registers : Power down interrupt */ | ||
142 | #define POWER_DOWN_INT (0x1U << 3) | ||
143 | |||
144 | /* Card Control Registers : Card interrupt RSR register */ | ||
145 | #define CARD_INTERRUPT_RSR_REG 0x3c | ||
146 | /* Card Control Registers : Power up RSR */ | ||
147 | #define POWER_UP_RSR (0x1U << 4) | ||
148 | /* Card Control Registers : Power down RSR */ | ||
149 | #define POWER_DOWN_RSR (0x1U << 3) | ||
150 | |||
151 | /* Card Control Registers : Miscellaneous Configuration Register */ | ||
152 | #define CARD_MISC_CFG_REG 0x6C | ||
153 | |||
154 | /* Host F1 read base 0 */ | ||
155 | #define HOST_F1_RD_BASE_0 0x0040 | ||
156 | /* Host F1 read base 1 */ | ||
157 | #define HOST_F1_RD_BASE_1 0x0041 | ||
158 | /* Host F1 card ready */ | ||
159 | #define HOST_F1_CARD_RDY 0x0020 | ||
160 | |||
161 | /* Firmware status 0 register */ | ||
162 | #define CARD_FW_STATUS0_REG 0x60 | ||
163 | /* Firmware status 1 register */ | ||
164 | #define CARD_FW_STATUS1_REG 0x61 | ||
165 | /* Rx length register */ | ||
166 | #define CARD_RX_LEN_REG 0x62 | ||
167 | /* Rx unit register */ | ||
168 | #define CARD_RX_UNIT_REG 0x63 | ||
169 | |||
170 | /* Event header Len*/ | ||
171 | #define MWIFIEX_EVENT_HEADER_LEN 8 | ||
172 | |||
173 | /* Max retry number of CMD53 write */ | ||
174 | #define MAX_WRITE_IOMEM_RETRY 2 | ||
175 | |||
176 | /* SDIO Tx aggregation in progress ? */ | ||
177 | #define MP_TX_AGGR_IN_PROGRESS(a) (a->mpa_tx.pkt_cnt > 0) | ||
178 | |||
179 | /* SDIO Tx aggregation buffer room for next packet ? */ | ||
180 | #define MP_TX_AGGR_BUF_HAS_ROOM(a, len) ((a->mpa_tx.buf_len+len) \ | ||
181 | <= a->mpa_tx.buf_size) | ||
182 | |||
183 | /* Copy current packet (SDIO Tx aggregation buffer) to SDIO buffer */ | ||
184 | #define MP_TX_AGGR_BUF_PUT(a, payload, pkt_len, port) do { \ | ||
185 | memmove(&a->mpa_tx.buf[a->mpa_tx.buf_len], \ | ||
186 | payload, pkt_len); \ | ||
187 | a->mpa_tx.buf_len += pkt_len; \ | ||
188 | if (!a->mpa_tx.pkt_cnt) \ | ||
189 | a->mpa_tx.start_port = port; \ | ||
190 | if (a->mpa_tx.start_port <= port) \ | ||
191 | a->mpa_tx.ports |= (1<<(a->mpa_tx.pkt_cnt)); \ | ||
192 | else \ | ||
193 | a->mpa_tx.ports |= (1<<(a->mpa_tx.pkt_cnt+1+(MAX_PORT - \ | ||
194 | a->mp_end_port))); \ | ||
195 | a->mpa_tx.pkt_cnt++; \ | ||
196 | } while (0); | ||
197 | |||
198 | /* SDIO Tx aggregation limit ? */ | ||
199 | #define MP_TX_AGGR_PKT_LIMIT_REACHED(a) \ | ||
200 | (a->mpa_tx.pkt_cnt == a->mpa_tx.pkt_aggr_limit) | ||
201 | |||
202 | /* SDIO Tx aggregation port limit ? */ | ||
203 | #define MP_TX_AGGR_PORT_LIMIT_REACHED(a) ((a->curr_wr_port < \ | ||
204 | a->mpa_tx.start_port) && (((MAX_PORT - \ | ||
205 | a->mpa_tx.start_port) + a->curr_wr_port) >= \ | ||
206 | SDIO_MP_AGGR_DEF_PKT_LIMIT)) | ||
207 | |||
208 | /* Reset SDIO Tx aggregation buffer parameters */ | ||
209 | #define MP_TX_AGGR_BUF_RESET(a) do { \ | ||
210 | a->mpa_tx.pkt_cnt = 0; \ | ||
211 | a->mpa_tx.buf_len = 0; \ | ||
212 | a->mpa_tx.ports = 0; \ | ||
213 | a->mpa_tx.start_port = 0; \ | ||
214 | } while (0); | ||
215 | |||
216 | /* SDIO Rx aggregation limit ? */ | ||
217 | #define MP_RX_AGGR_PKT_LIMIT_REACHED(a) \ | ||
218 | (a->mpa_rx.pkt_cnt == a->mpa_rx.pkt_aggr_limit) | ||
219 | |||
220 | /* SDIO Tx aggregation port limit ? */ | ||
221 | #define MP_RX_AGGR_PORT_LIMIT_REACHED(a) ((a->curr_rd_port < \ | ||
222 | a->mpa_rx.start_port) && (((MAX_PORT - \ | ||
223 | a->mpa_rx.start_port) + a->curr_rd_port) >= \ | ||
224 | SDIO_MP_AGGR_DEF_PKT_LIMIT)) | ||
225 | |||
226 | /* SDIO Rx aggregation in progress ? */ | ||
227 | #define MP_RX_AGGR_IN_PROGRESS(a) (a->mpa_rx.pkt_cnt > 0) | ||
228 | |||
229 | /* SDIO Rx aggregation buffer room for next packet ? */ | ||
230 | #define MP_RX_AGGR_BUF_HAS_ROOM(a, rx_len) \ | ||
231 | ((a->mpa_rx.buf_len+rx_len) <= a->mpa_rx.buf_size) | ||
232 | |||
233 | /* Prepare to copy current packet from card to SDIO Rx aggregation buffer */ | ||
234 | #define MP_RX_AGGR_SETUP(a, skb, port) do { \ | ||
235 | a->mpa_rx.buf_len += skb->len; \ | ||
236 | if (!a->mpa_rx.pkt_cnt) \ | ||
237 | a->mpa_rx.start_port = port; \ | ||
238 | if (a->mpa_rx.start_port <= port) \ | ||
239 | a->mpa_rx.ports |= (1<<(a->mpa_rx.pkt_cnt)); \ | ||
240 | else \ | ||
241 | a->mpa_rx.ports |= (1<<(a->mpa_rx.pkt_cnt+1)); \ | ||
242 | a->mpa_rx.skb_arr[a->mpa_rx.pkt_cnt] = skb; \ | ||
243 | a->mpa_rx.len_arr[a->mpa_rx.pkt_cnt] = skb->len; \ | ||
244 | a->mpa_rx.pkt_cnt++; \ | ||
245 | } while (0); | ||
246 | |||
247 | /* Reset SDIO Rx aggregation buffer parameters */ | ||
248 | #define MP_RX_AGGR_BUF_RESET(a) do { \ | ||
249 | a->mpa_rx.pkt_cnt = 0; \ | ||
250 | a->mpa_rx.buf_len = 0; \ | ||
251 | a->mpa_rx.ports = 0; \ | ||
252 | a->mpa_rx.start_port = 0; \ | ||
253 | } while (0); | ||
254 | |||
255 | |||
256 | /* data structure for SDIO MPA TX */ | ||
257 | struct mwifiex_sdio_mpa_tx { | ||
258 | /* multiport tx aggregation buffer pointer */ | ||
259 | u8 *buf; | ||
260 | u32 buf_len; | ||
261 | u32 pkt_cnt; | ||
262 | u16 ports; | ||
263 | u16 start_port; | ||
264 | u8 enabled; | ||
265 | u32 buf_size; | ||
266 | u32 pkt_aggr_limit; | ||
267 | }; | ||
268 | |||
269 | struct mwifiex_sdio_mpa_rx { | ||
270 | u8 *buf; | ||
271 | u32 buf_len; | ||
272 | u32 pkt_cnt; | ||
273 | u16 ports; | ||
274 | u16 start_port; | ||
275 | |||
276 | struct sk_buff *skb_arr[SDIO_MP_AGGR_DEF_PKT_LIMIT]; | ||
277 | u32 len_arr[SDIO_MP_AGGR_DEF_PKT_LIMIT]; | ||
278 | |||
279 | u8 enabled; | ||
280 | u32 buf_size; | ||
281 | u32 pkt_aggr_limit; | ||
282 | }; | ||
283 | |||
284 | int mwifiex_bus_register(void); | ||
285 | void mwifiex_bus_unregister(void); | ||
286 | |||
287 | struct sdio_mmc_card { | ||
288 | struct sdio_func *func; | ||
289 | struct mwifiex_adapter *adapter; | ||
290 | |||
291 | u16 mp_rd_bitmap; | ||
292 | u16 mp_wr_bitmap; | ||
293 | |||
294 | u16 mp_end_port; | ||
295 | u16 mp_data_port_mask; | ||
296 | |||
297 | u8 curr_rd_port; | ||
298 | u8 curr_wr_port; | ||
299 | |||
300 | u8 *mp_regs; | ||
301 | |||
302 | struct mwifiex_sdio_mpa_tx mpa_tx; | ||
303 | struct mwifiex_sdio_mpa_rx mpa_rx; | ||
304 | }; | ||
305 | #endif /* _MWIFIEX_SDIO_H */ | ||
diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c new file mode 100644 index 000000000000..6fff26153e26 --- /dev/null +++ b/drivers/net/wireless/mwifiex/sta_cmd.c | |||
@@ -0,0 +1,1226 @@ | |||
1 | /* | ||
2 | * Marvell Wireless LAN device driver: station command handling | ||
3 | * | ||
4 | * Copyright (C) 2011, Marvell International Ltd. | ||
5 | * | ||
6 | * This software file (the "File") is distributed by Marvell International | ||
7 | * Ltd. under the terms of the GNU General Public License Version 2, June 1991 | ||
8 | * (the "License"). You may use, redistribute and/or modify this File in | ||
9 | * accordance with the terms and conditions of the License, a copy of which | ||
10 | * is available by writing to the Free Software Foundation, Inc., | ||
11 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the | ||
12 | * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. | ||
13 | * | ||
14 | * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE | ||
15 | * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE | ||
16 | * ARE EXPRESSLY DISCLAIMED. The License provides additional details about | ||
17 | * this warranty disclaimer. | ||
18 | */ | ||
19 | |||
20 | #include "decl.h" | ||
21 | #include "ioctl.h" | ||
22 | #include "util.h" | ||
23 | #include "fw.h" | ||
24 | #include "main.h" | ||
25 | #include "wmm.h" | ||
26 | #include "11n.h" | ||
27 | |||
28 | /* | ||
29 | * This function prepares command to set/get RSSI information. | ||
30 | * | ||
31 | * Preparation includes - | ||
32 | * - Setting command ID, action and proper size | ||
33 | * - Setting data/beacon average factors | ||
34 | * - Resetting SNR/NF/RSSI values in private structure | ||
35 | * - Ensuring correct endian-ness | ||
36 | */ | ||
37 | static int | ||
38 | mwifiex_cmd_802_11_rssi_info(struct mwifiex_private *priv, | ||
39 | struct host_cmd_ds_command *cmd, u16 cmd_action) | ||
40 | { | ||
41 | cmd->command = cpu_to_le16(HostCmd_CMD_RSSI_INFO); | ||
42 | cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_rssi_info) + | ||
43 | S_DS_GEN); | ||
44 | cmd->params.rssi_info.action = cpu_to_le16(cmd_action); | ||
45 | cmd->params.rssi_info.ndata = cpu_to_le16(priv->data_avg_factor); | ||
46 | cmd->params.rssi_info.nbcn = cpu_to_le16(priv->bcn_avg_factor); | ||
47 | |||
48 | /* Reset SNR/NF/RSSI values in private structure */ | ||
49 | priv->data_rssi_last = 0; | ||
50 | priv->data_nf_last = 0; | ||
51 | priv->data_rssi_avg = 0; | ||
52 | priv->data_nf_avg = 0; | ||
53 | priv->bcn_rssi_last = 0; | ||
54 | priv->bcn_nf_last = 0; | ||
55 | priv->bcn_rssi_avg = 0; | ||
56 | priv->bcn_nf_avg = 0; | ||
57 | |||
58 | return 0; | ||
59 | } | ||
60 | |||
61 | /* | ||
62 | * This function prepares command to set MAC control. | ||
63 | * | ||
64 | * Preparation includes - | ||
65 | * - Setting command ID, action and proper size | ||
66 | * - Ensuring correct endian-ness | ||
67 | */ | ||
68 | static int mwifiex_cmd_mac_control(struct mwifiex_private *priv, | ||
69 | struct host_cmd_ds_command *cmd, | ||
70 | u16 cmd_action, void *data_buf) | ||
71 | { | ||
72 | struct host_cmd_ds_mac_control *mac_ctrl = &cmd->params.mac_ctrl; | ||
73 | u16 action = *((u16 *) data_buf); | ||
74 | |||
75 | if (cmd_action != HostCmd_ACT_GEN_SET) { | ||
76 | dev_err(priv->adapter->dev, | ||
77 | "mac_control: only support set cmd\n"); | ||
78 | return -1; | ||
79 | } | ||
80 | |||
81 | cmd->command = cpu_to_le16(HostCmd_CMD_MAC_CONTROL); | ||
82 | cmd->size = | ||
83 | cpu_to_le16(sizeof(struct host_cmd_ds_mac_control) + S_DS_GEN); | ||
84 | mac_ctrl->action = cpu_to_le16(action); | ||
85 | |||
86 | return 0; | ||
87 | } | ||
88 | |||
89 | /* | ||
90 | * This function prepares command to set/get SNMP MIB. | ||
91 | * | ||
92 | * Preparation includes - | ||
93 | * - Setting command ID, action and proper size | ||
94 | * - Setting SNMP MIB OID number and value | ||
95 | * (as required) | ||
96 | * - Ensuring correct endian-ness | ||
97 | * | ||
98 | * The following SNMP MIB OIDs are supported - | ||
99 | * - FRAG_THRESH_I : Fragmentation threshold | ||
100 | * - RTS_THRESH_I : RTS threshold | ||
101 | * - SHORT_RETRY_LIM_I : Short retry limit | ||
102 | * - DOT11D_I : 11d support | ||
103 | */ | ||
104 | static int mwifiex_cmd_802_11_snmp_mib(struct mwifiex_private *priv, | ||
105 | struct host_cmd_ds_command *cmd, | ||
106 | u16 cmd_action, u32 cmd_oid, | ||
107 | void *data_buf) | ||
108 | { | ||
109 | struct host_cmd_ds_802_11_snmp_mib *snmp_mib = &cmd->params.smib; | ||
110 | u32 ul_temp; | ||
111 | |||
112 | dev_dbg(priv->adapter->dev, "cmd: SNMP_CMD: cmd_oid = 0x%x\n", cmd_oid); | ||
113 | cmd->command = cpu_to_le16(HostCmd_CMD_802_11_SNMP_MIB); | ||
114 | cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_snmp_mib) | ||
115 | - 1 + S_DS_GEN); | ||
116 | |||
117 | if (cmd_action == HostCmd_ACT_GEN_GET) { | ||
118 | snmp_mib->query_type = cpu_to_le16(HostCmd_ACT_GEN_GET); | ||
119 | snmp_mib->buf_size = cpu_to_le16(MAX_SNMP_BUF_SIZE); | ||
120 | cmd->size = cpu_to_le16(le16_to_cpu(cmd->size) | ||
121 | + MAX_SNMP_BUF_SIZE); | ||
122 | } | ||
123 | |||
124 | switch (cmd_oid) { | ||
125 | case FRAG_THRESH_I: | ||
126 | snmp_mib->oid = cpu_to_le16((u16) FRAG_THRESH_I); | ||
127 | if (cmd_action == HostCmd_ACT_GEN_SET) { | ||
128 | snmp_mib->query_type = cpu_to_le16(HostCmd_ACT_GEN_SET); | ||
129 | snmp_mib->buf_size = cpu_to_le16(sizeof(u16)); | ||
130 | ul_temp = *((u32 *) data_buf); | ||
131 | *((__le16 *) (snmp_mib->value)) = | ||
132 | cpu_to_le16((u16) ul_temp); | ||
133 | cmd->size = cpu_to_le16(le16_to_cpu(cmd->size) | ||
134 | + sizeof(u16)); | ||
135 | } | ||
136 | break; | ||
137 | case RTS_THRESH_I: | ||
138 | snmp_mib->oid = cpu_to_le16((u16) RTS_THRESH_I); | ||
139 | if (cmd_action == HostCmd_ACT_GEN_SET) { | ||
140 | snmp_mib->query_type = cpu_to_le16(HostCmd_ACT_GEN_SET); | ||
141 | snmp_mib->buf_size = cpu_to_le16(sizeof(u16)); | ||
142 | ul_temp = *((u32 *) data_buf); | ||
143 | *(__le16 *) (snmp_mib->value) = | ||
144 | cpu_to_le16((u16) ul_temp); | ||
145 | cmd->size = cpu_to_le16(le16_to_cpu(cmd->size) | ||
146 | + sizeof(u16)); | ||
147 | } | ||
148 | break; | ||
149 | |||
150 | case SHORT_RETRY_LIM_I: | ||
151 | snmp_mib->oid = cpu_to_le16((u16) SHORT_RETRY_LIM_I); | ||
152 | if (cmd_action == HostCmd_ACT_GEN_SET) { | ||
153 | snmp_mib->query_type = cpu_to_le16(HostCmd_ACT_GEN_SET); | ||
154 | snmp_mib->buf_size = cpu_to_le16(sizeof(u16)); | ||
155 | ul_temp = (*(u32 *) data_buf); | ||
156 | *((__le16 *) (snmp_mib->value)) = | ||
157 | cpu_to_le16((u16) ul_temp); | ||
158 | cmd->size = cpu_to_le16(le16_to_cpu(cmd->size) | ||
159 | + sizeof(u16)); | ||
160 | } | ||
161 | break; | ||
162 | case DOT11D_I: | ||
163 | snmp_mib->oid = cpu_to_le16((u16) DOT11D_I); | ||
164 | if (cmd_action == HostCmd_ACT_GEN_SET) { | ||
165 | snmp_mib->query_type = cpu_to_le16(HostCmd_ACT_GEN_SET); | ||
166 | snmp_mib->buf_size = cpu_to_le16(sizeof(u16)); | ||
167 | ul_temp = *(u32 *) data_buf; | ||
168 | *((__le16 *) (snmp_mib->value)) = | ||
169 | cpu_to_le16((u16) ul_temp); | ||
170 | cmd->size = cpu_to_le16(le16_to_cpu(cmd->size) | ||
171 | + sizeof(u16)); | ||
172 | } | ||
173 | break; | ||
174 | default: | ||
175 | break; | ||
176 | } | ||
177 | dev_dbg(priv->adapter->dev, | ||
178 | "cmd: SNMP_CMD: Action=0x%x, OID=0x%x, OIDSize=0x%x," | ||
179 | " Value=0x%x\n", | ||
180 | cmd_action, cmd_oid, le16_to_cpu(snmp_mib->buf_size), | ||
181 | le16_to_cpu(*(__le16 *) snmp_mib->value)); | ||
182 | return 0; | ||
183 | } | ||
184 | |||
185 | /* | ||
186 | * This function prepares command to get log. | ||
187 | * | ||
188 | * Preparation includes - | ||
189 | * - Setting command ID and proper size | ||
190 | * - Ensuring correct endian-ness | ||
191 | */ | ||
192 | static int | ||
193 | mwifiex_cmd_802_11_get_log(struct mwifiex_private *priv, | ||
194 | struct host_cmd_ds_command *cmd) | ||
195 | { | ||
196 | cmd->command = cpu_to_le16(HostCmd_CMD_802_11_GET_LOG); | ||
197 | cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_get_log) + | ||
198 | S_DS_GEN); | ||
199 | return 0; | ||
200 | } | ||
201 | |||
202 | /* | ||
203 | * This function prepares command to set/get Tx data rate configuration. | ||
204 | * | ||
205 | * Preparation includes - | ||
206 | * - Setting command ID, action and proper size | ||
207 | * - Setting configuration index, rate scope and rate drop pattern | ||
208 | * parameters (as required) | ||
209 | * - Ensuring correct endian-ness | ||
210 | */ | ||
211 | static int mwifiex_cmd_tx_rate_cfg(struct mwifiex_private *priv, | ||
212 | struct host_cmd_ds_command *cmd, | ||
213 | u16 cmd_action, void *data_buf) | ||
214 | { | ||
215 | struct host_cmd_ds_tx_rate_cfg *rate_cfg = &cmd->params.tx_rate_cfg; | ||
216 | struct mwifiex_rate_scope *rate_scope; | ||
217 | struct mwifiex_rate_drop_pattern *rate_drop; | ||
218 | u16 *pbitmap_rates = (u16 *) data_buf; | ||
219 | |||
220 | u32 i; | ||
221 | |||
222 | cmd->command = cpu_to_le16(HostCmd_CMD_TX_RATE_CFG); | ||
223 | |||
224 | rate_cfg->action = cpu_to_le16(cmd_action); | ||
225 | rate_cfg->cfg_index = 0; | ||
226 | |||
227 | rate_scope = (struct mwifiex_rate_scope *) ((u8 *) rate_cfg + | ||
228 | sizeof(struct host_cmd_ds_tx_rate_cfg)); | ||
229 | rate_scope->type = cpu_to_le16(TLV_TYPE_RATE_SCOPE); | ||
230 | rate_scope->length = cpu_to_le16(sizeof(struct mwifiex_rate_scope) - | ||
231 | sizeof(struct mwifiex_ie_types_header)); | ||
232 | if (pbitmap_rates != NULL) { | ||
233 | rate_scope->hr_dsss_rate_bitmap = cpu_to_le16(pbitmap_rates[0]); | ||
234 | rate_scope->ofdm_rate_bitmap = cpu_to_le16(pbitmap_rates[1]); | ||
235 | for (i = 0; | ||
236 | i < sizeof(rate_scope->ht_mcs_rate_bitmap) / sizeof(u16); | ||
237 | i++) | ||
238 | rate_scope->ht_mcs_rate_bitmap[i] = | ||
239 | cpu_to_le16(pbitmap_rates[2 + i]); | ||
240 | } else { | ||
241 | rate_scope->hr_dsss_rate_bitmap = | ||
242 | cpu_to_le16(priv->bitmap_rates[0]); | ||
243 | rate_scope->ofdm_rate_bitmap = | ||
244 | cpu_to_le16(priv->bitmap_rates[1]); | ||
245 | for (i = 0; | ||
246 | i < sizeof(rate_scope->ht_mcs_rate_bitmap) / sizeof(u16); | ||
247 | i++) | ||
248 | rate_scope->ht_mcs_rate_bitmap[i] = | ||
249 | cpu_to_le16(priv->bitmap_rates[2 + i]); | ||
250 | } | ||
251 | |||
252 | rate_drop = (struct mwifiex_rate_drop_pattern *) ((u8 *) rate_scope + | ||
253 | sizeof(struct mwifiex_rate_scope)); | ||
254 | rate_drop->type = cpu_to_le16(TLV_TYPE_RATE_DROP_CONTROL); | ||
255 | rate_drop->length = cpu_to_le16(sizeof(rate_drop->rate_drop_mode)); | ||
256 | rate_drop->rate_drop_mode = 0; | ||
257 | |||
258 | cmd->size = | ||
259 | cpu_to_le16(S_DS_GEN + sizeof(struct host_cmd_ds_tx_rate_cfg) + | ||
260 | sizeof(struct mwifiex_rate_scope) + | ||
261 | sizeof(struct mwifiex_rate_drop_pattern)); | ||
262 | |||
263 | return 0; | ||
264 | } | ||
265 | |||
266 | /* | ||
267 | * This function prepares command to set/get Tx power configuration. | ||
268 | * | ||
269 | * Preparation includes - | ||
270 | * - Setting command ID, action and proper size | ||
271 | * - Setting Tx power mode, power group TLV | ||
272 | * (as required) | ||
273 | * - Ensuring correct endian-ness | ||
274 | */ | ||
275 | static int mwifiex_cmd_tx_power_cfg(struct mwifiex_private *priv, | ||
276 | struct host_cmd_ds_command *cmd, | ||
277 | u16 cmd_action, void *data_buf) | ||
278 | { | ||
279 | struct mwifiex_types_power_group *pg_tlv = NULL; | ||
280 | struct host_cmd_ds_txpwr_cfg *txp = NULL; | ||
281 | struct host_cmd_ds_txpwr_cfg *cmd_txp_cfg = &cmd->params.txp_cfg; | ||
282 | |||
283 | cmd->command = cpu_to_le16(HostCmd_CMD_TXPWR_CFG); | ||
284 | cmd->size = | ||
285 | cpu_to_le16(S_DS_GEN + sizeof(struct host_cmd_ds_txpwr_cfg)); | ||
286 | switch (cmd_action) { | ||
287 | case HostCmd_ACT_GEN_SET: | ||
288 | txp = (struct host_cmd_ds_txpwr_cfg *) data_buf; | ||
289 | if (txp->mode) { | ||
290 | pg_tlv = (struct mwifiex_types_power_group | ||
291 | *) ((unsigned long) data_buf + | ||
292 | sizeof(struct host_cmd_ds_txpwr_cfg)); | ||
293 | memmove(cmd_txp_cfg, data_buf, | ||
294 | sizeof(struct host_cmd_ds_txpwr_cfg) + | ||
295 | sizeof(struct mwifiex_types_power_group) + | ||
296 | pg_tlv->length); | ||
297 | |||
298 | pg_tlv = (struct mwifiex_types_power_group *) ((u8 *) | ||
299 | cmd_txp_cfg + | ||
300 | sizeof(struct host_cmd_ds_txpwr_cfg)); | ||
301 | cmd->size = cpu_to_le16(le16_to_cpu(cmd->size) + | ||
302 | sizeof(struct mwifiex_types_power_group) + | ||
303 | pg_tlv->length); | ||
304 | } else { | ||
305 | memmove(cmd_txp_cfg, data_buf, | ||
306 | sizeof(struct host_cmd_ds_txpwr_cfg)); | ||
307 | } | ||
308 | cmd_txp_cfg->action = cpu_to_le16(cmd_action); | ||
309 | break; | ||
310 | case HostCmd_ACT_GEN_GET: | ||
311 | cmd_txp_cfg->action = cpu_to_le16(cmd_action); | ||
312 | break; | ||
313 | } | ||
314 | |||
315 | return 0; | ||
316 | } | ||
317 | |||
318 | /* | ||
319 | * This function prepares command to set Host Sleep configuration. | ||
320 | * | ||
321 | * Preparation includes - | ||
322 | * - Setting command ID and proper size | ||
323 | * - Setting Host Sleep action, conditions, ARP filters | ||
324 | * (as required) | ||
325 | * - Ensuring correct endian-ness | ||
326 | */ | ||
327 | static int mwifiex_cmd_802_11_hs_cfg(struct mwifiex_private *priv, | ||
328 | struct host_cmd_ds_command *cmd, | ||
329 | u16 cmd_action, | ||
330 | struct mwifiex_hs_config_param *data_buf) | ||
331 | { | ||
332 | struct mwifiex_adapter *adapter = priv->adapter; | ||
333 | struct host_cmd_ds_802_11_hs_cfg_enh *hs_cfg = &cmd->params.opt_hs_cfg; | ||
334 | u16 hs_activate = false; | ||
335 | |||
336 | if (data_buf == NULL) | ||
337 | /* New Activate command */ | ||
338 | hs_activate = true; | ||
339 | cmd->command = cpu_to_le16(HostCmd_CMD_802_11_HS_CFG_ENH); | ||
340 | |||
341 | if (!hs_activate && | ||
342 | (data_buf->conditions | ||
343 | != cpu_to_le32(HOST_SLEEP_CFG_CANCEL)) | ||
344 | && ((adapter->arp_filter_size > 0) | ||
345 | && (adapter->arp_filter_size <= ARP_FILTER_MAX_BUF_SIZE))) { | ||
346 | dev_dbg(adapter->dev, | ||
347 | "cmd: Attach %d bytes ArpFilter to HSCfg cmd\n", | ||
348 | adapter->arp_filter_size); | ||
349 | memcpy(((u8 *) hs_cfg) + | ||
350 | sizeof(struct host_cmd_ds_802_11_hs_cfg_enh), | ||
351 | adapter->arp_filter, adapter->arp_filter_size); | ||
352 | cmd->size = cpu_to_le16(adapter->arp_filter_size + | ||
353 | sizeof(struct host_cmd_ds_802_11_hs_cfg_enh) | ||
354 | + S_DS_GEN); | ||
355 | } else { | ||
356 | cmd->size = cpu_to_le16(S_DS_GEN + sizeof(struct | ||
357 | host_cmd_ds_802_11_hs_cfg_enh)); | ||
358 | } | ||
359 | if (hs_activate) { | ||
360 | hs_cfg->action = cpu_to_le16(HS_ACTIVATE); | ||
361 | hs_cfg->params.hs_activate.resp_ctrl = RESP_NEEDED; | ||
362 | } else { | ||
363 | hs_cfg->action = cpu_to_le16(HS_CONFIGURE); | ||
364 | hs_cfg->params.hs_config.conditions = data_buf->conditions; | ||
365 | hs_cfg->params.hs_config.gpio = data_buf->gpio; | ||
366 | hs_cfg->params.hs_config.gap = data_buf->gap; | ||
367 | dev_dbg(adapter->dev, | ||
368 | "cmd: HS_CFG_CMD: condition:0x%x gpio:0x%x gap:0x%x\n", | ||
369 | hs_cfg->params.hs_config.conditions, | ||
370 | hs_cfg->params.hs_config.gpio, | ||
371 | hs_cfg->params.hs_config.gap); | ||
372 | } | ||
373 | |||
374 | return 0; | ||
375 | } | ||
376 | |||
377 | /* | ||
378 | * This function prepares command to set/get MAC address. | ||
379 | * | ||
380 | * Preparation includes - | ||
381 | * - Setting command ID, action and proper size | ||
382 | * - Setting MAC address (for SET only) | ||
383 | * - Ensuring correct endian-ness | ||
384 | */ | ||
385 | static int mwifiex_cmd_802_11_mac_address(struct mwifiex_private *priv, | ||
386 | struct host_cmd_ds_command *cmd, | ||
387 | u16 cmd_action) | ||
388 | { | ||
389 | cmd->command = cpu_to_le16(HostCmd_CMD_802_11_MAC_ADDRESS); | ||
390 | cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_mac_address) + | ||
391 | S_DS_GEN); | ||
392 | cmd->result = 0; | ||
393 | |||
394 | cmd->params.mac_addr.action = cpu_to_le16(cmd_action); | ||
395 | |||
396 | if (cmd_action == HostCmd_ACT_GEN_SET) | ||
397 | memcpy(cmd->params.mac_addr.mac_addr, priv->curr_addr, | ||
398 | ETH_ALEN); | ||
399 | return 0; | ||
400 | } | ||
401 | |||
402 | /* | ||
403 | * This function prepares command to set MAC multicast address. | ||
404 | * | ||
405 | * Preparation includes - | ||
406 | * - Setting command ID, action and proper size | ||
407 | * - Setting MAC multicast address | ||
408 | * - Ensuring correct endian-ness | ||
409 | */ | ||
410 | static int mwifiex_cmd_mac_multicast_adr(struct mwifiex_private *priv, | ||
411 | struct host_cmd_ds_command *cmd, | ||
412 | u16 cmd_action, void *data_buf) | ||
413 | { | ||
414 | struct mwifiex_multicast_list *mcast_list = | ||
415 | (struct mwifiex_multicast_list *) data_buf; | ||
416 | struct host_cmd_ds_mac_multicast_adr *mcast_addr = &cmd->params.mc_addr; | ||
417 | |||
418 | cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_mac_multicast_adr) + | ||
419 | S_DS_GEN); | ||
420 | cmd->command = cpu_to_le16(HostCmd_CMD_MAC_MULTICAST_ADR); | ||
421 | |||
422 | mcast_addr->action = cpu_to_le16(cmd_action); | ||
423 | mcast_addr->num_of_adrs = | ||
424 | cpu_to_le16((u16) mcast_list->num_multicast_addr); | ||
425 | memcpy(mcast_addr->mac_list, mcast_list->mac_list, | ||
426 | mcast_list->num_multicast_addr * ETH_ALEN); | ||
427 | |||
428 | return 0; | ||
429 | } | ||
430 | |||
431 | /* | ||
432 | * This function prepares command to deauthenticate. | ||
433 | * | ||
434 | * Preparation includes - | ||
435 | * - Setting command ID and proper size | ||
436 | * - Setting AP MAC address and reason code | ||
437 | * - Ensuring correct endian-ness | ||
438 | */ | ||
439 | static int mwifiex_cmd_802_11_deauthenticate(struct mwifiex_private *priv, | ||
440 | struct host_cmd_ds_command *cmd, | ||
441 | void *data_buf) | ||
442 | { | ||
443 | struct host_cmd_ds_802_11_deauthenticate *deauth = &cmd->params.deauth; | ||
444 | |||
445 | cmd->command = cpu_to_le16(HostCmd_CMD_802_11_DEAUTHENTICATE); | ||
446 | cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_deauthenticate) | ||
447 | + S_DS_GEN); | ||
448 | |||
449 | /* Set AP MAC address */ | ||
450 | memcpy(deauth->mac_addr, (u8 *) data_buf, ETH_ALEN); | ||
451 | |||
452 | dev_dbg(priv->adapter->dev, "cmd: Deauth: %pM\n", deauth->mac_addr); | ||
453 | |||
454 | deauth->reason_code = cpu_to_le16(WLAN_REASON_DEAUTH_LEAVING); | ||
455 | |||
456 | return 0; | ||
457 | } | ||
458 | |||
459 | /* | ||
460 | * This function prepares command to stop Ad-Hoc network. | ||
461 | * | ||
462 | * Preparation includes - | ||
463 | * - Setting command ID and proper size | ||
464 | * - Ensuring correct endian-ness | ||
465 | */ | ||
466 | static int mwifiex_cmd_802_11_ad_hoc_stop(struct mwifiex_private *priv, | ||
467 | struct host_cmd_ds_command *cmd) | ||
468 | { | ||
469 | cmd->command = cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_STOP); | ||
470 | cmd->size = cpu_to_le16(S_DS_GEN); | ||
471 | return 0; | ||
472 | } | ||
473 | |||
474 | /* | ||
475 | * This function sets WEP key(s) to key parameter TLV(s). | ||
476 | * | ||
477 | * Multi-key parameter TLVs are supported, so we can send multiple | ||
478 | * WEP keys in a single buffer. | ||
479 | */ | ||
480 | static int | ||
481 | mwifiex_set_keyparamset_wep(struct mwifiex_private *priv, | ||
482 | struct mwifiex_ie_type_key_param_set *key_param_set, | ||
483 | u16 *key_param_len) | ||
484 | { | ||
485 | int cur_key_param_len = 0; | ||
486 | u8 i; | ||
487 | |||
488 | /* Multi-key_param_set TLV is supported */ | ||
489 | for (i = 0; i < NUM_WEP_KEYS; i++) { | ||
490 | if ((priv->wep_key[i].key_length == WLAN_KEY_LEN_WEP40) || | ||
491 | (priv->wep_key[i].key_length == WLAN_KEY_LEN_WEP104)) { | ||
492 | key_param_set->type = | ||
493 | cpu_to_le16(TLV_TYPE_KEY_MATERIAL); | ||
494 | /* Key_param_set WEP fixed length */ | ||
495 | #define KEYPARAMSET_WEP_FIXED_LEN 8 | ||
496 | key_param_set->length = cpu_to_le16((u16) | ||
497 | (priv->wep_key[i]. | ||
498 | key_length + | ||
499 | KEYPARAMSET_WEP_FIXED_LEN)); | ||
500 | key_param_set->key_type_id = | ||
501 | cpu_to_le16(KEY_TYPE_ID_WEP); | ||
502 | key_param_set->key_info = | ||
503 | cpu_to_le16(KEY_INFO_WEP_ENABLED | | ||
504 | KEY_INFO_WEP_UNICAST | | ||
505 | KEY_INFO_WEP_MCAST); | ||
506 | key_param_set->key_len = | ||
507 | cpu_to_le16(priv->wep_key[i].key_length); | ||
508 | /* Set WEP key index */ | ||
509 | key_param_set->key[0] = i; | ||
510 | /* Set default Tx key flag */ | ||
511 | if (i == | ||
512 | (priv-> | ||
513 | wep_key_curr_index & HostCmd_WEP_KEY_INDEX_MASK)) | ||
514 | key_param_set->key[1] = 1; | ||
515 | else | ||
516 | key_param_set->key[1] = 0; | ||
517 | memmove(&key_param_set->key[2], | ||
518 | priv->wep_key[i].key_material, | ||
519 | priv->wep_key[i].key_length); | ||
520 | |||
521 | cur_key_param_len = priv->wep_key[i].key_length + | ||
522 | KEYPARAMSET_WEP_FIXED_LEN + | ||
523 | sizeof(struct mwifiex_ie_types_header); | ||
524 | *key_param_len += (u16) cur_key_param_len; | ||
525 | key_param_set = | ||
526 | (struct mwifiex_ie_type_key_param_set *) | ||
527 | ((u8 *)key_param_set + | ||
528 | cur_key_param_len); | ||
529 | } else if (!priv->wep_key[i].key_length) { | ||
530 | continue; | ||
531 | } else { | ||
532 | dev_err(priv->adapter->dev, | ||
533 | "key%d Length = %d is incorrect\n", | ||
534 | (i + 1), priv->wep_key[i].key_length); | ||
535 | return -1; | ||
536 | } | ||
537 | } | ||
538 | |||
539 | return 0; | ||
540 | } | ||
541 | |||
542 | /* | ||
543 | * This function prepares command to set/get/reset network key(s). | ||
544 | * | ||
545 | * Preparation includes - | ||
546 | * - Setting command ID, action and proper size | ||
547 | * - Setting WEP keys, WAPI keys or WPA keys along with required | ||
548 | * encryption (TKIP, AES) (as required) | ||
549 | * - Ensuring correct endian-ness | ||
550 | */ | ||
551 | static int mwifiex_cmd_802_11_key_material(struct mwifiex_private *priv, | ||
552 | struct host_cmd_ds_command *cmd, | ||
553 | u16 cmd_action, | ||
554 | u32 cmd_oid, void *data_buf) | ||
555 | { | ||
556 | struct host_cmd_ds_802_11_key_material *key_material = | ||
557 | &cmd->params.key_material; | ||
558 | struct mwifiex_ds_encrypt_key *enc_key = | ||
559 | (struct mwifiex_ds_encrypt_key *) data_buf; | ||
560 | u16 key_param_len = 0; | ||
561 | int ret = 0; | ||
562 | const u8 bc_mac[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; | ||
563 | |||
564 | cmd->command = cpu_to_le16(HostCmd_CMD_802_11_KEY_MATERIAL); | ||
565 | key_material->action = cpu_to_le16(cmd_action); | ||
566 | |||
567 | if (cmd_action == HostCmd_ACT_GEN_GET) { | ||
568 | cmd->size = | ||
569 | cpu_to_le16(sizeof(key_material->action) + S_DS_GEN); | ||
570 | return ret; | ||
571 | } | ||
572 | |||
573 | if (!enc_key) { | ||
574 | memset(&key_material->key_param_set, 0, | ||
575 | (NUM_WEP_KEYS * | ||
576 | sizeof(struct mwifiex_ie_type_key_param_set))); | ||
577 | ret = mwifiex_set_keyparamset_wep(priv, | ||
578 | &key_material->key_param_set, | ||
579 | &key_param_len); | ||
580 | cmd->size = cpu_to_le16(key_param_len + | ||
581 | sizeof(key_material->action) + S_DS_GEN); | ||
582 | return ret; | ||
583 | } else | ||
584 | memset(&key_material->key_param_set, 0, | ||
585 | sizeof(struct mwifiex_ie_type_key_param_set)); | ||
586 | if (enc_key->is_wapi_key) { | ||
587 | dev_dbg(priv->adapter->dev, "info: Set WAPI Key\n"); | ||
588 | key_material->key_param_set.key_type_id = | ||
589 | cpu_to_le16(KEY_TYPE_ID_WAPI); | ||
590 | if (cmd_oid == KEY_INFO_ENABLED) | ||
591 | key_material->key_param_set.key_info = | ||
592 | cpu_to_le16(KEY_INFO_WAPI_ENABLED); | ||
593 | else | ||
594 | key_material->key_param_set.key_info = | ||
595 | cpu_to_le16(!KEY_INFO_WAPI_ENABLED); | ||
596 | |||
597 | key_material->key_param_set.key[0] = enc_key->key_index; | ||
598 | if (!priv->sec_info.wapi_key_on) | ||
599 | key_material->key_param_set.key[1] = 1; | ||
600 | else | ||
601 | /* set 0 when re-key */ | ||
602 | key_material->key_param_set.key[1] = 0; | ||
603 | |||
604 | if (0 != memcmp(enc_key->mac_addr, bc_mac, sizeof(bc_mac))) { | ||
605 | /* WAPI pairwise key: unicast */ | ||
606 | key_material->key_param_set.key_info |= | ||
607 | cpu_to_le16(KEY_INFO_WAPI_UNICAST); | ||
608 | } else { /* WAPI group key: multicast */ | ||
609 | key_material->key_param_set.key_info |= | ||
610 | cpu_to_le16(KEY_INFO_WAPI_MCAST); | ||
611 | priv->sec_info.wapi_key_on = true; | ||
612 | } | ||
613 | |||
614 | key_material->key_param_set.type = | ||
615 | cpu_to_le16(TLV_TYPE_KEY_MATERIAL); | ||
616 | key_material->key_param_set.key_len = | ||
617 | cpu_to_le16(WAPI_KEY_LEN); | ||
618 | memcpy(&key_material->key_param_set.key[2], | ||
619 | enc_key->key_material, enc_key->key_len); | ||
620 | memcpy(&key_material->key_param_set.key[2 + enc_key->key_len], | ||
621 | enc_key->wapi_rxpn, WAPI_RXPN_LEN); | ||
622 | key_material->key_param_set.length = | ||
623 | cpu_to_le16(WAPI_KEY_LEN + KEYPARAMSET_FIXED_LEN); | ||
624 | |||
625 | key_param_len = (WAPI_KEY_LEN + KEYPARAMSET_FIXED_LEN) + | ||
626 | sizeof(struct mwifiex_ie_types_header); | ||
627 | cmd->size = cpu_to_le16(key_param_len + | ||
628 | sizeof(key_material->action) + S_DS_GEN); | ||
629 | return ret; | ||
630 | } | ||
631 | if (enc_key->key_len == WLAN_KEY_LEN_CCMP) { | ||
632 | dev_dbg(priv->adapter->dev, "cmd: WPA_AES\n"); | ||
633 | key_material->key_param_set.key_type_id = | ||
634 | cpu_to_le16(KEY_TYPE_ID_AES); | ||
635 | if (cmd_oid == KEY_INFO_ENABLED) | ||
636 | key_material->key_param_set.key_info = | ||
637 | cpu_to_le16(KEY_INFO_AES_ENABLED); | ||
638 | else | ||
639 | key_material->key_param_set.key_info = | ||
640 | cpu_to_le16(!KEY_INFO_AES_ENABLED); | ||
641 | |||
642 | if (enc_key->key_index & MWIFIEX_KEY_INDEX_UNICAST) | ||
643 | /* AES pairwise key: unicast */ | ||
644 | key_material->key_param_set.key_info |= | ||
645 | cpu_to_le16(KEY_INFO_AES_UNICAST); | ||
646 | else /* AES group key: multicast */ | ||
647 | key_material->key_param_set.key_info |= | ||
648 | cpu_to_le16(KEY_INFO_AES_MCAST); | ||
649 | } else if (enc_key->key_len == WLAN_KEY_LEN_TKIP) { | ||
650 | dev_dbg(priv->adapter->dev, "cmd: WPA_TKIP\n"); | ||
651 | key_material->key_param_set.key_type_id = | ||
652 | cpu_to_le16(KEY_TYPE_ID_TKIP); | ||
653 | key_material->key_param_set.key_info = | ||
654 | cpu_to_le16(KEY_INFO_TKIP_ENABLED); | ||
655 | |||
656 | if (enc_key->key_index & MWIFIEX_KEY_INDEX_UNICAST) | ||
657 | /* TKIP pairwise key: unicast */ | ||
658 | key_material->key_param_set.key_info |= | ||
659 | cpu_to_le16(KEY_INFO_TKIP_UNICAST); | ||
660 | else /* TKIP group key: multicast */ | ||
661 | key_material->key_param_set.key_info |= | ||
662 | cpu_to_le16(KEY_INFO_TKIP_MCAST); | ||
663 | } | ||
664 | |||
665 | if (key_material->key_param_set.key_type_id) { | ||
666 | key_material->key_param_set.type = | ||
667 | cpu_to_le16(TLV_TYPE_KEY_MATERIAL); | ||
668 | key_material->key_param_set.key_len = | ||
669 | cpu_to_le16((u16) enc_key->key_len); | ||
670 | memcpy(key_material->key_param_set.key, enc_key->key_material, | ||
671 | enc_key->key_len); | ||
672 | key_material->key_param_set.length = | ||
673 | cpu_to_le16((u16) enc_key->key_len + | ||
674 | KEYPARAMSET_FIXED_LEN); | ||
675 | |||
676 | key_param_len = (u16) (enc_key->key_len + KEYPARAMSET_FIXED_LEN) | ||
677 | + sizeof(struct mwifiex_ie_types_header); | ||
678 | |||
679 | cmd->size = cpu_to_le16(key_param_len + | ||
680 | sizeof(key_material->action) + S_DS_GEN); | ||
681 | } | ||
682 | |||
683 | return ret; | ||
684 | } | ||
685 | |||
686 | /* | ||
687 | * This function prepares command to set/get 11d domain information. | ||
688 | * | ||
689 | * Preparation includes - | ||
690 | * - Setting command ID, action and proper size | ||
691 | * - Setting domain information fields (for SET only) | ||
692 | * - Ensuring correct endian-ness | ||
693 | */ | ||
694 | static int mwifiex_cmd_802_11d_domain_info(struct mwifiex_private *priv, | ||
695 | struct host_cmd_ds_command *cmd, | ||
696 | u16 cmd_action) | ||
697 | { | ||
698 | struct mwifiex_adapter *adapter = priv->adapter; | ||
699 | struct host_cmd_ds_802_11d_domain_info *domain_info = | ||
700 | &cmd->params.domain_info; | ||
701 | struct mwifiex_ietypes_domain_param_set *domain = | ||
702 | &domain_info->domain; | ||
703 | u8 no_of_triplet = adapter->domain_reg.no_of_triplet; | ||
704 | |||
705 | dev_dbg(adapter->dev, "info: 11D: no_of_triplet=0x%x\n", no_of_triplet); | ||
706 | |||
707 | cmd->command = cpu_to_le16(HostCmd_CMD_802_11D_DOMAIN_INFO); | ||
708 | domain_info->action = cpu_to_le16(cmd_action); | ||
709 | if (cmd_action == HostCmd_ACT_GEN_GET) { | ||
710 | cmd->size = cpu_to_le16(sizeof(domain_info->action) + S_DS_GEN); | ||
711 | return 0; | ||
712 | } | ||
713 | |||
714 | /* Set domain info fields */ | ||
715 | domain->header.type = cpu_to_le16(WLAN_EID_COUNTRY); | ||
716 | memcpy(domain->country_code, adapter->domain_reg.country_code, | ||
717 | sizeof(domain->country_code)); | ||
718 | |||
719 | domain->header.len = cpu_to_le16((no_of_triplet * | ||
720 | sizeof(struct ieee80211_country_ie_triplet)) + | ||
721 | sizeof(domain->country_code)); | ||
722 | |||
723 | if (no_of_triplet) { | ||
724 | memcpy(domain->triplet, adapter->domain_reg.triplet, | ||
725 | no_of_triplet * | ||
726 | sizeof(struct ieee80211_country_ie_triplet)); | ||
727 | |||
728 | cmd->size = cpu_to_le16(sizeof(domain_info->action) + | ||
729 | le16_to_cpu(domain->header.len) + | ||
730 | sizeof(struct mwifiex_ie_types_header) | ||
731 | + S_DS_GEN); | ||
732 | } else { | ||
733 | cmd->size = cpu_to_le16(sizeof(domain_info->action) + S_DS_GEN); | ||
734 | } | ||
735 | |||
736 | return 0; | ||
737 | } | ||
738 | |||
739 | /* | ||
740 | * This function prepares command to set/get RF channel. | ||
741 | * | ||
742 | * Preparation includes - | ||
743 | * - Setting command ID, action and proper size | ||
744 | * - Setting RF type and current RF channel (for SET only) | ||
745 | * - Ensuring correct endian-ness | ||
746 | */ | ||
747 | static int mwifiex_cmd_802_11_rf_channel(struct mwifiex_private *priv, | ||
748 | struct host_cmd_ds_command *cmd, | ||
749 | u16 cmd_action, void *data_buf) | ||
750 | { | ||
751 | struct host_cmd_ds_802_11_rf_channel *rf_chan = | ||
752 | &cmd->params.rf_channel; | ||
753 | uint16_t rf_type = le16_to_cpu(rf_chan->rf_type); | ||
754 | |||
755 | cmd->command = cpu_to_le16(HostCmd_CMD_802_11_RF_CHANNEL); | ||
756 | cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_rf_channel) | ||
757 | + S_DS_GEN); | ||
758 | |||
759 | if (cmd_action == HostCmd_ACT_GEN_SET) { | ||
760 | if ((priv->adapter->adhoc_start_band & BAND_A) | ||
761 | || (priv->adapter->adhoc_start_band & BAND_AN)) | ||
762 | rf_chan->rf_type = | ||
763 | cpu_to_le16(HostCmd_SCAN_RADIO_TYPE_A); | ||
764 | |||
765 | rf_type = le16_to_cpu(rf_chan->rf_type); | ||
766 | SET_SECONDARYCHAN(rf_type, priv->adapter->chan_offset); | ||
767 | rf_chan->current_channel = cpu_to_le16(*((u16 *) data_buf)); | ||
768 | } | ||
769 | rf_chan->action = cpu_to_le16(cmd_action); | ||
770 | return 0; | ||
771 | } | ||
772 | |||
773 | /* | ||
774 | * This function prepares command to set/get IBSS coalescing status. | ||
775 | * | ||
776 | * Preparation includes - | ||
777 | * - Setting command ID, action and proper size | ||
778 | * - Setting status to enable or disable (for SET only) | ||
779 | * - Ensuring correct endian-ness | ||
780 | */ | ||
781 | static int mwifiex_cmd_ibss_coalescing_status(struct mwifiex_private *priv, | ||
782 | struct host_cmd_ds_command *cmd, | ||
783 | u16 cmd_action, void *data_buf) | ||
784 | { | ||
785 | struct host_cmd_ds_802_11_ibss_status *ibss_coal = | ||
786 | &(cmd->params.ibss_coalescing); | ||
787 | u16 enable = 0; | ||
788 | |||
789 | cmd->command = cpu_to_le16(HostCmd_CMD_802_11_IBSS_COALESCING_STATUS); | ||
790 | cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_ibss_status) + | ||
791 | S_DS_GEN); | ||
792 | cmd->result = 0; | ||
793 | ibss_coal->action = cpu_to_le16(cmd_action); | ||
794 | |||
795 | switch (cmd_action) { | ||
796 | case HostCmd_ACT_GEN_SET: | ||
797 | if (data_buf != NULL) | ||
798 | enable = *(u16 *) data_buf; | ||
799 | ibss_coal->enable = cpu_to_le16(enable); | ||
800 | break; | ||
801 | |||
802 | /* In other case.. Nothing to do */ | ||
803 | case HostCmd_ACT_GEN_GET: | ||
804 | default: | ||
805 | break; | ||
806 | } | ||
807 | |||
808 | return 0; | ||
809 | } | ||
810 | |||
811 | /* | ||
812 | * This function prepares command to set/get register value. | ||
813 | * | ||
814 | * Preparation includes - | ||
815 | * - Setting command ID, action and proper size | ||
816 | * - Setting register offset (for both GET and SET) and | ||
817 | * register value (for SET only) | ||
818 | * - Ensuring correct endian-ness | ||
819 | * | ||
820 | * The following type of registers can be accessed with this function - | ||
821 | * - MAC register | ||
822 | * - BBP register | ||
823 | * - RF register | ||
824 | * - PMIC register | ||
825 | * - CAU register | ||
826 | * - EEPROM | ||
827 | */ | ||
828 | static int mwifiex_cmd_reg_access(struct host_cmd_ds_command *cmd, | ||
829 | u16 cmd_action, void *data_buf) | ||
830 | { | ||
831 | struct mwifiex_ds_reg_rw *reg_rw; | ||
832 | |||
833 | reg_rw = (struct mwifiex_ds_reg_rw *) data_buf; | ||
834 | switch (le16_to_cpu(cmd->command)) { | ||
835 | case HostCmd_CMD_MAC_REG_ACCESS: | ||
836 | { | ||
837 | struct host_cmd_ds_mac_reg_access *mac_reg; | ||
838 | |||
839 | cmd->size = cpu_to_le16(sizeof(*mac_reg) + S_DS_GEN); | ||
840 | mac_reg = (struct host_cmd_ds_mac_reg_access *) &cmd-> | ||
841 | params.mac_reg; | ||
842 | mac_reg->action = cpu_to_le16(cmd_action); | ||
843 | mac_reg->offset = | ||
844 | cpu_to_le16((u16) le32_to_cpu(reg_rw->offset)); | ||
845 | mac_reg->value = reg_rw->value; | ||
846 | break; | ||
847 | } | ||
848 | case HostCmd_CMD_BBP_REG_ACCESS: | ||
849 | { | ||
850 | struct host_cmd_ds_bbp_reg_access *bbp_reg; | ||
851 | |||
852 | cmd->size = cpu_to_le16(sizeof(*bbp_reg) + S_DS_GEN); | ||
853 | bbp_reg = (struct host_cmd_ds_bbp_reg_access *) &cmd-> | ||
854 | params.bbp_reg; | ||
855 | bbp_reg->action = cpu_to_le16(cmd_action); | ||
856 | bbp_reg->offset = | ||
857 | cpu_to_le16((u16) le32_to_cpu(reg_rw->offset)); | ||
858 | bbp_reg->value = (u8) le32_to_cpu(reg_rw->value); | ||
859 | break; | ||
860 | } | ||
861 | case HostCmd_CMD_RF_REG_ACCESS: | ||
862 | { | ||
863 | struct host_cmd_ds_rf_reg_access *rf_reg; | ||
864 | |||
865 | cmd->size = cpu_to_le16(sizeof(*rf_reg) + S_DS_GEN); | ||
866 | rf_reg = (struct host_cmd_ds_rf_reg_access *) &cmd-> | ||
867 | params.rf_reg; | ||
868 | rf_reg->action = cpu_to_le16(cmd_action); | ||
869 | rf_reg->offset = | ||
870 | cpu_to_le16((u16) le32_to_cpu(reg_rw->offset)); | ||
871 | rf_reg->value = (u8) le32_to_cpu(reg_rw->value); | ||
872 | break; | ||
873 | } | ||
874 | case HostCmd_CMD_PMIC_REG_ACCESS: | ||
875 | { | ||
876 | struct host_cmd_ds_pmic_reg_access *pmic_reg; | ||
877 | |||
878 | cmd->size = cpu_to_le16(sizeof(*pmic_reg) + S_DS_GEN); | ||
879 | pmic_reg = (struct host_cmd_ds_pmic_reg_access *) &cmd-> | ||
880 | params.pmic_reg; | ||
881 | pmic_reg->action = cpu_to_le16(cmd_action); | ||
882 | pmic_reg->offset = | ||
883 | cpu_to_le16((u16) le32_to_cpu(reg_rw->offset)); | ||
884 | pmic_reg->value = (u8) le32_to_cpu(reg_rw->value); | ||
885 | break; | ||
886 | } | ||
887 | case HostCmd_CMD_CAU_REG_ACCESS: | ||
888 | { | ||
889 | struct host_cmd_ds_rf_reg_access *cau_reg; | ||
890 | |||
891 | cmd->size = cpu_to_le16(sizeof(*cau_reg) + S_DS_GEN); | ||
892 | cau_reg = (struct host_cmd_ds_rf_reg_access *) &cmd-> | ||
893 | params.rf_reg; | ||
894 | cau_reg->action = cpu_to_le16(cmd_action); | ||
895 | cau_reg->offset = | ||
896 | cpu_to_le16((u16) le32_to_cpu(reg_rw->offset)); | ||
897 | cau_reg->value = (u8) le32_to_cpu(reg_rw->value); | ||
898 | break; | ||
899 | } | ||
900 | case HostCmd_CMD_802_11_EEPROM_ACCESS: | ||
901 | { | ||
902 | struct mwifiex_ds_read_eeprom *rd_eeprom = | ||
903 | (struct mwifiex_ds_read_eeprom *) data_buf; | ||
904 | struct host_cmd_ds_802_11_eeprom_access *cmd_eeprom = | ||
905 | (struct host_cmd_ds_802_11_eeprom_access *) | ||
906 | &cmd->params.eeprom; | ||
907 | |||
908 | cmd->size = cpu_to_le16(sizeof(*cmd_eeprom) + S_DS_GEN); | ||
909 | cmd_eeprom->action = cpu_to_le16(cmd_action); | ||
910 | cmd_eeprom->offset = rd_eeprom->offset; | ||
911 | cmd_eeprom->byte_count = rd_eeprom->byte_count; | ||
912 | cmd_eeprom->value = 0; | ||
913 | break; | ||
914 | } | ||
915 | default: | ||
916 | return -1; | ||
917 | } | ||
918 | |||
919 | return 0; | ||
920 | } | ||
921 | |||
922 | /* | ||
923 | * This function prepares the commands before sending them to the firmware. | ||
924 | * | ||
925 | * This is a generic function which calls specific command preparation | ||
926 | * routines based upon the command number. | ||
927 | */ | ||
928 | int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no, | ||
929 | u16 cmd_action, u32 cmd_oid, | ||
930 | void *data_buf, void *cmd_buf) | ||
931 | { | ||
932 | struct host_cmd_ds_command *cmd_ptr = | ||
933 | (struct host_cmd_ds_command *) cmd_buf; | ||
934 | int ret = 0; | ||
935 | |||
936 | /* Prepare command */ | ||
937 | switch (cmd_no) { | ||
938 | case HostCmd_CMD_GET_HW_SPEC: | ||
939 | ret = mwifiex_cmd_get_hw_spec(priv, cmd_ptr); | ||
940 | break; | ||
941 | case HostCmd_CMD_MAC_CONTROL: | ||
942 | ret = mwifiex_cmd_mac_control(priv, cmd_ptr, cmd_action, | ||
943 | data_buf); | ||
944 | break; | ||
945 | case HostCmd_CMD_802_11_MAC_ADDRESS: | ||
946 | ret = mwifiex_cmd_802_11_mac_address(priv, cmd_ptr, | ||
947 | cmd_action); | ||
948 | break; | ||
949 | case HostCmd_CMD_MAC_MULTICAST_ADR: | ||
950 | ret = mwifiex_cmd_mac_multicast_adr(priv, cmd_ptr, cmd_action, | ||
951 | data_buf); | ||
952 | break; | ||
953 | case HostCmd_CMD_TX_RATE_CFG: | ||
954 | ret = mwifiex_cmd_tx_rate_cfg(priv, cmd_ptr, cmd_action, | ||
955 | data_buf); | ||
956 | break; | ||
957 | case HostCmd_CMD_TXPWR_CFG: | ||
958 | ret = mwifiex_cmd_tx_power_cfg(priv, cmd_ptr, cmd_action, | ||
959 | data_buf); | ||
960 | break; | ||
961 | case HostCmd_CMD_802_11_PS_MODE_ENH: | ||
962 | ret = mwifiex_cmd_enh_power_mode(priv, cmd_ptr, cmd_action, | ||
963 | (uint16_t)cmd_oid, data_buf); | ||
964 | break; | ||
965 | case HostCmd_CMD_802_11_HS_CFG_ENH: | ||
966 | ret = mwifiex_cmd_802_11_hs_cfg(priv, cmd_ptr, cmd_action, | ||
967 | (struct mwifiex_hs_config_param *) data_buf); | ||
968 | break; | ||
969 | case HostCmd_CMD_802_11_SCAN: | ||
970 | ret = mwifiex_cmd_802_11_scan(priv, cmd_ptr, data_buf); | ||
971 | break; | ||
972 | case HostCmd_CMD_802_11_BG_SCAN_QUERY: | ||
973 | ret = mwifiex_cmd_802_11_bg_scan_query(priv, cmd_ptr, | ||
974 | data_buf); | ||
975 | break; | ||
976 | case HostCmd_CMD_802_11_ASSOCIATE: | ||
977 | ret = mwifiex_cmd_802_11_associate(priv, cmd_ptr, data_buf); | ||
978 | break; | ||
979 | case HostCmd_CMD_802_11_DEAUTHENTICATE: | ||
980 | ret = mwifiex_cmd_802_11_deauthenticate(priv, cmd_ptr, | ||
981 | data_buf); | ||
982 | break; | ||
983 | case HostCmd_CMD_802_11_AD_HOC_START: | ||
984 | ret = mwifiex_cmd_802_11_ad_hoc_start(priv, cmd_ptr, | ||
985 | data_buf); | ||
986 | break; | ||
987 | case HostCmd_CMD_802_11_GET_LOG: | ||
988 | ret = mwifiex_cmd_802_11_get_log(priv, cmd_ptr); | ||
989 | break; | ||
990 | case HostCmd_CMD_802_11_AD_HOC_JOIN: | ||
991 | ret = mwifiex_cmd_802_11_ad_hoc_join(priv, cmd_ptr, | ||
992 | data_buf); | ||
993 | break; | ||
994 | case HostCmd_CMD_802_11_AD_HOC_STOP: | ||
995 | ret = mwifiex_cmd_802_11_ad_hoc_stop(priv, cmd_ptr); | ||
996 | break; | ||
997 | case HostCmd_CMD_RSSI_INFO: | ||
998 | ret = mwifiex_cmd_802_11_rssi_info(priv, cmd_ptr, cmd_action); | ||
999 | break; | ||
1000 | case HostCmd_CMD_802_11_SNMP_MIB: | ||
1001 | ret = mwifiex_cmd_802_11_snmp_mib(priv, cmd_ptr, cmd_action, | ||
1002 | cmd_oid, data_buf); | ||
1003 | break; | ||
1004 | case HostCmd_CMD_802_11_TX_RATE_QUERY: | ||
1005 | cmd_ptr->command = | ||
1006 | cpu_to_le16(HostCmd_CMD_802_11_TX_RATE_QUERY); | ||
1007 | cmd_ptr->size = | ||
1008 | cpu_to_le16(sizeof(struct host_cmd_ds_tx_rate_query) + | ||
1009 | S_DS_GEN); | ||
1010 | priv->tx_rate = 0; | ||
1011 | ret = 0; | ||
1012 | break; | ||
1013 | case HostCmd_CMD_VERSION_EXT: | ||
1014 | cmd_ptr->command = cpu_to_le16(cmd_no); | ||
1015 | cmd_ptr->params.verext.version_str_sel = | ||
1016 | (u8) (*((u32 *) data_buf)); | ||
1017 | memcpy(&cmd_ptr->params, data_buf, | ||
1018 | sizeof(struct host_cmd_ds_version_ext)); | ||
1019 | cmd_ptr->size = | ||
1020 | cpu_to_le16(sizeof(struct host_cmd_ds_version_ext) + | ||
1021 | S_DS_GEN); | ||
1022 | ret = 0; | ||
1023 | break; | ||
1024 | case HostCmd_CMD_802_11_RF_CHANNEL: | ||
1025 | ret = mwifiex_cmd_802_11_rf_channel(priv, cmd_ptr, cmd_action, | ||
1026 | data_buf); | ||
1027 | break; | ||
1028 | case HostCmd_CMD_FUNC_INIT: | ||
1029 | if (priv->adapter->hw_status == MWIFIEX_HW_STATUS_RESET) | ||
1030 | priv->adapter->hw_status = MWIFIEX_HW_STATUS_READY; | ||
1031 | cmd_ptr->command = cpu_to_le16(cmd_no); | ||
1032 | cmd_ptr->size = cpu_to_le16(S_DS_GEN); | ||
1033 | break; | ||
1034 | case HostCmd_CMD_FUNC_SHUTDOWN: | ||
1035 | priv->adapter->hw_status = MWIFIEX_HW_STATUS_RESET; | ||
1036 | cmd_ptr->command = cpu_to_le16(cmd_no); | ||
1037 | cmd_ptr->size = cpu_to_le16(S_DS_GEN); | ||
1038 | break; | ||
1039 | case HostCmd_CMD_11N_ADDBA_REQ: | ||
1040 | ret = mwifiex_cmd_11n_addba_req(priv, cmd_ptr, data_buf); | ||
1041 | break; | ||
1042 | case HostCmd_CMD_11N_DELBA: | ||
1043 | ret = mwifiex_cmd_11n_delba(priv, cmd_ptr, data_buf); | ||
1044 | break; | ||
1045 | case HostCmd_CMD_11N_ADDBA_RSP: | ||
1046 | ret = mwifiex_cmd_11n_addba_rsp_gen(priv, cmd_ptr, data_buf); | ||
1047 | break; | ||
1048 | case HostCmd_CMD_802_11_KEY_MATERIAL: | ||
1049 | ret = mwifiex_cmd_802_11_key_material(priv, cmd_ptr, | ||
1050 | cmd_action, cmd_oid, | ||
1051 | data_buf); | ||
1052 | break; | ||
1053 | case HostCmd_CMD_802_11D_DOMAIN_INFO: | ||
1054 | ret = mwifiex_cmd_802_11d_domain_info(priv, cmd_ptr, | ||
1055 | cmd_action); | ||
1056 | break; | ||
1057 | case HostCmd_CMD_RECONFIGURE_TX_BUFF: | ||
1058 | ret = mwifiex_cmd_recfg_tx_buf(priv, cmd_ptr, cmd_action, | ||
1059 | data_buf); | ||
1060 | break; | ||
1061 | case HostCmd_CMD_AMSDU_AGGR_CTRL: | ||
1062 | ret = mwifiex_cmd_amsdu_aggr_ctrl(priv, cmd_ptr, cmd_action, | ||
1063 | data_buf); | ||
1064 | break; | ||
1065 | case HostCmd_CMD_11N_CFG: | ||
1066 | ret = mwifiex_cmd_11n_cfg(priv, cmd_ptr, cmd_action, | ||
1067 | data_buf); | ||
1068 | break; | ||
1069 | case HostCmd_CMD_WMM_GET_STATUS: | ||
1070 | dev_dbg(priv->adapter->dev, | ||
1071 | "cmd: WMM: WMM_GET_STATUS cmd sent\n"); | ||
1072 | cmd_ptr->command = cpu_to_le16(HostCmd_CMD_WMM_GET_STATUS); | ||
1073 | cmd_ptr->size = | ||
1074 | cpu_to_le16(sizeof(struct host_cmd_ds_wmm_get_status) + | ||
1075 | S_DS_GEN); | ||
1076 | ret = 0; | ||
1077 | break; | ||
1078 | case HostCmd_CMD_802_11_IBSS_COALESCING_STATUS: | ||
1079 | ret = mwifiex_cmd_ibss_coalescing_status(priv, cmd_ptr, | ||
1080 | cmd_action, data_buf); | ||
1081 | break; | ||
1082 | case HostCmd_CMD_MAC_REG_ACCESS: | ||
1083 | case HostCmd_CMD_BBP_REG_ACCESS: | ||
1084 | case HostCmd_CMD_RF_REG_ACCESS: | ||
1085 | case HostCmd_CMD_PMIC_REG_ACCESS: | ||
1086 | case HostCmd_CMD_CAU_REG_ACCESS: | ||
1087 | case HostCmd_CMD_802_11_EEPROM_ACCESS: | ||
1088 | ret = mwifiex_cmd_reg_access(cmd_ptr, cmd_action, data_buf); | ||
1089 | break; | ||
1090 | case HostCmd_CMD_SET_BSS_MODE: | ||
1091 | cmd_ptr->command = cpu_to_le16(cmd_no); | ||
1092 | if (priv->bss_mode == NL80211_IFTYPE_ADHOC) | ||
1093 | cmd_ptr->params.bss_mode.con_type = | ||
1094 | CONNECTION_TYPE_ADHOC; | ||
1095 | else if (priv->bss_mode == NL80211_IFTYPE_STATION) | ||
1096 | cmd_ptr->params.bss_mode.con_type = | ||
1097 | CONNECTION_TYPE_INFRA; | ||
1098 | cmd_ptr->size = cpu_to_le16(sizeof(struct | ||
1099 | host_cmd_ds_set_bss_mode) + S_DS_GEN); | ||
1100 | ret = 0; | ||
1101 | break; | ||
1102 | default: | ||
1103 | dev_err(priv->adapter->dev, | ||
1104 | "PREP_CMD: unknown cmd- %#x\n", cmd_no); | ||
1105 | ret = -1; | ||
1106 | break; | ||
1107 | } | ||
1108 | return ret; | ||
1109 | } | ||
1110 | |||
1111 | /* | ||
1112 | * This function issues commands to initialize firmware. | ||
1113 | * | ||
1114 | * This is called after firmware download to bring the card to | ||
1115 | * working state. | ||
1116 | * | ||
1117 | * The following commands are issued sequentially - | ||
1118 | * - Function init (for first interface only) | ||
1119 | * - Read MAC address (for first interface only) | ||
1120 | * - Reconfigure Tx buffer size (for first interface only) | ||
1121 | * - Enable auto deep sleep (for first interface only) | ||
1122 | * - Get Tx rate | ||
1123 | * - Get Tx power | ||
1124 | * - Set IBSS coalescing status | ||
1125 | * - Set AMSDU aggregation control | ||
1126 | * - Set 11d control | ||
1127 | * - Set MAC control (this must be the last command to initialize firmware) | ||
1128 | */ | ||
1129 | int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta) | ||
1130 | { | ||
1131 | int ret = 0; | ||
1132 | u16 enable = true; | ||
1133 | struct mwifiex_ds_11n_amsdu_aggr_ctrl amsdu_aggr_ctrl; | ||
1134 | struct mwifiex_ds_auto_ds auto_ds; | ||
1135 | enum state_11d_t state_11d; | ||
1136 | |||
1137 | if (first_sta) { | ||
1138 | |||
1139 | ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_FUNC_INIT, | ||
1140 | HostCmd_ACT_GEN_SET, 0, NULL, NULL); | ||
1141 | if (ret) | ||
1142 | return -1; | ||
1143 | /* Read MAC address from HW */ | ||
1144 | ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_GET_HW_SPEC, | ||
1145 | HostCmd_ACT_GEN_GET, 0, NULL, NULL); | ||
1146 | if (ret) | ||
1147 | return -1; | ||
1148 | |||
1149 | /* Reconfigure tx buf size */ | ||
1150 | ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_RECONFIGURE_TX_BUFF, | ||
1151 | HostCmd_ACT_GEN_SET, 0, NULL, | ||
1152 | &priv->adapter->tx_buf_size); | ||
1153 | if (ret) | ||
1154 | return -1; | ||
1155 | |||
1156 | /* Enable IEEE PS by default */ | ||
1157 | priv->adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_PSP; | ||
1158 | ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_PS_MODE_ENH, | ||
1159 | EN_AUTO_PS, BITMAP_STA_PS, NULL, | ||
1160 | NULL); | ||
1161 | if (ret) | ||
1162 | return -1; | ||
1163 | } | ||
1164 | |||
1165 | /* get tx rate */ | ||
1166 | ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_TX_RATE_CFG, | ||
1167 | HostCmd_ACT_GEN_GET, 0, NULL, NULL); | ||
1168 | if (ret) | ||
1169 | return -1; | ||
1170 | priv->data_rate = 0; | ||
1171 | |||
1172 | /* get tx power */ | ||
1173 | ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_TXPWR_CFG, | ||
1174 | HostCmd_ACT_GEN_GET, 0, NULL, NULL); | ||
1175 | if (ret) | ||
1176 | return -1; | ||
1177 | |||
1178 | /* set ibss coalescing_status */ | ||
1179 | ret = mwifiex_prepare_cmd(priv, | ||
1180 | HostCmd_CMD_802_11_IBSS_COALESCING_STATUS, | ||
1181 | HostCmd_ACT_GEN_SET, 0, NULL, &enable); | ||
1182 | if (ret) | ||
1183 | return -1; | ||
1184 | |||
1185 | memset(&amsdu_aggr_ctrl, 0, sizeof(amsdu_aggr_ctrl)); | ||
1186 | amsdu_aggr_ctrl.enable = true; | ||
1187 | /* Send request to firmware */ | ||
1188 | ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_AMSDU_AGGR_CTRL, | ||
1189 | HostCmd_ACT_GEN_SET, 0, NULL, | ||
1190 | (void *) &amsdu_aggr_ctrl); | ||
1191 | if (ret) | ||
1192 | return -1; | ||
1193 | /* MAC Control must be the last command in init_fw */ | ||
1194 | /* set MAC Control */ | ||
1195 | ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_MAC_CONTROL, | ||
1196 | HostCmd_ACT_GEN_SET, 0, NULL, | ||
1197 | &priv->curr_pkt_filter); | ||
1198 | if (ret) | ||
1199 | return -1; | ||
1200 | |||
1201 | if (first_sta) { | ||
1202 | /* Enable auto deep sleep */ | ||
1203 | auto_ds.auto_ds = DEEP_SLEEP_ON; | ||
1204 | auto_ds.idle_time = DEEP_SLEEP_IDLE_TIME; | ||
1205 | ret = mwifiex_prepare_cmd(priv, | ||
1206 | HostCmd_CMD_802_11_PS_MODE_ENH, | ||
1207 | EN_AUTO_PS, BITMAP_AUTO_DS, NULL, | ||
1208 | &auto_ds); | ||
1209 | if (ret) | ||
1210 | return -1; | ||
1211 | } | ||
1212 | |||
1213 | /* Send cmd to FW to enable/disable 11D function */ | ||
1214 | state_11d = ENABLE_11D; | ||
1215 | ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB, | ||
1216 | HostCmd_ACT_GEN_SET, DOT11D_I, | ||
1217 | NULL, &state_11d); | ||
1218 | if (ret) | ||
1219 | dev_err(priv->adapter->dev, "11D: failed to enable 11D\n"); | ||
1220 | |||
1221 | /* set last_init_cmd */ | ||
1222 | priv->adapter->last_init_cmd = HostCmd_CMD_802_11_SNMP_MIB; | ||
1223 | ret = -EINPROGRESS; | ||
1224 | |||
1225 | return ret; | ||
1226 | } | ||
diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c new file mode 100644 index 000000000000..74add45b99b6 --- /dev/null +++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c | |||
@@ -0,0 +1,983 @@ | |||
1 | /* | ||
2 | * Marvell Wireless LAN device driver: station command response handling | ||
3 | * | ||
4 | * Copyright (C) 2011, Marvell International Ltd. | ||
5 | * | ||
6 | * This software file (the "File") is distributed by Marvell International | ||
7 | * Ltd. under the terms of the GNU General Public License Version 2, June 1991 | ||
8 | * (the "License"). You may use, redistribute and/or modify this File in | ||
9 | * accordance with the terms and conditions of the License, a copy of which | ||
10 | * is available by writing to the Free Software Foundation, Inc., | ||
11 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the | ||
12 | * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. | ||
13 | * | ||
14 | * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE | ||
15 | * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE | ||
16 | * ARE EXPRESSLY DISCLAIMED. The License provides additional details about | ||
17 | * this warranty disclaimer. | ||
18 | */ | ||
19 | |||
20 | #include "decl.h" | ||
21 | #include "ioctl.h" | ||
22 | #include "util.h" | ||
23 | #include "fw.h" | ||
24 | #include "main.h" | ||
25 | #include "wmm.h" | ||
26 | #include "11n.h" | ||
27 | |||
28 | |||
29 | /* | ||
30 | * This function handles the command response error case. | ||
31 | * | ||
32 | * For scan response error, the function cancels all the pending | ||
33 | * scan commands and generates an event to inform the applications | ||
34 | * of the scan completion. | ||
35 | * | ||
36 | * For Power Save command failure, we do not retry enter PS | ||
37 | * command in case of Ad-hoc mode. | ||
38 | * | ||
39 | * For all other response errors, the current command buffer is freed | ||
40 | * and returned to the free command queue. | ||
41 | */ | ||
42 | static void | ||
43 | mwifiex_process_cmdresp_error(struct mwifiex_private *priv, | ||
44 | struct host_cmd_ds_command *resp, | ||
45 | struct mwifiex_wait_queue *wq_buf) | ||
46 | { | ||
47 | struct cmd_ctrl_node *cmd_node = NULL, *tmp_node = NULL; | ||
48 | struct mwifiex_adapter *adapter = priv->adapter; | ||
49 | struct host_cmd_ds_802_11_ps_mode_enh *pm; | ||
50 | unsigned long flags; | ||
51 | |||
52 | dev_err(adapter->dev, "CMD_RESP: cmd %#x error, result=%#x\n", | ||
53 | resp->command, resp->result); | ||
54 | if (wq_buf) | ||
55 | wq_buf->status = MWIFIEX_ERROR_FW_CMDRESP; | ||
56 | |||
57 | switch (le16_to_cpu(resp->command)) { | ||
58 | case HostCmd_CMD_802_11_PS_MODE_ENH: | ||
59 | pm = &resp->params.psmode_enh; | ||
60 | dev_err(adapter->dev, "PS_MODE_ENH cmd failed: " | ||
61 | "result=0x%x action=0x%X\n", | ||
62 | resp->result, le16_to_cpu(pm->action)); | ||
63 | /* We do not re-try enter-ps command in ad-hoc mode. */ | ||
64 | if (le16_to_cpu(pm->action) == EN_AUTO_PS && | ||
65 | (le16_to_cpu(pm->params.ps_bitmap) & BITMAP_STA_PS) && | ||
66 | priv->bss_mode == NL80211_IFTYPE_ADHOC) | ||
67 | adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_CAM; | ||
68 | |||
69 | break; | ||
70 | case HostCmd_CMD_802_11_SCAN: | ||
71 | /* Cancel all pending scan command */ | ||
72 | spin_lock_irqsave(&adapter->scan_pending_q_lock, flags); | ||
73 | list_for_each_entry_safe(cmd_node, tmp_node, | ||
74 | &adapter->scan_pending_q, list) { | ||
75 | list_del(&cmd_node->list); | ||
76 | spin_unlock_irqrestore(&adapter->scan_pending_q_lock, | ||
77 | flags); | ||
78 | mwifiex_insert_cmd_to_free_q(adapter, cmd_node); | ||
79 | spin_lock_irqsave(&adapter->scan_pending_q_lock, flags); | ||
80 | } | ||
81 | spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags); | ||
82 | |||
83 | spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); | ||
84 | adapter->scan_processing = false; | ||
85 | spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); | ||
86 | if (priv->report_scan_result) | ||
87 | priv->report_scan_result = false; | ||
88 | if (priv->scan_pending_on_block) { | ||
89 | priv->scan_pending_on_block = false; | ||
90 | up(&priv->async_sem); | ||
91 | } | ||
92 | break; | ||
93 | |||
94 | case HostCmd_CMD_MAC_CONTROL: | ||
95 | break; | ||
96 | |||
97 | default: | ||
98 | break; | ||
99 | } | ||
100 | /* Handling errors here */ | ||
101 | mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd); | ||
102 | |||
103 | spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); | ||
104 | adapter->curr_cmd = NULL; | ||
105 | spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); | ||
106 | |||
107 | return; | ||
108 | } | ||
109 | |||
110 | /* | ||
111 | * This function handles the command response of get RSSI info. | ||
112 | * | ||
113 | * Handling includes changing the header fields into CPU format | ||
114 | * and saving the following parameters in driver - | ||
115 | * - Last data and beacon RSSI value | ||
116 | * - Average data and beacon RSSI value | ||
117 | * - Last data and beacon NF value | ||
118 | * - Average data and beacon NF value | ||
119 | * | ||
120 | * The parameters are send to the application as well, along with | ||
121 | * calculated SNR values. | ||
122 | */ | ||
123 | static int mwifiex_ret_802_11_rssi_info(struct mwifiex_private *priv, | ||
124 | struct host_cmd_ds_command *resp, | ||
125 | void *data_buf) | ||
126 | { | ||
127 | struct host_cmd_ds_802_11_rssi_info_rsp *rssi_info_rsp = | ||
128 | &resp->params.rssi_info_rsp; | ||
129 | struct mwifiex_ds_get_signal *signal = NULL; | ||
130 | |||
131 | priv->data_rssi_last = le16_to_cpu(rssi_info_rsp->data_rssi_last); | ||
132 | priv->data_nf_last = le16_to_cpu(rssi_info_rsp->data_nf_last); | ||
133 | |||
134 | priv->data_rssi_avg = le16_to_cpu(rssi_info_rsp->data_rssi_avg); | ||
135 | priv->data_nf_avg = le16_to_cpu(rssi_info_rsp->data_nf_avg); | ||
136 | |||
137 | priv->bcn_rssi_last = le16_to_cpu(rssi_info_rsp->bcn_rssi_last); | ||
138 | priv->bcn_nf_last = le16_to_cpu(rssi_info_rsp->bcn_nf_last); | ||
139 | |||
140 | priv->bcn_rssi_avg = le16_to_cpu(rssi_info_rsp->bcn_rssi_avg); | ||
141 | priv->bcn_nf_avg = le16_to_cpu(rssi_info_rsp->bcn_nf_avg); | ||
142 | |||
143 | /* Need to indicate IOCTL complete */ | ||
144 | if (data_buf) { | ||
145 | signal = (struct mwifiex_ds_get_signal *) data_buf; | ||
146 | memset(signal, 0, sizeof(struct mwifiex_ds_get_signal)); | ||
147 | |||
148 | signal->selector = ALL_RSSI_INFO_MASK; | ||
149 | |||
150 | /* RSSI */ | ||
151 | signal->bcn_rssi_last = priv->bcn_rssi_last; | ||
152 | signal->bcn_rssi_avg = priv->bcn_rssi_avg; | ||
153 | signal->data_rssi_last = priv->data_rssi_last; | ||
154 | signal->data_rssi_avg = priv->data_rssi_avg; | ||
155 | |||
156 | /* SNR */ | ||
157 | signal->bcn_snr_last = | ||
158 | CAL_SNR(priv->bcn_rssi_last, priv->bcn_nf_last); | ||
159 | signal->bcn_snr_avg = | ||
160 | CAL_SNR(priv->bcn_rssi_avg, priv->bcn_nf_avg); | ||
161 | signal->data_snr_last = | ||
162 | CAL_SNR(priv->data_rssi_last, priv->data_nf_last); | ||
163 | signal->data_snr_avg = | ||
164 | CAL_SNR(priv->data_rssi_avg, priv->data_nf_avg); | ||
165 | |||
166 | /* NF */ | ||
167 | signal->bcn_nf_last = priv->bcn_nf_last; | ||
168 | signal->bcn_nf_avg = priv->bcn_nf_avg; | ||
169 | signal->data_nf_last = priv->data_nf_last; | ||
170 | signal->data_nf_avg = priv->data_nf_avg; | ||
171 | } | ||
172 | |||
173 | return 0; | ||
174 | } | ||
175 | |||
176 | /* | ||
177 | * This function handles the command response of set/get SNMP | ||
178 | * MIB parameters. | ||
179 | * | ||
180 | * Handling includes changing the header fields into CPU format | ||
181 | * and saving the parameter in driver. | ||
182 | * | ||
183 | * The following parameters are supported - | ||
184 | * - Fragmentation threshold | ||
185 | * - RTS threshold | ||
186 | * - Short retry limit | ||
187 | */ | ||
188 | static int mwifiex_ret_802_11_snmp_mib(struct mwifiex_private *priv, | ||
189 | struct host_cmd_ds_command *resp, | ||
190 | void *data_buf) | ||
191 | { | ||
192 | struct host_cmd_ds_802_11_snmp_mib *smib = &resp->params.smib; | ||
193 | u16 oid = le16_to_cpu(smib->oid); | ||
194 | u16 query_type = le16_to_cpu(smib->query_type); | ||
195 | u32 ul_temp; | ||
196 | |||
197 | dev_dbg(priv->adapter->dev, "info: SNMP_RESP: oid value = %#x," | ||
198 | " query_type = %#x, buf size = %#x\n", | ||
199 | oid, query_type, le16_to_cpu(smib->buf_size)); | ||
200 | if (query_type == HostCmd_ACT_GEN_GET) { | ||
201 | ul_temp = le16_to_cpu(*((__le16 *) (smib->value))); | ||
202 | if (data_buf) | ||
203 | *(u32 *)data_buf = ul_temp; | ||
204 | switch (oid) { | ||
205 | case FRAG_THRESH_I: | ||
206 | dev_dbg(priv->adapter->dev, | ||
207 | "info: SNMP_RESP: FragThsd =%u\n", ul_temp); | ||
208 | break; | ||
209 | case RTS_THRESH_I: | ||
210 | dev_dbg(priv->adapter->dev, | ||
211 | "info: SNMP_RESP: RTSThsd =%u\n", ul_temp); | ||
212 | break; | ||
213 | case SHORT_RETRY_LIM_I: | ||
214 | dev_dbg(priv->adapter->dev, | ||
215 | "info: SNMP_RESP: TxRetryCount=%u\n", ul_temp); | ||
216 | break; | ||
217 | default: | ||
218 | break; | ||
219 | } | ||
220 | } | ||
221 | |||
222 | return 0; | ||
223 | } | ||
224 | |||
225 | /* | ||
226 | * This function handles the command response of get log request | ||
227 | * | ||
228 | * Handling includes changing the header fields into CPU format | ||
229 | * and sending the received parameters to application. | ||
230 | */ | ||
231 | static int mwifiex_ret_get_log(struct mwifiex_private *priv, | ||
232 | struct host_cmd_ds_command *resp, | ||
233 | void *data_buf) | ||
234 | { | ||
235 | struct host_cmd_ds_802_11_get_log *get_log = | ||
236 | (struct host_cmd_ds_802_11_get_log *) &resp->params.get_log; | ||
237 | struct mwifiex_ds_get_stats *stats = NULL; | ||
238 | |||
239 | if (data_buf) { | ||
240 | stats = (struct mwifiex_ds_get_stats *) data_buf; | ||
241 | stats->mcast_tx_frame = le32_to_cpu(get_log->mcast_tx_frame); | ||
242 | stats->failed = le32_to_cpu(get_log->failed); | ||
243 | stats->retry = le32_to_cpu(get_log->retry); | ||
244 | stats->multi_retry = le32_to_cpu(get_log->multi_retry); | ||
245 | stats->frame_dup = le32_to_cpu(get_log->frame_dup); | ||
246 | stats->rts_success = le32_to_cpu(get_log->rts_success); | ||
247 | stats->rts_failure = le32_to_cpu(get_log->rts_failure); | ||
248 | stats->ack_failure = le32_to_cpu(get_log->ack_failure); | ||
249 | stats->rx_frag = le32_to_cpu(get_log->rx_frag); | ||
250 | stats->mcast_rx_frame = le32_to_cpu(get_log->mcast_rx_frame); | ||
251 | stats->fcs_error = le32_to_cpu(get_log->fcs_error); | ||
252 | stats->tx_frame = le32_to_cpu(get_log->tx_frame); | ||
253 | stats->wep_icv_error[0] = | ||
254 | le32_to_cpu(get_log->wep_icv_err_cnt[0]); | ||
255 | stats->wep_icv_error[1] = | ||
256 | le32_to_cpu(get_log->wep_icv_err_cnt[1]); | ||
257 | stats->wep_icv_error[2] = | ||
258 | le32_to_cpu(get_log->wep_icv_err_cnt[2]); | ||
259 | stats->wep_icv_error[3] = | ||
260 | le32_to_cpu(get_log->wep_icv_err_cnt[3]); | ||
261 | } | ||
262 | |||
263 | return 0; | ||
264 | } | ||
265 | |||
266 | /* | ||
267 | * This function handles the command response of set/get Tx rate | ||
268 | * configurations. | ||
269 | * | ||
270 | * Handling includes changing the header fields into CPU format | ||
271 | * and saving the following parameters in driver - | ||
272 | * - DSSS rate bitmap | ||
273 | * - OFDM rate bitmap | ||
274 | * - HT MCS rate bitmaps | ||
275 | * | ||
276 | * Based on the new rate bitmaps, the function re-evaluates if | ||
277 | * auto data rate has been activated. If not, it sends another | ||
278 | * query to the firmware to get the current Tx data rate and updates | ||
279 | * the driver value. | ||
280 | */ | ||
281 | static int mwifiex_ret_tx_rate_cfg(struct mwifiex_private *priv, | ||
282 | struct host_cmd_ds_command *resp, | ||
283 | void *data_buf) | ||
284 | { | ||
285 | struct mwifiex_adapter *adapter = priv->adapter; | ||
286 | struct mwifiex_rate_cfg *ds_rate = NULL; | ||
287 | struct host_cmd_ds_tx_rate_cfg *rate_cfg = &resp->params.tx_rate_cfg; | ||
288 | struct mwifiex_rate_scope *rate_scope; | ||
289 | struct mwifiex_ie_types_header *head = NULL; | ||
290 | u16 tlv, tlv_buf_len; | ||
291 | u8 *tlv_buf; | ||
292 | u32 i; | ||
293 | int ret = 0; | ||
294 | |||
295 | tlv_buf = (u8 *) ((u8 *) rate_cfg) + | ||
296 | sizeof(struct host_cmd_ds_tx_rate_cfg); | ||
297 | tlv_buf_len = *(u16 *) (tlv_buf + sizeof(u16)); | ||
298 | |||
299 | while (tlv_buf && tlv_buf_len > 0) { | ||
300 | tlv = (*tlv_buf); | ||
301 | tlv = tlv | (*(tlv_buf + 1) << 8); | ||
302 | |||
303 | switch (tlv) { | ||
304 | case TLV_TYPE_RATE_SCOPE: | ||
305 | rate_scope = (struct mwifiex_rate_scope *) tlv_buf; | ||
306 | priv->bitmap_rates[0] = | ||
307 | le16_to_cpu(rate_scope->hr_dsss_rate_bitmap); | ||
308 | priv->bitmap_rates[1] = | ||
309 | le16_to_cpu(rate_scope->ofdm_rate_bitmap); | ||
310 | for (i = 0; | ||
311 | i < | ||
312 | sizeof(rate_scope->ht_mcs_rate_bitmap) / | ||
313 | sizeof(u16); i++) | ||
314 | priv->bitmap_rates[2 + i] = | ||
315 | le16_to_cpu(rate_scope-> | ||
316 | ht_mcs_rate_bitmap[i]); | ||
317 | break; | ||
318 | /* Add RATE_DROP tlv here */ | ||
319 | } | ||
320 | |||
321 | head = (struct mwifiex_ie_types_header *) tlv_buf; | ||
322 | tlv_buf += le16_to_cpu(head->len) + sizeof(*head); | ||
323 | tlv_buf_len -= le16_to_cpu(head->len); | ||
324 | } | ||
325 | |||
326 | priv->is_data_rate_auto = mwifiex_is_rate_auto(priv); | ||
327 | |||
328 | if (priv->is_data_rate_auto) | ||
329 | priv->data_rate = 0; | ||
330 | else | ||
331 | ret = mwifiex_prepare_cmd(priv, | ||
332 | HostCmd_CMD_802_11_TX_RATE_QUERY, | ||
333 | HostCmd_ACT_GEN_GET, 0, NULL, NULL); | ||
334 | |||
335 | if (data_buf) { | ||
336 | ds_rate = (struct mwifiex_rate_cfg *) data_buf; | ||
337 | if (le16_to_cpu(rate_cfg->action) == HostCmd_ACT_GEN_GET) { | ||
338 | if (priv->is_data_rate_auto) { | ||
339 | ds_rate->is_rate_auto = 1; | ||
340 | } else { | ||
341 | ds_rate->rate = | ||
342 | mwifiex_get_rate_index(adapter, | ||
343 | priv-> | ||
344 | bitmap_rates, | ||
345 | sizeof(priv-> | ||
346 | bitmap_rates)); | ||
347 | if (ds_rate->rate >= | ||
348 | MWIFIEX_RATE_BITMAP_OFDM0 | ||
349 | && ds_rate->rate <= | ||
350 | MWIFIEX_RATE_BITMAP_OFDM7) | ||
351 | ds_rate->rate -= | ||
352 | (MWIFIEX_RATE_BITMAP_OFDM0 - | ||
353 | MWIFIEX_RATE_INDEX_OFDM0); | ||
354 | if (ds_rate->rate >= | ||
355 | MWIFIEX_RATE_BITMAP_MCS0 | ||
356 | && ds_rate->rate <= | ||
357 | MWIFIEX_RATE_BITMAP_MCS127) | ||
358 | ds_rate->rate -= | ||
359 | (MWIFIEX_RATE_BITMAP_MCS0 - | ||
360 | MWIFIEX_RATE_INDEX_MCS0); | ||
361 | } | ||
362 | } | ||
363 | } | ||
364 | |||
365 | return ret; | ||
366 | } | ||
367 | |||
368 | /* | ||
369 | * This function handles the command response of get Tx power level. | ||
370 | * | ||
371 | * Handling includes saving the maximum and minimum Tx power levels | ||
372 | * in driver, as well as sending the values to user. | ||
373 | */ | ||
374 | static int mwifiex_get_power_level(struct mwifiex_private *priv, void *data_buf) | ||
375 | { | ||
376 | int length = -1, max_power = -1, min_power = -1; | ||
377 | struct mwifiex_types_power_group *pg_tlv_hdr = NULL; | ||
378 | struct mwifiex_power_group *pg = NULL; | ||
379 | |||
380 | if (data_buf) { | ||
381 | pg_tlv_hdr = | ||
382 | (struct mwifiex_types_power_group *) ((u8 *) data_buf | ||
383 | + sizeof(struct host_cmd_ds_txpwr_cfg)); | ||
384 | pg = (struct mwifiex_power_group *) ((u8 *) pg_tlv_hdr + | ||
385 | sizeof(struct mwifiex_types_power_group)); | ||
386 | length = pg_tlv_hdr->length; | ||
387 | if (length > 0) { | ||
388 | max_power = pg->power_max; | ||
389 | min_power = pg->power_min; | ||
390 | length -= sizeof(struct mwifiex_power_group); | ||
391 | } | ||
392 | while (length) { | ||
393 | pg++; | ||
394 | if (max_power < pg->power_max) | ||
395 | max_power = pg->power_max; | ||
396 | |||
397 | if (min_power > pg->power_min) | ||
398 | min_power = pg->power_min; | ||
399 | |||
400 | length -= sizeof(struct mwifiex_power_group); | ||
401 | } | ||
402 | if (pg_tlv_hdr->length > 0) { | ||
403 | priv->min_tx_power_level = (u8) min_power; | ||
404 | priv->max_tx_power_level = (u8) max_power; | ||
405 | } | ||
406 | } else { | ||
407 | return -1; | ||
408 | } | ||
409 | |||
410 | return 0; | ||
411 | } | ||
412 | |||
413 | /* | ||
414 | * This function handles the command response of set/get Tx power | ||
415 | * configurations. | ||
416 | * | ||
417 | * Handling includes changing the header fields into CPU format | ||
418 | * and saving the current Tx power level in driver. | ||
419 | */ | ||
420 | static int mwifiex_ret_tx_power_cfg(struct mwifiex_private *priv, | ||
421 | struct host_cmd_ds_command *resp, | ||
422 | void *data_buf) | ||
423 | { | ||
424 | struct mwifiex_adapter *adapter = priv->adapter; | ||
425 | struct host_cmd_ds_txpwr_cfg *txp_cfg = &resp->params.txp_cfg; | ||
426 | struct mwifiex_types_power_group *pg_tlv_hdr = NULL; | ||
427 | struct mwifiex_power_group *pg = NULL; | ||
428 | u16 action = le16_to_cpu(txp_cfg->action); | ||
429 | |||
430 | switch (action) { | ||
431 | case HostCmd_ACT_GEN_GET: | ||
432 | { | ||
433 | pg_tlv_hdr = | ||
434 | (struct mwifiex_types_power_group *) ((u8 *) | ||
435 | txp_cfg + | ||
436 | sizeof | ||
437 | (struct | ||
438 | host_cmd_ds_txpwr_cfg)); | ||
439 | pg = (struct mwifiex_power_group *) ((u8 *) | ||
440 | pg_tlv_hdr + | ||
441 | sizeof(struct | ||
442 | mwifiex_types_power_group)); | ||
443 | if (adapter->hw_status == | ||
444 | MWIFIEX_HW_STATUS_INITIALIZING) | ||
445 | mwifiex_get_power_level(priv, txp_cfg); | ||
446 | priv->tx_power_level = (u16) pg->power_min; | ||
447 | break; | ||
448 | } | ||
449 | case HostCmd_ACT_GEN_SET: | ||
450 | if (le32_to_cpu(txp_cfg->mode)) { | ||
451 | pg_tlv_hdr = | ||
452 | (struct mwifiex_types_power_group *) ((u8 *) | ||
453 | txp_cfg + | ||
454 | sizeof | ||
455 | (struct | ||
456 | host_cmd_ds_txpwr_cfg)); | ||
457 | pg = (struct mwifiex_power_group *) ((u8 *) pg_tlv_hdr | ||
458 | + | ||
459 | sizeof(struct | ||
460 | mwifiex_types_power_group)); | ||
461 | if (pg->power_max == pg->power_min) | ||
462 | priv->tx_power_level = (u16) pg->power_min; | ||
463 | } | ||
464 | break; | ||
465 | default: | ||
466 | dev_err(adapter->dev, "CMD_RESP: unknown cmd action %d\n", | ||
467 | action); | ||
468 | return 0; | ||
469 | } | ||
470 | dev_dbg(adapter->dev, | ||
471 | "info: Current TxPower Level = %d, Max Power=%d, Min Power=%d\n", | ||
472 | priv->tx_power_level, priv->max_tx_power_level, | ||
473 | priv->min_tx_power_level); | ||
474 | |||
475 | return 0; | ||
476 | } | ||
477 | |||
478 | /* | ||
479 | * This function handles the command response of set/get MAC address. | ||
480 | * | ||
481 | * Handling includes saving the MAC address in driver. | ||
482 | */ | ||
483 | static int mwifiex_ret_802_11_mac_address(struct mwifiex_private *priv, | ||
484 | struct host_cmd_ds_command *resp) | ||
485 | { | ||
486 | struct host_cmd_ds_802_11_mac_address *cmd_mac_addr = | ||
487 | &resp->params.mac_addr; | ||
488 | |||
489 | memcpy(priv->curr_addr, cmd_mac_addr->mac_addr, ETH_ALEN); | ||
490 | |||
491 | dev_dbg(priv->adapter->dev, | ||
492 | "info: set mac address: %pM\n", priv->curr_addr); | ||
493 | |||
494 | return 0; | ||
495 | } | ||
496 | |||
497 | /* | ||
498 | * This function handles the command response of set/get MAC multicast | ||
499 | * address. | ||
500 | */ | ||
501 | static int mwifiex_ret_mac_multicast_adr(struct mwifiex_private *priv, | ||
502 | struct host_cmd_ds_command *resp) | ||
503 | { | ||
504 | return 0; | ||
505 | } | ||
506 | |||
507 | /* | ||
508 | * This function handles the command response of get Tx rate query. | ||
509 | * | ||
510 | * Handling includes changing the header fields into CPU format | ||
511 | * and saving the Tx rate and HT information parameters in driver. | ||
512 | * | ||
513 | * Both rate configuration and current data rate can be retrieved | ||
514 | * with this request. | ||
515 | */ | ||
516 | static int mwifiex_ret_802_11_tx_rate_query(struct mwifiex_private *priv, | ||
517 | struct host_cmd_ds_command *resp) | ||
518 | { | ||
519 | struct mwifiex_adapter *adapter = priv->adapter; | ||
520 | |||
521 | priv->tx_rate = resp->params.tx_rate.tx_rate; | ||
522 | priv->tx_htinfo = resp->params.tx_rate.ht_info; | ||
523 | if (!priv->is_data_rate_auto) | ||
524 | priv->data_rate = | ||
525 | mwifiex_index_to_data_rate(adapter, priv->tx_rate, | ||
526 | priv->tx_htinfo); | ||
527 | |||
528 | return 0; | ||
529 | } | ||
530 | |||
531 | /* | ||
532 | * This function handles the command response of a deauthenticate | ||
533 | * command. | ||
534 | * | ||
535 | * If the deauthenticated MAC matches the current BSS MAC, the connection | ||
536 | * state is reset. | ||
537 | */ | ||
538 | static int mwifiex_ret_802_11_deauthenticate(struct mwifiex_private *priv, | ||
539 | struct host_cmd_ds_command *resp) | ||
540 | { | ||
541 | struct mwifiex_adapter *adapter = priv->adapter; | ||
542 | |||
543 | adapter->dbg.num_cmd_deauth++; | ||
544 | if (!memcmp(resp->params.deauth.mac_addr, | ||
545 | &priv->curr_bss_params.bss_descriptor.mac_address, | ||
546 | sizeof(resp->params.deauth.mac_addr))) | ||
547 | mwifiex_reset_connect_state(priv); | ||
548 | |||
549 | return 0; | ||
550 | } | ||
551 | |||
552 | /* | ||
553 | * This function handles the command response of ad-hoc stop. | ||
554 | * | ||
555 | * The function resets the connection state in driver. | ||
556 | */ | ||
557 | static int mwifiex_ret_802_11_ad_hoc_stop(struct mwifiex_private *priv, | ||
558 | struct host_cmd_ds_command *resp) | ||
559 | { | ||
560 | mwifiex_reset_connect_state(priv); | ||
561 | return 0; | ||
562 | } | ||
563 | |||
564 | /* | ||
565 | * This function handles the command response of set/get key material. | ||
566 | * | ||
567 | * Handling includes updating the driver parameters to reflect the | ||
568 | * changes. | ||
569 | */ | ||
570 | static int mwifiex_ret_802_11_key_material(struct mwifiex_private *priv, | ||
571 | struct host_cmd_ds_command *resp) | ||
572 | { | ||
573 | struct host_cmd_ds_802_11_key_material *key = | ||
574 | &resp->params.key_material; | ||
575 | |||
576 | if (le16_to_cpu(key->action) == HostCmd_ACT_GEN_SET) { | ||
577 | if ((le16_to_cpu(key->key_param_set.key_info) & | ||
578 | KEY_INFO_TKIP_MCAST)) { | ||
579 | dev_dbg(priv->adapter->dev, "info: key: GTK is set\n"); | ||
580 | priv->wpa_is_gtk_set = true; | ||
581 | priv->scan_block = false; | ||
582 | } | ||
583 | } | ||
584 | |||
585 | memset(priv->aes_key.key_param_set.key, 0, | ||
586 | sizeof(key->key_param_set.key)); | ||
587 | priv->aes_key.key_param_set.key_len = key->key_param_set.key_len; | ||
588 | memcpy(priv->aes_key.key_param_set.key, key->key_param_set.key, | ||
589 | le16_to_cpu(priv->aes_key.key_param_set.key_len)); | ||
590 | |||
591 | return 0; | ||
592 | } | ||
593 | |||
594 | /* | ||
595 | * This function handles the command response of get 11d domain information. | ||
596 | */ | ||
597 | static int mwifiex_ret_802_11d_domain_info(struct mwifiex_private *priv, | ||
598 | struct host_cmd_ds_command *resp) | ||
599 | { | ||
600 | struct host_cmd_ds_802_11d_domain_info_rsp *domain_info = | ||
601 | &resp->params.domain_info_resp; | ||
602 | struct mwifiex_ietypes_domain_param_set *domain = &domain_info->domain; | ||
603 | u16 action = le16_to_cpu(domain_info->action); | ||
604 | u8 no_of_triplet = 0; | ||
605 | |||
606 | no_of_triplet = (u8) ((le16_to_cpu(domain->header.len) - | ||
607 | IEEE80211_COUNTRY_STRING_LEN) / | ||
608 | sizeof(struct ieee80211_country_ie_triplet)); | ||
609 | |||
610 | dev_dbg(priv->adapter->dev, "info: 11D Domain Info Resp:" | ||
611 | " no_of_triplet=%d\n", no_of_triplet); | ||
612 | |||
613 | if (no_of_triplet > MWIFIEX_MAX_TRIPLET_802_11D) { | ||
614 | dev_warn(priv->adapter->dev, | ||
615 | "11D: invalid number of triplets %d " | ||
616 | "returned!!\n", no_of_triplet); | ||
617 | return -1; | ||
618 | } | ||
619 | |||
620 | switch (action) { | ||
621 | case HostCmd_ACT_GEN_SET: /* Proc Set Action */ | ||
622 | break; | ||
623 | case HostCmd_ACT_GEN_GET: | ||
624 | break; | ||
625 | default: | ||
626 | dev_err(priv->adapter->dev, | ||
627 | "11D: invalid action:%d\n", domain_info->action); | ||
628 | return -1; | ||
629 | } | ||
630 | |||
631 | return 0; | ||
632 | } | ||
633 | |||
634 | /* | ||
635 | * This function handles the command response of get RF channel. | ||
636 | * | ||
637 | * Handling includes changing the header fields into CPU format | ||
638 | * and saving the new channel in driver. | ||
639 | */ | ||
640 | static int mwifiex_ret_802_11_rf_channel(struct mwifiex_private *priv, | ||
641 | struct host_cmd_ds_command *resp, | ||
642 | void *data_buf) | ||
643 | { | ||
644 | struct host_cmd_ds_802_11_rf_channel *rf_channel = | ||
645 | &resp->params.rf_channel; | ||
646 | u16 new_channel = le16_to_cpu(rf_channel->current_channel); | ||
647 | |||
648 | if (priv->curr_bss_params.bss_descriptor.channel != new_channel) { | ||
649 | dev_dbg(priv->adapter->dev, "cmd: Channel Switch: %d to %d\n", | ||
650 | priv->curr_bss_params.bss_descriptor.channel, | ||
651 | new_channel); | ||
652 | /* Update the channel again */ | ||
653 | priv->curr_bss_params.bss_descriptor.channel = new_channel; | ||
654 | } | ||
655 | if (data_buf) | ||
656 | *((u16 *)data_buf) = new_channel; | ||
657 | |||
658 | return 0; | ||
659 | } | ||
660 | |||
661 | /* | ||
662 | * This function handles the command response of get extended version. | ||
663 | * | ||
664 | * Handling includes forming the extended version string and sending it | ||
665 | * to application. | ||
666 | */ | ||
667 | static int mwifiex_ret_ver_ext(struct mwifiex_private *priv, | ||
668 | struct host_cmd_ds_command *resp, | ||
669 | void *data_buf) | ||
670 | { | ||
671 | struct host_cmd_ds_version_ext *ver_ext = &resp->params.verext; | ||
672 | struct host_cmd_ds_version_ext *version_ext = NULL; | ||
673 | |||
674 | if (data_buf) { | ||
675 | version_ext = (struct host_cmd_ds_version_ext *)data_buf; | ||
676 | version_ext->version_str_sel = ver_ext->version_str_sel; | ||
677 | memcpy(version_ext->version_str, ver_ext->version_str, | ||
678 | sizeof(char) * 128); | ||
679 | memcpy(priv->version_str, ver_ext->version_str, 128); | ||
680 | } | ||
681 | return 0; | ||
682 | } | ||
683 | |||
684 | /* | ||
685 | * This function handles the command response of register access. | ||
686 | * | ||
687 | * The register value and offset are returned to the user. For EEPROM | ||
688 | * access, the byte count is also returned. | ||
689 | */ | ||
690 | static int mwifiex_ret_reg_access(u16 type, struct host_cmd_ds_command *resp, | ||
691 | void *data_buf) | ||
692 | { | ||
693 | struct mwifiex_ds_reg_rw *reg_rw = NULL; | ||
694 | struct mwifiex_ds_read_eeprom *eeprom = NULL; | ||
695 | |||
696 | if (data_buf) { | ||
697 | reg_rw = (struct mwifiex_ds_reg_rw *) data_buf; | ||
698 | eeprom = (struct mwifiex_ds_read_eeprom *) data_buf; | ||
699 | switch (type) { | ||
700 | case HostCmd_CMD_MAC_REG_ACCESS: | ||
701 | { | ||
702 | struct host_cmd_ds_mac_reg_access *reg; | ||
703 | reg = (struct host_cmd_ds_mac_reg_access *) | ||
704 | &resp->params.mac_reg; | ||
705 | reg_rw->offset = cpu_to_le32( | ||
706 | (u32) le16_to_cpu(reg->offset)); | ||
707 | reg_rw->value = reg->value; | ||
708 | break; | ||
709 | } | ||
710 | case HostCmd_CMD_BBP_REG_ACCESS: | ||
711 | { | ||
712 | struct host_cmd_ds_bbp_reg_access *reg; | ||
713 | reg = (struct host_cmd_ds_bbp_reg_access *) | ||
714 | &resp->params.bbp_reg; | ||
715 | reg_rw->offset = cpu_to_le32( | ||
716 | (u32) le16_to_cpu(reg->offset)); | ||
717 | reg_rw->value = cpu_to_le32((u32) reg->value); | ||
718 | break; | ||
719 | } | ||
720 | |||
721 | case HostCmd_CMD_RF_REG_ACCESS: | ||
722 | { | ||
723 | struct host_cmd_ds_rf_reg_access *reg; | ||
724 | reg = (struct host_cmd_ds_rf_reg_access *) | ||
725 | &resp->params.rf_reg; | ||
726 | reg_rw->offset = cpu_to_le32( | ||
727 | (u32) le16_to_cpu(reg->offset)); | ||
728 | reg_rw->value = cpu_to_le32((u32) reg->value); | ||
729 | break; | ||
730 | } | ||
731 | case HostCmd_CMD_PMIC_REG_ACCESS: | ||
732 | { | ||
733 | struct host_cmd_ds_pmic_reg_access *reg; | ||
734 | reg = (struct host_cmd_ds_pmic_reg_access *) | ||
735 | &resp->params.pmic_reg; | ||
736 | reg_rw->offset = cpu_to_le32( | ||
737 | (u32) le16_to_cpu(reg->offset)); | ||
738 | reg_rw->value = cpu_to_le32((u32) reg->value); | ||
739 | break; | ||
740 | } | ||
741 | case HostCmd_CMD_CAU_REG_ACCESS: | ||
742 | { | ||
743 | struct host_cmd_ds_rf_reg_access *reg; | ||
744 | reg = (struct host_cmd_ds_rf_reg_access *) | ||
745 | &resp->params.rf_reg; | ||
746 | reg_rw->offset = cpu_to_le32( | ||
747 | (u32) le16_to_cpu(reg->offset)); | ||
748 | reg_rw->value = cpu_to_le32((u32) reg->value); | ||
749 | break; | ||
750 | } | ||
751 | case HostCmd_CMD_802_11_EEPROM_ACCESS: | ||
752 | { | ||
753 | struct host_cmd_ds_802_11_eeprom_access | ||
754 | *cmd_eeprom = | ||
755 | (struct host_cmd_ds_802_11_eeprom_access | ||
756 | *) &resp->params.eeprom; | ||
757 | pr_debug("info: EEPROM read len=%x\n", | ||
758 | cmd_eeprom->byte_count); | ||
759 | if (le16_to_cpu(eeprom->byte_count) < | ||
760 | le16_to_cpu( | ||
761 | cmd_eeprom->byte_count)) { | ||
762 | eeprom->byte_count = cpu_to_le16(0); | ||
763 | pr_debug("info: EEPROM read " | ||
764 | "length is too big\n"); | ||
765 | return -1; | ||
766 | } | ||
767 | eeprom->offset = cmd_eeprom->offset; | ||
768 | eeprom->byte_count = cmd_eeprom->byte_count; | ||
769 | if (le16_to_cpu(eeprom->byte_count) > 0) | ||
770 | memcpy(&eeprom->value, | ||
771 | &cmd_eeprom->value, | ||
772 | le16_to_cpu(eeprom->byte_count)); | ||
773 | |||
774 | break; | ||
775 | } | ||
776 | default: | ||
777 | return -1; | ||
778 | } | ||
779 | } | ||
780 | return 0; | ||
781 | } | ||
782 | |||
783 | /* | ||
784 | * This function handles the command response of get IBSS coalescing status. | ||
785 | * | ||
786 | * If the received BSSID is different than the current one, the current BSSID, | ||
787 | * beacon interval, ATIM window and ERP information are updated, along with | ||
788 | * changing the ad-hoc state accordingly. | ||
789 | */ | ||
790 | static int mwifiex_ret_ibss_coalescing_status(struct mwifiex_private *priv, | ||
791 | struct host_cmd_ds_command *resp) | ||
792 | { | ||
793 | struct host_cmd_ds_802_11_ibss_status *ibss_coal_resp = | ||
794 | &(resp->params.ibss_coalescing); | ||
795 | u8 zero_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 }; | ||
796 | |||
797 | if (le16_to_cpu(ibss_coal_resp->action) == HostCmd_ACT_GEN_SET) | ||
798 | return 0; | ||
799 | |||
800 | dev_dbg(priv->adapter->dev, | ||
801 | "info: new BSSID %pM\n", ibss_coal_resp->bssid); | ||
802 | |||
803 | /* If rsp has NULL BSSID, Just return..... No Action */ | ||
804 | if (!memcmp(ibss_coal_resp->bssid, zero_mac, ETH_ALEN)) { | ||
805 | dev_warn(priv->adapter->dev, "new BSSID is NULL\n"); | ||
806 | return 0; | ||
807 | } | ||
808 | |||
809 | /* If BSSID is diff, modify current BSS parameters */ | ||
810 | if (memcmp(priv->curr_bss_params.bss_descriptor.mac_address, | ||
811 | ibss_coal_resp->bssid, ETH_ALEN)) { | ||
812 | /* BSSID */ | ||
813 | memcpy(priv->curr_bss_params.bss_descriptor.mac_address, | ||
814 | ibss_coal_resp->bssid, ETH_ALEN); | ||
815 | |||
816 | /* Beacon Interval */ | ||
817 | priv->curr_bss_params.bss_descriptor.beacon_period | ||
818 | = le16_to_cpu(ibss_coal_resp->beacon_interval); | ||
819 | |||
820 | /* ERP Information */ | ||
821 | priv->curr_bss_params.bss_descriptor.erp_flags = | ||
822 | (u8) le16_to_cpu(ibss_coal_resp->use_g_rate_protect); | ||
823 | |||
824 | priv->adhoc_state = ADHOC_COALESCED; | ||
825 | } | ||
826 | |||
827 | return 0; | ||
828 | } | ||
829 | |||
830 | /* | ||
831 | * This function handles the command responses. | ||
832 | * | ||
833 | * This is a generic function, which calls command specific | ||
834 | * response handlers based on the command ID. | ||
835 | */ | ||
836 | int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, | ||
837 | u16 cmdresp_no, void *cmd_buf, void *wq_buf) | ||
838 | { | ||
839 | int ret = 0; | ||
840 | struct mwifiex_adapter *adapter = priv->adapter; | ||
841 | struct host_cmd_ds_command *resp = | ||
842 | (struct host_cmd_ds_command *) cmd_buf; | ||
843 | struct mwifiex_wait_queue *wait_queue = | ||
844 | (struct mwifiex_wait_queue *) wq_buf; | ||
845 | void *data_buf = adapter->curr_cmd->data_buf; | ||
846 | |||
847 | /* If the command is not successful, cleanup and return failure */ | ||
848 | if (resp->result != HostCmd_RESULT_OK) { | ||
849 | mwifiex_process_cmdresp_error(priv, resp, wait_queue); | ||
850 | return -1; | ||
851 | } | ||
852 | /* Command successful, handle response */ | ||
853 | switch (cmdresp_no) { | ||
854 | case HostCmd_CMD_GET_HW_SPEC: | ||
855 | ret = mwifiex_ret_get_hw_spec(priv, resp); | ||
856 | break; | ||
857 | case HostCmd_CMD_MAC_CONTROL: | ||
858 | break; | ||
859 | case HostCmd_CMD_802_11_MAC_ADDRESS: | ||
860 | ret = mwifiex_ret_802_11_mac_address(priv, resp); | ||
861 | break; | ||
862 | case HostCmd_CMD_MAC_MULTICAST_ADR: | ||
863 | ret = mwifiex_ret_mac_multicast_adr(priv, resp); | ||
864 | break; | ||
865 | case HostCmd_CMD_TX_RATE_CFG: | ||
866 | ret = mwifiex_ret_tx_rate_cfg(priv, resp, data_buf); | ||
867 | break; | ||
868 | case HostCmd_CMD_802_11_SCAN: | ||
869 | ret = mwifiex_ret_802_11_scan(priv, resp, wait_queue); | ||
870 | wait_queue = NULL; | ||
871 | adapter->curr_cmd->wq_buf = NULL; | ||
872 | break; | ||
873 | case HostCmd_CMD_802_11_BG_SCAN_QUERY: | ||
874 | ret = mwifiex_ret_802_11_scan(priv, resp, wait_queue); | ||
875 | dev_dbg(adapter->dev, | ||
876 | "info: CMD_RESP: BG_SCAN result is ready!\n"); | ||
877 | break; | ||
878 | case HostCmd_CMD_TXPWR_CFG: | ||
879 | ret = mwifiex_ret_tx_power_cfg(priv, resp, data_buf); | ||
880 | break; | ||
881 | case HostCmd_CMD_802_11_PS_MODE_ENH: | ||
882 | ret = mwifiex_ret_enh_power_mode(priv, resp, data_buf); | ||
883 | break; | ||
884 | case HostCmd_CMD_802_11_HS_CFG_ENH: | ||
885 | ret = mwifiex_ret_802_11_hs_cfg(priv, resp); | ||
886 | break; | ||
887 | case HostCmd_CMD_802_11_ASSOCIATE: | ||
888 | ret = mwifiex_ret_802_11_associate(priv, resp, wait_queue); | ||
889 | break; | ||
890 | case HostCmd_CMD_802_11_DEAUTHENTICATE: | ||
891 | ret = mwifiex_ret_802_11_deauthenticate(priv, resp); | ||
892 | break; | ||
893 | case HostCmd_CMD_802_11_AD_HOC_START: | ||
894 | case HostCmd_CMD_802_11_AD_HOC_JOIN: | ||
895 | ret = mwifiex_ret_802_11_ad_hoc(priv, resp, wait_queue); | ||
896 | break; | ||
897 | case HostCmd_CMD_802_11_AD_HOC_STOP: | ||
898 | ret = mwifiex_ret_802_11_ad_hoc_stop(priv, resp); | ||
899 | break; | ||
900 | case HostCmd_CMD_802_11_GET_LOG: | ||
901 | ret = mwifiex_ret_get_log(priv, resp, data_buf); | ||
902 | break; | ||
903 | case HostCmd_CMD_RSSI_INFO: | ||
904 | ret = mwifiex_ret_802_11_rssi_info(priv, resp, data_buf); | ||
905 | break; | ||
906 | case HostCmd_CMD_802_11_SNMP_MIB: | ||
907 | ret = mwifiex_ret_802_11_snmp_mib(priv, resp, data_buf); | ||
908 | break; | ||
909 | case HostCmd_CMD_802_11_TX_RATE_QUERY: | ||
910 | ret = mwifiex_ret_802_11_tx_rate_query(priv, resp); | ||
911 | break; | ||
912 | case HostCmd_CMD_802_11_RF_CHANNEL: | ||
913 | ret = mwifiex_ret_802_11_rf_channel(priv, resp, data_buf); | ||
914 | break; | ||
915 | case HostCmd_CMD_VERSION_EXT: | ||
916 | ret = mwifiex_ret_ver_ext(priv, resp, data_buf); | ||
917 | break; | ||
918 | case HostCmd_CMD_FUNC_INIT: | ||
919 | case HostCmd_CMD_FUNC_SHUTDOWN: | ||
920 | break; | ||
921 | case HostCmd_CMD_802_11_KEY_MATERIAL: | ||
922 | ret = mwifiex_ret_802_11_key_material(priv, resp); | ||
923 | break; | ||
924 | case HostCmd_CMD_802_11D_DOMAIN_INFO: | ||
925 | ret = mwifiex_ret_802_11d_domain_info(priv, resp); | ||
926 | break; | ||
927 | case HostCmd_CMD_11N_ADDBA_REQ: | ||
928 | ret = mwifiex_ret_11n_addba_req(priv, resp); | ||
929 | break; | ||
930 | case HostCmd_CMD_11N_DELBA: | ||
931 | ret = mwifiex_ret_11n_delba(priv, resp); | ||
932 | break; | ||
933 | case HostCmd_CMD_11N_ADDBA_RSP: | ||
934 | ret = mwifiex_ret_11n_addba_resp(priv, resp); | ||
935 | break; | ||
936 | case HostCmd_CMD_RECONFIGURE_TX_BUFF: | ||
937 | adapter->tx_buf_size = (u16) le16_to_cpu(resp->params. | ||
938 | tx_buf.buff_size); | ||
939 | adapter->tx_buf_size = (adapter->tx_buf_size / | ||
940 | MWIFIEX_SDIO_BLOCK_SIZE) * | ||
941 | MWIFIEX_SDIO_BLOCK_SIZE; | ||
942 | adapter->curr_tx_buf_size = adapter->tx_buf_size; | ||
943 | dev_dbg(adapter->dev, | ||
944 | "cmd: max_tx_buf_size=%d, tx_buf_size=%d\n", | ||
945 | adapter->max_tx_buf_size, adapter->tx_buf_size); | ||
946 | |||
947 | if (adapter->if_ops.update_mp_end_port) | ||
948 | adapter->if_ops.update_mp_end_port(adapter, | ||
949 | le16_to_cpu(resp-> | ||
950 | params. | ||
951 | tx_buf. | ||
952 | mp_end_port)); | ||
953 | break; | ||
954 | case HostCmd_CMD_AMSDU_AGGR_CTRL: | ||
955 | ret = mwifiex_ret_amsdu_aggr_ctrl(priv, resp, data_buf); | ||
956 | break; | ||
957 | case HostCmd_CMD_WMM_GET_STATUS: | ||
958 | ret = mwifiex_ret_wmm_get_status(priv, resp); | ||
959 | break; | ||
960 | case HostCmd_CMD_802_11_IBSS_COALESCING_STATUS: | ||
961 | ret = mwifiex_ret_ibss_coalescing_status(priv, resp); | ||
962 | break; | ||
963 | case HostCmd_CMD_MAC_REG_ACCESS: | ||
964 | case HostCmd_CMD_BBP_REG_ACCESS: | ||
965 | case HostCmd_CMD_RF_REG_ACCESS: | ||
966 | case HostCmd_CMD_PMIC_REG_ACCESS: | ||
967 | case HostCmd_CMD_CAU_REG_ACCESS: | ||
968 | case HostCmd_CMD_802_11_EEPROM_ACCESS: | ||
969 | ret = mwifiex_ret_reg_access(cmdresp_no, resp, data_buf); | ||
970 | break; | ||
971 | case HostCmd_CMD_SET_BSS_MODE: | ||
972 | break; | ||
973 | case HostCmd_CMD_11N_CFG: | ||
974 | ret = mwifiex_ret_11n_cfg(priv, resp, data_buf); | ||
975 | break; | ||
976 | default: | ||
977 | dev_err(adapter->dev, "CMD_RESP: unknown cmd response %#x\n", | ||
978 | resp->command); | ||
979 | break; | ||
980 | } | ||
981 | |||
982 | return ret; | ||
983 | } | ||
diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c new file mode 100644 index 000000000000..936d7c175e75 --- /dev/null +++ b/drivers/net/wireless/mwifiex/sta_event.c | |||
@@ -0,0 +1,405 @@ | |||
1 | /* | ||
2 | * Marvell Wireless LAN device driver: station event handling | ||
3 | * | ||
4 | * Copyright (C) 2011, Marvell International Ltd. | ||
5 | * | ||
6 | * This software file (the "File") is distributed by Marvell International | ||
7 | * Ltd. under the terms of the GNU General Public License Version 2, June 1991 | ||
8 | * (the "License"). You may use, redistribute and/or modify this File in | ||
9 | * accordance with the terms and conditions of the License, a copy of which | ||
10 | * is available by writing to the Free Software Foundation, Inc., | ||
11 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the | ||
12 | * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. | ||
13 | * | ||
14 | * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE | ||
15 | * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE | ||
16 | * ARE EXPRESSLY DISCLAIMED. The License provides additional details about | ||
17 | * this warranty disclaimer. | ||
18 | */ | ||
19 | |||
20 | #include "decl.h" | ||
21 | #include "ioctl.h" | ||
22 | #include "util.h" | ||
23 | #include "fw.h" | ||
24 | #include "main.h" | ||
25 | #include "wmm.h" | ||
26 | #include "11n.h" | ||
27 | |||
28 | /* | ||
29 | * This function resets the connection state. | ||
30 | * | ||
31 | * The function is invoked after receiving a disconnect event from firmware, | ||
32 | * and performs the following actions - | ||
33 | * - Set media status to disconnected | ||
34 | * - Clean up Tx and Rx packets | ||
35 | * - Resets SNR/NF/RSSI value in driver | ||
36 | * - Resets security configurations in driver | ||
37 | * - Enables auto data rate | ||
38 | * - Saves the previous SSID and BSSID so that they can | ||
39 | * be used for re-association, if required | ||
40 | * - Erases current SSID and BSSID information | ||
41 | * - Sends a disconnect event to upper layers/applications. | ||
42 | */ | ||
43 | void | ||
44 | mwifiex_reset_connect_state(struct mwifiex_private *priv) | ||
45 | { | ||
46 | struct mwifiex_adapter *adapter = priv->adapter; | ||
47 | |||
48 | if (!priv->media_connected) | ||
49 | return; | ||
50 | |||
51 | dev_dbg(adapter->dev, "info: handles disconnect event\n"); | ||
52 | |||
53 | priv->media_connected = false; | ||
54 | |||
55 | priv->scan_block = false; | ||
56 | |||
57 | /* Free Tx and Rx packets, report disconnect to upper layer */ | ||
58 | mwifiex_clean_txrx(priv); | ||
59 | |||
60 | /* Reset SNR/NF/RSSI values */ | ||
61 | priv->data_rssi_last = 0; | ||
62 | priv->data_nf_last = 0; | ||
63 | priv->data_rssi_avg = 0; | ||
64 | priv->data_nf_avg = 0; | ||
65 | priv->bcn_rssi_last = 0; | ||
66 | priv->bcn_nf_last = 0; | ||
67 | priv->bcn_rssi_avg = 0; | ||
68 | priv->bcn_nf_avg = 0; | ||
69 | priv->rxpd_rate = 0; | ||
70 | priv->rxpd_htinfo = 0; | ||
71 | priv->sec_info.wpa_enabled = false; | ||
72 | priv->sec_info.wpa2_enabled = false; | ||
73 | priv->wpa_ie_len = 0; | ||
74 | |||
75 | priv->sec_info.wapi_enabled = false; | ||
76 | priv->wapi_ie_len = 0; | ||
77 | priv->sec_info.wapi_key_on = false; | ||
78 | |||
79 | priv->sec_info.encryption_mode = 0; | ||
80 | |||
81 | /* Enable auto data rate */ | ||
82 | priv->is_data_rate_auto = true; | ||
83 | priv->data_rate = 0; | ||
84 | |||
85 | if (priv->bss_mode == NL80211_IFTYPE_ADHOC) { | ||
86 | priv->adhoc_state = ADHOC_IDLE; | ||
87 | priv->adhoc_is_link_sensed = false; | ||
88 | } | ||
89 | |||
90 | /* | ||
91 | * Memorize the previous SSID and BSSID so | ||
92 | * it could be used for re-assoc | ||
93 | */ | ||
94 | |||
95 | dev_dbg(adapter->dev, "info: previous SSID=%s, SSID len=%u\n", | ||
96 | priv->prev_ssid.ssid, priv->prev_ssid.ssid_len); | ||
97 | |||
98 | dev_dbg(adapter->dev, "info: current SSID=%s, SSID len=%u\n", | ||
99 | priv->curr_bss_params.bss_descriptor.ssid.ssid, | ||
100 | priv->curr_bss_params.bss_descriptor.ssid.ssid_len); | ||
101 | |||
102 | memcpy(&priv->prev_ssid, | ||
103 | &priv->curr_bss_params.bss_descriptor.ssid, | ||
104 | sizeof(struct mwifiex_802_11_ssid)); | ||
105 | |||
106 | memcpy(priv->prev_bssid, | ||
107 | priv->curr_bss_params.bss_descriptor.mac_address, ETH_ALEN); | ||
108 | |||
109 | /* Need to erase the current SSID and BSSID info */ | ||
110 | memset(&priv->curr_bss_params, 0x00, sizeof(priv->curr_bss_params)); | ||
111 | |||
112 | adapter->tx_lock_flag = false; | ||
113 | adapter->pps_uapsd_mode = false; | ||
114 | |||
115 | if (adapter->num_cmd_timeout && adapter->curr_cmd) | ||
116 | return; | ||
117 | priv->media_connected = false; | ||
118 | if (!priv->disconnect) { | ||
119 | priv->disconnect = 1; | ||
120 | dev_dbg(adapter->dev, "info: successfully disconnected from" | ||
121 | " %pM: reason code %d\n", priv->cfg_bssid, | ||
122 | WLAN_REASON_DEAUTH_LEAVING); | ||
123 | cfg80211_disconnected(priv->netdev, | ||
124 | WLAN_REASON_DEAUTH_LEAVING, NULL, 0, | ||
125 | GFP_KERNEL); | ||
126 | queue_work(priv->workqueue, &priv->cfg_workqueue); | ||
127 | } | ||
128 | if (!netif_queue_stopped(priv->netdev)) | ||
129 | netif_stop_queue(priv->netdev); | ||
130 | if (netif_carrier_ok(priv->netdev)) | ||
131 | netif_carrier_off(priv->netdev); | ||
132 | /* Reset wireless stats signal info */ | ||
133 | priv->w_stats.qual.level = 0; | ||
134 | priv->w_stats.qual.noise = 0; | ||
135 | } | ||
136 | |||
137 | /* | ||
138 | * This function handles events generated by firmware. | ||
139 | * | ||
140 | * This is a generic function and handles all events. | ||
141 | * | ||
142 | * Event specific routines are called by this function based | ||
143 | * upon the generated event cause. | ||
144 | * | ||
145 | * For the following events, the function just forwards them to upper | ||
146 | * layers, optionally recording the change - | ||
147 | * - EVENT_LINK_SENSED | ||
148 | * - EVENT_MIC_ERR_UNICAST | ||
149 | * - EVENT_MIC_ERR_MULTICAST | ||
150 | * - EVENT_PORT_RELEASE | ||
151 | * - EVENT_RSSI_LOW | ||
152 | * - EVENT_SNR_LOW | ||
153 | * - EVENT_MAX_FAIL | ||
154 | * - EVENT_RSSI_HIGH | ||
155 | * - EVENT_SNR_HIGH | ||
156 | * - EVENT_DATA_RSSI_LOW | ||
157 | * - EVENT_DATA_SNR_LOW | ||
158 | * - EVENT_DATA_RSSI_HIGH | ||
159 | * - EVENT_DATA_SNR_HIGH | ||
160 | * - EVENT_LINK_QUALITY | ||
161 | * - EVENT_PRE_BEACON_LOST | ||
162 | * - EVENT_IBSS_COALESCED | ||
163 | * - EVENT_WEP_ICV_ERR | ||
164 | * - EVENT_BW_CHANGE | ||
165 | * - EVENT_HOSTWAKE_STAIE | ||
166 | * | ||
167 | * For the following events, no action is taken - | ||
168 | * - EVENT_MIB_CHANGED | ||
169 | * - EVENT_INIT_DONE | ||
170 | * - EVENT_DUMMY_HOST_WAKEUP_SIGNAL | ||
171 | * | ||
172 | * Rest of the supported events requires driver handling - | ||
173 | * - EVENT_DEAUTHENTICATED | ||
174 | * - EVENT_DISASSOCIATED | ||
175 | * - EVENT_LINK_LOST | ||
176 | * - EVENT_PS_SLEEP | ||
177 | * - EVENT_PS_AWAKE | ||
178 | * - EVENT_DEEP_SLEEP_AWAKE | ||
179 | * - EVENT_HS_ACT_REQ | ||
180 | * - EVENT_ADHOC_BCN_LOST | ||
181 | * - EVENT_BG_SCAN_REPORT | ||
182 | * - EVENT_WMM_STATUS_CHANGE | ||
183 | * - EVENT_ADDBA | ||
184 | * - EVENT_DELBA | ||
185 | * - EVENT_BA_STREAM_TIEMOUT | ||
186 | * - EVENT_AMSDU_AGGR_CTRL | ||
187 | */ | ||
188 | int mwifiex_process_sta_event(struct mwifiex_private *priv) | ||
189 | { | ||
190 | struct mwifiex_adapter *adapter = priv->adapter; | ||
191 | int ret = 0; | ||
192 | u32 eventcause = adapter->event_cause; | ||
193 | |||
194 | switch (eventcause) { | ||
195 | case EVENT_DUMMY_HOST_WAKEUP_SIGNAL: | ||
196 | dev_err(adapter->dev, "invalid EVENT: DUMMY_HOST_WAKEUP_SIGNAL," | ||
197 | " ignoring it\n"); | ||
198 | break; | ||
199 | case EVENT_LINK_SENSED: | ||
200 | dev_dbg(adapter->dev, "event: LINK_SENSED\n"); | ||
201 | if (!netif_carrier_ok(priv->netdev)) | ||
202 | netif_carrier_on(priv->netdev); | ||
203 | if (netif_queue_stopped(priv->netdev)) | ||
204 | netif_wake_queue(priv->netdev); | ||
205 | break; | ||
206 | |||
207 | case EVENT_DEAUTHENTICATED: | ||
208 | dev_dbg(adapter->dev, "event: Deauthenticated\n"); | ||
209 | adapter->dbg.num_event_deauth++; | ||
210 | if (priv->media_connected) | ||
211 | mwifiex_reset_connect_state(priv); | ||
212 | break; | ||
213 | |||
214 | case EVENT_DISASSOCIATED: | ||
215 | dev_dbg(adapter->dev, "event: Disassociated\n"); | ||
216 | adapter->dbg.num_event_disassoc++; | ||
217 | if (priv->media_connected) | ||
218 | mwifiex_reset_connect_state(priv); | ||
219 | break; | ||
220 | |||
221 | case EVENT_LINK_LOST: | ||
222 | dev_dbg(adapter->dev, "event: Link lost\n"); | ||
223 | adapter->dbg.num_event_link_lost++; | ||
224 | if (priv->media_connected) | ||
225 | mwifiex_reset_connect_state(priv); | ||
226 | break; | ||
227 | |||
228 | case EVENT_PS_SLEEP: | ||
229 | dev_dbg(adapter->dev, "info: EVENT: SLEEP\n"); | ||
230 | |||
231 | adapter->ps_state = PS_STATE_PRE_SLEEP; | ||
232 | |||
233 | mwifiex_check_ps_cond(adapter); | ||
234 | break; | ||
235 | |||
236 | case EVENT_PS_AWAKE: | ||
237 | dev_dbg(adapter->dev, "info: EVENT: AWAKE\n"); | ||
238 | if (!adapter->pps_uapsd_mode && | ||
239 | priv->media_connected && | ||
240 | adapter->sleep_period.period) { | ||
241 | adapter->pps_uapsd_mode = true; | ||
242 | dev_dbg(adapter->dev, | ||
243 | "event: PPS/UAPSD mode activated\n"); | ||
244 | } | ||
245 | adapter->tx_lock_flag = false; | ||
246 | if (adapter->pps_uapsd_mode && adapter->gen_null_pkt) { | ||
247 | if (mwifiex_check_last_packet_indication(priv)) { | ||
248 | if (!adapter->data_sent) { | ||
249 | if (!mwifiex_send_null_packet(priv, | ||
250 | MWIFIEX_TxPD_POWER_MGMT_NULL_PACKET | ||
251 | | | ||
252 | MWIFIEX_TxPD_POWER_MGMT_LAST_PACKET)) | ||
253 | adapter->ps_state = | ||
254 | PS_STATE_SLEEP; | ||
255 | return 0; | ||
256 | } | ||
257 | } | ||
258 | } | ||
259 | adapter->ps_state = PS_STATE_AWAKE; | ||
260 | adapter->pm_wakeup_card_req = false; | ||
261 | adapter->pm_wakeup_fw_try = false; | ||
262 | |||
263 | break; | ||
264 | |||
265 | case EVENT_DEEP_SLEEP_AWAKE: | ||
266 | adapter->if_ops.wakeup_complete(adapter); | ||
267 | dev_dbg(adapter->dev, "event: DS_AWAKE\n"); | ||
268 | if (adapter->is_deep_sleep) | ||
269 | adapter->is_deep_sleep = false; | ||
270 | break; | ||
271 | |||
272 | case EVENT_HS_ACT_REQ: | ||
273 | dev_dbg(adapter->dev, "event: HS_ACT_REQ\n"); | ||
274 | ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_HS_CFG_ENH, | ||
275 | 0, 0, NULL, NULL); | ||
276 | break; | ||
277 | |||
278 | case EVENT_MIC_ERR_UNICAST: | ||
279 | dev_dbg(adapter->dev, "event: UNICAST MIC ERROR\n"); | ||
280 | break; | ||
281 | |||
282 | case EVENT_MIC_ERR_MULTICAST: | ||
283 | dev_dbg(adapter->dev, "event: MULTICAST MIC ERROR\n"); | ||
284 | break; | ||
285 | case EVENT_MIB_CHANGED: | ||
286 | case EVENT_INIT_DONE: | ||
287 | break; | ||
288 | |||
289 | case EVENT_ADHOC_BCN_LOST: | ||
290 | dev_dbg(adapter->dev, "event: ADHOC_BCN_LOST\n"); | ||
291 | priv->adhoc_is_link_sensed = false; | ||
292 | mwifiex_clean_txrx(priv); | ||
293 | if (!netif_queue_stopped(priv->netdev)) | ||
294 | netif_stop_queue(priv->netdev); | ||
295 | if (netif_carrier_ok(priv->netdev)) | ||
296 | netif_carrier_off(priv->netdev); | ||
297 | break; | ||
298 | |||
299 | case EVENT_BG_SCAN_REPORT: | ||
300 | dev_dbg(adapter->dev, "event: BGS_REPORT\n"); | ||
301 | /* Clear the previous scan result */ | ||
302 | memset(adapter->scan_table, 0x00, | ||
303 | sizeof(struct mwifiex_bssdescriptor) * IW_MAX_AP); | ||
304 | adapter->num_in_scan_table = 0; | ||
305 | adapter->bcn_buf_end = adapter->bcn_buf; | ||
306 | ret = mwifiex_prepare_cmd(priv, | ||
307 | HostCmd_CMD_802_11_BG_SCAN_QUERY, | ||
308 | HostCmd_ACT_GEN_GET, 0, NULL, NULL); | ||
309 | break; | ||
310 | |||
311 | case EVENT_PORT_RELEASE: | ||
312 | dev_dbg(adapter->dev, "event: PORT RELEASE\n"); | ||
313 | break; | ||
314 | |||
315 | case EVENT_WMM_STATUS_CHANGE: | ||
316 | dev_dbg(adapter->dev, "event: WMM status changed\n"); | ||
317 | ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_WMM_GET_STATUS, | ||
318 | 0, 0, NULL, NULL); | ||
319 | break; | ||
320 | |||
321 | case EVENT_RSSI_LOW: | ||
322 | dev_dbg(adapter->dev, "event: Beacon RSSI_LOW\n"); | ||
323 | break; | ||
324 | case EVENT_SNR_LOW: | ||
325 | dev_dbg(adapter->dev, "event: Beacon SNR_LOW\n"); | ||
326 | break; | ||
327 | case EVENT_MAX_FAIL: | ||
328 | dev_dbg(adapter->dev, "event: MAX_FAIL\n"); | ||
329 | break; | ||
330 | case EVENT_RSSI_HIGH: | ||
331 | dev_dbg(adapter->dev, "event: Beacon RSSI_HIGH\n"); | ||
332 | break; | ||
333 | case EVENT_SNR_HIGH: | ||
334 | dev_dbg(adapter->dev, "event: Beacon SNR_HIGH\n"); | ||
335 | break; | ||
336 | case EVENT_DATA_RSSI_LOW: | ||
337 | dev_dbg(adapter->dev, "event: Data RSSI_LOW\n"); | ||
338 | break; | ||
339 | case EVENT_DATA_SNR_LOW: | ||
340 | dev_dbg(adapter->dev, "event: Data SNR_LOW\n"); | ||
341 | break; | ||
342 | case EVENT_DATA_RSSI_HIGH: | ||
343 | dev_dbg(adapter->dev, "event: Data RSSI_HIGH\n"); | ||
344 | break; | ||
345 | case EVENT_DATA_SNR_HIGH: | ||
346 | dev_dbg(adapter->dev, "event: Data SNR_HIGH\n"); | ||
347 | break; | ||
348 | case EVENT_LINK_QUALITY: | ||
349 | dev_dbg(adapter->dev, "event: Link Quality\n"); | ||
350 | break; | ||
351 | case EVENT_PRE_BEACON_LOST: | ||
352 | dev_dbg(adapter->dev, "event: Pre-Beacon Lost\n"); | ||
353 | break; | ||
354 | case EVENT_IBSS_COALESCED: | ||
355 | dev_dbg(adapter->dev, "event: IBSS_COALESCED\n"); | ||
356 | ret = mwifiex_prepare_cmd(priv, | ||
357 | HostCmd_CMD_802_11_IBSS_COALESCING_STATUS, | ||
358 | HostCmd_ACT_GEN_GET, 0, NULL, NULL); | ||
359 | break; | ||
360 | case EVENT_ADDBA: | ||
361 | dev_dbg(adapter->dev, "event: ADDBA Request\n"); | ||
362 | mwifiex_prepare_cmd(priv, HostCmd_CMD_11N_ADDBA_RSP, | ||
363 | HostCmd_ACT_GEN_SET, 0, NULL, | ||
364 | adapter->event_body); | ||
365 | break; | ||
366 | case EVENT_DELBA: | ||
367 | dev_dbg(adapter->dev, "event: DELBA Request\n"); | ||
368 | mwifiex_11n_delete_ba_stream(priv, adapter->event_body); | ||
369 | break; | ||
370 | case EVENT_BA_STREAM_TIEMOUT: | ||
371 | dev_dbg(adapter->dev, "event: BA Stream timeout\n"); | ||
372 | mwifiex_11n_ba_stream_timeout(priv, | ||
373 | (struct host_cmd_ds_11n_batimeout | ||
374 | *) | ||
375 | adapter->event_body); | ||
376 | break; | ||
377 | case EVENT_AMSDU_AGGR_CTRL: | ||
378 | dev_dbg(adapter->dev, "event: AMSDU_AGGR_CTRL %d\n", | ||
379 | *(u16 *) adapter->event_body); | ||
380 | adapter->tx_buf_size = | ||
381 | min(adapter->curr_tx_buf_size, | ||
382 | le16_to_cpu(*(__le16 *) adapter->event_body)); | ||
383 | dev_dbg(adapter->dev, "event: tx_buf_size %d\n", | ||
384 | adapter->tx_buf_size); | ||
385 | break; | ||
386 | |||
387 | case EVENT_WEP_ICV_ERR: | ||
388 | dev_dbg(adapter->dev, "event: WEP ICV error\n"); | ||
389 | break; | ||
390 | |||
391 | case EVENT_BW_CHANGE: | ||
392 | dev_dbg(adapter->dev, "event: BW Change\n"); | ||
393 | break; | ||
394 | |||
395 | case EVENT_HOSTWAKE_STAIE: | ||
396 | dev_dbg(adapter->dev, "event: HOSTWAKE_STAIE %d\n", eventcause); | ||
397 | break; | ||
398 | default: | ||
399 | dev_dbg(adapter->dev, "event: unknown event id: %#x\n", | ||
400 | eventcause); | ||
401 | break; | ||
402 | } | ||
403 | |||
404 | return ret; | ||
405 | } | ||
diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c new file mode 100644 index 000000000000..b163507b1fe0 --- /dev/null +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c | |||
@@ -0,0 +1,2360 @@ | |||
1 | /* | ||
2 | * Marvell Wireless LAN device driver: functions for station ioctl | ||
3 | * | ||
4 | * Copyright (C) 2011, Marvell International Ltd. | ||
5 | * | ||
6 | * This software file (the "File") is distributed by Marvell International | ||
7 | * Ltd. under the terms of the GNU General Public License Version 2, June 1991 | ||
8 | * (the "License"). You may use, redistribute and/or modify this File in | ||
9 | * accordance with the terms and conditions of the License, a copy of which | ||
10 | * is available by writing to the Free Software Foundation, Inc., | ||
11 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the | ||
12 | * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. | ||
13 | * | ||
14 | * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE | ||
15 | * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE | ||
16 | * ARE EXPRESSLY DISCLAIMED. The License provides additional details about | ||
17 | * this warranty disclaimer. | ||
18 | */ | ||
19 | |||
20 | #include "decl.h" | ||
21 | #include "ioctl.h" | ||
22 | #include "util.h" | ||
23 | #include "fw.h" | ||
24 | #include "main.h" | ||
25 | #include "wmm.h" | ||
26 | #include "11n.h" | ||
27 | #include "cfg80211.h" | ||
28 | |||
29 | /* | ||
30 | * Copies the multicast address list from device to driver. | ||
31 | * | ||
32 | * This function does not validate the destination memory for | ||
33 | * size, and the calling function must ensure enough memory is | ||
34 | * available. | ||
35 | */ | ||
36 | static int | ||
37 | mwifiex_copy_mcast_addr(struct mwifiex_multicast_list *mlist, | ||
38 | struct net_device *dev) | ||
39 | { | ||
40 | int i = 0; | ||
41 | struct netdev_hw_addr *ha; | ||
42 | |||
43 | netdev_for_each_mc_addr(ha, dev) | ||
44 | memcpy(&mlist->mac_list[i++], ha->addr, ETH_ALEN); | ||
45 | |||
46 | return i; | ||
47 | } | ||
48 | |||
49 | /* | ||
50 | * Allocate and fills a wait queue with proper parameters. | ||
51 | * | ||
52 | * This function needs to be called before an IOCTL request can be made. | ||
53 | * It can handle the following wait options: | ||
54 | * MWIFIEX_NO_WAIT - Waiting is disabled | ||
55 | * MWIFIEX_IOCTL_WAIT - Waiting is done on IOCTL wait queue | ||
56 | * MWIFIEX_CMD_WAIT - Waiting is done on command wait queue | ||
57 | * MWIFIEX_WSTATS_WAIT - Waiting is done on stats wait queue | ||
58 | */ | ||
59 | struct mwifiex_wait_queue * | ||
60 | mwifiex_alloc_fill_wait_queue(struct mwifiex_private *priv, | ||
61 | u8 wait_option) | ||
62 | { | ||
63 | struct mwifiex_wait_queue *wait = NULL; | ||
64 | |||
65 | wait = (struct mwifiex_wait_queue *) | ||
66 | kzalloc(sizeof(struct mwifiex_wait_queue), GFP_ATOMIC); | ||
67 | if (!wait) { | ||
68 | dev_err(priv->adapter->dev, "%s: fail to alloc buffer\n", | ||
69 | __func__); | ||
70 | return wait; | ||
71 | } | ||
72 | |||
73 | wait->bss_index = priv->bss_index; | ||
74 | |||
75 | switch (wait_option) { | ||
76 | case MWIFIEX_NO_WAIT: | ||
77 | wait->enabled = 0; | ||
78 | break; | ||
79 | case MWIFIEX_IOCTL_WAIT: | ||
80 | priv->ioctl_wait_q_woken = false; | ||
81 | wait->start_time = jiffies; | ||
82 | wait->wait = &priv->ioctl_wait_q; | ||
83 | wait->condition = &priv->ioctl_wait_q_woken; | ||
84 | wait->enabled = 1; | ||
85 | break; | ||
86 | case MWIFIEX_CMD_WAIT: | ||
87 | priv->cmd_wait_q_woken = false; | ||
88 | wait->start_time = jiffies; | ||
89 | wait->wait = &priv->cmd_wait_q; | ||
90 | wait->condition = &priv->cmd_wait_q_woken; | ||
91 | wait->enabled = 1; | ||
92 | break; | ||
93 | case MWIFIEX_WSTATS_WAIT: | ||
94 | priv->w_stats_wait_q_woken = false; | ||
95 | wait->start_time = jiffies; | ||
96 | wait->wait = &priv->w_stats_wait_q; | ||
97 | wait->condition = &priv->w_stats_wait_q_woken; | ||
98 | wait->enabled = 1; | ||
99 | break; | ||
100 | } | ||
101 | |||
102 | return wait; | ||
103 | } | ||
104 | |||
105 | /* | ||
106 | * Wait queue completion handler. | ||
107 | * | ||
108 | * This function waits on a particular wait queue. | ||
109 | * For NO_WAIT option, it returns immediately. It also cancels the | ||
110 | * pending IOCTL request after waking up, in case of errors. | ||
111 | */ | ||
112 | static void | ||
113 | mwifiex_wait_ioctl_complete(struct mwifiex_private *priv, | ||
114 | struct mwifiex_wait_queue *wait, | ||
115 | u8 wait_option) | ||
116 | { | ||
117 | bool cancel_flag = false; | ||
118 | |||
119 | switch (wait_option) { | ||
120 | case MWIFIEX_NO_WAIT: | ||
121 | break; | ||
122 | case MWIFIEX_IOCTL_WAIT: | ||
123 | wait_event_interruptible(priv->ioctl_wait_q, | ||
124 | priv->ioctl_wait_q_woken); | ||
125 | if (!priv->ioctl_wait_q_woken) | ||
126 | cancel_flag = true; | ||
127 | break; | ||
128 | case MWIFIEX_CMD_WAIT: | ||
129 | wait_event_interruptible(priv->cmd_wait_q, | ||
130 | priv->cmd_wait_q_woken); | ||
131 | if (!priv->cmd_wait_q_woken) | ||
132 | cancel_flag = true; | ||
133 | break; | ||
134 | case MWIFIEX_WSTATS_WAIT: | ||
135 | wait_event_interruptible(priv->w_stats_wait_q, | ||
136 | priv->w_stats_wait_q_woken); | ||
137 | if (!priv->w_stats_wait_q_woken) | ||
138 | cancel_flag = true; | ||
139 | break; | ||
140 | } | ||
141 | if (cancel_flag) { | ||
142 | mwifiex_cancel_pending_ioctl(priv->adapter, wait); | ||
143 | dev_dbg(priv->adapter->dev, "cmd: IOCTL cancel: wait=%p, wait_option=%d\n", | ||
144 | wait, wait_option); | ||
145 | } | ||
146 | |||
147 | return; | ||
148 | } | ||
149 | |||
150 | /* | ||
151 | * The function waits for the request to complete and issues the | ||
152 | * completion handler, if required. | ||
153 | */ | ||
154 | int mwifiex_request_ioctl(struct mwifiex_private *priv, | ||
155 | struct mwifiex_wait_queue *wait, | ||
156 | int status, u8 wait_option) | ||
157 | { | ||
158 | switch (status) { | ||
159 | case -EINPROGRESS: | ||
160 | dev_dbg(priv->adapter->dev, "cmd: IOCTL pending: wait=%p, wait_option=%d\n", | ||
161 | wait, wait_option); | ||
162 | atomic_inc(&priv->adapter->ioctl_pending); | ||
163 | /* Status pending, wake up main process */ | ||
164 | queue_work(priv->adapter->workqueue, &priv->adapter->main_work); | ||
165 | |||
166 | /* Wait for completion */ | ||
167 | if (wait_option) { | ||
168 | mwifiex_wait_ioctl_complete(priv, wait, wait_option); | ||
169 | status = wait->status; | ||
170 | } | ||
171 | break; | ||
172 | case 0: | ||
173 | case -1: | ||
174 | case -EBUSY: | ||
175 | default: | ||
176 | break; | ||
177 | } | ||
178 | return status; | ||
179 | } | ||
180 | EXPORT_SYMBOL_GPL(mwifiex_request_ioctl); | ||
181 | |||
182 | /* | ||
183 | * IOCTL request handler to set/get MAC address. | ||
184 | * | ||
185 | * This function prepares the correct firmware command and | ||
186 | * issues it to get the extended version information. | ||
187 | */ | ||
188 | static int mwifiex_bss_ioctl_mac_address(struct mwifiex_private *priv, | ||
189 | struct mwifiex_wait_queue *wait, | ||
190 | u8 action, u8 *mac) | ||
191 | { | ||
192 | int ret = 0; | ||
193 | |||
194 | if ((action == HostCmd_ACT_GEN_GET) && mac) { | ||
195 | memcpy(mac, priv->curr_addr, ETH_ALEN); | ||
196 | return 0; | ||
197 | } | ||
198 | |||
199 | /* Send request to firmware */ | ||
200 | ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_MAC_ADDRESS, | ||
201 | action, 0, wait, mac); | ||
202 | if (!ret) | ||
203 | ret = -EINPROGRESS; | ||
204 | |||
205 | return ret; | ||
206 | } | ||
207 | |||
208 | /* | ||
209 | * Sends IOCTL request to set MAC address. | ||
210 | * | ||
211 | * This function allocates the IOCTL request buffer, fills it | ||
212 | * with requisite parameters and calls the IOCTL handler. | ||
213 | */ | ||
214 | int mwifiex_request_set_mac_address(struct mwifiex_private *priv) | ||
215 | { | ||
216 | struct mwifiex_wait_queue *wait = NULL; | ||
217 | int status = 0; | ||
218 | u8 wait_option = MWIFIEX_CMD_WAIT; | ||
219 | |||
220 | /* Allocate wait buffer */ | ||
221 | wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); | ||
222 | if (!wait) | ||
223 | return -ENOMEM; | ||
224 | |||
225 | status = mwifiex_bss_ioctl_mac_address(priv, wait, HostCmd_ACT_GEN_SET, | ||
226 | NULL); | ||
227 | |||
228 | status = mwifiex_request_ioctl(priv, wait, status, wait_option); | ||
229 | if (!status) | ||
230 | memcpy(priv->netdev->dev_addr, priv->curr_addr, ETH_ALEN); | ||
231 | else | ||
232 | dev_err(priv->adapter->dev, "set mac address failed: status=%d" | ||
233 | " error_code=%#x\n", status, wait->status); | ||
234 | |||
235 | kfree(wait); | ||
236 | return status; | ||
237 | } | ||
238 | |||
239 | /* | ||
240 | * IOCTL request handler to set multicast list. | ||
241 | * | ||
242 | * This function prepares the correct firmware command and | ||
243 | * issues it to set the multicast list. | ||
244 | * | ||
245 | * This function can be used to enable promiscuous mode, or enable all | ||
246 | * multicast packets, or to enable selective multicast. | ||
247 | */ | ||
248 | static int | ||
249 | mwifiex_bss_ioctl_multicast_list(struct mwifiex_private *priv, | ||
250 | struct mwifiex_wait_queue *wait, | ||
251 | u16 action, | ||
252 | struct mwifiex_multicast_list *mcast_list) | ||
253 | { | ||
254 | int ret = 0; | ||
255 | u16 old_pkt_filter; | ||
256 | |||
257 | old_pkt_filter = priv->curr_pkt_filter; | ||
258 | if (action == HostCmd_ACT_GEN_GET) | ||
259 | return -1; | ||
260 | |||
261 | if (mcast_list->mode == MWIFIEX_PROMISC_MODE) { | ||
262 | dev_dbg(priv->adapter->dev, "info: Enable Promiscuous mode\n"); | ||
263 | priv->curr_pkt_filter |= HostCmd_ACT_MAC_PROMISCUOUS_ENABLE; | ||
264 | priv->curr_pkt_filter &= | ||
265 | ~HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE; | ||
266 | } else { | ||
267 | /* Multicast */ | ||
268 | priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_PROMISCUOUS_ENABLE; | ||
269 | if (mcast_list->mode == MWIFIEX_MULTICAST_MODE) { | ||
270 | dev_dbg(priv->adapter->dev, | ||
271 | "info: Enabling All Multicast!\n"); | ||
272 | priv->curr_pkt_filter |= | ||
273 | HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE; | ||
274 | } else { | ||
275 | priv->curr_pkt_filter &= | ||
276 | ~HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE; | ||
277 | if (mcast_list->num_multicast_addr) { | ||
278 | dev_dbg(priv->adapter->dev, | ||
279 | "info: Set multicast list=%d\n", | ||
280 | mcast_list->num_multicast_addr); | ||
281 | /* Set multicast addresses to firmware */ | ||
282 | if (old_pkt_filter == priv->curr_pkt_filter) { | ||
283 | /* Send request to firmware */ | ||
284 | ret = mwifiex_prepare_cmd(priv, | ||
285 | HostCmd_CMD_MAC_MULTICAST_ADR, | ||
286 | action, 0, wait, mcast_list); | ||
287 | if (!ret) | ||
288 | ret = -EINPROGRESS; | ||
289 | } else { | ||
290 | /* Send request to firmware */ | ||
291 | ret = mwifiex_prepare_cmd(priv, | ||
292 | HostCmd_CMD_MAC_MULTICAST_ADR, | ||
293 | action, 0, NULL, | ||
294 | mcast_list); | ||
295 | } | ||
296 | } | ||
297 | } | ||
298 | } | ||
299 | dev_dbg(priv->adapter->dev, | ||
300 | "info: old_pkt_filter=%#x, curr_pkt_filter=%#x\n", | ||
301 | old_pkt_filter, priv->curr_pkt_filter); | ||
302 | if (old_pkt_filter != priv->curr_pkt_filter) { | ||
303 | ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_MAC_CONTROL, action, | ||
304 | 0, wait, &priv->curr_pkt_filter); | ||
305 | if (!ret) | ||
306 | ret = -EINPROGRESS; | ||
307 | } | ||
308 | |||
309 | return ret; | ||
310 | } | ||
311 | |||
312 | /* | ||
313 | * Sends IOCTL request to set multicast list. | ||
314 | * | ||
315 | * This function allocates the IOCTL request buffer, fills it | ||
316 | * with requisite parameters and calls the IOCTL handler. | ||
317 | */ | ||
318 | void | ||
319 | mwifiex_request_set_multicast_list(struct mwifiex_private *priv, | ||
320 | struct net_device *dev) | ||
321 | { | ||
322 | struct mwifiex_wait_queue *wait = NULL; | ||
323 | struct mwifiex_multicast_list mcast_list; | ||
324 | u8 wait_option = MWIFIEX_NO_WAIT; | ||
325 | int status = 0; | ||
326 | |||
327 | /* Allocate wait buffer */ | ||
328 | wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); | ||
329 | if (!wait) | ||
330 | return; | ||
331 | |||
332 | if (dev->flags & IFF_PROMISC) { | ||
333 | mcast_list.mode = MWIFIEX_PROMISC_MODE; | ||
334 | } else if (dev->flags & IFF_ALLMULTI || | ||
335 | netdev_mc_count(dev) > MWIFIEX_MAX_MULTICAST_LIST_SIZE) { | ||
336 | mcast_list.mode = MWIFIEX_ALL_MULTI_MODE; | ||
337 | } else { | ||
338 | mcast_list.mode = MWIFIEX_MULTICAST_MODE; | ||
339 | if (netdev_mc_count(dev)) | ||
340 | mcast_list.num_multicast_addr = | ||
341 | mwifiex_copy_mcast_addr(&mcast_list, dev); | ||
342 | } | ||
343 | status = mwifiex_bss_ioctl_multicast_list(priv, wait, | ||
344 | HostCmd_ACT_GEN_SET, | ||
345 | &mcast_list); | ||
346 | |||
347 | status = mwifiex_request_ioctl(priv, wait, status, wait_option); | ||
348 | if (wait && status != -EINPROGRESS) | ||
349 | kfree(wait); | ||
350 | |||
351 | return; | ||
352 | } | ||
353 | |||
354 | /* | ||
355 | * IOCTL request handler to disconnect from a BSS/IBSS. | ||
356 | */ | ||
357 | static int mwifiex_bss_ioctl_stop(struct mwifiex_private *priv, | ||
358 | struct mwifiex_wait_queue *wait, u8 *mac) | ||
359 | { | ||
360 | return mwifiex_deauthenticate(priv, wait, mac); | ||
361 | } | ||
362 | |||
363 | /* | ||
364 | * Sends IOCTL request to disconnect from a BSS. | ||
365 | * | ||
366 | * This function allocates the IOCTL request buffer, fills it | ||
367 | * with requisite parameters and calls the IOCTL handler. | ||
368 | */ | ||
369 | int mwifiex_disconnect(struct mwifiex_private *priv, u8 wait_option, u8 *mac) | ||
370 | { | ||
371 | struct mwifiex_wait_queue *wait = NULL; | ||
372 | int status = 0; | ||
373 | |||
374 | /* Allocate wait buffer */ | ||
375 | wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); | ||
376 | if (!wait) | ||
377 | return -ENOMEM; | ||
378 | |||
379 | status = mwifiex_bss_ioctl_stop(priv, wait, mac); | ||
380 | |||
381 | status = mwifiex_request_ioctl(priv, wait, status, wait_option); | ||
382 | |||
383 | kfree(wait); | ||
384 | return status; | ||
385 | } | ||
386 | EXPORT_SYMBOL_GPL(mwifiex_disconnect); | ||
387 | |||
388 | /* | ||
389 | * IOCTL request handler to join a BSS/IBSS. | ||
390 | * | ||
391 | * In Ad-Hoc mode, the IBSS is created if not found in scan list. | ||
392 | * In both Ad-Hoc and infra mode, an deauthentication is performed | ||
393 | * first. | ||
394 | */ | ||
395 | static int mwifiex_bss_ioctl_start(struct mwifiex_private *priv, | ||
396 | struct mwifiex_wait_queue *wait, | ||
397 | struct mwifiex_ssid_bssid *ssid_bssid) | ||
398 | { | ||
399 | int ret = 0; | ||
400 | struct mwifiex_adapter *adapter = priv->adapter; | ||
401 | s32 i = -1; | ||
402 | |||
403 | priv->scan_block = false; | ||
404 | if (!ssid_bssid) | ||
405 | return -1; | ||
406 | |||
407 | if (priv->bss_mode == NL80211_IFTYPE_STATION) { | ||
408 | /* Infra mode */ | ||
409 | ret = mwifiex_deauthenticate(priv, NULL, NULL); | ||
410 | if (ret) | ||
411 | return ret; | ||
412 | |||
413 | /* Search for the requested SSID in the scan table */ | ||
414 | if (ssid_bssid->ssid.ssid_len) | ||
415 | i = mwifiex_find_ssid_in_list(priv, &ssid_bssid->ssid, | ||
416 | NULL, NL80211_IFTYPE_STATION); | ||
417 | else | ||
418 | i = mwifiex_find_bssid_in_list(priv, | ||
419 | (u8 *) &ssid_bssid->bssid, | ||
420 | NL80211_IFTYPE_STATION); | ||
421 | if (i < 0) | ||
422 | return -1; | ||
423 | |||
424 | dev_dbg(adapter->dev, | ||
425 | "info: SSID found in scan list ... associating...\n"); | ||
426 | |||
427 | /* Clear any past association response stored for | ||
428 | * application retrieval */ | ||
429 | priv->assoc_rsp_size = 0; | ||
430 | ret = mwifiex_associate(priv, wait, &adapter->scan_table[i]); | ||
431 | if (ret) | ||
432 | return ret; | ||
433 | } else { | ||
434 | /* Adhoc mode */ | ||
435 | /* If the requested SSID matches current SSID, return */ | ||
436 | if (ssid_bssid->ssid.ssid_len && | ||
437 | (!mwifiex_ssid_cmp | ||
438 | (&priv->curr_bss_params.bss_descriptor.ssid, | ||
439 | &ssid_bssid->ssid))) | ||
440 | return 0; | ||
441 | |||
442 | /* Exit Adhoc mode first */ | ||
443 | dev_dbg(adapter->dev, "info: Sending Adhoc Stop\n"); | ||
444 | ret = mwifiex_deauthenticate(priv, NULL, NULL); | ||
445 | if (ret) | ||
446 | return ret; | ||
447 | |||
448 | priv->adhoc_is_link_sensed = false; | ||
449 | |||
450 | /* Search for the requested network in the scan table */ | ||
451 | if (ssid_bssid->ssid.ssid_len) | ||
452 | i = mwifiex_find_ssid_in_list(priv, | ||
453 | &ssid_bssid->ssid, NULL, | ||
454 | NL80211_IFTYPE_ADHOC); | ||
455 | else | ||
456 | i = mwifiex_find_bssid_in_list(priv, | ||
457 | (u8 *)&ssid_bssid->bssid, | ||
458 | NL80211_IFTYPE_ADHOC); | ||
459 | |||
460 | if (i >= 0) { | ||
461 | dev_dbg(adapter->dev, "info: network found in scan" | ||
462 | " list. Joining...\n"); | ||
463 | ret = mwifiex_adhoc_join(priv, wait, | ||
464 | &adapter->scan_table[i]); | ||
465 | if (ret) | ||
466 | return ret; | ||
467 | } else { /* i >= 0 */ | ||
468 | dev_dbg(adapter->dev, "info: Network not found in " | ||
469 | "the list, creating adhoc with ssid = %s\n", | ||
470 | ssid_bssid->ssid.ssid); | ||
471 | ret = mwifiex_adhoc_start(priv, wait, | ||
472 | &ssid_bssid->ssid); | ||
473 | if (ret) | ||
474 | return ret; | ||
475 | } | ||
476 | } | ||
477 | |||
478 | if (!ret) | ||
479 | ret = -EINPROGRESS; | ||
480 | |||
481 | return ret; | ||
482 | } | ||
483 | |||
484 | /* | ||
485 | * Sends IOCTL request to connect with a BSS. | ||
486 | * | ||
487 | * This function allocates the IOCTL request buffer, fills it | ||
488 | * with requisite parameters and calls the IOCTL handler. | ||
489 | */ | ||
490 | int mwifiex_bss_start(struct mwifiex_private *priv, u8 wait_option, | ||
491 | struct mwifiex_ssid_bssid *ssid_bssid) | ||
492 | { | ||
493 | struct mwifiex_wait_queue *wait = NULL; | ||
494 | struct mwifiex_ssid_bssid tmp_ssid_bssid; | ||
495 | int status = 0; | ||
496 | |||
497 | /* Stop the O.S. TX queue if needed */ | ||
498 | if (!netif_queue_stopped(priv->netdev)) | ||
499 | netif_stop_queue(priv->netdev); | ||
500 | |||
501 | /* Allocate wait buffer */ | ||
502 | wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); | ||
503 | if (!wait) | ||
504 | return -ENOMEM; | ||
505 | |||
506 | if (ssid_bssid) | ||
507 | memcpy(&tmp_ssid_bssid, ssid_bssid, | ||
508 | sizeof(struct mwifiex_ssid_bssid)); | ||
509 | status = mwifiex_bss_ioctl_start(priv, wait, &tmp_ssid_bssid); | ||
510 | |||
511 | status = mwifiex_request_ioctl(priv, wait, status, wait_option); | ||
512 | |||
513 | kfree(wait); | ||
514 | return status; | ||
515 | } | ||
516 | |||
517 | /* | ||
518 | * IOCTL request handler to set host sleep configuration. | ||
519 | * | ||
520 | * This function prepares the correct firmware command and | ||
521 | * issues it. | ||
522 | */ | ||
523 | static int | ||
524 | mwifiex_pm_ioctl_hs_cfg(struct mwifiex_private *priv, | ||
525 | struct mwifiex_wait_queue *wait, | ||
526 | u16 action, struct mwifiex_ds_hs_cfg *hs_cfg) | ||
527 | { | ||
528 | struct mwifiex_adapter *adapter = priv->adapter; | ||
529 | int status = 0; | ||
530 | u32 prev_cond = 0; | ||
531 | |||
532 | switch (action) { | ||
533 | case HostCmd_ACT_GEN_SET: | ||
534 | if (adapter->pps_uapsd_mode) { | ||
535 | dev_dbg(adapter->dev, "info: Host Sleep IOCTL" | ||
536 | " is blocked in UAPSD/PPS mode\n"); | ||
537 | status = -1; | ||
538 | break; | ||
539 | } | ||
540 | if (hs_cfg->is_invoke_hostcmd) { | ||
541 | if (hs_cfg->conditions == HOST_SLEEP_CFG_CANCEL) { | ||
542 | if (!adapter->is_hs_configured) | ||
543 | /* Already cancelled */ | ||
544 | break; | ||
545 | /* Save previous condition */ | ||
546 | prev_cond = le32_to_cpu(adapter->hs_cfg | ||
547 | .conditions); | ||
548 | adapter->hs_cfg.conditions = | ||
549 | cpu_to_le32(hs_cfg->conditions); | ||
550 | } else if (hs_cfg->conditions) { | ||
551 | adapter->hs_cfg.conditions = | ||
552 | cpu_to_le32(hs_cfg->conditions); | ||
553 | adapter->hs_cfg.gpio = (u8)hs_cfg->gpio; | ||
554 | if (hs_cfg->gap) | ||
555 | adapter->hs_cfg.gap = (u8)hs_cfg->gap; | ||
556 | } else if (adapter->hs_cfg.conditions == | ||
557 | cpu_to_le32( | ||
558 | HOST_SLEEP_CFG_CANCEL)) { | ||
559 | /* Return failure if no parameters for HS | ||
560 | enable */ | ||
561 | status = -1; | ||
562 | break; | ||
563 | } | ||
564 | status = mwifiex_prepare_cmd(priv, | ||
565 | HostCmd_CMD_802_11_HS_CFG_ENH, | ||
566 | HostCmd_ACT_GEN_SET, | ||
567 | 0, wait, &adapter->hs_cfg); | ||
568 | if (!status) | ||
569 | status = -EINPROGRESS; | ||
570 | if (hs_cfg->conditions == HOST_SLEEP_CFG_CANCEL) | ||
571 | /* Restore previous condition */ | ||
572 | adapter->hs_cfg.conditions = | ||
573 | cpu_to_le32(prev_cond); | ||
574 | } else { | ||
575 | adapter->hs_cfg.conditions = | ||
576 | cpu_to_le32(hs_cfg->conditions); | ||
577 | adapter->hs_cfg.gpio = (u8)hs_cfg->gpio; | ||
578 | adapter->hs_cfg.gap = (u8)hs_cfg->gap; | ||
579 | } | ||
580 | break; | ||
581 | case HostCmd_ACT_GEN_GET: | ||
582 | hs_cfg->conditions = le32_to_cpu(adapter->hs_cfg.conditions); | ||
583 | hs_cfg->gpio = adapter->hs_cfg.gpio; | ||
584 | hs_cfg->gap = adapter->hs_cfg.gap; | ||
585 | break; | ||
586 | default: | ||
587 | status = -1; | ||
588 | break; | ||
589 | } | ||
590 | |||
591 | return status; | ||
592 | } | ||
593 | |||
594 | /* | ||
595 | * Sends IOCTL request to set Host Sleep parameters. | ||
596 | * | ||
597 | * This function allocates the IOCTL request buffer, fills it | ||
598 | * with requisite parameters and calls the IOCTL handler. | ||
599 | */ | ||
600 | int mwifiex_set_hs_params(struct mwifiex_private *priv, u16 action, | ||
601 | u8 wait_option, | ||
602 | struct mwifiex_ds_hs_cfg *hscfg) | ||
603 | { | ||
604 | int ret = 0; | ||
605 | struct mwifiex_wait_queue *wait = NULL; | ||
606 | |||
607 | if (!hscfg) | ||
608 | return -ENOMEM; | ||
609 | |||
610 | /* Allocate wait buffer */ | ||
611 | wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); | ||
612 | if (!wait) | ||
613 | return -ENOMEM; | ||
614 | |||
615 | ret = mwifiex_pm_ioctl_hs_cfg(priv, wait, action, hscfg); | ||
616 | |||
617 | ret = mwifiex_request_ioctl(priv, wait, ret, wait_option); | ||
618 | |||
619 | if (wait && (ret != -EINPROGRESS)) | ||
620 | kfree(wait); | ||
621 | return ret; | ||
622 | } | ||
623 | |||
624 | /* | ||
625 | * Sends IOCTL request to cancel the existing Host Sleep configuration. | ||
626 | * | ||
627 | * This function allocates the IOCTL request buffer, fills it | ||
628 | * with requisite parameters and calls the IOCTL handler. | ||
629 | */ | ||
630 | int mwifiex_cancel_hs(struct mwifiex_private *priv, u8 wait_option) | ||
631 | { | ||
632 | int ret = 0; | ||
633 | struct mwifiex_ds_hs_cfg hscfg; | ||
634 | |||
635 | /* Cancel Host Sleep */ | ||
636 | hscfg.conditions = HOST_SLEEP_CFG_CANCEL; | ||
637 | hscfg.is_invoke_hostcmd = true; | ||
638 | ret = mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_SET, | ||
639 | wait_option, &hscfg); | ||
640 | |||
641 | return ret; | ||
642 | } | ||
643 | EXPORT_SYMBOL_GPL(mwifiex_cancel_hs); | ||
644 | |||
645 | /* | ||
646 | * Sends IOCTL request to cancel the existing Host Sleep configuration. | ||
647 | * | ||
648 | * This function allocates the IOCTL request buffer, fills it | ||
649 | * with requisite parameters and calls the IOCTL handler. | ||
650 | */ | ||
651 | int mwifiex_enable_hs(struct mwifiex_adapter *adapter) | ||
652 | { | ||
653 | struct mwifiex_ds_hs_cfg hscfg; | ||
654 | |||
655 | if (adapter->hs_activated) { | ||
656 | dev_dbg(adapter->dev, "cmd: HS Already actived\n"); | ||
657 | return true; | ||
658 | } | ||
659 | |||
660 | /* Enable Host Sleep */ | ||
661 | adapter->hs_activate_wait_q_woken = false; | ||
662 | |||
663 | memset(&hscfg, 0, sizeof(struct mwifiex_hs_config_param)); | ||
664 | hscfg.is_invoke_hostcmd = true; | ||
665 | |||
666 | if (mwifiex_set_hs_params(mwifiex_get_priv(adapter, | ||
667 | MWIFIEX_BSS_ROLE_STA), | ||
668 | HostCmd_ACT_GEN_SET, | ||
669 | MWIFIEX_IOCTL_WAIT, &hscfg)) { | ||
670 | dev_err(adapter->dev, "IOCTL request HS enable failed\n"); | ||
671 | return false; | ||
672 | } | ||
673 | |||
674 | wait_event_interruptible(adapter->hs_activate_wait_q, | ||
675 | adapter->hs_activate_wait_q_woken); | ||
676 | |||
677 | return true; | ||
678 | } | ||
679 | EXPORT_SYMBOL_GPL(mwifiex_enable_hs); | ||
680 | |||
681 | /* | ||
682 | * IOCTL request handler to get signal information. | ||
683 | * | ||
684 | * This function prepares the correct firmware command and | ||
685 | * issues it to get the signal (RSSI) information. | ||
686 | * | ||
687 | * This only works in the connected mode. | ||
688 | */ | ||
689 | static int mwifiex_get_info_signal(struct mwifiex_private *priv, | ||
690 | struct mwifiex_wait_queue *wait, | ||
691 | struct mwifiex_ds_get_signal *signal) | ||
692 | { | ||
693 | int ret = 0; | ||
694 | |||
695 | if (!wait) { | ||
696 | dev_err(priv->adapter->dev, "WAIT information is not present\n"); | ||
697 | return -1; | ||
698 | } | ||
699 | |||
700 | /* Signal info can be obtained only if connected */ | ||
701 | if (!priv->media_connected) { | ||
702 | dev_dbg(priv->adapter->dev, | ||
703 | "info: Can not get signal in disconnected state\n"); | ||
704 | return -1; | ||
705 | } | ||
706 | |||
707 | /* Send request to firmware */ | ||
708 | ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_RSSI_INFO, | ||
709 | HostCmd_ACT_GEN_GET, 0, wait, signal); | ||
710 | |||
711 | if (!ret) | ||
712 | ret = -EINPROGRESS; | ||
713 | |||
714 | return ret; | ||
715 | } | ||
716 | |||
717 | /* | ||
718 | * IOCTL request handler to get statistics. | ||
719 | * | ||
720 | * This function prepares the correct firmware command and | ||
721 | * issues it to get the statistics (RSSI) information. | ||
722 | */ | ||
723 | static int mwifiex_get_info_stats(struct mwifiex_private *priv, | ||
724 | struct mwifiex_wait_queue *wait, | ||
725 | struct mwifiex_ds_get_stats *log) | ||
726 | { | ||
727 | int ret = 0; | ||
728 | |||
729 | if (!wait) { | ||
730 | dev_err(priv->adapter->dev, "MWIFIEX IOCTL information is not present\n"); | ||
731 | return -1; | ||
732 | } | ||
733 | |||
734 | /* Send request to firmware */ | ||
735 | ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_GET_LOG, | ||
736 | HostCmd_ACT_GEN_GET, 0, wait, log); | ||
737 | |||
738 | if (!ret) | ||
739 | ret = -EINPROGRESS; | ||
740 | |||
741 | return ret; | ||
742 | } | ||
743 | |||
744 | /* | ||
745 | * IOCTL request handler to get BSS information. | ||
746 | * | ||
747 | * This function collates the information from different driver structures | ||
748 | * to send to the user. | ||
749 | */ | ||
750 | int mwifiex_get_bss_info(struct mwifiex_private *priv, | ||
751 | struct mwifiex_bss_info *info) | ||
752 | { | ||
753 | struct mwifiex_adapter *adapter = priv->adapter; | ||
754 | struct mwifiex_bssdescriptor *bss_desc; | ||
755 | s32 tbl_idx = 0; | ||
756 | |||
757 | if (!info) | ||
758 | return -1; | ||
759 | |||
760 | /* Get current BSS info */ | ||
761 | bss_desc = &priv->curr_bss_params.bss_descriptor; | ||
762 | |||
763 | /* BSS mode */ | ||
764 | info->bss_mode = priv->bss_mode; | ||
765 | |||
766 | /* SSID */ | ||
767 | memcpy(&info->ssid, &bss_desc->ssid, | ||
768 | sizeof(struct mwifiex_802_11_ssid)); | ||
769 | |||
770 | /* BSSID */ | ||
771 | memcpy(&info->bssid, &bss_desc->mac_address, ETH_ALEN); | ||
772 | |||
773 | /* Channel */ | ||
774 | info->bss_chan = bss_desc->channel; | ||
775 | |||
776 | /* Region code */ | ||
777 | info->region_code = adapter->region_code; | ||
778 | |||
779 | /* Scan table index if connected */ | ||
780 | info->scan_table_idx = 0; | ||
781 | if (priv->media_connected) { | ||
782 | tbl_idx = | ||
783 | mwifiex_find_ssid_in_list(priv, &bss_desc->ssid, | ||
784 | bss_desc->mac_address, | ||
785 | priv->bss_mode); | ||
786 | if (tbl_idx >= 0) | ||
787 | info->scan_table_idx = tbl_idx; | ||
788 | } | ||
789 | |||
790 | /* Connection status */ | ||
791 | info->media_connected = priv->media_connected; | ||
792 | |||
793 | /* Tx power information */ | ||
794 | info->max_power_level = priv->max_tx_power_level; | ||
795 | info->min_power_level = priv->min_tx_power_level; | ||
796 | |||
797 | /* AdHoc state */ | ||
798 | info->adhoc_state = priv->adhoc_state; | ||
799 | |||
800 | /* Last beacon NF */ | ||
801 | info->bcn_nf_last = priv->bcn_nf_last; | ||
802 | |||
803 | /* wep status */ | ||
804 | if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_ENABLED) | ||
805 | info->wep_status = true; | ||
806 | else | ||
807 | info->wep_status = false; | ||
808 | |||
809 | info->is_hs_configured = adapter->is_hs_configured; | ||
810 | info->is_deep_sleep = adapter->is_deep_sleep; | ||
811 | |||
812 | return 0; | ||
813 | } | ||
814 | |||
815 | /* | ||
816 | * IOCTL request handler to get extended version information. | ||
817 | * | ||
818 | * This function prepares the correct firmware command and | ||
819 | * issues it to get the extended version information. | ||
820 | */ | ||
821 | static int mwifiex_get_info_ver_ext(struct mwifiex_private *priv, | ||
822 | struct mwifiex_wait_queue *wait, | ||
823 | struct mwifiex_ver_ext *ver_ext) | ||
824 | { | ||
825 | int ret = 0; | ||
826 | |||
827 | /* Send request to firmware */ | ||
828 | ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_VERSION_EXT, | ||
829 | HostCmd_ACT_GEN_GET, 0, wait, ver_ext); | ||
830 | if (!ret) | ||
831 | ret = -EINPROGRESS; | ||
832 | |||
833 | return ret; | ||
834 | } | ||
835 | |||
836 | /* | ||
837 | * IOCTL request handler to set/get SNMP MIB parameters. | ||
838 | * | ||
839 | * This function prepares the correct firmware command and | ||
840 | * issues it. | ||
841 | * | ||
842 | * Currently the following parameters are supported - | ||
843 | * Set/get RTS Threshold | ||
844 | * Set/get fragmentation threshold | ||
845 | * Set/get retry count | ||
846 | */ | ||
847 | int mwifiex_snmp_mib_ioctl(struct mwifiex_private *priv, | ||
848 | struct mwifiex_wait_queue *wait, | ||
849 | u32 cmd_oid, u16 action, u32 *value) | ||
850 | { | ||
851 | int ret = 0; | ||
852 | |||
853 | if (!value) | ||
854 | return -1; | ||
855 | |||
856 | /* Send request to firmware */ | ||
857 | ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB, | ||
858 | action, cmd_oid, wait, value); | ||
859 | |||
860 | if (!ret) | ||
861 | ret = -EINPROGRESS; | ||
862 | |||
863 | return ret; | ||
864 | } | ||
865 | |||
866 | /* | ||
867 | * IOCTL request handler to set/get band configurations. | ||
868 | * | ||
869 | * For SET operation, it performs extra checks to make sure the Ad-Hoc | ||
870 | * band and channel are compatible. Otherwise it returns an error. | ||
871 | * | ||
872 | * For GET operation, this function retrieves the following information - | ||
873 | * - Infra bands | ||
874 | * - Ad-hoc band | ||
875 | * - Ad-hoc channel | ||
876 | * - Secondary channel offset | ||
877 | */ | ||
878 | int mwifiex_radio_ioctl_band_cfg(struct mwifiex_private *priv, | ||
879 | u16 action, | ||
880 | struct mwifiex_ds_band_cfg *radio_cfg) | ||
881 | { | ||
882 | struct mwifiex_adapter *adapter = priv->adapter; | ||
883 | u8 infra_band = 0; | ||
884 | u8 adhoc_band = 0; | ||
885 | u32 adhoc_channel = 0; | ||
886 | |||
887 | if (action == HostCmd_ACT_GEN_GET) { | ||
888 | /* Infra Bands */ | ||
889 | radio_cfg->config_bands = adapter->config_bands; | ||
890 | /* Adhoc Band */ | ||
891 | radio_cfg->adhoc_start_band = adapter->adhoc_start_band; | ||
892 | /* Adhoc channel */ | ||
893 | radio_cfg->adhoc_channel = priv->adhoc_channel; | ||
894 | /* Secondary channel offset */ | ||
895 | radio_cfg->sec_chan_offset = adapter->chan_offset; | ||
896 | return 0; | ||
897 | } | ||
898 | |||
899 | /* For action = SET */ | ||
900 | infra_band = (u8) radio_cfg->config_bands; | ||
901 | adhoc_band = (u8) radio_cfg->adhoc_start_band; | ||
902 | adhoc_channel = radio_cfg->adhoc_channel; | ||
903 | |||
904 | /* SET Infra band */ | ||
905 | if ((infra_band | adapter->fw_bands) & ~adapter->fw_bands) | ||
906 | return -1; | ||
907 | |||
908 | adapter->config_bands = infra_band; | ||
909 | |||
910 | /* SET Ad-hoc Band */ | ||
911 | if ((adhoc_band | adapter->fw_bands) & ~adapter->fw_bands) | ||
912 | return -1; | ||
913 | |||
914 | if (adhoc_band) | ||
915 | adapter->adhoc_start_band = adhoc_band; | ||
916 | adapter->chan_offset = (u8) radio_cfg->sec_chan_offset; | ||
917 | /* | ||
918 | * If no adhoc_channel is supplied verify if the existing adhoc | ||
919 | * channel compiles with new adhoc_band | ||
920 | */ | ||
921 | if (!adhoc_channel) { | ||
922 | if (!mwifiex_get_cfp_by_band_and_channel_from_cfg80211 | ||
923 | (priv, adapter->adhoc_start_band, | ||
924 | priv->adhoc_channel)) { | ||
925 | /* Pass back the default channel */ | ||
926 | radio_cfg->adhoc_channel = DEFAULT_AD_HOC_CHANNEL; | ||
927 | if ((adapter->adhoc_start_band & BAND_A) | ||
928 | || (adapter->adhoc_start_band & BAND_AN)) | ||
929 | radio_cfg->adhoc_channel = | ||
930 | DEFAULT_AD_HOC_CHANNEL_A; | ||
931 | } | ||
932 | } else { /* Retrurn error if adhoc_band and | ||
933 | adhoc_channel combination is invalid */ | ||
934 | if (!mwifiex_get_cfp_by_band_and_channel_from_cfg80211 | ||
935 | (priv, adapter->adhoc_start_band, (u16) adhoc_channel)) | ||
936 | return -1; | ||
937 | priv->adhoc_channel = (u8) adhoc_channel; | ||
938 | } | ||
939 | if ((adhoc_band & BAND_GN) || (adhoc_band & BAND_AN)) | ||
940 | adapter->adhoc_11n_enabled = true; | ||
941 | else | ||
942 | adapter->adhoc_11n_enabled = false; | ||
943 | |||
944 | return 0; | ||
945 | } | ||
946 | |||
947 | /* | ||
948 | * IOCTL request handler to set/get active channel. | ||
949 | * | ||
950 | * This function performs validity checking on channel/frequency | ||
951 | * compatibility and returns failure if not valid. | ||
952 | */ | ||
953 | int mwifiex_bss_ioctl_channel(struct mwifiex_private *priv, u16 action, | ||
954 | struct mwifiex_chan_freq_power *chan) | ||
955 | { | ||
956 | struct mwifiex_adapter *adapter = priv->adapter; | ||
957 | struct mwifiex_chan_freq_power *cfp = NULL; | ||
958 | |||
959 | if (!chan) | ||
960 | return -1; | ||
961 | |||
962 | if (action == HostCmd_ACT_GEN_GET) { | ||
963 | cfp = mwifiex_get_cfp_by_band_and_channel_from_cfg80211(priv, | ||
964 | priv->curr_bss_params.band, | ||
965 | (u16) priv->curr_bss_params.bss_descriptor. | ||
966 | channel); | ||
967 | chan->channel = cfp->channel; | ||
968 | chan->freq = cfp->freq; | ||
969 | |||
970 | return 0; | ||
971 | } | ||
972 | if (!chan->channel && !chan->freq) | ||
973 | return -1; | ||
974 | if (adapter->adhoc_start_band & BAND_AN) | ||
975 | adapter->adhoc_start_band = BAND_G | BAND_B | BAND_GN; | ||
976 | else if (adapter->adhoc_start_band & BAND_A) | ||
977 | adapter->adhoc_start_band = BAND_G | BAND_B; | ||
978 | if (chan->channel) { | ||
979 | if (chan->channel <= MAX_CHANNEL_BAND_BG) | ||
980 | cfp = mwifiex_get_cfp_by_band_and_channel_from_cfg80211 | ||
981 | (priv, 0, (u16) chan->channel); | ||
982 | if (!cfp) { | ||
983 | cfp = mwifiex_get_cfp_by_band_and_channel_from_cfg80211 | ||
984 | (priv, BAND_A, (u16) chan->channel); | ||
985 | if (cfp) { | ||
986 | if (adapter->adhoc_11n_enabled) | ||
987 | adapter->adhoc_start_band = BAND_A | ||
988 | | BAND_AN; | ||
989 | else | ||
990 | adapter->adhoc_start_band = BAND_A; | ||
991 | } | ||
992 | } | ||
993 | } else { | ||
994 | if (chan->freq <= MAX_FREQUENCY_BAND_BG) | ||
995 | cfp = mwifiex_get_cfp_by_band_and_freq_from_cfg80211( | ||
996 | priv, 0, chan->freq); | ||
997 | if (!cfp) { | ||
998 | cfp = mwifiex_get_cfp_by_band_and_freq_from_cfg80211 | ||
999 | (priv, BAND_A, chan->freq); | ||
1000 | if (cfp) { | ||
1001 | if (adapter->adhoc_11n_enabled) | ||
1002 | adapter->adhoc_start_band = BAND_A | ||
1003 | | BAND_AN; | ||
1004 | else | ||
1005 | adapter->adhoc_start_band = BAND_A; | ||
1006 | } | ||
1007 | } | ||
1008 | } | ||
1009 | if (!cfp || !cfp->channel) { | ||
1010 | dev_err(adapter->dev, "invalid channel/freq\n"); | ||
1011 | return -1; | ||
1012 | } | ||
1013 | priv->adhoc_channel = (u8) cfp->channel; | ||
1014 | chan->channel = cfp->channel; | ||
1015 | chan->freq = cfp->freq; | ||
1016 | |||
1017 | return 0; | ||
1018 | } | ||
1019 | |||
1020 | /* | ||
1021 | * IOCTL request handler to set/get Ad-Hoc channel. | ||
1022 | * | ||
1023 | * This function prepares the correct firmware command and | ||
1024 | * issues it to set or get the ad-hoc channel. | ||
1025 | */ | ||
1026 | static int mwifiex_bss_ioctl_ibss_channel(struct mwifiex_private *priv, | ||
1027 | struct mwifiex_wait_queue *wait, | ||
1028 | u16 action, u16 *channel) | ||
1029 | { | ||
1030 | int ret = 0; | ||
1031 | |||
1032 | if (action == HostCmd_ACT_GEN_GET) { | ||
1033 | if (!priv->media_connected) { | ||
1034 | *channel = priv->adhoc_channel; | ||
1035 | return ret; | ||
1036 | } | ||
1037 | } else { | ||
1038 | priv->adhoc_channel = (u8) *channel; | ||
1039 | } | ||
1040 | |||
1041 | /* Send request to firmware */ | ||
1042 | ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_RF_CHANNEL, | ||
1043 | action, 0, wait, channel); | ||
1044 | if (!ret) | ||
1045 | ret = -EINPROGRESS; | ||
1046 | |||
1047 | return ret; | ||
1048 | } | ||
1049 | |||
1050 | /* | ||
1051 | * IOCTL request handler to find a particular BSS. | ||
1052 | * | ||
1053 | * The BSS can be searched with either a BSSID or a SSID. If none of | ||
1054 | * these are provided, just the best BSS (best RSSI) is returned. | ||
1055 | */ | ||
1056 | int mwifiex_bss_ioctl_find_bss(struct mwifiex_private *priv, | ||
1057 | struct mwifiex_wait_queue *wait, | ||
1058 | struct mwifiex_ssid_bssid *ssid_bssid) | ||
1059 | { | ||
1060 | struct mwifiex_adapter *adapter = priv->adapter; | ||
1061 | int ret = 0; | ||
1062 | struct mwifiex_bssdescriptor *bss_desc; | ||
1063 | u8 zero_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 }; | ||
1064 | u8 mac[ETH_ALEN]; | ||
1065 | int i = 0; | ||
1066 | |||
1067 | if (memcmp(ssid_bssid->bssid, zero_mac, sizeof(zero_mac))) { | ||
1068 | i = mwifiex_find_bssid_in_list(priv, | ||
1069 | (u8 *) ssid_bssid->bssid, | ||
1070 | priv->bss_mode); | ||
1071 | if (i < 0) { | ||
1072 | memcpy(mac, ssid_bssid->bssid, sizeof(mac)); | ||
1073 | dev_err(adapter->dev, "cannot find bssid %pM\n", mac); | ||
1074 | return -1; | ||
1075 | } | ||
1076 | bss_desc = &adapter->scan_table[i]; | ||
1077 | memcpy(&ssid_bssid->ssid, &bss_desc->ssid, | ||
1078 | sizeof(struct mwifiex_802_11_ssid)); | ||
1079 | } else if (ssid_bssid->ssid.ssid_len) { | ||
1080 | i = mwifiex_find_ssid_in_list(priv, &ssid_bssid->ssid, NULL, | ||
1081 | priv->bss_mode); | ||
1082 | if (i < 0) { | ||
1083 | dev_err(adapter->dev, "cannot find ssid %s\n", | ||
1084 | ssid_bssid->ssid.ssid); | ||
1085 | return -1; | ||
1086 | } | ||
1087 | bss_desc = &adapter->scan_table[i]; | ||
1088 | memcpy(ssid_bssid->bssid, bss_desc->mac_address, ETH_ALEN); | ||
1089 | } else { | ||
1090 | ret = mwifiex_find_best_network(priv, ssid_bssid); | ||
1091 | } | ||
1092 | |||
1093 | return ret; | ||
1094 | } | ||
1095 | |||
1096 | /* | ||
1097 | * IOCTL request handler to change Ad-Hoc channel. | ||
1098 | * | ||
1099 | * This function allocates the IOCTL request buffer, fills it | ||
1100 | * with requisite parameters and calls the IOCTL handler. | ||
1101 | * | ||
1102 | * The function follows the following steps to perform the change - | ||
1103 | * - Get current IBSS information | ||
1104 | * - Get current channel | ||
1105 | * - If no change is required, return | ||
1106 | * - If not connected, change channel and return | ||
1107 | * - If connected, | ||
1108 | * - Disconnect | ||
1109 | * - Change channel | ||
1110 | * - Perform specific SSID scan with same SSID | ||
1111 | * - Start/Join the IBSS | ||
1112 | */ | ||
1113 | int | ||
1114 | mwifiex_drv_change_adhoc_chan(struct mwifiex_private *priv, int channel) | ||
1115 | { | ||
1116 | int ret = 0; | ||
1117 | int status = 0; | ||
1118 | struct mwifiex_bss_info bss_info; | ||
1119 | struct mwifiex_wait_queue *wait = NULL; | ||
1120 | u8 wait_option = MWIFIEX_IOCTL_WAIT; | ||
1121 | struct mwifiex_ssid_bssid ssid_bssid; | ||
1122 | u16 curr_chan = 0; | ||
1123 | |||
1124 | memset(&bss_info, 0, sizeof(bss_info)); | ||
1125 | |||
1126 | /* Get BSS information */ | ||
1127 | if (mwifiex_get_bss_info(priv, &bss_info)) | ||
1128 | return -1; | ||
1129 | |||
1130 | /* Allocate wait buffer */ | ||
1131 | wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); | ||
1132 | if (!wait) | ||
1133 | return -ENOMEM; | ||
1134 | |||
1135 | /* Get current channel */ | ||
1136 | status = mwifiex_bss_ioctl_ibss_channel(priv, wait, HostCmd_ACT_GEN_GET, | ||
1137 | &curr_chan); | ||
1138 | |||
1139 | if (mwifiex_request_ioctl(priv, wait, status, wait_option)) { | ||
1140 | ret = -1; | ||
1141 | goto done; | ||
1142 | } | ||
1143 | if (curr_chan == channel) { | ||
1144 | ret = 0; | ||
1145 | goto done; | ||
1146 | } | ||
1147 | dev_dbg(priv->adapter->dev, "cmd: updating channel from %d to %d\n", | ||
1148 | curr_chan, channel); | ||
1149 | |||
1150 | if (!bss_info.media_connected) { | ||
1151 | ret = 0; | ||
1152 | goto done; | ||
1153 | } | ||
1154 | |||
1155 | /* Do disonnect */ | ||
1156 | memset(&ssid_bssid, 0, ETH_ALEN); | ||
1157 | status = mwifiex_bss_ioctl_stop(priv, wait, ssid_bssid.bssid); | ||
1158 | |||
1159 | if (mwifiex_request_ioctl(priv, wait, status, wait_option)) { | ||
1160 | ret = -1; | ||
1161 | goto done; | ||
1162 | } | ||
1163 | |||
1164 | status = mwifiex_bss_ioctl_ibss_channel(priv, wait, HostCmd_ACT_GEN_SET, | ||
1165 | (u16 *) &channel); | ||
1166 | |||
1167 | if (mwifiex_request_ioctl(priv, wait, status, wait_option)) { | ||
1168 | ret = -1; | ||
1169 | goto done; | ||
1170 | } | ||
1171 | |||
1172 | /* Do specific SSID scanning */ | ||
1173 | if (mwifiex_request_scan(priv, wait_option, &bss_info.ssid)) { | ||
1174 | ret = -1; | ||
1175 | goto done; | ||
1176 | } | ||
1177 | /* Start/Join Adhoc network */ | ||
1178 | memset(&ssid_bssid, 0, sizeof(struct mwifiex_ssid_bssid)); | ||
1179 | memcpy(&ssid_bssid.ssid, &bss_info.ssid, | ||
1180 | sizeof(struct mwifiex_802_11_ssid)); | ||
1181 | |||
1182 | status = mwifiex_bss_ioctl_start(priv, wait, &ssid_bssid); | ||
1183 | |||
1184 | if (mwifiex_request_ioctl(priv, wait, status, wait_option)) | ||
1185 | ret = -1; | ||
1186 | |||
1187 | done: | ||
1188 | kfree(wait); | ||
1189 | return ret; | ||
1190 | } | ||
1191 | |||
1192 | /* | ||
1193 | * IOCTL request handler to get rate. | ||
1194 | * | ||
1195 | * This function prepares the correct firmware command and | ||
1196 | * issues it to get the current rate if it is connected, | ||
1197 | * otherwise, the function returns the lowest supported rate | ||
1198 | * for the band. | ||
1199 | */ | ||
1200 | static int mwifiex_rate_ioctl_get_rate_value(struct mwifiex_private *priv, | ||
1201 | struct mwifiex_wait_queue *wait, | ||
1202 | struct mwifiex_rate_cfg *rate_cfg) | ||
1203 | { | ||
1204 | struct mwifiex_adapter *adapter = priv->adapter; | ||
1205 | int ret = 0; | ||
1206 | |||
1207 | rate_cfg->is_rate_auto = priv->is_data_rate_auto; | ||
1208 | if (!priv->media_connected) { | ||
1209 | switch (adapter->config_bands) { | ||
1210 | case BAND_B: | ||
1211 | /* Return the lowest supported rate for B band */ | ||
1212 | rate_cfg->rate = supported_rates_b[0] & 0x7f; | ||
1213 | break; | ||
1214 | case BAND_G: | ||
1215 | case BAND_G | BAND_GN: | ||
1216 | /* Return the lowest supported rate for G band */ | ||
1217 | rate_cfg->rate = supported_rates_g[0] & 0x7f; | ||
1218 | break; | ||
1219 | case BAND_B | BAND_G: | ||
1220 | case BAND_A | BAND_B | BAND_G: | ||
1221 | case BAND_A | BAND_B: | ||
1222 | case BAND_A | BAND_B | BAND_G | BAND_AN | BAND_GN: | ||
1223 | case BAND_B | BAND_G | BAND_GN: | ||
1224 | /* Return the lowest supported rate for BG band */ | ||
1225 | rate_cfg->rate = supported_rates_bg[0] & 0x7f; | ||
1226 | break; | ||
1227 | case BAND_A: | ||
1228 | case BAND_A | BAND_G: | ||
1229 | case BAND_A | BAND_G | BAND_AN | BAND_GN: | ||
1230 | case BAND_A | BAND_AN: | ||
1231 | /* Return the lowest supported rate for A band */ | ||
1232 | rate_cfg->rate = supported_rates_a[0] & 0x7f; | ||
1233 | break; | ||
1234 | case BAND_GN: | ||
1235 | /* Return the lowest supported rate for N band */ | ||
1236 | rate_cfg->rate = supported_rates_n[0] & 0x7f; | ||
1237 | break; | ||
1238 | default: | ||
1239 | dev_warn(adapter->dev, "invalid band %#x\n", | ||
1240 | adapter->config_bands); | ||
1241 | break; | ||
1242 | } | ||
1243 | } else { | ||
1244 | /* Send request to firmware */ | ||
1245 | ret = mwifiex_prepare_cmd(priv, | ||
1246 | HostCmd_CMD_802_11_TX_RATE_QUERY, | ||
1247 | HostCmd_ACT_GEN_GET, 0, wait, NULL); | ||
1248 | if (!ret) | ||
1249 | ret = -EINPROGRESS; | ||
1250 | } | ||
1251 | |||
1252 | return ret; | ||
1253 | } | ||
1254 | |||
1255 | /* | ||
1256 | * IOCTL request handler to set rate. | ||
1257 | * | ||
1258 | * This function prepares the correct firmware command and | ||
1259 | * issues it to set the current rate. | ||
1260 | * | ||
1261 | * The function also performs validation checking on the supplied value. | ||
1262 | */ | ||
1263 | static int mwifiex_rate_ioctl_set_rate_value(struct mwifiex_private *priv, | ||
1264 | struct mwifiex_wait_queue *wait, | ||
1265 | struct mwifiex_rate_cfg *rate_cfg) | ||
1266 | { | ||
1267 | u8 rates[MWIFIEX_SUPPORTED_RATES]; | ||
1268 | u8 *rate = NULL; | ||
1269 | int rate_index = 0; | ||
1270 | u16 bitmap_rates[MAX_BITMAP_RATES_SIZE]; | ||
1271 | u32 i = 0; | ||
1272 | int ret = 0; | ||
1273 | struct mwifiex_adapter *adapter = priv->adapter; | ||
1274 | |||
1275 | if (rate_cfg->is_rate_auto) { | ||
1276 | memset(bitmap_rates, 0, sizeof(bitmap_rates)); | ||
1277 | /* Support all HR/DSSS rates */ | ||
1278 | bitmap_rates[0] = 0x000F; | ||
1279 | /* Support all OFDM rates */ | ||
1280 | bitmap_rates[1] = 0x00FF; | ||
1281 | /* Support all HT-MCSs rate */ | ||
1282 | for (i = 0; i < ARRAY_SIZE(priv->bitmap_rates) - 3; i++) | ||
1283 | bitmap_rates[i + 2] = 0xFFFF; | ||
1284 | bitmap_rates[9] = 0x3FFF; | ||
1285 | } else { | ||
1286 | memset(rates, 0, sizeof(rates)); | ||
1287 | mwifiex_get_active_data_rates(priv, rates); | ||
1288 | rate = rates; | ||
1289 | for (i = 0; (rate[i] && i < MWIFIEX_SUPPORTED_RATES); i++) { | ||
1290 | dev_dbg(adapter->dev, "info: rate=%#x wanted=%#x\n", | ||
1291 | rate[i], rate_cfg->rate); | ||
1292 | if ((rate[i] & 0x7f) == (rate_cfg->rate & 0x7f)) | ||
1293 | break; | ||
1294 | } | ||
1295 | if (!rate[i] || (i == MWIFIEX_SUPPORTED_RATES)) { | ||
1296 | dev_err(adapter->dev, "fixed data rate %#x is out " | ||
1297 | "of range\n", rate_cfg->rate); | ||
1298 | return -1; | ||
1299 | } | ||
1300 | memset(bitmap_rates, 0, sizeof(bitmap_rates)); | ||
1301 | |||
1302 | rate_index = | ||
1303 | mwifiex_data_rate_to_index(adapter, rate_cfg->rate); | ||
1304 | |||
1305 | /* Only allow b/g rates to be set */ | ||
1306 | if (rate_index >= MWIFIEX_RATE_INDEX_HRDSSS0 && | ||
1307 | rate_index <= MWIFIEX_RATE_INDEX_HRDSSS3) { | ||
1308 | bitmap_rates[0] = 1 << rate_index; | ||
1309 | } else { | ||
1310 | rate_index -= 1; /* There is a 0x00 in the table */ | ||
1311 | if (rate_index >= MWIFIEX_RATE_INDEX_OFDM0 && | ||
1312 | rate_index <= MWIFIEX_RATE_INDEX_OFDM7) | ||
1313 | bitmap_rates[1] = 1 << (rate_index - | ||
1314 | MWIFIEX_RATE_INDEX_OFDM0); | ||
1315 | } | ||
1316 | } | ||
1317 | |||
1318 | /* Send request to firmware */ | ||
1319 | ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_TX_RATE_CFG, | ||
1320 | HostCmd_ACT_GEN_SET, 0, wait, bitmap_rates); | ||
1321 | if (!ret) | ||
1322 | ret = -EINPROGRESS; | ||
1323 | |||
1324 | return ret; | ||
1325 | } | ||
1326 | |||
1327 | /* | ||
1328 | * IOCTL request handler to set/get rate. | ||
1329 | * | ||
1330 | * This function can be used to set/get either the rate value or the | ||
1331 | * rate index. | ||
1332 | */ | ||
1333 | static int mwifiex_rate_ioctl_cfg(struct mwifiex_private *priv, | ||
1334 | struct mwifiex_wait_queue *wait, | ||
1335 | struct mwifiex_rate_cfg *rate_cfg) | ||
1336 | { | ||
1337 | int status = 0; | ||
1338 | |||
1339 | if (!rate_cfg) | ||
1340 | return -1; | ||
1341 | |||
1342 | if (rate_cfg->action == HostCmd_ACT_GEN_GET) | ||
1343 | status = mwifiex_rate_ioctl_get_rate_value( | ||
1344 | priv, wait, rate_cfg); | ||
1345 | else | ||
1346 | status = mwifiex_rate_ioctl_set_rate_value( | ||
1347 | priv, wait, rate_cfg); | ||
1348 | |||
1349 | return status; | ||
1350 | } | ||
1351 | |||
1352 | /* | ||
1353 | * Sends IOCTL request to get the data rate. | ||
1354 | * | ||
1355 | * This function allocates the IOCTL request buffer, fills it | ||
1356 | * with requisite parameters and calls the IOCTL handler. | ||
1357 | */ | ||
1358 | int mwifiex_drv_get_data_rate(struct mwifiex_private *priv, | ||
1359 | struct mwifiex_rate_cfg *rate) | ||
1360 | { | ||
1361 | int ret = 0; | ||
1362 | struct mwifiex_wait_queue *wait = NULL; | ||
1363 | u8 wait_option = MWIFIEX_IOCTL_WAIT; | ||
1364 | |||
1365 | /* Allocate wait buffer */ | ||
1366 | wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); | ||
1367 | if (!wait) | ||
1368 | return -ENOMEM; | ||
1369 | |||
1370 | memset(rate, 0, sizeof(struct mwifiex_rate_cfg)); | ||
1371 | rate->action = HostCmd_ACT_GEN_GET; | ||
1372 | ret = mwifiex_rate_ioctl_cfg(priv, wait, rate); | ||
1373 | |||
1374 | ret = mwifiex_request_ioctl(priv, wait, ret, wait_option); | ||
1375 | if (!ret) { | ||
1376 | if (rate && rate->is_rate_auto) | ||
1377 | rate->rate = mwifiex_index_to_data_rate(priv->adapter, | ||
1378 | priv->tx_rate, priv->tx_htinfo); | ||
1379 | else if (rate) | ||
1380 | rate->rate = priv->data_rate; | ||
1381 | } else { | ||
1382 | ret = -1; | ||
1383 | } | ||
1384 | |||
1385 | kfree(wait); | ||
1386 | return ret; | ||
1387 | } | ||
1388 | |||
1389 | /* | ||
1390 | * IOCTL request handler to set tx power configuration. | ||
1391 | * | ||
1392 | * This function prepares the correct firmware command and | ||
1393 | * issues it. | ||
1394 | * | ||
1395 | * For non-auto power mode, all the following power groups are set - | ||
1396 | * - Modulation class HR/DSSS | ||
1397 | * - Modulation class OFDM | ||
1398 | * - Modulation class HTBW20 | ||
1399 | * - Modulation class HTBW40 | ||
1400 | */ | ||
1401 | static int mwifiex_power_ioctl_set_power(struct mwifiex_private *priv, | ||
1402 | struct mwifiex_wait_queue *wait, | ||
1403 | struct mwifiex_power_cfg *power_cfg) | ||
1404 | { | ||
1405 | int ret = 0; | ||
1406 | struct host_cmd_ds_txpwr_cfg *txp_cfg = NULL; | ||
1407 | struct mwifiex_types_power_group *pg_tlv = NULL; | ||
1408 | struct mwifiex_power_group *pg = NULL; | ||
1409 | u8 *buf = NULL; | ||
1410 | u16 dbm = 0; | ||
1411 | |||
1412 | if (!power_cfg->is_power_auto) { | ||
1413 | dbm = (u16) power_cfg->power_level; | ||
1414 | if ((dbm < priv->min_tx_power_level) || | ||
1415 | (dbm > priv->max_tx_power_level)) { | ||
1416 | dev_err(priv->adapter->dev, "txpower value %d dBm" | ||
1417 | " is out of range (%d dBm-%d dBm)\n", | ||
1418 | dbm, priv->min_tx_power_level, | ||
1419 | priv->max_tx_power_level); | ||
1420 | return -1; | ||
1421 | } | ||
1422 | } | ||
1423 | buf = kzalloc(MWIFIEX_SIZE_OF_CMD_BUFFER, GFP_KERNEL); | ||
1424 | if (!buf) { | ||
1425 | dev_err(priv->adapter->dev, "%s: failed to alloc cmd buffer\n", | ||
1426 | __func__); | ||
1427 | return -1; | ||
1428 | } | ||
1429 | |||
1430 | txp_cfg = (struct host_cmd_ds_txpwr_cfg *) buf; | ||
1431 | txp_cfg->action = cpu_to_le16(HostCmd_ACT_GEN_SET); | ||
1432 | if (!power_cfg->is_power_auto) { | ||
1433 | txp_cfg->mode = cpu_to_le32(1); | ||
1434 | pg_tlv = (struct mwifiex_types_power_group *) (buf + | ||
1435 | sizeof(struct host_cmd_ds_txpwr_cfg)); | ||
1436 | pg_tlv->type = TLV_TYPE_POWER_GROUP; | ||
1437 | pg_tlv->length = 4 * sizeof(struct mwifiex_power_group); | ||
1438 | pg = (struct mwifiex_power_group *) (buf + | ||
1439 | sizeof(struct host_cmd_ds_txpwr_cfg) + | ||
1440 | sizeof(struct mwifiex_types_power_group)); | ||
1441 | /* Power group for modulation class HR/DSSS */ | ||
1442 | pg->first_rate_code = 0x00; | ||
1443 | pg->last_rate_code = 0x03; | ||
1444 | pg->modulation_class = MOD_CLASS_HR_DSSS; | ||
1445 | pg->power_step = 0; | ||
1446 | pg->power_min = (s8) dbm; | ||
1447 | pg->power_max = (s8) dbm; | ||
1448 | pg++; | ||
1449 | /* Power group for modulation class OFDM */ | ||
1450 | pg->first_rate_code = 0x00; | ||
1451 | pg->last_rate_code = 0x07; | ||
1452 | pg->modulation_class = MOD_CLASS_OFDM; | ||
1453 | pg->power_step = 0; | ||
1454 | pg->power_min = (s8) dbm; | ||
1455 | pg->power_max = (s8) dbm; | ||
1456 | pg++; | ||
1457 | /* Power group for modulation class HTBW20 */ | ||
1458 | pg->first_rate_code = 0x00; | ||
1459 | pg->last_rate_code = 0x20; | ||
1460 | pg->modulation_class = MOD_CLASS_HT; | ||
1461 | pg->power_step = 0; | ||
1462 | pg->power_min = (s8) dbm; | ||
1463 | pg->power_max = (s8) dbm; | ||
1464 | pg->ht_bandwidth = HT_BW_20; | ||
1465 | pg++; | ||
1466 | /* Power group for modulation class HTBW40 */ | ||
1467 | pg->first_rate_code = 0x00; | ||
1468 | pg->last_rate_code = 0x20; | ||
1469 | pg->modulation_class = MOD_CLASS_HT; | ||
1470 | pg->power_step = 0; | ||
1471 | pg->power_min = (s8) dbm; | ||
1472 | pg->power_max = (s8) dbm; | ||
1473 | pg->ht_bandwidth = HT_BW_40; | ||
1474 | } | ||
1475 | /* Send request to firmware */ | ||
1476 | ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_TXPWR_CFG, | ||
1477 | HostCmd_ACT_GEN_SET, 0, wait, buf); | ||
1478 | if (!ret) | ||
1479 | ret = -EINPROGRESS; | ||
1480 | kfree(buf); | ||
1481 | |||
1482 | return ret; | ||
1483 | } | ||
1484 | |||
1485 | /* | ||
1486 | * IOCTL request handler to get power save mode. | ||
1487 | * | ||
1488 | * This function prepares the correct firmware command and | ||
1489 | * issues it. | ||
1490 | */ | ||
1491 | static int mwifiex_pm_ioctl_ps_mode(struct mwifiex_private *priv, | ||
1492 | struct mwifiex_wait_queue *wait, | ||
1493 | u32 *ps_mode, u16 action) | ||
1494 | { | ||
1495 | int ret = 0; | ||
1496 | struct mwifiex_adapter *adapter = priv->adapter; | ||
1497 | u16 sub_cmd; | ||
1498 | |||
1499 | if (action == HostCmd_ACT_GEN_SET) { | ||
1500 | if (*ps_mode) | ||
1501 | adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_PSP; | ||
1502 | else | ||
1503 | adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_CAM; | ||
1504 | sub_cmd = (*ps_mode) ? EN_AUTO_PS : DIS_AUTO_PS; | ||
1505 | ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_PS_MODE_ENH, | ||
1506 | sub_cmd, BITMAP_STA_PS, wait, NULL); | ||
1507 | if ((!ret) && (sub_cmd == DIS_AUTO_PS)) | ||
1508 | ret = mwifiex_prepare_cmd(priv, | ||
1509 | HostCmd_CMD_802_11_PS_MODE_ENH, GET_PS, | ||
1510 | 0, NULL, NULL); | ||
1511 | } else { | ||
1512 | ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_PS_MODE_ENH, | ||
1513 | GET_PS, 0, wait, NULL); | ||
1514 | } | ||
1515 | |||
1516 | if (!ret) | ||
1517 | ret = -EINPROGRESS; | ||
1518 | |||
1519 | return ret; | ||
1520 | } | ||
1521 | |||
1522 | /* | ||
1523 | * IOCTL request handler to set/reset WPA IE. | ||
1524 | * | ||
1525 | * The supplied WPA IE is treated as a opaque buffer. Only the first field | ||
1526 | * is checked to determine WPA version. If buffer length is zero, the existing | ||
1527 | * WPA IE is reset. | ||
1528 | */ | ||
1529 | static int mwifiex_set_wpa_ie_helper(struct mwifiex_private *priv, | ||
1530 | u8 *ie_data_ptr, u16 ie_len) | ||
1531 | { | ||
1532 | if (ie_len) { | ||
1533 | if (ie_len > sizeof(priv->wpa_ie)) { | ||
1534 | dev_err(priv->adapter->dev, | ||
1535 | "failed to copy WPA IE, too big\n"); | ||
1536 | return -1; | ||
1537 | } | ||
1538 | memcpy(priv->wpa_ie, ie_data_ptr, ie_len); | ||
1539 | priv->wpa_ie_len = (u8) ie_len; | ||
1540 | dev_dbg(priv->adapter->dev, "cmd: Set Wpa_ie_len=%d IE=%#x\n", | ||
1541 | priv->wpa_ie_len, priv->wpa_ie[0]); | ||
1542 | |||
1543 | if (priv->wpa_ie[0] == WLAN_EID_WPA) { | ||
1544 | priv->sec_info.wpa_enabled = true; | ||
1545 | } else if (priv->wpa_ie[0] == WLAN_EID_RSN) { | ||
1546 | priv->sec_info.wpa2_enabled = true; | ||
1547 | } else { | ||
1548 | priv->sec_info.wpa_enabled = false; | ||
1549 | priv->sec_info.wpa2_enabled = false; | ||
1550 | } | ||
1551 | } else { | ||
1552 | memset(priv->wpa_ie, 0, sizeof(priv->wpa_ie)); | ||
1553 | priv->wpa_ie_len = 0; | ||
1554 | dev_dbg(priv->adapter->dev, "info: reset wpa_ie_len=%d IE=%#x\n", | ||
1555 | priv->wpa_ie_len, priv->wpa_ie[0]); | ||
1556 | priv->sec_info.wpa_enabled = false; | ||
1557 | priv->sec_info.wpa2_enabled = false; | ||
1558 | } | ||
1559 | |||
1560 | return 0; | ||
1561 | } | ||
1562 | |||
1563 | /* | ||
1564 | * IOCTL request handler to set/reset WAPI IE. | ||
1565 | * | ||
1566 | * The supplied WAPI IE is treated as a opaque buffer. Only the first field | ||
1567 | * is checked to internally enable WAPI. If buffer length is zero, the existing | ||
1568 | * WAPI IE is reset. | ||
1569 | */ | ||
1570 | static int mwifiex_set_wapi_ie(struct mwifiex_private *priv, | ||
1571 | u8 *ie_data_ptr, u16 ie_len) | ||
1572 | { | ||
1573 | if (ie_len) { | ||
1574 | if (ie_len > sizeof(priv->wapi_ie)) { | ||
1575 | dev_dbg(priv->adapter->dev, | ||
1576 | "info: failed to copy WAPI IE, too big\n"); | ||
1577 | return -1; | ||
1578 | } | ||
1579 | memcpy(priv->wapi_ie, ie_data_ptr, ie_len); | ||
1580 | priv->wapi_ie_len = ie_len; | ||
1581 | dev_dbg(priv->adapter->dev, "cmd: Set wapi_ie_len=%d IE=%#x\n", | ||
1582 | priv->wapi_ie_len, priv->wapi_ie[0]); | ||
1583 | |||
1584 | if (priv->wapi_ie[0] == WLAN_EID_BSS_AC_ACCESS_DELAY) | ||
1585 | priv->sec_info.wapi_enabled = true; | ||
1586 | } else { | ||
1587 | memset(priv->wapi_ie, 0, sizeof(priv->wapi_ie)); | ||
1588 | priv->wapi_ie_len = ie_len; | ||
1589 | dev_dbg(priv->adapter->dev, | ||
1590 | "info: Reset wapi_ie_len=%d IE=%#x\n", | ||
1591 | priv->wapi_ie_len, priv->wapi_ie[0]); | ||
1592 | priv->sec_info.wapi_enabled = false; | ||
1593 | } | ||
1594 | return 0; | ||
1595 | } | ||
1596 | |||
1597 | /* | ||
1598 | * IOCTL request handler to set WAPI key. | ||
1599 | * | ||
1600 | * This function prepares the correct firmware command and | ||
1601 | * issues it. | ||
1602 | */ | ||
1603 | static int mwifiex_sec_ioctl_set_wapi_key(struct mwifiex_adapter *adapter, | ||
1604 | struct mwifiex_wait_queue *wait, | ||
1605 | struct mwifiex_ds_encrypt_key *encrypt_key) | ||
1606 | { | ||
1607 | int ret = 0; | ||
1608 | struct mwifiex_private *priv = adapter->priv[wait->bss_index]; | ||
1609 | |||
1610 | ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL, | ||
1611 | HostCmd_ACT_GEN_SET, KEY_INFO_ENABLED, | ||
1612 | wait, encrypt_key); | ||
1613 | if (!ret) | ||
1614 | ret = -EINPROGRESS; | ||
1615 | |||
1616 | return ret; | ||
1617 | } | ||
1618 | |||
1619 | /* | ||
1620 | * IOCTL request handler to set WEP network key. | ||
1621 | * | ||
1622 | * This function prepares the correct firmware command and | ||
1623 | * issues it, after validation checks. | ||
1624 | */ | ||
1625 | static int mwifiex_sec_ioctl_set_wep_key(struct mwifiex_adapter *adapter, | ||
1626 | struct mwifiex_wait_queue *wait, | ||
1627 | struct mwifiex_ds_encrypt_key *encrypt_key) | ||
1628 | { | ||
1629 | int ret = 0; | ||
1630 | struct mwifiex_private *priv = adapter->priv[wait->bss_index]; | ||
1631 | struct mwifiex_wep_key *wep_key = NULL; | ||
1632 | int index; | ||
1633 | |||
1634 | if (priv->wep_key_curr_index >= NUM_WEP_KEYS) | ||
1635 | priv->wep_key_curr_index = 0; | ||
1636 | wep_key = &priv->wep_key[priv->wep_key_curr_index]; | ||
1637 | index = encrypt_key->key_index; | ||
1638 | if (encrypt_key->key_disable) { | ||
1639 | priv->sec_info.wep_status = MWIFIEX_802_11_WEP_DISABLED; | ||
1640 | } else if (!encrypt_key->key_len) { | ||
1641 | /* Copy the required key as the current key */ | ||
1642 | wep_key = &priv->wep_key[index]; | ||
1643 | if (!wep_key->key_length) { | ||
1644 | dev_err(adapter->dev, | ||
1645 | "key not set, so cannot enable it\n"); | ||
1646 | return -1; | ||
1647 | } | ||
1648 | priv->wep_key_curr_index = (u16) index; | ||
1649 | priv->sec_info.wep_status = MWIFIEX_802_11_WEP_ENABLED; | ||
1650 | } else { | ||
1651 | wep_key = &priv->wep_key[index]; | ||
1652 | /* Cleanup */ | ||
1653 | memset(wep_key, 0, sizeof(struct mwifiex_wep_key)); | ||
1654 | /* Copy the key in the driver */ | ||
1655 | memcpy(wep_key->key_material, | ||
1656 | encrypt_key->key_material, | ||
1657 | encrypt_key->key_len); | ||
1658 | wep_key->key_index = index; | ||
1659 | wep_key->key_length = encrypt_key->key_len; | ||
1660 | priv->sec_info.wep_status = MWIFIEX_802_11_WEP_ENABLED; | ||
1661 | } | ||
1662 | if (wep_key->key_length) { | ||
1663 | /* Send request to firmware */ | ||
1664 | ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL, | ||
1665 | HostCmd_ACT_GEN_SET, 0, NULL, NULL); | ||
1666 | if (ret) | ||
1667 | return ret; | ||
1668 | } | ||
1669 | if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_ENABLED) | ||
1670 | priv->curr_pkt_filter |= HostCmd_ACT_MAC_WEP_ENABLE; | ||
1671 | else | ||
1672 | priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_WEP_ENABLE; | ||
1673 | |||
1674 | /* Send request to firmware */ | ||
1675 | ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_MAC_CONTROL, | ||
1676 | HostCmd_ACT_GEN_SET, 0, wait, | ||
1677 | &priv->curr_pkt_filter); | ||
1678 | if (!ret) | ||
1679 | ret = -EINPROGRESS; | ||
1680 | |||
1681 | return ret; | ||
1682 | } | ||
1683 | |||
1684 | /* | ||
1685 | * IOCTL request handler to set WPA key. | ||
1686 | * | ||
1687 | * This function prepares the correct firmware command and | ||
1688 | * issues it, after validation checks. | ||
1689 | * | ||
1690 | * Current driver only supports key length of up to 32 bytes. | ||
1691 | * | ||
1692 | * This function can also be used to disable a currently set key. | ||
1693 | */ | ||
1694 | static int mwifiex_sec_ioctl_set_wpa_key(struct mwifiex_adapter *adapter, | ||
1695 | struct mwifiex_wait_queue *wait, | ||
1696 | struct mwifiex_ds_encrypt_key *encrypt_key) | ||
1697 | { | ||
1698 | int ret = 0; | ||
1699 | struct mwifiex_private *priv = adapter->priv[wait->bss_index]; | ||
1700 | u8 remove_key = false; | ||
1701 | struct host_cmd_ds_802_11_key_material *ibss_key; | ||
1702 | |||
1703 | /* Current driver only supports key length of up to 32 bytes */ | ||
1704 | if (encrypt_key->key_len > MWIFIEX_MAX_KEY_LENGTH) { | ||
1705 | dev_err(adapter->dev, "key length too long\n"); | ||
1706 | return -1; | ||
1707 | } | ||
1708 | |||
1709 | if (priv->bss_mode == NL80211_IFTYPE_ADHOC) { | ||
1710 | /* | ||
1711 | * IBSS/WPA-None uses only one key (Group) for both receiving | ||
1712 | * and sending unicast and multicast packets. | ||
1713 | */ | ||
1714 | /* Send the key as PTK to firmware */ | ||
1715 | encrypt_key->key_index = MWIFIEX_KEY_INDEX_UNICAST; | ||
1716 | ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL, | ||
1717 | HostCmd_ACT_GEN_SET, KEY_INFO_ENABLED, | ||
1718 | NULL, encrypt_key); | ||
1719 | if (ret) | ||
1720 | return ret; | ||
1721 | |||
1722 | ibss_key = &priv->aes_key; | ||
1723 | memset(ibss_key, 0, | ||
1724 | sizeof(struct host_cmd_ds_802_11_key_material)); | ||
1725 | /* Copy the key in the driver */ | ||
1726 | memcpy(ibss_key->key_param_set.key, encrypt_key->key_material, | ||
1727 | encrypt_key->key_len); | ||
1728 | memcpy(&ibss_key->key_param_set.key_len, &encrypt_key->key_len, | ||
1729 | sizeof(ibss_key->key_param_set.key_len)); | ||
1730 | ibss_key->key_param_set.key_type_id | ||
1731 | = cpu_to_le16(KEY_TYPE_ID_TKIP); | ||
1732 | ibss_key->key_param_set.key_info | ||
1733 | = cpu_to_le16(KEY_INFO_TKIP_ENABLED); | ||
1734 | |||
1735 | /* Send the key as GTK to firmware */ | ||
1736 | encrypt_key->key_index = ~MWIFIEX_KEY_INDEX_UNICAST; | ||
1737 | } | ||
1738 | |||
1739 | if (!encrypt_key->key_index) | ||
1740 | encrypt_key->key_index = MWIFIEX_KEY_INDEX_UNICAST; | ||
1741 | |||
1742 | if (remove_key) | ||
1743 | /* Send request to firmware */ | ||
1744 | ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL, | ||
1745 | HostCmd_ACT_GEN_SET, | ||
1746 | !(KEY_INFO_ENABLED), | ||
1747 | wait, encrypt_key); | ||
1748 | else | ||
1749 | /* Send request to firmware */ | ||
1750 | ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL, | ||
1751 | HostCmd_ACT_GEN_SET, KEY_INFO_ENABLED, | ||
1752 | wait, encrypt_key); | ||
1753 | |||
1754 | if (!ret) | ||
1755 | ret = -EINPROGRESS; | ||
1756 | |||
1757 | return ret; | ||
1758 | } | ||
1759 | |||
1760 | /* | ||
1761 | * IOCTL request handler to set/get network keys. | ||
1762 | * | ||
1763 | * This is a generic key handling function which supports WEP, WPA | ||
1764 | * and WAPI. | ||
1765 | */ | ||
1766 | static int | ||
1767 | mwifiex_sec_ioctl_encrypt_key(struct mwifiex_private *priv, | ||
1768 | struct mwifiex_wait_queue *wait, | ||
1769 | struct mwifiex_ds_encrypt_key *encrypt_key) | ||
1770 | { | ||
1771 | int status = 0; | ||
1772 | struct mwifiex_adapter *adapter = priv->adapter; | ||
1773 | |||
1774 | if (encrypt_key->is_wapi_key) | ||
1775 | status = mwifiex_sec_ioctl_set_wapi_key(adapter, wait, | ||
1776 | encrypt_key); | ||
1777 | else if (encrypt_key->key_len > WLAN_KEY_LEN_WEP104) | ||
1778 | status = mwifiex_sec_ioctl_set_wpa_key(adapter, wait, | ||
1779 | encrypt_key); | ||
1780 | else | ||
1781 | status = mwifiex_sec_ioctl_set_wep_key(adapter, wait, | ||
1782 | encrypt_key); | ||
1783 | return status; | ||
1784 | } | ||
1785 | |||
1786 | /* | ||
1787 | * This function returns the driver version. | ||
1788 | */ | ||
1789 | int | ||
1790 | mwifiex_drv_get_driver_version(struct mwifiex_adapter *adapter, char *version, | ||
1791 | int max_len) | ||
1792 | { | ||
1793 | union { | ||
1794 | u32 l; | ||
1795 | u8 c[4]; | ||
1796 | } ver; | ||
1797 | char fw_ver[32]; | ||
1798 | |||
1799 | ver.l = adapter->fw_release_number; | ||
1800 | sprintf(fw_ver, "%u.%u.%u.p%u", ver.c[2], ver.c[1], ver.c[0], ver.c[3]); | ||
1801 | |||
1802 | snprintf(version, max_len, driver_version, fw_ver); | ||
1803 | |||
1804 | dev_dbg(adapter->dev, "info: MWIFIEX VERSION: %s\n", version); | ||
1805 | |||
1806 | return 0; | ||
1807 | } | ||
1808 | |||
1809 | /* | ||
1810 | * Sends IOCTL request to set Tx power. It can be set to either auto | ||
1811 | * or a fixed value. | ||
1812 | * | ||
1813 | * This function allocates the IOCTL request buffer, fills it | ||
1814 | * with requisite parameters and calls the IOCTL handler. | ||
1815 | */ | ||
1816 | int | ||
1817 | mwifiex_set_tx_power(struct mwifiex_private *priv, int type, int dbm) | ||
1818 | { | ||
1819 | struct mwifiex_power_cfg power_cfg; | ||
1820 | struct mwifiex_wait_queue *wait = NULL; | ||
1821 | int status = 0; | ||
1822 | int ret = 0; | ||
1823 | |||
1824 | wait = mwifiex_alloc_fill_wait_queue(priv, MWIFIEX_IOCTL_WAIT); | ||
1825 | if (!wait) | ||
1826 | return -ENOMEM; | ||
1827 | |||
1828 | if (type == NL80211_TX_POWER_FIXED) { | ||
1829 | power_cfg.is_power_auto = 0; | ||
1830 | power_cfg.power_level = dbm; | ||
1831 | } else { | ||
1832 | power_cfg.is_power_auto = 1; | ||
1833 | } | ||
1834 | status = mwifiex_power_ioctl_set_power(priv, wait, &power_cfg); | ||
1835 | |||
1836 | ret = mwifiex_request_ioctl(priv, wait, status, MWIFIEX_IOCTL_WAIT); | ||
1837 | |||
1838 | kfree(wait); | ||
1839 | return ret; | ||
1840 | } | ||
1841 | |||
1842 | /* | ||
1843 | * Sends IOCTL request to get scan table. | ||
1844 | * | ||
1845 | * This function allocates the IOCTL request buffer, fills it | ||
1846 | * with requisite parameters and calls the IOCTL handler. | ||
1847 | */ | ||
1848 | int mwifiex_get_scan_table(struct mwifiex_private *priv, u8 wait_option, | ||
1849 | struct mwifiex_scan_resp *scan_resp) | ||
1850 | { | ||
1851 | struct mwifiex_wait_queue *wait = NULL; | ||
1852 | struct mwifiex_scan_resp scan; | ||
1853 | int status = 0; | ||
1854 | |||
1855 | /* Allocate wait buffer */ | ||
1856 | wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); | ||
1857 | if (!wait) | ||
1858 | return -ENOMEM; | ||
1859 | |||
1860 | status = mwifiex_scan_networks(priv, wait, HostCmd_ACT_GEN_GET, | ||
1861 | NULL, &scan); | ||
1862 | |||
1863 | status = mwifiex_request_ioctl(priv, wait, status, wait_option); | ||
1864 | if (!status) { | ||
1865 | if (scan_resp) | ||
1866 | memcpy(scan_resp, &scan, | ||
1867 | sizeof(struct mwifiex_scan_resp)); | ||
1868 | } | ||
1869 | |||
1870 | if (wait && (status != -EINPROGRESS)) | ||
1871 | kfree(wait); | ||
1872 | return status; | ||
1873 | } | ||
1874 | |||
1875 | /* | ||
1876 | * Sends IOCTL request to get signal information. | ||
1877 | * | ||
1878 | * This function allocates the IOCTL request buffer, fills it | ||
1879 | * with requisite parameters and calls the IOCTL handler. | ||
1880 | */ | ||
1881 | int mwifiex_get_signal_info(struct mwifiex_private *priv, u8 wait_option, | ||
1882 | struct mwifiex_ds_get_signal *signal) | ||
1883 | { | ||
1884 | struct mwifiex_ds_get_signal info; | ||
1885 | struct mwifiex_wait_queue *wait = NULL; | ||
1886 | int status = 0; | ||
1887 | |||
1888 | /* Allocate wait buffer */ | ||
1889 | wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); | ||
1890 | if (!wait) | ||
1891 | return -ENOMEM; | ||
1892 | |||
1893 | info.selector = ALL_RSSI_INFO_MASK; | ||
1894 | |||
1895 | status = mwifiex_get_info_signal(priv, wait, &info); | ||
1896 | |||
1897 | status = mwifiex_request_ioctl(priv, wait, status, wait_option); | ||
1898 | if (!status) { | ||
1899 | if (signal) | ||
1900 | memcpy(signal, &info, | ||
1901 | sizeof(struct mwifiex_ds_get_signal)); | ||
1902 | if (info.selector & BCN_RSSI_AVG_MASK) | ||
1903 | priv->w_stats.qual.level = info.bcn_rssi_avg; | ||
1904 | if (info.selector & BCN_NF_AVG_MASK) | ||
1905 | priv->w_stats.qual.noise = info.bcn_nf_avg; | ||
1906 | } | ||
1907 | |||
1908 | if (wait && (status != -EINPROGRESS)) | ||
1909 | kfree(wait); | ||
1910 | return status; | ||
1911 | } | ||
1912 | |||
1913 | /* | ||
1914 | * Sends IOCTL request to set encoding parameters. | ||
1915 | * | ||
1916 | * This function allocates the IOCTL request buffer, fills it | ||
1917 | * with requisite parameters and calls the IOCTL handler. | ||
1918 | */ | ||
1919 | int mwifiex_set_encode(struct mwifiex_private *priv, const u8 *key, | ||
1920 | int key_len, u8 key_index, int disable) | ||
1921 | { | ||
1922 | struct mwifiex_wait_queue *wait = NULL; | ||
1923 | struct mwifiex_ds_encrypt_key encrypt_key; | ||
1924 | int status = 0; | ||
1925 | int ret = 0; | ||
1926 | |||
1927 | wait = mwifiex_alloc_fill_wait_queue(priv, MWIFIEX_IOCTL_WAIT); | ||
1928 | if (!wait) | ||
1929 | return -ENOMEM; | ||
1930 | |||
1931 | memset(&encrypt_key, 0, sizeof(struct mwifiex_ds_encrypt_key)); | ||
1932 | encrypt_key.key_len = key_len; | ||
1933 | if (!disable) { | ||
1934 | encrypt_key.key_index = key_index; | ||
1935 | if (key_len) | ||
1936 | memcpy(encrypt_key.key_material, key, key_len); | ||
1937 | } else { | ||
1938 | encrypt_key.key_disable = true; | ||
1939 | } | ||
1940 | |||
1941 | status = mwifiex_sec_ioctl_encrypt_key(priv, wait, &encrypt_key); | ||
1942 | |||
1943 | if (mwifiex_request_ioctl(priv, wait, status, MWIFIEX_IOCTL_WAIT)) | ||
1944 | ret = -EFAULT; | ||
1945 | |||
1946 | kfree(wait); | ||
1947 | return ret; | ||
1948 | } | ||
1949 | |||
1950 | /* | ||
1951 | * Sends IOCTL request to set power management parameters. | ||
1952 | * | ||
1953 | * This function allocates the IOCTL request buffer, fills it | ||
1954 | * with requisite parameters and calls the IOCTL handler. | ||
1955 | */ | ||
1956 | int | ||
1957 | mwifiex_drv_set_power(struct mwifiex_private *priv, bool power_on) | ||
1958 | { | ||
1959 | int ret = 0; | ||
1960 | int status = 0; | ||
1961 | struct mwifiex_wait_queue *wait = NULL; | ||
1962 | u32 ps_mode; | ||
1963 | |||
1964 | wait = mwifiex_alloc_fill_wait_queue(priv, MWIFIEX_IOCTL_WAIT); | ||
1965 | if (!wait) | ||
1966 | return -ENOMEM; | ||
1967 | |||
1968 | ps_mode = power_on; | ||
1969 | status = mwifiex_pm_ioctl_ps_mode(priv, wait, &ps_mode, | ||
1970 | HostCmd_ACT_GEN_SET); | ||
1971 | |||
1972 | ret = mwifiex_request_ioctl(priv, wait, status, MWIFIEX_IOCTL_WAIT); | ||
1973 | |||
1974 | kfree(wait); | ||
1975 | return ret; | ||
1976 | } | ||
1977 | |||
1978 | /* | ||
1979 | * Sends IOCTL request to get extended version. | ||
1980 | * | ||
1981 | * This function allocates the IOCTL request buffer, fills it | ||
1982 | * with requisite parameters and calls the IOCTL handler. | ||
1983 | */ | ||
1984 | int | ||
1985 | mwifiex_get_ver_ext(struct mwifiex_private *priv) | ||
1986 | { | ||
1987 | struct mwifiex_ver_ext ver_ext; | ||
1988 | struct mwifiex_wait_queue *wait = NULL; | ||
1989 | int status = 0; | ||
1990 | int ret = 0; | ||
1991 | u8 wait_option = MWIFIEX_IOCTL_WAIT; | ||
1992 | |||
1993 | /* Allocate wait buffer */ | ||
1994 | wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); | ||
1995 | if (!wait) | ||
1996 | return -ENOMEM; | ||
1997 | |||
1998 | /* get fw version */ | ||
1999 | memset(&ver_ext, 0, sizeof(struct host_cmd_ds_version_ext)); | ||
2000 | status = mwifiex_get_info_ver_ext(priv, wait, &ver_ext); | ||
2001 | |||
2002 | ret = mwifiex_request_ioctl(priv, wait, status, wait_option); | ||
2003 | |||
2004 | if (ret) | ||
2005 | ret = -1; | ||
2006 | |||
2007 | kfree(wait); | ||
2008 | return ret; | ||
2009 | } | ||
2010 | |||
2011 | /* | ||
2012 | * Sends IOCTL request to get statistics information. | ||
2013 | * | ||
2014 | * This function allocates the IOCTL request buffer, fills it | ||
2015 | * with requisite parameters and calls the IOCTL handler. | ||
2016 | */ | ||
2017 | int | ||
2018 | mwifiex_get_stats_info(struct mwifiex_private *priv, | ||
2019 | struct mwifiex_ds_get_stats *log) | ||
2020 | { | ||
2021 | int ret = 0; | ||
2022 | int status = 0; | ||
2023 | struct mwifiex_wait_queue *wait = NULL; | ||
2024 | struct mwifiex_ds_get_stats get_log; | ||
2025 | u8 wait_option = MWIFIEX_IOCTL_WAIT; | ||
2026 | |||
2027 | /* Allocate wait buffer */ | ||
2028 | wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); | ||
2029 | if (!wait) | ||
2030 | return -ENOMEM; | ||
2031 | |||
2032 | memset(&get_log, 0, sizeof(struct mwifiex_ds_get_stats)); | ||
2033 | status = mwifiex_get_info_stats(priv, wait, &get_log); | ||
2034 | |||
2035 | /* Send IOCTL request to MWIFIEX */ | ||
2036 | ret = mwifiex_request_ioctl(priv, wait, status, wait_option); | ||
2037 | if (!ret) { | ||
2038 | if (log) | ||
2039 | memcpy(log, &get_log, sizeof(struct | ||
2040 | mwifiex_ds_get_stats)); | ||
2041 | priv->w_stats.discard.fragment = get_log.fcs_error; | ||
2042 | priv->w_stats.discard.retries = get_log.retry; | ||
2043 | priv->w_stats.discard.misc = get_log.ack_failure; | ||
2044 | } | ||
2045 | |||
2046 | kfree(wait); | ||
2047 | return ret; | ||
2048 | } | ||
2049 | |||
2050 | /* | ||
2051 | * IOCTL request handler to read/write register. | ||
2052 | * | ||
2053 | * This function prepares the correct firmware command and | ||
2054 | * issues it. | ||
2055 | * | ||
2056 | * Access to the following registers are supported - | ||
2057 | * - MAC | ||
2058 | * - BBP | ||
2059 | * - RF | ||
2060 | * - PMIC | ||
2061 | * - CAU | ||
2062 | */ | ||
2063 | static int mwifiex_reg_mem_ioctl_reg_rw(struct mwifiex_private *priv, | ||
2064 | struct mwifiex_wait_queue *wait, | ||
2065 | struct mwifiex_ds_reg_rw *reg_rw, | ||
2066 | u16 action) | ||
2067 | { | ||
2068 | int ret = 0; | ||
2069 | u16 cmd_no; | ||
2070 | |||
2071 | switch (le32_to_cpu(reg_rw->type)) { | ||
2072 | case MWIFIEX_REG_MAC: | ||
2073 | cmd_no = HostCmd_CMD_MAC_REG_ACCESS; | ||
2074 | break; | ||
2075 | case MWIFIEX_REG_BBP: | ||
2076 | cmd_no = HostCmd_CMD_BBP_REG_ACCESS; | ||
2077 | break; | ||
2078 | case MWIFIEX_REG_RF: | ||
2079 | cmd_no = HostCmd_CMD_RF_REG_ACCESS; | ||
2080 | break; | ||
2081 | case MWIFIEX_REG_PMIC: | ||
2082 | cmd_no = HostCmd_CMD_PMIC_REG_ACCESS; | ||
2083 | break; | ||
2084 | case MWIFIEX_REG_CAU: | ||
2085 | cmd_no = HostCmd_CMD_CAU_REG_ACCESS; | ||
2086 | break; | ||
2087 | default: | ||
2088 | return -1; | ||
2089 | } | ||
2090 | |||
2091 | /* Send request to firmware */ | ||
2092 | ret = mwifiex_prepare_cmd(priv, cmd_no, action, 0, wait, reg_rw); | ||
2093 | |||
2094 | if (!ret) | ||
2095 | ret = -EINPROGRESS; | ||
2096 | |||
2097 | return ret; | ||
2098 | } | ||
2099 | |||
2100 | /* | ||
2101 | * Sends IOCTL request to write to a register. | ||
2102 | * | ||
2103 | * This function allocates the IOCTL request buffer, fills it | ||
2104 | * with requisite parameters and calls the IOCTL handler. | ||
2105 | */ | ||
2106 | int | ||
2107 | mwifiex_reg_write(struct mwifiex_private *priv, u32 reg_type, | ||
2108 | u32 reg_offset, u32 reg_value) | ||
2109 | { | ||
2110 | int ret = 0; | ||
2111 | int status = 0; | ||
2112 | struct mwifiex_wait_queue *wait = NULL; | ||
2113 | struct mwifiex_ds_reg_rw reg_rw; | ||
2114 | |||
2115 | wait = mwifiex_alloc_fill_wait_queue(priv, MWIFIEX_IOCTL_WAIT); | ||
2116 | if (!wait) | ||
2117 | return -ENOMEM; | ||
2118 | |||
2119 | reg_rw.type = cpu_to_le32(reg_type); | ||
2120 | reg_rw.offset = cpu_to_le32(reg_offset); | ||
2121 | reg_rw.value = cpu_to_le32(reg_value); | ||
2122 | status = mwifiex_reg_mem_ioctl_reg_rw(priv, wait, ®_rw, | ||
2123 | HostCmd_ACT_GEN_SET); | ||
2124 | |||
2125 | ret = mwifiex_request_ioctl(priv, wait, status, MWIFIEX_IOCTL_WAIT); | ||
2126 | |||
2127 | kfree(wait); | ||
2128 | return ret; | ||
2129 | } | ||
2130 | |||
2131 | /* | ||
2132 | * Sends IOCTL request to read from a register. | ||
2133 | * | ||
2134 | * This function allocates the IOCTL request buffer, fills it | ||
2135 | * with requisite parameters and calls the IOCTL handler. | ||
2136 | */ | ||
2137 | int | ||
2138 | mwifiex_reg_read(struct mwifiex_private *priv, u32 reg_type, | ||
2139 | u32 reg_offset, u32 *value) | ||
2140 | { | ||
2141 | int ret = 0; | ||
2142 | int status = 0; | ||
2143 | struct mwifiex_wait_queue *wait = NULL; | ||
2144 | struct mwifiex_ds_reg_rw reg_rw; | ||
2145 | |||
2146 | wait = mwifiex_alloc_fill_wait_queue(priv, MWIFIEX_IOCTL_WAIT); | ||
2147 | if (!wait) | ||
2148 | return -ENOMEM; | ||
2149 | |||
2150 | reg_rw.type = cpu_to_le32(reg_type); | ||
2151 | reg_rw.offset = cpu_to_le32(reg_offset); | ||
2152 | status = mwifiex_reg_mem_ioctl_reg_rw(priv, wait, ®_rw, | ||
2153 | HostCmd_ACT_GEN_GET); | ||
2154 | |||
2155 | ret = mwifiex_request_ioctl(priv, wait, status, MWIFIEX_IOCTL_WAIT); | ||
2156 | if (ret) | ||
2157 | goto done; | ||
2158 | |||
2159 | *value = le32_to_cpu(reg_rw.value); | ||
2160 | |||
2161 | done: | ||
2162 | kfree(wait); | ||
2163 | return ret; | ||
2164 | } | ||
2165 | |||
2166 | /* | ||
2167 | * IOCTL request handler to read EEPROM. | ||
2168 | * | ||
2169 | * This function prepares the correct firmware command and | ||
2170 | * issues it. | ||
2171 | */ | ||
2172 | static int | ||
2173 | mwifiex_reg_mem_ioctl_read_eeprom(struct mwifiex_private *priv, | ||
2174 | struct mwifiex_wait_queue *wait, | ||
2175 | struct mwifiex_ds_read_eeprom *rd_eeprom) | ||
2176 | { | ||
2177 | int ret = 0; | ||
2178 | |||
2179 | /* Send request to firmware */ | ||
2180 | ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_EEPROM_ACCESS, | ||
2181 | HostCmd_ACT_GEN_GET, 0, wait, rd_eeprom); | ||
2182 | |||
2183 | if (!ret) | ||
2184 | ret = -EINPROGRESS; | ||
2185 | |||
2186 | return ret; | ||
2187 | } | ||
2188 | |||
2189 | /* | ||
2190 | * Sends IOCTL request to read from EEPROM. | ||
2191 | * | ||
2192 | * This function allocates the IOCTL request buffer, fills it | ||
2193 | * with requisite parameters and calls the IOCTL handler. | ||
2194 | */ | ||
2195 | int | ||
2196 | mwifiex_eeprom_read(struct mwifiex_private *priv, u16 offset, u16 bytes, | ||
2197 | u8 *value) | ||
2198 | { | ||
2199 | int ret = 0; | ||
2200 | int status = 0; | ||
2201 | struct mwifiex_wait_queue *wait = NULL; | ||
2202 | struct mwifiex_ds_read_eeprom rd_eeprom; | ||
2203 | |||
2204 | wait = mwifiex_alloc_fill_wait_queue(priv, MWIFIEX_IOCTL_WAIT); | ||
2205 | if (!wait) | ||
2206 | return -ENOMEM; | ||
2207 | |||
2208 | rd_eeprom.offset = cpu_to_le16((u16) offset); | ||
2209 | rd_eeprom.byte_count = cpu_to_le16((u16) bytes); | ||
2210 | status = mwifiex_reg_mem_ioctl_read_eeprom(priv, wait, &rd_eeprom); | ||
2211 | |||
2212 | ret = mwifiex_request_ioctl(priv, wait, status, MWIFIEX_IOCTL_WAIT); | ||
2213 | if (ret) | ||
2214 | goto done; | ||
2215 | |||
2216 | memcpy(value, rd_eeprom.value, MAX_EEPROM_DATA); | ||
2217 | done: | ||
2218 | kfree(wait); | ||
2219 | return ret; | ||
2220 | } | ||
2221 | |||
2222 | /* | ||
2223 | * This function sets a generic IE. In addition to generic IE, it can | ||
2224 | * also handle WPA, WPA2 and WAPI IEs. | ||
2225 | */ | ||
2226 | static int | ||
2227 | mwifiex_set_gen_ie_helper(struct mwifiex_private *priv, u8 *ie_data_ptr, | ||
2228 | u16 ie_len) | ||
2229 | { | ||
2230 | int ret = 0; | ||
2231 | struct ieee_types_vendor_header *pvendor_ie; | ||
2232 | const u8 wpa_oui[] = { 0x00, 0x50, 0xf2, 0x01 }; | ||
2233 | const u8 wps_oui[] = { 0x00, 0x50, 0xf2, 0x04 }; | ||
2234 | |||
2235 | /* If the passed length is zero, reset the buffer */ | ||
2236 | if (!ie_len) { | ||
2237 | priv->gen_ie_buf_len = 0; | ||
2238 | priv->wps.session_enable = false; | ||
2239 | |||
2240 | return 0; | ||
2241 | } else if (!ie_data_ptr) { | ||
2242 | return -1; | ||
2243 | } | ||
2244 | pvendor_ie = (struct ieee_types_vendor_header *) ie_data_ptr; | ||
2245 | /* Test to see if it is a WPA IE, if not, then it is a gen IE */ | ||
2246 | if (((pvendor_ie->element_id == WLAN_EID_WPA) | ||
2247 | && (!memcmp(pvendor_ie->oui, wpa_oui, sizeof(wpa_oui)))) | ||
2248 | || (pvendor_ie->element_id == WLAN_EID_RSN)) { | ||
2249 | |||
2250 | /* IE is a WPA/WPA2 IE so call set_wpa function */ | ||
2251 | ret = mwifiex_set_wpa_ie_helper(priv, ie_data_ptr, ie_len); | ||
2252 | priv->wps.session_enable = false; | ||
2253 | |||
2254 | return ret; | ||
2255 | } else if (pvendor_ie->element_id == WLAN_EID_BSS_AC_ACCESS_DELAY) { | ||
2256 | /* IE is a WAPI IE so call set_wapi function */ | ||
2257 | ret = mwifiex_set_wapi_ie(priv, ie_data_ptr, ie_len); | ||
2258 | |||
2259 | return ret; | ||
2260 | } | ||
2261 | /* | ||
2262 | * Verify that the passed length is not larger than the | ||
2263 | * available space remaining in the buffer | ||
2264 | */ | ||
2265 | if (ie_len < (sizeof(priv->gen_ie_buf) - priv->gen_ie_buf_len)) { | ||
2266 | |||
2267 | /* Test to see if it is a WPS IE, if so, enable | ||
2268 | * wps session flag | ||
2269 | */ | ||
2270 | pvendor_ie = (struct ieee_types_vendor_header *) ie_data_ptr; | ||
2271 | if ((pvendor_ie->element_id == WLAN_EID_VENDOR_SPECIFIC) | ||
2272 | && (!memcmp(pvendor_ie->oui, wps_oui, | ||
2273 | sizeof(wps_oui)))) { | ||
2274 | priv->wps.session_enable = true; | ||
2275 | dev_dbg(priv->adapter->dev, | ||
2276 | "info: WPS Session Enabled.\n"); | ||
2277 | } | ||
2278 | |||
2279 | /* Append the passed data to the end of the | ||
2280 | genIeBuffer */ | ||
2281 | memcpy(priv->gen_ie_buf + priv->gen_ie_buf_len, ie_data_ptr, | ||
2282 | ie_len); | ||
2283 | /* Increment the stored buffer length by the | ||
2284 | size passed */ | ||
2285 | priv->gen_ie_buf_len += ie_len; | ||
2286 | } else { | ||
2287 | /* Passed data does not fit in the remaining | ||
2288 | buffer space */ | ||
2289 | ret = -1; | ||
2290 | } | ||
2291 | |||
2292 | /* Return 0, or -1 for error case */ | ||
2293 | return ret; | ||
2294 | } | ||
2295 | |||
2296 | /* | ||
2297 | * IOCTL request handler to set/get generic IE. | ||
2298 | * | ||
2299 | * In addition to various generic IEs, this function can also be | ||
2300 | * used to set the ARP filter. | ||
2301 | */ | ||
2302 | static int mwifiex_misc_ioctl_gen_ie(struct mwifiex_private *priv, | ||
2303 | struct mwifiex_ds_misc_gen_ie *gen_ie, | ||
2304 | u16 action) | ||
2305 | { | ||
2306 | struct mwifiex_adapter *adapter = priv->adapter; | ||
2307 | |||
2308 | switch (gen_ie->type) { | ||
2309 | case MWIFIEX_IE_TYPE_GEN_IE: | ||
2310 | if (action == HostCmd_ACT_GEN_GET) { | ||
2311 | gen_ie->len = priv->wpa_ie_len; | ||
2312 | memcpy(gen_ie->ie_data, priv->wpa_ie, gen_ie->len); | ||
2313 | } else { | ||
2314 | mwifiex_set_gen_ie_helper(priv, gen_ie->ie_data, | ||
2315 | (u16) gen_ie->len); | ||
2316 | } | ||
2317 | break; | ||
2318 | case MWIFIEX_IE_TYPE_ARP_FILTER: | ||
2319 | memset(adapter->arp_filter, 0, sizeof(adapter->arp_filter)); | ||
2320 | if (gen_ie->len > ARP_FILTER_MAX_BUF_SIZE) { | ||
2321 | adapter->arp_filter_size = 0; | ||
2322 | dev_err(adapter->dev, "invalid ARP filter size\n"); | ||
2323 | return -1; | ||
2324 | } else { | ||
2325 | memcpy(adapter->arp_filter, gen_ie->ie_data, | ||
2326 | gen_ie->len); | ||
2327 | adapter->arp_filter_size = gen_ie->len; | ||
2328 | } | ||
2329 | break; | ||
2330 | default: | ||
2331 | dev_err(adapter->dev, "invalid IE type\n"); | ||
2332 | return -1; | ||
2333 | } | ||
2334 | return 0; | ||
2335 | } | ||
2336 | |||
2337 | /* | ||
2338 | * Sends IOCTL request to set a generic IE. | ||
2339 | * | ||
2340 | * This function allocates the IOCTL request buffer, fills it | ||
2341 | * with requisite parameters and calls the IOCTL handler. | ||
2342 | */ | ||
2343 | int | ||
2344 | mwifiex_set_gen_ie(struct mwifiex_private *priv, u8 *ie, int ie_len) | ||
2345 | { | ||
2346 | struct mwifiex_ds_misc_gen_ie gen_ie; | ||
2347 | int status = 0; | ||
2348 | |||
2349 | if (ie_len > IW_CUSTOM_MAX) | ||
2350 | return -EFAULT; | ||
2351 | |||
2352 | gen_ie.type = MWIFIEX_IE_TYPE_GEN_IE; | ||
2353 | gen_ie.len = ie_len; | ||
2354 | memcpy(gen_ie.ie_data, ie, ie_len); | ||
2355 | status = mwifiex_misc_ioctl_gen_ie(priv, &gen_ie, HostCmd_ACT_GEN_SET); | ||
2356 | if (status) | ||
2357 | return -EFAULT; | ||
2358 | |||
2359 | return 0; | ||
2360 | } | ||
diff --git a/drivers/net/wireless/mwifiex/sta_rx.c b/drivers/net/wireless/mwifiex/sta_rx.c new file mode 100644 index 000000000000..8282679e64fd --- /dev/null +++ b/drivers/net/wireless/mwifiex/sta_rx.c | |||
@@ -0,0 +1,182 @@ | |||
1 | /* | ||
2 | * Marvell Wireless LAN device driver: station RX data handling | ||
3 | * | ||
4 | * Copyright (C) 2011, Marvell International Ltd. | ||
5 | * | ||
6 | * This software file (the "File") is distributed by Marvell International | ||
7 | * Ltd. under the terms of the GNU General Public License Version 2, June 1991 | ||
8 | * (the "License"). You may use, redistribute and/or modify this File in | ||
9 | * accordance with the terms and conditions of the License, a copy of which | ||
10 | * is available by writing to the Free Software Foundation, Inc., | ||
11 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the | ||
12 | * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. | ||
13 | * | ||
14 | * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE | ||
15 | * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE | ||
16 | * ARE EXPRESSLY DISCLAIMED. The License provides additional details about | ||
17 | * this warranty disclaimer. | ||
18 | */ | ||
19 | |||
20 | #include "decl.h" | ||
21 | #include "ioctl.h" | ||
22 | #include "util.h" | ||
23 | #include "fw.h" | ||
24 | #include "main.h" | ||
25 | #include "11n_aggr.h" | ||
26 | #include "11n_rxreorder.h" | ||
27 | |||
28 | /* | ||
29 | * This function processes the received packet and forwards it | ||
30 | * to kernel/upper layer. | ||
31 | * | ||
32 | * This function parses through the received packet and determines | ||
33 | * if it is a debug packet or normal packet. | ||
34 | * | ||
35 | * For non-debug packets, the function chops off unnecessary leading | ||
36 | * header bytes, reconstructs the packet as an ethernet frame or | ||
37 | * 802.2/llc/snap frame as required, and sends it to kernel/upper layer. | ||
38 | * | ||
39 | * The completion callback is called after processing in complete. | ||
40 | */ | ||
41 | int mwifiex_process_rx_packet(struct mwifiex_adapter *adapter, | ||
42 | struct sk_buff *skb) | ||
43 | { | ||
44 | int ret = 0; | ||
45 | struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb); | ||
46 | struct mwifiex_private *priv = adapter->priv[rx_info->bss_index]; | ||
47 | struct rx_packet_hdr *rx_pkt_hdr; | ||
48 | struct rxpd *local_rx_pd; | ||
49 | int hdr_chop; | ||
50 | struct ethhdr *eth_hdr; | ||
51 | u8 rfc1042_eth_hdr[ETH_ALEN] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; | ||
52 | |||
53 | local_rx_pd = (struct rxpd *) (skb->data); | ||
54 | |||
55 | rx_pkt_hdr = (struct rx_packet_hdr *) ((u8 *) local_rx_pd + | ||
56 | local_rx_pd->rx_pkt_offset); | ||
57 | |||
58 | if (!memcmp(&rx_pkt_hdr->rfc1042_hdr, | ||
59 | rfc1042_eth_hdr, sizeof(rfc1042_eth_hdr))) { | ||
60 | /* | ||
61 | * Replace the 803 header and rfc1042 header (llc/snap) with an | ||
62 | * EthernetII header, keep the src/dst and snap_type | ||
63 | * (ethertype). | ||
64 | * The firmware only passes up SNAP frames converting | ||
65 | * all RX Data from 802.11 to 802.2/LLC/SNAP frames. | ||
66 | * To create the Ethernet II, just move the src, dst address | ||
67 | * right before the snap_type. | ||
68 | */ | ||
69 | eth_hdr = (struct ethhdr *) | ||
70 | ((u8 *) &rx_pkt_hdr->eth803_hdr | ||
71 | + sizeof(rx_pkt_hdr->eth803_hdr) + | ||
72 | sizeof(rx_pkt_hdr->rfc1042_hdr) | ||
73 | - sizeof(rx_pkt_hdr->eth803_hdr.h_dest) | ||
74 | - sizeof(rx_pkt_hdr->eth803_hdr.h_source) | ||
75 | - sizeof(rx_pkt_hdr->rfc1042_hdr.snap_type)); | ||
76 | |||
77 | memcpy(eth_hdr->h_source, rx_pkt_hdr->eth803_hdr.h_source, | ||
78 | sizeof(eth_hdr->h_source)); | ||
79 | memcpy(eth_hdr->h_dest, rx_pkt_hdr->eth803_hdr.h_dest, | ||
80 | sizeof(eth_hdr->h_dest)); | ||
81 | |||
82 | /* Chop off the rxpd + the excess memory from the 802.2/llc/snap | ||
83 | header that was removed. */ | ||
84 | hdr_chop = (u8 *) eth_hdr - (u8 *) local_rx_pd; | ||
85 | } else { | ||
86 | /* Chop off the rxpd */ | ||
87 | hdr_chop = (u8 *) &rx_pkt_hdr->eth803_hdr - | ||
88 | (u8 *) local_rx_pd; | ||
89 | } | ||
90 | |||
91 | /* Chop off the leading header bytes so the it points to the start of | ||
92 | either the reconstructed EthII frame or the 802.2/llc/snap frame */ | ||
93 | skb_pull(skb, hdr_chop); | ||
94 | |||
95 | priv->rxpd_rate = local_rx_pd->rx_rate; | ||
96 | |||
97 | priv->rxpd_htinfo = local_rx_pd->ht_info; | ||
98 | |||
99 | ret = mwifiex_recv_packet(adapter, skb); | ||
100 | if (ret == -1) | ||
101 | dev_err(adapter->dev, "recv packet failed\n"); | ||
102 | |||
103 | return ret; | ||
104 | } | ||
105 | |||
106 | /* | ||
107 | * This function processes the received buffer. | ||
108 | * | ||
109 | * The function looks into the RxPD and performs sanity tests on the | ||
110 | * received buffer to ensure its a valid packet, before processing it | ||
111 | * further. If the packet is determined to be aggregated, it is | ||
112 | * de-aggregated accordingly. Non-unicast packets are sent directly to | ||
113 | * the kernel/upper layers. Unicast packets are handed over to the | ||
114 | * Rx reordering routine if 11n is enabled. | ||
115 | * | ||
116 | * The completion callback is called after processing in complete. | ||
117 | */ | ||
118 | int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *adapter, | ||
119 | struct sk_buff *skb) | ||
120 | { | ||
121 | int ret = 0; | ||
122 | struct rxpd *local_rx_pd; | ||
123 | struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb); | ||
124 | struct rx_packet_hdr *rx_pkt_hdr; | ||
125 | u8 ta[ETH_ALEN]; | ||
126 | u16 rx_pkt_type = 0; | ||
127 | struct mwifiex_private *priv = adapter->priv[rx_info->bss_index]; | ||
128 | |||
129 | local_rx_pd = (struct rxpd *) (skb->data); | ||
130 | rx_pkt_type = local_rx_pd->rx_pkt_type; | ||
131 | |||
132 | rx_pkt_hdr = (struct rx_packet_hdr *) ((u8 *) local_rx_pd + | ||
133 | local_rx_pd->rx_pkt_offset); | ||
134 | |||
135 | if ((local_rx_pd->rx_pkt_offset + local_rx_pd->rx_pkt_length) > | ||
136 | (u16) skb->len) { | ||
137 | dev_err(adapter->dev, "wrong rx packet: len=%d," | ||
138 | " rx_pkt_offset=%d, rx_pkt_length=%d\n", skb->len, | ||
139 | local_rx_pd->rx_pkt_offset, local_rx_pd->rx_pkt_length); | ||
140 | priv->stats.rx_dropped++; | ||
141 | dev_kfree_skb_any(skb); | ||
142 | return ret; | ||
143 | } | ||
144 | if (local_rx_pd->rx_pkt_type == PKT_TYPE_AMSDU) { | ||
145 | mwifiex_11n_deaggregate_pkt(priv, skb); | ||
146 | return ret; | ||
147 | } | ||
148 | /* | ||
149 | * If the packet is not an unicast packet then send the packet | ||
150 | * directly to os. Don't pass thru rx reordering | ||
151 | */ | ||
152 | if (!IS_11N_ENABLED(priv) || | ||
153 | memcmp(priv->curr_addr, rx_pkt_hdr->eth803_hdr.h_dest, ETH_ALEN)) { | ||
154 | mwifiex_process_rx_packet(adapter, skb); | ||
155 | return ret; | ||
156 | } | ||
157 | |||
158 | if (mwifiex_queuing_ra_based(priv)) { | ||
159 | memcpy(ta, rx_pkt_hdr->eth803_hdr.h_source, ETH_ALEN); | ||
160 | } else { | ||
161 | if (rx_pkt_type != PKT_TYPE_BAR) | ||
162 | priv->rx_seq[local_rx_pd->priority] = | ||
163 | local_rx_pd->seq_num; | ||
164 | memcpy(ta, priv->curr_bss_params.bss_descriptor.mac_address, | ||
165 | ETH_ALEN); | ||
166 | } | ||
167 | |||
168 | /* Reorder and send to OS */ | ||
169 | ret = mwifiex_11n_rx_reorder_pkt(priv, local_rx_pd->seq_num, | ||
170 | local_rx_pd->priority, ta, | ||
171 | (u8) local_rx_pd->rx_pkt_type, | ||
172 | (void *) skb); | ||
173 | |||
174 | if (ret || (rx_pkt_type == PKT_TYPE_BAR)) { | ||
175 | if (priv && (ret == -1)) | ||
176 | priv->stats.rx_dropped++; | ||
177 | |||
178 | dev_kfree_skb_any(skb); | ||
179 | } | ||
180 | |||
181 | return ret; | ||
182 | } | ||
diff --git a/drivers/net/wireless/mwifiex/sta_tx.c b/drivers/net/wireless/mwifiex/sta_tx.c new file mode 100644 index 000000000000..e8db6bd021c6 --- /dev/null +++ b/drivers/net/wireless/mwifiex/sta_tx.c | |||
@@ -0,0 +1,202 @@ | |||
1 | /* | ||
2 | * Marvell Wireless LAN device driver: station TX data handling | ||
3 | * | ||
4 | * Copyright (C) 2011, Marvell International Ltd. | ||
5 | * | ||
6 | * This software file (the "File") is distributed by Marvell International | ||
7 | * Ltd. under the terms of the GNU General Public License Version 2, June 1991 | ||
8 | * (the "License"). You may use, redistribute and/or modify this File in | ||
9 | * accordance with the terms and conditions of the License, a copy of which | ||
10 | * is available by writing to the Free Software Foundation, Inc., | ||
11 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the | ||
12 | * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. | ||
13 | * | ||
14 | * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE | ||
15 | * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE | ||
16 | * ARE EXPRESSLY DISCLAIMED. The License provides additional details about | ||
17 | * this warranty disclaimer. | ||
18 | */ | ||
19 | |||
20 | #include "decl.h" | ||
21 | #include "ioctl.h" | ||
22 | #include "util.h" | ||
23 | #include "fw.h" | ||
24 | #include "main.h" | ||
25 | #include "wmm.h" | ||
26 | |||
27 | /* | ||
28 | * This function fills the TxPD for tx packets. | ||
29 | * | ||
30 | * The Tx buffer received by this function should already have the | ||
31 | * header space allocated for TxPD. | ||
32 | * | ||
33 | * This function inserts the TxPD in between interface header and actual | ||
34 | * data and adjusts the buffer pointers accordingly. | ||
35 | * | ||
36 | * The following TxPD fields are set by this function, as required - | ||
37 | * - BSS number | ||
38 | * - Tx packet length and offset | ||
39 | * - Priority | ||
40 | * - Packet delay | ||
41 | * - Priority specific Tx control | ||
42 | * - Flags | ||
43 | */ | ||
44 | void *mwifiex_process_sta_txpd(struct mwifiex_private *priv, | ||
45 | struct sk_buff *skb) | ||
46 | { | ||
47 | struct mwifiex_adapter *adapter = priv->adapter; | ||
48 | struct txpd *local_tx_pd; | ||
49 | struct mwifiex_txinfo *tx_info = MWIFIEX_SKB_TXCB(skb); | ||
50 | |||
51 | if (!skb->len) { | ||
52 | dev_err(adapter->dev, "Tx: bad packet length: %d\n", | ||
53 | skb->len); | ||
54 | tx_info->status_code = MWIFIEX_ERROR_PKT_SIZE_INVALID; | ||
55 | return skb->data; | ||
56 | } | ||
57 | |||
58 | BUG_ON(skb_headroom(skb) < (sizeof(*local_tx_pd) + INTF_HEADER_LEN)); | ||
59 | skb_push(skb, sizeof(*local_tx_pd)); | ||
60 | |||
61 | local_tx_pd = (struct txpd *) skb->data; | ||
62 | memset(local_tx_pd, 0, sizeof(struct txpd)); | ||
63 | local_tx_pd->bss_num = priv->bss_num; | ||
64 | local_tx_pd->bss_type = priv->bss_type; | ||
65 | local_tx_pd->tx_pkt_length = cpu_to_le16((u16) (skb->len - | ||
66 | sizeof(struct txpd))); | ||
67 | |||
68 | local_tx_pd->priority = (u8) skb->priority; | ||
69 | local_tx_pd->pkt_delay_2ms = | ||
70 | mwifiex_wmm_compute_drv_pkt_delay(priv, skb); | ||
71 | |||
72 | if (local_tx_pd->priority < | ||
73 | ARRAY_SIZE(priv->wmm.user_pri_pkt_tx_ctrl)) | ||
74 | /* | ||
75 | * Set the priority specific tx_control field, setting of 0 will | ||
76 | * cause the default value to be used later in this function | ||
77 | */ | ||
78 | local_tx_pd->tx_control = | ||
79 | cpu_to_le32(priv->wmm.user_pri_pkt_tx_ctrl[local_tx_pd-> | ||
80 | priority]); | ||
81 | |||
82 | if (adapter->pps_uapsd_mode) { | ||
83 | if (mwifiex_check_last_packet_indication(priv)) { | ||
84 | adapter->tx_lock_flag = true; | ||
85 | local_tx_pd->flags = | ||
86 | MWIFIEX_TxPD_POWER_MGMT_LAST_PACKET; | ||
87 | } | ||
88 | } | ||
89 | |||
90 | /* Offset of actual data */ | ||
91 | local_tx_pd->tx_pkt_offset = cpu_to_le16(sizeof(struct txpd)); | ||
92 | |||
93 | /* make space for INTF_HEADER_LEN */ | ||
94 | skb_push(skb, INTF_HEADER_LEN); | ||
95 | |||
96 | if (!local_tx_pd->tx_control) | ||
97 | /* TxCtrl set by user or default */ | ||
98 | local_tx_pd->tx_control = cpu_to_le32(priv->pkt_tx_ctrl); | ||
99 | |||
100 | return skb->data; | ||
101 | } | ||
102 | |||
103 | /* | ||
104 | * This function tells firmware to send a NULL data packet. | ||
105 | * | ||
106 | * The function creates a NULL data packet with TxPD and sends to the | ||
107 | * firmware for transmission, with highest priority setting. | ||
108 | */ | ||
109 | int mwifiex_send_null_packet(struct mwifiex_private *priv, u8 flags) | ||
110 | { | ||
111 | struct mwifiex_adapter *adapter = priv->adapter; | ||
112 | struct txpd *local_tx_pd; | ||
113 | /* sizeof(struct txpd) + Interface specific header */ | ||
114 | #define NULL_PACKET_HDR 64 | ||
115 | u32 data_len = NULL_PACKET_HDR; | ||
116 | struct sk_buff *skb = NULL; | ||
117 | int ret = 0; | ||
118 | struct mwifiex_txinfo *tx_info = NULL; | ||
119 | |||
120 | if (adapter->surprise_removed) | ||
121 | return -1; | ||
122 | |||
123 | if (!priv->media_connected) | ||
124 | return -1; | ||
125 | |||
126 | if (adapter->data_sent) | ||
127 | return -1; | ||
128 | |||
129 | skb = dev_alloc_skb(data_len); | ||
130 | if (!skb) | ||
131 | return -1; | ||
132 | |||
133 | tx_info = MWIFIEX_SKB_TXCB(skb); | ||
134 | tx_info->bss_index = priv->bss_index; | ||
135 | skb_reserve(skb, sizeof(struct txpd) + INTF_HEADER_LEN); | ||
136 | skb_push(skb, sizeof(struct txpd)); | ||
137 | |||
138 | local_tx_pd = (struct txpd *) skb->data; | ||
139 | local_tx_pd->tx_control = cpu_to_le32(priv->pkt_tx_ctrl); | ||
140 | local_tx_pd->flags = flags; | ||
141 | local_tx_pd->priority = WMM_HIGHEST_PRIORITY; | ||
142 | local_tx_pd->tx_pkt_offset = cpu_to_le16(sizeof(struct txpd)); | ||
143 | local_tx_pd->bss_num = priv->bss_num; | ||
144 | local_tx_pd->bss_type = priv->bss_type; | ||
145 | |||
146 | skb_push(skb, INTF_HEADER_LEN); | ||
147 | |||
148 | ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA, | ||
149 | skb->data, skb->len, NULL); | ||
150 | switch (ret) { | ||
151 | case -EBUSY: | ||
152 | adapter->data_sent = true; | ||
153 | /* Fall through FAILURE handling */ | ||
154 | case -1: | ||
155 | dev_kfree_skb_any(skb); | ||
156 | dev_err(adapter->dev, "%s: host_to_card failed: ret=%d\n", | ||
157 | __func__, ret); | ||
158 | adapter->dbg.num_tx_host_to_card_failure++; | ||
159 | break; | ||
160 | case 0: | ||
161 | dev_kfree_skb_any(skb); | ||
162 | dev_dbg(adapter->dev, "data: %s: host_to_card succeeded\n", | ||
163 | __func__); | ||
164 | adapter->tx_lock_flag = true; | ||
165 | break; | ||
166 | case -EINPROGRESS: | ||
167 | break; | ||
168 | default: | ||
169 | break; | ||
170 | } | ||
171 | |||
172 | return ret; | ||
173 | } | ||
174 | |||
175 | /* | ||
176 | * This function checks if we need to send last packet indication. | ||
177 | */ | ||
178 | u8 | ||
179 | mwifiex_check_last_packet_indication(struct mwifiex_private *priv) | ||
180 | { | ||
181 | struct mwifiex_adapter *adapter = priv->adapter; | ||
182 | u8 ret = false; | ||
183 | u8 prop_ps = true; | ||
184 | |||
185 | if (!adapter->sleep_period.period) | ||
186 | return ret; | ||
187 | if (mwifiex_wmm_lists_empty(adapter)) { | ||
188 | if ((priv->curr_bss_params.wmm_uapsd_enabled && | ||
189 | priv->wmm_qosinfo) || prop_ps) | ||
190 | ret = true; | ||
191 | } | ||
192 | |||
193 | if (ret && !adapter->cmd_sent && !adapter->curr_cmd | ||
194 | && !is_command_pending(adapter)) { | ||
195 | adapter->delay_null_pkt = false; | ||
196 | ret = true; | ||
197 | } else { | ||
198 | ret = false; | ||
199 | adapter->delay_null_pkt = true; | ||
200 | } | ||
201 | return ret; | ||
202 | } | ||
diff --git a/drivers/net/wireless/mwifiex/txrx.c b/drivers/net/wireless/mwifiex/txrx.c new file mode 100644 index 000000000000..f06923cb1c4b --- /dev/null +++ b/drivers/net/wireless/mwifiex/txrx.c | |||
@@ -0,0 +1,202 @@ | |||
1 | /* | ||
2 | * Marvell Wireless LAN device driver: generic TX/RX data handling | ||
3 | * | ||
4 | * Copyright (C) 2011, Marvell International Ltd. | ||
5 | * | ||
6 | * This software file (the "File") is distributed by Marvell International | ||
7 | * Ltd. under the terms of the GNU General Public License Version 2, June 1991 | ||
8 | * (the "License"). You may use, redistribute and/or modify this File in | ||
9 | * accordance with the terms and conditions of the License, a copy of which | ||
10 | * is available by writing to the Free Software Foundation, Inc., | ||
11 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the | ||
12 | * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. | ||
13 | * | ||
14 | * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE | ||
15 | * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE | ||
16 | * ARE EXPRESSLY DISCLAIMED. The License provides additional details about | ||
17 | * this warranty disclaimer. | ||
18 | */ | ||
19 | |||
20 | #include "decl.h" | ||
21 | #include "ioctl.h" | ||
22 | #include "util.h" | ||
23 | #include "fw.h" | ||
24 | #include "main.h" | ||
25 | #include "wmm.h" | ||
26 | |||
27 | /* | ||
28 | * This function processes the received buffer. | ||
29 | * | ||
30 | * Main responsibility of this function is to parse the RxPD to | ||
31 | * identify the correct interface this packet is headed for and | ||
32 | * forwarding it to the associated handling function, where the | ||
33 | * packet will be further processed and sent to kernel/upper layer | ||
34 | * if required. | ||
35 | */ | ||
36 | int mwifiex_handle_rx_packet(struct mwifiex_adapter *adapter, | ||
37 | struct sk_buff *skb) | ||
38 | { | ||
39 | int ret = 0; | ||
40 | struct mwifiex_private *priv = | ||
41 | mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); | ||
42 | struct rxpd *local_rx_pd; | ||
43 | struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb); | ||
44 | |||
45 | local_rx_pd = (struct rxpd *) (skb->data); | ||
46 | /* Get the BSS number from rxpd, get corresponding priv */ | ||
47 | priv = mwifiex_get_priv_by_id(adapter, local_rx_pd->bss_num & | ||
48 | BSS_NUM_MASK, local_rx_pd->bss_type); | ||
49 | if (!priv) | ||
50 | priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); | ||
51 | |||
52 | rx_info->bss_index = priv->bss_index; | ||
53 | ret = mwifiex_process_sta_rx_packet(adapter, skb); | ||
54 | |||
55 | return ret; | ||
56 | } | ||
57 | EXPORT_SYMBOL_GPL(mwifiex_handle_rx_packet); | ||
58 | |||
59 | /* | ||
60 | * This function sends a packet to device. | ||
61 | * | ||
62 | * It processes the packet to add the TxPD, checks condition and | ||
63 | * sends the processed packet to firmware for transmission. | ||
64 | * | ||
65 | * On successful completion, the function calls the completion callback | ||
66 | * and logs the time. | ||
67 | */ | ||
68 | int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb, | ||
69 | struct mwifiex_tx_param *tx_param) | ||
70 | { | ||
71 | int ret = -1; | ||
72 | struct mwifiex_adapter *adapter = priv->adapter; | ||
73 | u8 *head_ptr = NULL; | ||
74 | struct txpd *local_tx_pd = NULL; | ||
75 | |||
76 | head_ptr = (u8 *) mwifiex_process_sta_txpd(priv, skb); | ||
77 | if (head_ptr) { | ||
78 | if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) | ||
79 | local_tx_pd = | ||
80 | (struct txpd *) (head_ptr + INTF_HEADER_LEN); | ||
81 | |||
82 | ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA, | ||
83 | skb->data, skb->len, tx_param); | ||
84 | } | ||
85 | |||
86 | switch (ret) { | ||
87 | case -EBUSY: | ||
88 | if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) && | ||
89 | (adapter->pps_uapsd_mode) && | ||
90 | (adapter->tx_lock_flag)) { | ||
91 | priv->adapter->tx_lock_flag = false; | ||
92 | local_tx_pd->flags = 0; | ||
93 | } | ||
94 | dev_dbg(adapter->dev, "data: -EBUSY is returned\n"); | ||
95 | break; | ||
96 | case -1: | ||
97 | adapter->data_sent = false; | ||
98 | dev_err(adapter->dev, "mwifiex_write_data_async failed: 0x%X\n", | ||
99 | ret); | ||
100 | adapter->dbg.num_tx_host_to_card_failure++; | ||
101 | mwifiex_write_data_complete(adapter, skb, ret); | ||
102 | break; | ||
103 | case -EINPROGRESS: | ||
104 | adapter->data_sent = false; | ||
105 | break; | ||
106 | case 0: | ||
107 | mwifiex_write_data_complete(adapter, skb, ret); | ||
108 | break; | ||
109 | default: | ||
110 | break; | ||
111 | } | ||
112 | |||
113 | return ret; | ||
114 | } | ||
115 | |||
116 | /* | ||
117 | * Packet send completion callback handler. | ||
118 | * | ||
119 | * It either frees the buffer directly or forwards it to another | ||
120 | * completion callback which checks conditions, updates statistics, | ||
121 | * wakes up stalled traffic queue if required, and then frees the buffer. | ||
122 | */ | ||
123 | int mwifiex_write_data_complete(struct mwifiex_adapter *adapter, | ||
124 | struct sk_buff *skb, int status) | ||
125 | { | ||
126 | struct mwifiex_private *priv = NULL, *tpriv = NULL; | ||
127 | struct mwifiex_txinfo *tx_info = NULL; | ||
128 | int i; | ||
129 | |||
130 | if (!skb) | ||
131 | return 0; | ||
132 | |||
133 | tx_info = MWIFIEX_SKB_TXCB(skb); | ||
134 | priv = mwifiex_bss_index_to_priv(adapter, tx_info->bss_index); | ||
135 | if (!priv) | ||
136 | goto done; | ||
137 | |||
138 | priv->netdev->trans_start = jiffies; | ||
139 | if (!status) { | ||
140 | priv->stats.tx_packets++; | ||
141 | priv->stats.tx_bytes += skb->len; | ||
142 | } else { | ||
143 | priv->stats.tx_errors++; | ||
144 | } | ||
145 | atomic_dec(&adapter->tx_pending); | ||
146 | |||
147 | for (i = 0; i < adapter->priv_num; i++) { | ||
148 | |||
149 | tpriv = adapter->priv[i]; | ||
150 | |||
151 | if ((GET_BSS_ROLE(tpriv) == MWIFIEX_BSS_ROLE_STA) | ||
152 | && (tpriv->media_connected)) { | ||
153 | if (netif_queue_stopped(tpriv->netdev)) | ||
154 | netif_wake_queue(tpriv->netdev); | ||
155 | } | ||
156 | } | ||
157 | done: | ||
158 | dev_kfree_skb_any(skb); | ||
159 | |||
160 | return 0; | ||
161 | } | ||
162 | |||
163 | /* | ||
164 | * Packet receive completion callback handler. | ||
165 | * | ||
166 | * This function calls another completion callback handler which | ||
167 | * updates the statistics, and optionally updates the parent buffer | ||
168 | * use count before freeing the received packet. | ||
169 | */ | ||
170 | int mwifiex_recv_packet_complete(struct mwifiex_adapter *adapter, | ||
171 | struct sk_buff *skb, int status) | ||
172 | { | ||
173 | struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb); | ||
174 | struct mwifiex_rxinfo *rx_info_parent = NULL; | ||
175 | struct mwifiex_private *priv; | ||
176 | struct sk_buff *skb_parent = NULL; | ||
177 | unsigned long flags; | ||
178 | |||
179 | priv = adapter->priv[rx_info->bss_index]; | ||
180 | |||
181 | if (priv && (status == -1)) | ||
182 | priv->stats.rx_dropped++; | ||
183 | |||
184 | if (rx_info->parent) { | ||
185 | skb_parent = rx_info->parent; | ||
186 | rx_info_parent = MWIFIEX_SKB_RXCB(skb_parent); | ||
187 | |||
188 | spin_lock_irqsave(&priv->rx_pkt_lock, flags); | ||
189 | --rx_info_parent->use_count; | ||
190 | |||
191 | if (!rx_info_parent->use_count) { | ||
192 | spin_unlock_irqrestore(&priv->rx_pkt_lock, flags); | ||
193 | dev_kfree_skb_any(skb_parent); | ||
194 | } else { | ||
195 | spin_unlock_irqrestore(&priv->rx_pkt_lock, flags); | ||
196 | } | ||
197 | } else { | ||
198 | dev_kfree_skb_any(skb); | ||
199 | } | ||
200 | |||
201 | return 0; | ||
202 | } | ||
diff --git a/drivers/net/wireless/mwifiex/util.c b/drivers/net/wireless/mwifiex/util.c new file mode 100644 index 000000000000..205022aa52f5 --- /dev/null +++ b/drivers/net/wireless/mwifiex/util.c | |||
@@ -0,0 +1,252 @@ | |||
1 | /* | ||
2 | * Marvell Wireless LAN device driver: utility functions | ||
3 | * | ||
4 | * Copyright (C) 2011, Marvell International Ltd. | ||
5 | * | ||
6 | * This software file (the "File") is distributed by Marvell International | ||
7 | * Ltd. under the terms of the GNU General Public License Version 2, June 1991 | ||
8 | * (the "License"). You may use, redistribute and/or modify this File in | ||
9 | * accordance with the terms and conditions of the License, a copy of which | ||
10 | * is available by writing to the Free Software Foundation, Inc., | ||
11 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the | ||
12 | * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. | ||
13 | * | ||
14 | * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE | ||
15 | * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE | ||
16 | * ARE EXPRESSLY DISCLAIMED. The License provides additional details about | ||
17 | * this warranty disclaimer. | ||
18 | */ | ||
19 | |||
20 | #include "decl.h" | ||
21 | #include "ioctl.h" | ||
22 | #include "util.h" | ||
23 | #include "fw.h" | ||
24 | #include "main.h" | ||
25 | #include "wmm.h" | ||
26 | #include "11n.h" | ||
27 | |||
28 | /* | ||
29 | * Firmware initialization complete callback handler. | ||
30 | * | ||
31 | * This function wakes up the function waiting on the init | ||
32 | * wait queue for the firmware initialization to complete. | ||
33 | */ | ||
34 | int mwifiex_init_fw_complete(struct mwifiex_adapter *adapter) | ||
35 | { | ||
36 | |||
37 | adapter->init_wait_q_woken = true; | ||
38 | wake_up_interruptible(&adapter->init_wait_q); | ||
39 | return 0; | ||
40 | } | ||
41 | |||
42 | /* | ||
43 | * Firmware shutdown complete callback handler. | ||
44 | * | ||
45 | * This function sets the hardware status to not ready and wakes up | ||
46 | * the function waiting on the init wait queue for the firmware | ||
47 | * shutdown to complete. | ||
48 | */ | ||
49 | int mwifiex_shutdown_fw_complete(struct mwifiex_adapter *adapter) | ||
50 | { | ||
51 | adapter->hw_status = MWIFIEX_HW_STATUS_NOT_READY; | ||
52 | adapter->init_wait_q_woken = true; | ||
53 | wake_up_interruptible(&adapter->init_wait_q); | ||
54 | return 0; | ||
55 | } | ||
56 | |||
57 | /* | ||
58 | * IOCTL request handler to send function init/shutdown command | ||
59 | * to firmware. | ||
60 | * | ||
61 | * This function prepares the correct firmware command and | ||
62 | * issues it. | ||
63 | */ | ||
64 | int mwifiex_misc_ioctl_init_shutdown(struct mwifiex_adapter *adapter, | ||
65 | struct mwifiex_wait_queue *wait, | ||
66 | u32 func_init_shutdown) | ||
67 | { | ||
68 | struct mwifiex_private *priv = adapter->priv[wait->bss_index]; | ||
69 | int ret; | ||
70 | u16 cmd; | ||
71 | |||
72 | if (func_init_shutdown == MWIFIEX_FUNC_INIT) { | ||
73 | cmd = HostCmd_CMD_FUNC_INIT; | ||
74 | } else if (func_init_shutdown == MWIFIEX_FUNC_SHUTDOWN) { | ||
75 | cmd = HostCmd_CMD_FUNC_SHUTDOWN; | ||
76 | } else { | ||
77 | dev_err(adapter->dev, "unsupported parameter\n"); | ||
78 | return -1; | ||
79 | } | ||
80 | |||
81 | /* Send command to firmware */ | ||
82 | ret = mwifiex_prepare_cmd(priv, cmd, HostCmd_ACT_GEN_SET, | ||
83 | 0, wait, NULL); | ||
84 | |||
85 | if (!ret) | ||
86 | ret = -EINPROGRESS; | ||
87 | |||
88 | return ret; | ||
89 | } | ||
90 | |||
91 | /* | ||
92 | * IOCTL request handler to set/get debug information. | ||
93 | * | ||
94 | * This function collates/sets the information from/to different driver | ||
95 | * structures. | ||
96 | */ | ||
97 | int mwifiex_get_debug_info(struct mwifiex_private *priv, | ||
98 | struct mwifiex_debug_info *info) | ||
99 | { | ||
100 | struct mwifiex_adapter *adapter = priv->adapter; | ||
101 | |||
102 | if (info) { | ||
103 | memcpy(info->packets_out, | ||
104 | priv->wmm.packets_out, | ||
105 | sizeof(priv->wmm.packets_out)); | ||
106 | info->max_tx_buf_size = (u32) adapter->max_tx_buf_size; | ||
107 | info->tx_buf_size = (u32) adapter->tx_buf_size; | ||
108 | info->rx_tbl_num = mwifiex_get_rx_reorder_tbl( | ||
109 | priv, info->rx_tbl); | ||
110 | info->tx_tbl_num = mwifiex_get_tx_ba_stream_tbl( | ||
111 | priv, info->tx_tbl); | ||
112 | info->ps_mode = adapter->ps_mode; | ||
113 | info->ps_state = adapter->ps_state; | ||
114 | info->is_deep_sleep = adapter->is_deep_sleep; | ||
115 | info->pm_wakeup_card_req = adapter->pm_wakeup_card_req; | ||
116 | info->pm_wakeup_fw_try = adapter->pm_wakeup_fw_try; | ||
117 | info->is_hs_configured = adapter->is_hs_configured; | ||
118 | info->hs_activated = adapter->hs_activated; | ||
119 | info->num_cmd_host_to_card_failure | ||
120 | = adapter->dbg.num_cmd_host_to_card_failure; | ||
121 | info->num_cmd_sleep_cfm_host_to_card_failure | ||
122 | = adapter->dbg.num_cmd_sleep_cfm_host_to_card_failure; | ||
123 | info->num_tx_host_to_card_failure | ||
124 | = adapter->dbg.num_tx_host_to_card_failure; | ||
125 | info->num_event_deauth = adapter->dbg.num_event_deauth; | ||
126 | info->num_event_disassoc = adapter->dbg.num_event_disassoc; | ||
127 | info->num_event_link_lost = adapter->dbg.num_event_link_lost; | ||
128 | info->num_cmd_deauth = adapter->dbg.num_cmd_deauth; | ||
129 | info->num_cmd_assoc_success = | ||
130 | adapter->dbg.num_cmd_assoc_success; | ||
131 | info->num_cmd_assoc_failure = | ||
132 | adapter->dbg.num_cmd_assoc_failure; | ||
133 | info->num_tx_timeout = adapter->dbg.num_tx_timeout; | ||
134 | info->num_cmd_timeout = adapter->dbg.num_cmd_timeout; | ||
135 | info->timeout_cmd_id = adapter->dbg.timeout_cmd_id; | ||
136 | info->timeout_cmd_act = adapter->dbg.timeout_cmd_act; | ||
137 | memcpy(info->last_cmd_id, adapter->dbg.last_cmd_id, | ||
138 | sizeof(adapter->dbg.last_cmd_id)); | ||
139 | memcpy(info->last_cmd_act, adapter->dbg.last_cmd_act, | ||
140 | sizeof(adapter->dbg.last_cmd_act)); | ||
141 | info->last_cmd_index = adapter->dbg.last_cmd_index; | ||
142 | memcpy(info->last_cmd_resp_id, adapter->dbg.last_cmd_resp_id, | ||
143 | sizeof(adapter->dbg.last_cmd_resp_id)); | ||
144 | info->last_cmd_resp_index = adapter->dbg.last_cmd_resp_index; | ||
145 | memcpy(info->last_event, adapter->dbg.last_event, | ||
146 | sizeof(adapter->dbg.last_event)); | ||
147 | info->last_event_index = adapter->dbg.last_event_index; | ||
148 | info->data_sent = adapter->data_sent; | ||
149 | info->cmd_sent = adapter->cmd_sent; | ||
150 | info->cmd_resp_received = adapter->cmd_resp_received; | ||
151 | } | ||
152 | |||
153 | return 0; | ||
154 | } | ||
155 | |||
156 | /* | ||
157 | * This function processes the received packet before sending it to the | ||
158 | * kernel. | ||
159 | * | ||
160 | * It extracts the SKB from the received buffer and sends it to kernel. | ||
161 | * In case the received buffer does not contain the data in SKB format, | ||
162 | * the function creates a blank SKB, fills it with the data from the | ||
163 | * received buffer and then sends this new SKB to the kernel. | ||
164 | */ | ||
165 | int mwifiex_recv_packet(struct mwifiex_adapter *adapter, struct sk_buff *skb) | ||
166 | { | ||
167 | struct mwifiex_rxinfo *rx_info = NULL; | ||
168 | struct mwifiex_private *priv = NULL; | ||
169 | |||
170 | if (!skb) | ||
171 | return -1; | ||
172 | |||
173 | rx_info = MWIFIEX_SKB_RXCB(skb); | ||
174 | priv = mwifiex_bss_index_to_priv(adapter, rx_info->bss_index); | ||
175 | if (!priv) | ||
176 | return -1; | ||
177 | |||
178 | skb->dev = priv->netdev; | ||
179 | skb->protocol = eth_type_trans(skb, priv->netdev); | ||
180 | skb->ip_summed = CHECKSUM_NONE; | ||
181 | priv->stats.rx_bytes += skb->len; | ||
182 | priv->stats.rx_packets++; | ||
183 | if (in_interrupt()) | ||
184 | netif_rx(skb); | ||
185 | else | ||
186 | netif_rx_ni(skb); | ||
187 | |||
188 | return 0; | ||
189 | } | ||
190 | |||
191 | /* | ||
192 | * Receive packet completion callback handler. | ||
193 | * | ||
194 | * This function updates the statistics and frees the buffer SKB. | ||
195 | */ | ||
196 | int mwifiex_recv_complete(struct mwifiex_adapter *adapter, | ||
197 | struct sk_buff *skb, int status) | ||
198 | { | ||
199 | struct mwifiex_private *priv = NULL; | ||
200 | struct mwifiex_rxinfo *rx_info = NULL; | ||
201 | |||
202 | if (!skb) | ||
203 | return 0; | ||
204 | |||
205 | rx_info = MWIFIEX_SKB_RXCB(skb); | ||
206 | priv = mwifiex_bss_index_to_priv(adapter, rx_info->bss_index); | ||
207 | |||
208 | if (priv && (status == -1)) | ||
209 | priv->stats.rx_dropped++; | ||
210 | |||
211 | dev_kfree_skb_any(skb); | ||
212 | |||
213 | return 0; | ||
214 | } | ||
215 | |||
216 | /* | ||
217 | * IOCTL completion callback handler. | ||
218 | * | ||
219 | * This function is called when a pending IOCTL is completed. | ||
220 | * | ||
221 | * If work queue support is enabled, the function wakes up the | ||
222 | * corresponding waiting function. Otherwise, it processes the | ||
223 | * IOCTL response and frees the response buffer. | ||
224 | */ | ||
225 | int mwifiex_ioctl_complete(struct mwifiex_adapter *adapter, | ||
226 | struct mwifiex_wait_queue *wait_queue, | ||
227 | int status) | ||
228 | { | ||
229 | enum mwifiex_error_code status_code = | ||
230 | (enum mwifiex_error_code) wait_queue->status; | ||
231 | |||
232 | atomic_dec(&adapter->ioctl_pending); | ||
233 | |||
234 | dev_dbg(adapter->dev, "cmd: IOCTL completed: status=%d," | ||
235 | " status_code=%#x\n", status, status_code); | ||
236 | |||
237 | if (wait_queue->enabled) { | ||
238 | *wait_queue->condition = true; | ||
239 | wait_queue->status = status; | ||
240 | if (status && (status_code == MWIFIEX_ERROR_CMD_TIMEOUT)) | ||
241 | dev_err(adapter->dev, "cmd timeout\n"); | ||
242 | else | ||
243 | wake_up_interruptible(wait_queue->wait); | ||
244 | } else { | ||
245 | if (status) | ||
246 | dev_err(adapter->dev, "cmd failed: status_code=%#x\n", | ||
247 | status_code); | ||
248 | kfree(wait_queue); | ||
249 | } | ||
250 | |||
251 | return 0; | ||
252 | } | ||
diff --git a/drivers/net/wireless/mwifiex/util.h b/drivers/net/wireless/mwifiex/util.h new file mode 100644 index 000000000000..9506afc6c0e4 --- /dev/null +++ b/drivers/net/wireless/mwifiex/util.h | |||
@@ -0,0 +1,32 @@ | |||
1 | /* | ||
2 | * Marvell Wireless LAN device driver: utility functions | ||
3 | * | ||
4 | * Copyright (C) 2011, Marvell International Ltd. | ||
5 | * | ||
6 | * This software file (the "File") is distributed by Marvell International | ||
7 | * Ltd. under the terms of the GNU General Public License Version 2, June 1991 | ||
8 | * (the "License"). You may use, redistribute and/or modify this File in | ||
9 | * accordance with the terms and conditions of the License, a copy of which | ||
10 | * is available by writing to the Free Software Foundation, Inc., | ||
11 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the | ||
12 | * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. | ||
13 | * | ||
14 | * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE | ||
15 | * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE | ||
16 | * ARE EXPRESSLY DISCLAIMED. The License provides additional details about | ||
17 | * this warranty disclaimer. | ||
18 | */ | ||
19 | |||
20 | #ifndef _MWIFIEX_UTIL_H_ | ||
21 | #define _MWIFIEX_UTIL_H_ | ||
22 | |||
23 | static inline struct mwifiex_rxinfo *MWIFIEX_SKB_RXCB(struct sk_buff *skb) | ||
24 | { | ||
25 | return (struct mwifiex_rxinfo *)skb->cb; | ||
26 | } | ||
27 | |||
28 | static inline struct mwifiex_txinfo *MWIFIEX_SKB_TXCB(struct sk_buff *skb) | ||
29 | { | ||
30 | return (struct mwifiex_txinfo *)skb->cb; | ||
31 | } | ||
32 | #endif /* !_MWIFIEX_UTIL_H_ */ | ||
diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c new file mode 100644 index 000000000000..1cfbc6bed692 --- /dev/null +++ b/drivers/net/wireless/mwifiex/wmm.c | |||
@@ -0,0 +1,1237 @@ | |||
1 | /* | ||
2 | * Marvell Wireless LAN device driver: WMM | ||
3 | * | ||
4 | * Copyright (C) 2011, Marvell International Ltd. | ||
5 | * | ||
6 | * This software file (the "File") is distributed by Marvell International | ||
7 | * Ltd. under the terms of the GNU General Public License Version 2, June 1991 | ||
8 | * (the "License"). You may use, redistribute and/or modify this File in | ||
9 | * accordance with the terms and conditions of the License, a copy of which | ||
10 | * is available by writing to the Free Software Foundation, Inc., | ||
11 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the | ||
12 | * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. | ||
13 | * | ||
14 | * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE | ||
15 | * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE | ||
16 | * ARE EXPRESSLY DISCLAIMED. The License provides additional details about | ||
17 | * this warranty disclaimer. | ||
18 | */ | ||
19 | |||
20 | #include "decl.h" | ||
21 | #include "ioctl.h" | ||
22 | #include "util.h" | ||
23 | #include "fw.h" | ||
24 | #include "main.h" | ||
25 | #include "wmm.h" | ||
26 | #include "11n.h" | ||
27 | |||
28 | |||
29 | /* Maximum value FW can accept for driver delay in packet transmission */ | ||
30 | #define DRV_PKT_DELAY_TO_FW_MAX 512 | ||
31 | |||
32 | |||
33 | #define WMM_QUEUED_PACKET_LOWER_LIMIT 180 | ||
34 | |||
35 | #define WMM_QUEUED_PACKET_UPPER_LIMIT 200 | ||
36 | |||
37 | /* Offset for TOS field in the IP header */ | ||
38 | #define IPTOS_OFFSET 5 | ||
39 | |||
40 | /* WMM information IE */ | ||
41 | static const u8 wmm_info_ie[] = { WLAN_EID_VENDOR_SPECIFIC, 0x07, | ||
42 | 0x00, 0x50, 0xf2, 0x02, | ||
43 | 0x00, 0x01, 0x00 | ||
44 | }; | ||
45 | |||
46 | static const u8 wmm_aci_to_qidx_map[] = { WMM_AC_BE, | ||
47 | WMM_AC_BK, | ||
48 | WMM_AC_VI, | ||
49 | WMM_AC_VO | ||
50 | }; | ||
51 | |||
52 | static u8 tos_to_tid[] = { | ||
53 | /* TID DSCP_P2 DSCP_P1 DSCP_P0 WMM_AC */ | ||
54 | 0x01, /* 0 1 0 AC_BK */ | ||
55 | 0x02, /* 0 0 0 AC_BK */ | ||
56 | 0x00, /* 0 0 1 AC_BE */ | ||
57 | 0x03, /* 0 1 1 AC_BE */ | ||
58 | 0x04, /* 1 0 0 AC_VI */ | ||
59 | 0x05, /* 1 0 1 AC_VI */ | ||
60 | 0x06, /* 1 1 0 AC_VO */ | ||
61 | 0x07 /* 1 1 1 AC_VO */ | ||
62 | }; | ||
63 | |||
64 | /* | ||
65 | * This table inverses the tos_to_tid operation to get a priority | ||
66 | * which is in sequential order, and can be compared. | ||
67 | * Use this to compare the priority of two different TIDs. | ||
68 | */ | ||
69 | static u8 tos_to_tid_inv[] = { | ||
70 | 0x02, /* from tos_to_tid[2] = 0 */ | ||
71 | 0x00, /* from tos_to_tid[0] = 1 */ | ||
72 | 0x01, /* from tos_to_tid[1] = 2 */ | ||
73 | 0x03, | ||
74 | 0x04, | ||
75 | 0x05, | ||
76 | 0x06, | ||
77 | 0x07}; | ||
78 | |||
79 | static u8 ac_to_tid[4][2] = { {1, 2}, {0, 3}, {4, 5}, {6, 7} }; | ||
80 | |||
81 | /* | ||
82 | * This function debug prints the priority parameters for a WMM AC. | ||
83 | */ | ||
84 | static void | ||
85 | mwifiex_wmm_ac_debug_print(const struct ieee_types_wmm_ac_parameters *ac_param) | ||
86 | { | ||
87 | const char *ac_str[] = { "BK", "BE", "VI", "VO" }; | ||
88 | |||
89 | pr_debug("info: WMM AC_%s: ACI=%d, ACM=%d, Aifsn=%d, " | ||
90 | "EcwMin=%d, EcwMax=%d, TxopLimit=%d\n", | ||
91 | ac_str[wmm_aci_to_qidx_map[(ac_param->aci_aifsn_bitmap | ||
92 | & MWIFIEX_ACI) >> 5]], | ||
93 | (ac_param->aci_aifsn_bitmap & MWIFIEX_ACI) >> 5, | ||
94 | (ac_param->aci_aifsn_bitmap & MWIFIEX_ACM) >> 4, | ||
95 | ac_param->aci_aifsn_bitmap & MWIFIEX_AIFSN, | ||
96 | ac_param->ecw_bitmap & MWIFIEX_ECW_MIN, | ||
97 | (ac_param->ecw_bitmap & MWIFIEX_ECW_MAX) >> 4, | ||
98 | le16_to_cpu(ac_param->tx_op_limit)); | ||
99 | } | ||
100 | |||
101 | /* | ||
102 | * This function allocates a route address list. | ||
103 | * | ||
104 | * The function also initializes the list with the provided RA. | ||
105 | */ | ||
106 | static struct mwifiex_ra_list_tbl * | ||
107 | mwifiex_wmm_allocate_ralist_node(struct mwifiex_adapter *adapter, u8 *ra) | ||
108 | { | ||
109 | struct mwifiex_ra_list_tbl *ra_list; | ||
110 | |||
111 | ra_list = kzalloc(sizeof(struct mwifiex_ra_list_tbl), GFP_ATOMIC); | ||
112 | |||
113 | if (!ra_list) { | ||
114 | dev_err(adapter->dev, "%s: failed to alloc ra_list\n", | ||
115 | __func__); | ||
116 | return NULL; | ||
117 | } | ||
118 | INIT_LIST_HEAD(&ra_list->list); | ||
119 | skb_queue_head_init(&ra_list->skb_head); | ||
120 | |||
121 | memcpy(ra_list->ra, ra, ETH_ALEN); | ||
122 | |||
123 | ra_list->total_pkts_size = 0; | ||
124 | |||
125 | dev_dbg(adapter->dev, "info: allocated ra_list %p\n", ra_list); | ||
126 | |||
127 | return ra_list; | ||
128 | } | ||
129 | |||
130 | /* | ||
131 | * This function allocates and adds a RA list for all TIDs | ||
132 | * with the given RA. | ||
133 | */ | ||
134 | void | ||
135 | mwifiex_ralist_add(struct mwifiex_private *priv, u8 *ra) | ||
136 | { | ||
137 | int i; | ||
138 | struct mwifiex_ra_list_tbl *ra_list; | ||
139 | struct mwifiex_adapter *adapter = priv->adapter; | ||
140 | |||
141 | for (i = 0; i < MAX_NUM_TID; ++i) { | ||
142 | ra_list = mwifiex_wmm_allocate_ralist_node(adapter, ra); | ||
143 | dev_dbg(adapter->dev, "info: created ra_list %p\n", ra_list); | ||
144 | |||
145 | if (!ra_list) | ||
146 | break; | ||
147 | |||
148 | if (!mwifiex_queuing_ra_based(priv)) | ||
149 | ra_list->is_11n_enabled = IS_11N_ENABLED(priv); | ||
150 | else | ||
151 | ra_list->is_11n_enabled = false; | ||
152 | |||
153 | dev_dbg(adapter->dev, "data: ralist %p: is_11n_enabled=%d\n", | ||
154 | ra_list, ra_list->is_11n_enabled); | ||
155 | |||
156 | list_add_tail(&ra_list->list, | ||
157 | &priv->wmm.tid_tbl_ptr[i].ra_list); | ||
158 | |||
159 | if (!priv->wmm.tid_tbl_ptr[i].ra_list_curr) | ||
160 | priv->wmm.tid_tbl_ptr[i].ra_list_curr = ra_list; | ||
161 | } | ||
162 | } | ||
163 | |||
164 | /* | ||
165 | * This function sets the WMM queue priorities to their default values. | ||
166 | */ | ||
167 | static void mwifiex_wmm_default_queue_priorities(struct mwifiex_private *priv) | ||
168 | { | ||
169 | /* Default queue priorities: VO->VI->BE->BK */ | ||
170 | priv->wmm.queue_priority[0] = WMM_AC_VO; | ||
171 | priv->wmm.queue_priority[1] = WMM_AC_VI; | ||
172 | priv->wmm.queue_priority[2] = WMM_AC_BE; | ||
173 | priv->wmm.queue_priority[3] = WMM_AC_BK; | ||
174 | } | ||
175 | |||
176 | /* | ||
177 | * This function map ACs to TIDs. | ||
178 | */ | ||
179 | static void | ||
180 | mwifiex_wmm_queue_priorities_tid(struct mwifiex_private *priv, | ||
181 | u8 queue_priority[]) | ||
182 | { | ||
183 | int i; | ||
184 | |||
185 | for (i = 0; i < 4; ++i) { | ||
186 | tos_to_tid[7 - (i * 2)] = ac_to_tid[queue_priority[i]][1]; | ||
187 | tos_to_tid[6 - (i * 2)] = ac_to_tid[queue_priority[i]][0]; | ||
188 | } | ||
189 | } | ||
190 | |||
191 | /* | ||
192 | * This function initializes WMM priority queues. | ||
193 | */ | ||
194 | void | ||
195 | mwifiex_wmm_setup_queue_priorities(struct mwifiex_private *priv, | ||
196 | struct ieee_types_wmm_parameter *wmm_ie) | ||
197 | { | ||
198 | u16 cw_min, avg_back_off, tmp[4]; | ||
199 | u32 i, j, num_ac; | ||
200 | u8 ac_idx; | ||
201 | |||
202 | if (!wmm_ie || !priv->wmm_enabled) { | ||
203 | /* WMM is not enabled, just set the defaults and return */ | ||
204 | mwifiex_wmm_default_queue_priorities(priv); | ||
205 | return; | ||
206 | } | ||
207 | |||
208 | dev_dbg(priv->adapter->dev, "info: WMM Parameter IE: version=%d, " | ||
209 | "qos_info Parameter Set Count=%d, Reserved=%#x\n", | ||
210 | wmm_ie->vend_hdr.version, wmm_ie->qos_info_bitmap & | ||
211 | IEEE80211_WMM_IE_AP_QOSINFO_PARAM_SET_CNT_MASK, | ||
212 | wmm_ie->reserved); | ||
213 | |||
214 | for (num_ac = 0; num_ac < ARRAY_SIZE(wmm_ie->ac_params); num_ac++) { | ||
215 | cw_min = (1 << (wmm_ie->ac_params[num_ac].ecw_bitmap & | ||
216 | MWIFIEX_ECW_MIN)) - 1; | ||
217 | avg_back_off = (cw_min >> 1) + | ||
218 | (wmm_ie->ac_params[num_ac].aci_aifsn_bitmap & | ||
219 | MWIFIEX_AIFSN); | ||
220 | |||
221 | ac_idx = wmm_aci_to_qidx_map[(wmm_ie->ac_params[num_ac]. | ||
222 | aci_aifsn_bitmap & | ||
223 | MWIFIEX_ACI) >> 5]; | ||
224 | priv->wmm.queue_priority[ac_idx] = ac_idx; | ||
225 | tmp[ac_idx] = avg_back_off; | ||
226 | |||
227 | dev_dbg(priv->adapter->dev, "info: WMM: CWmax=%d CWmin=%d Avg Back-off=%d\n", | ||
228 | (1 << ((wmm_ie->ac_params[num_ac].ecw_bitmap & | ||
229 | MWIFIEX_ECW_MAX) >> 4)) - 1, | ||
230 | cw_min, avg_back_off); | ||
231 | mwifiex_wmm_ac_debug_print(&wmm_ie->ac_params[num_ac]); | ||
232 | } | ||
233 | |||
234 | /* Bubble sort */ | ||
235 | for (i = 0; i < num_ac; i++) { | ||
236 | for (j = 1; j < num_ac - i; j++) { | ||
237 | if (tmp[j - 1] > tmp[j]) { | ||
238 | swap(tmp[j - 1], tmp[j]); | ||
239 | swap(priv->wmm.queue_priority[j - 1], | ||
240 | priv->wmm.queue_priority[j]); | ||
241 | } else if (tmp[j - 1] == tmp[j]) { | ||
242 | if (priv->wmm.queue_priority[j - 1] | ||
243 | < priv->wmm.queue_priority[j]) | ||
244 | swap(priv->wmm.queue_priority[j - 1], | ||
245 | priv->wmm.queue_priority[j]); | ||
246 | } | ||
247 | } | ||
248 | } | ||
249 | |||
250 | mwifiex_wmm_queue_priorities_tid(priv, priv->wmm.queue_priority); | ||
251 | } | ||
252 | |||
253 | /* | ||
254 | * This function evaluates whether or not an AC is to be downgraded. | ||
255 | * | ||
256 | * In case the AC is not enabled, the highest AC is returned that is | ||
257 | * enabled and does not require admission control. | ||
258 | */ | ||
259 | static enum mwifiex_wmm_ac_e | ||
260 | mwifiex_wmm_eval_downgrade_ac(struct mwifiex_private *priv, | ||
261 | enum mwifiex_wmm_ac_e eval_ac) | ||
262 | { | ||
263 | int down_ac; | ||
264 | enum mwifiex_wmm_ac_e ret_ac; | ||
265 | struct mwifiex_wmm_ac_status *ac_status; | ||
266 | |||
267 | ac_status = &priv->wmm.ac_status[eval_ac]; | ||
268 | |||
269 | if (!ac_status->disabled) | ||
270 | /* Okay to use this AC, its enabled */ | ||
271 | return eval_ac; | ||
272 | |||
273 | /* Setup a default return value of the lowest priority */ | ||
274 | ret_ac = WMM_AC_BK; | ||
275 | |||
276 | /* | ||
277 | * Find the highest AC that is enabled and does not require | ||
278 | * admission control. The spec disallows downgrading to an AC, | ||
279 | * which is enabled due to a completed admission control. | ||
280 | * Unadmitted traffic is not to be sent on an AC with admitted | ||
281 | * traffic. | ||
282 | */ | ||
283 | for (down_ac = WMM_AC_BK; down_ac < eval_ac; down_ac++) { | ||
284 | ac_status = &priv->wmm.ac_status[down_ac]; | ||
285 | |||
286 | if (!ac_status->disabled && !ac_status->flow_required) | ||
287 | /* AC is enabled and does not require admission | ||
288 | control */ | ||
289 | ret_ac = (enum mwifiex_wmm_ac_e) down_ac; | ||
290 | } | ||
291 | |||
292 | return ret_ac; | ||
293 | } | ||
294 | |||
295 | /* | ||
296 | * This function downgrades WMM priority queue. | ||
297 | */ | ||
298 | void | ||
299 | mwifiex_wmm_setup_ac_downgrade(struct mwifiex_private *priv) | ||
300 | { | ||
301 | int ac_val; | ||
302 | |||
303 | dev_dbg(priv->adapter->dev, "info: WMM: AC Priorities:" | ||
304 | "BK(0), BE(1), VI(2), VO(3)\n"); | ||
305 | |||
306 | if (!priv->wmm_enabled) { | ||
307 | /* WMM is not enabled, default priorities */ | ||
308 | for (ac_val = WMM_AC_BK; ac_val <= WMM_AC_VO; ac_val++) | ||
309 | priv->wmm.ac_down_graded_vals[ac_val] = | ||
310 | (enum mwifiex_wmm_ac_e) ac_val; | ||
311 | } else { | ||
312 | for (ac_val = WMM_AC_BK; ac_val <= WMM_AC_VO; ac_val++) { | ||
313 | priv->wmm.ac_down_graded_vals[ac_val] | ||
314 | = mwifiex_wmm_eval_downgrade_ac(priv, | ||
315 | (enum mwifiex_wmm_ac_e) ac_val); | ||
316 | dev_dbg(priv->adapter->dev, "info: WMM: AC PRIO %d maps to %d\n", | ||
317 | ac_val, priv->wmm.ac_down_graded_vals[ac_val]); | ||
318 | } | ||
319 | } | ||
320 | } | ||
321 | |||
322 | /* | ||
323 | * This function converts the IP TOS field to an WMM AC | ||
324 | * Queue assignment. | ||
325 | */ | ||
326 | static enum mwifiex_wmm_ac_e | ||
327 | mwifiex_wmm_convert_tos_to_ac(struct mwifiex_adapter *adapter, u32 tos) | ||
328 | { | ||
329 | /* Map of TOS UP values to WMM AC */ | ||
330 | const enum mwifiex_wmm_ac_e tos_to_ac[] = { WMM_AC_BE, | ||
331 | WMM_AC_BK, | ||
332 | WMM_AC_BK, | ||
333 | WMM_AC_BE, | ||
334 | WMM_AC_VI, | ||
335 | WMM_AC_VI, | ||
336 | WMM_AC_VO, | ||
337 | WMM_AC_VO | ||
338 | }; | ||
339 | |||
340 | if (tos >= ARRAY_SIZE(tos_to_ac)) | ||
341 | return WMM_AC_BE; | ||
342 | |||
343 | return tos_to_ac[tos]; | ||
344 | } | ||
345 | |||
346 | /* | ||
347 | * This function evaluates a given TID and downgrades it to a lower | ||
348 | * TID if the WMM Parameter IE received from the AP indicates that the | ||
349 | * AP is disabled (due to call admission control (ACM bit). Mapping | ||
350 | * of TID to AC is taken care of internally. | ||
351 | */ | ||
352 | static u8 | ||
353 | mwifiex_wmm_downgrade_tid(struct mwifiex_private *priv, u32 tid) | ||
354 | { | ||
355 | enum mwifiex_wmm_ac_e ac, ac_down; | ||
356 | u8 new_tid; | ||
357 | |||
358 | ac = mwifiex_wmm_convert_tos_to_ac(priv->adapter, tid); | ||
359 | ac_down = priv->wmm.ac_down_graded_vals[ac]; | ||
360 | |||
361 | /* Send the index to tid array, picking from the array will be | ||
362 | * taken care by dequeuing function | ||
363 | */ | ||
364 | new_tid = ac_to_tid[ac_down][tid % 2]; | ||
365 | |||
366 | return new_tid; | ||
367 | } | ||
368 | |||
369 | /* | ||
370 | * This function initializes the WMM state information and the | ||
371 | * WMM data path queues. | ||
372 | */ | ||
373 | void | ||
374 | mwifiex_wmm_init(struct mwifiex_adapter *adapter) | ||
375 | { | ||
376 | int i, j; | ||
377 | struct mwifiex_private *priv; | ||
378 | |||
379 | for (j = 0; j < adapter->priv_num; ++j) { | ||
380 | priv = adapter->priv[j]; | ||
381 | if (!priv) | ||
382 | continue; | ||
383 | |||
384 | for (i = 0; i < MAX_NUM_TID; ++i) { | ||
385 | priv->aggr_prio_tbl[i].amsdu = tos_to_tid_inv[i]; | ||
386 | priv->aggr_prio_tbl[i].ampdu_ap = tos_to_tid_inv[i]; | ||
387 | priv->aggr_prio_tbl[i].ampdu_user = tos_to_tid_inv[i]; | ||
388 | priv->wmm.tid_tbl_ptr[i].ra_list_curr = NULL; | ||
389 | } | ||
390 | |||
391 | priv->aggr_prio_tbl[6].amsdu | ||
392 | = priv->aggr_prio_tbl[6].ampdu_ap | ||
393 | = priv->aggr_prio_tbl[6].ampdu_user | ||
394 | = BA_STREAM_NOT_ALLOWED; | ||
395 | |||
396 | priv->aggr_prio_tbl[7].amsdu = priv->aggr_prio_tbl[7].ampdu_ap | ||
397 | = priv->aggr_prio_tbl[7].ampdu_user | ||
398 | = BA_STREAM_NOT_ALLOWED; | ||
399 | |||
400 | priv->add_ba_param.timeout = MWIFIEX_DEFAULT_BLOCK_ACK_TIMEOUT; | ||
401 | priv->add_ba_param.tx_win_size = MWIFIEX_AMPDU_DEF_TXWINSIZE; | ||
402 | priv->add_ba_param.rx_win_size = MWIFIEX_AMPDU_DEF_RXWINSIZE; | ||
403 | } | ||
404 | } | ||
405 | |||
406 | /* | ||
407 | * This function checks if WMM Tx queue is empty. | ||
408 | */ | ||
409 | int | ||
410 | mwifiex_wmm_lists_empty(struct mwifiex_adapter *adapter) | ||
411 | { | ||
412 | int i, j; | ||
413 | struct mwifiex_private *priv; | ||
414 | |||
415 | for (j = 0; j < adapter->priv_num; ++j) { | ||
416 | priv = adapter->priv[j]; | ||
417 | if (priv) { | ||
418 | for (i = 0; i < MAX_NUM_TID; i++) | ||
419 | if (!mwifiex_wmm_is_ra_list_empty(adapter, | ||
420 | &priv->wmm.tid_tbl_ptr[i].ra_list)) | ||
421 | return false; | ||
422 | } | ||
423 | } | ||
424 | |||
425 | return true; | ||
426 | } | ||
427 | |||
428 | /* | ||
429 | * This function deletes all packets in an RA list node. | ||
430 | * | ||
431 | * The packet sent completion callback handler are called with | ||
432 | * status failure, after they are dequeued to ensure proper | ||
433 | * cleanup. The RA list node itself is freed at the end. | ||
434 | */ | ||
435 | static void | ||
436 | mwifiex_wmm_del_pkts_in_ralist_node(struct mwifiex_private *priv, | ||
437 | struct mwifiex_ra_list_tbl *ra_list) | ||
438 | { | ||
439 | struct mwifiex_adapter *adapter = priv->adapter; | ||
440 | struct sk_buff *skb, *tmp; | ||
441 | |||
442 | skb_queue_walk_safe(&ra_list->skb_head, skb, tmp) | ||
443 | mwifiex_write_data_complete(adapter, skb, -1); | ||
444 | } | ||
445 | |||
446 | /* | ||
447 | * This function deletes all packets in an RA list. | ||
448 | * | ||
449 | * Each nodes in the RA list are freed individually first, and then | ||
450 | * the RA list itself is freed. | ||
451 | */ | ||
452 | static void | ||
453 | mwifiex_wmm_del_pkts_in_ralist(struct mwifiex_private *priv, | ||
454 | struct list_head *ra_list_head) | ||
455 | { | ||
456 | struct mwifiex_ra_list_tbl *ra_list; | ||
457 | |||
458 | list_for_each_entry(ra_list, ra_list_head, list) | ||
459 | mwifiex_wmm_del_pkts_in_ralist_node(priv, ra_list); | ||
460 | } | ||
461 | |||
462 | /* | ||
463 | * This function deletes all packets in all RA lists. | ||
464 | */ | ||
465 | static void mwifiex_wmm_cleanup_queues(struct mwifiex_private *priv) | ||
466 | { | ||
467 | int i; | ||
468 | |||
469 | for (i = 0; i < MAX_NUM_TID; i++) | ||
470 | mwifiex_wmm_del_pkts_in_ralist(priv, &priv->wmm.tid_tbl_ptr[i]. | ||
471 | ra_list); | ||
472 | } | ||
473 | |||
474 | /* | ||
475 | * This function deletes all route addresses from all RA lists. | ||
476 | */ | ||
477 | static void mwifiex_wmm_delete_all_ralist(struct mwifiex_private *priv) | ||
478 | { | ||
479 | struct mwifiex_ra_list_tbl *ra_list, *tmp_node; | ||
480 | int i; | ||
481 | |||
482 | for (i = 0; i < MAX_NUM_TID; ++i) { | ||
483 | dev_dbg(priv->adapter->dev, | ||
484 | "info: ra_list: freeing buf for tid %d\n", i); | ||
485 | list_for_each_entry_safe(ra_list, tmp_node, | ||
486 | &priv->wmm.tid_tbl_ptr[i].ra_list, list) { | ||
487 | list_del(&ra_list->list); | ||
488 | kfree(ra_list); | ||
489 | } | ||
490 | |||
491 | INIT_LIST_HEAD(&priv->wmm.tid_tbl_ptr[i].ra_list); | ||
492 | |||
493 | priv->wmm.tid_tbl_ptr[i].ra_list_curr = NULL; | ||
494 | } | ||
495 | } | ||
496 | |||
497 | /* | ||
498 | * This function cleans up the Tx and Rx queues. | ||
499 | * | ||
500 | * Cleanup includes - | ||
501 | * - All packets in RA lists | ||
502 | * - All entries in Rx reorder table | ||
503 | * - All entries in Tx BA stream table | ||
504 | * - MPA buffer (if required) | ||
505 | * - All RA lists | ||
506 | */ | ||
507 | void | ||
508 | mwifiex_clean_txrx(struct mwifiex_private *priv) | ||
509 | { | ||
510 | unsigned long flags; | ||
511 | |||
512 | mwifiex_11n_cleanup_reorder_tbl(priv); | ||
513 | spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags); | ||
514 | |||
515 | mwifiex_wmm_cleanup_queues(priv); | ||
516 | mwifiex_11n_delete_all_tx_ba_stream_tbl(priv); | ||
517 | |||
518 | if (priv->adapter->if_ops.cleanup_mpa_buf) | ||
519 | priv->adapter->if_ops.cleanup_mpa_buf(priv->adapter); | ||
520 | |||
521 | mwifiex_wmm_delete_all_ralist(priv); | ||
522 | memcpy(tos_to_tid, ac_to_tid, sizeof(tos_to_tid)); | ||
523 | |||
524 | spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags); | ||
525 | } | ||
526 | |||
527 | /* | ||
528 | * This function retrieves a particular RA list node, matching with the | ||
529 | * given TID and RA address. | ||
530 | */ | ||
531 | static struct mwifiex_ra_list_tbl * | ||
532 | mwifiex_wmm_get_ralist_node(struct mwifiex_private *priv, u8 tid, | ||
533 | u8 *ra_addr) | ||
534 | { | ||
535 | struct mwifiex_ra_list_tbl *ra_list; | ||
536 | |||
537 | list_for_each_entry(ra_list, &priv->wmm.tid_tbl_ptr[tid].ra_list, | ||
538 | list) { | ||
539 | if (!memcmp(ra_list->ra, ra_addr, ETH_ALEN)) | ||
540 | return ra_list; | ||
541 | } | ||
542 | |||
543 | return NULL; | ||
544 | } | ||
545 | |||
546 | /* | ||
547 | * This function retrieves an RA list node for a given TID and | ||
548 | * RA address pair. | ||
549 | * | ||
550 | * If no such node is found, a new node is added first and then | ||
551 | * retrieved. | ||
552 | */ | ||
553 | static struct mwifiex_ra_list_tbl * | ||
554 | mwifiex_wmm_get_queue_raptr(struct mwifiex_private *priv, u8 tid, u8 *ra_addr) | ||
555 | { | ||
556 | struct mwifiex_ra_list_tbl *ra_list; | ||
557 | |||
558 | ra_list = mwifiex_wmm_get_ralist_node(priv, tid, ra_addr); | ||
559 | if (ra_list) | ||
560 | return ra_list; | ||
561 | mwifiex_ralist_add(priv, ra_addr); | ||
562 | |||
563 | return mwifiex_wmm_get_ralist_node(priv, tid, ra_addr); | ||
564 | } | ||
565 | |||
566 | /* | ||
567 | * This function checks if a particular RA list node exists in a given TID | ||
568 | * table index. | ||
569 | */ | ||
570 | int | ||
571 | mwifiex_is_ralist_valid(struct mwifiex_private *priv, | ||
572 | struct mwifiex_ra_list_tbl *ra_list, int ptr_index) | ||
573 | { | ||
574 | struct mwifiex_ra_list_tbl *rlist; | ||
575 | |||
576 | list_for_each_entry(rlist, &priv->wmm.tid_tbl_ptr[ptr_index].ra_list, | ||
577 | list) { | ||
578 | if (rlist == ra_list) | ||
579 | return true; | ||
580 | } | ||
581 | |||
582 | return false; | ||
583 | } | ||
584 | |||
585 | /* | ||
586 | * This function adds a packet to WMM queue. | ||
587 | * | ||
588 | * In disconnected state the packet is immediately dropped and the | ||
589 | * packet send completion callback is called with status failure. | ||
590 | * | ||
591 | * Otherwise, the correct RA list node is located and the packet | ||
592 | * is queued at the list tail. | ||
593 | */ | ||
594 | void | ||
595 | mwifiex_wmm_add_buf_txqueue(struct mwifiex_adapter *adapter, | ||
596 | struct sk_buff *skb) | ||
597 | { | ||
598 | struct mwifiex_txinfo *tx_info = MWIFIEX_SKB_TXCB(skb); | ||
599 | struct mwifiex_private *priv = adapter->priv[tx_info->bss_index]; | ||
600 | u32 tid; | ||
601 | struct mwifiex_ra_list_tbl *ra_list; | ||
602 | u8 ra[ETH_ALEN], tid_down; | ||
603 | unsigned long flags; | ||
604 | |||
605 | if (!priv->media_connected) { | ||
606 | dev_dbg(adapter->dev, "data: drop packet in disconnect\n"); | ||
607 | mwifiex_write_data_complete(adapter, skb, -1); | ||
608 | return; | ||
609 | } | ||
610 | |||
611 | tid = skb->priority; | ||
612 | |||
613 | spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags); | ||
614 | |||
615 | tid_down = mwifiex_wmm_downgrade_tid(priv, tid); | ||
616 | |||
617 | /* In case of infra as we have already created the list during | ||
618 | association we just don't have to call get_queue_raptr, we will | ||
619 | have only 1 raptr for a tid in case of infra */ | ||
620 | if (!mwifiex_queuing_ra_based(priv)) { | ||
621 | if (!list_empty(&priv->wmm.tid_tbl_ptr[tid_down].ra_list)) | ||
622 | ra_list = list_first_entry( | ||
623 | &priv->wmm.tid_tbl_ptr[tid_down].ra_list, | ||
624 | struct mwifiex_ra_list_tbl, list); | ||
625 | else | ||
626 | ra_list = NULL; | ||
627 | } else { | ||
628 | memcpy(ra, skb->data, ETH_ALEN); | ||
629 | ra_list = mwifiex_wmm_get_queue_raptr(priv, tid_down, ra); | ||
630 | } | ||
631 | |||
632 | if (!ra_list) { | ||
633 | spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags); | ||
634 | mwifiex_write_data_complete(adapter, skb, -1); | ||
635 | return; | ||
636 | } | ||
637 | |||
638 | skb_queue_tail(&ra_list->skb_head, skb); | ||
639 | |||
640 | ra_list->total_pkts_size += skb->len; | ||
641 | |||
642 | spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags); | ||
643 | } | ||
644 | |||
645 | /* | ||
646 | * This function processes the get WMM status command response from firmware. | ||
647 | * | ||
648 | * The response may contain multiple TLVs - | ||
649 | * - AC Queue status TLVs | ||
650 | * - Current WMM Parameter IE TLV | ||
651 | * - Admission Control action frame TLVs | ||
652 | * | ||
653 | * This function parses the TLVs and then calls further specific functions | ||
654 | * to process any changes in the queue prioritize or state. | ||
655 | */ | ||
656 | int mwifiex_ret_wmm_get_status(struct mwifiex_private *priv, | ||
657 | const struct host_cmd_ds_command *resp) | ||
658 | { | ||
659 | u8 *curr = (u8 *) &resp->params.get_wmm_status; | ||
660 | uint16_t resp_len = le16_to_cpu(resp->size), tlv_len; | ||
661 | int valid = true; | ||
662 | |||
663 | struct mwifiex_ie_types_data *tlv_hdr; | ||
664 | struct mwifiex_ie_types_wmm_queue_status *tlv_wmm_qstatus; | ||
665 | struct ieee_types_wmm_parameter *wmm_param_ie = NULL; | ||
666 | struct mwifiex_wmm_ac_status *ac_status; | ||
667 | |||
668 | dev_dbg(priv->adapter->dev, "info: WMM: WMM_GET_STATUS cmdresp received: %d\n", | ||
669 | resp_len); | ||
670 | |||
671 | while ((resp_len >= sizeof(tlv_hdr->header)) && valid) { | ||
672 | tlv_hdr = (struct mwifiex_ie_types_data *) curr; | ||
673 | tlv_len = le16_to_cpu(tlv_hdr->header.len); | ||
674 | |||
675 | switch (le16_to_cpu(tlv_hdr->header.type)) { | ||
676 | case TLV_TYPE_WMMQSTATUS: | ||
677 | tlv_wmm_qstatus = | ||
678 | (struct mwifiex_ie_types_wmm_queue_status *) | ||
679 | tlv_hdr; | ||
680 | dev_dbg(priv->adapter->dev, | ||
681 | "info: CMD_RESP: WMM_GET_STATUS:" | ||
682 | " QSTATUS TLV: %d, %d, %d\n", | ||
683 | tlv_wmm_qstatus->queue_index, | ||
684 | tlv_wmm_qstatus->flow_required, | ||
685 | tlv_wmm_qstatus->disabled); | ||
686 | |||
687 | ac_status = &priv->wmm.ac_status[tlv_wmm_qstatus-> | ||
688 | queue_index]; | ||
689 | ac_status->disabled = tlv_wmm_qstatus->disabled; | ||
690 | ac_status->flow_required = | ||
691 | tlv_wmm_qstatus->flow_required; | ||
692 | ac_status->flow_created = tlv_wmm_qstatus->flow_created; | ||
693 | break; | ||
694 | |||
695 | case WLAN_EID_VENDOR_SPECIFIC: | ||
696 | /* | ||
697 | * Point the regular IEEE IE 2 bytes into the Marvell IE | ||
698 | * and setup the IEEE IE type and length byte fields | ||
699 | */ | ||
700 | |||
701 | wmm_param_ie = | ||
702 | (struct ieee_types_wmm_parameter *) (curr + | ||
703 | 2); | ||
704 | wmm_param_ie->vend_hdr.len = (u8) tlv_len; | ||
705 | wmm_param_ie->vend_hdr.element_id = | ||
706 | WLAN_EID_VENDOR_SPECIFIC; | ||
707 | |||
708 | dev_dbg(priv->adapter->dev, | ||
709 | "info: CMD_RESP: WMM_GET_STATUS:" | ||
710 | " WMM Parameter Set Count: %d\n", | ||
711 | wmm_param_ie->qos_info_bitmap & | ||
712 | IEEE80211_WMM_IE_AP_QOSINFO_PARAM_SET_CNT_MASK); | ||
713 | |||
714 | memcpy((u8 *) &priv->curr_bss_params.bss_descriptor. | ||
715 | wmm_ie, wmm_param_ie, | ||
716 | wmm_param_ie->vend_hdr.len + 2); | ||
717 | |||
718 | break; | ||
719 | |||
720 | default: | ||
721 | valid = false; | ||
722 | break; | ||
723 | } | ||
724 | |||
725 | curr += (tlv_len + sizeof(tlv_hdr->header)); | ||
726 | resp_len -= (tlv_len + sizeof(tlv_hdr->header)); | ||
727 | } | ||
728 | |||
729 | mwifiex_wmm_setup_queue_priorities(priv, wmm_param_ie); | ||
730 | mwifiex_wmm_setup_ac_downgrade(priv); | ||
731 | |||
732 | return 0; | ||
733 | } | ||
734 | |||
735 | /* | ||
736 | * Callback handler from the command module to allow insertion of a WMM TLV. | ||
737 | * | ||
738 | * If the BSS we are associating to supports WMM, this function adds the | ||
739 | * required WMM Information IE to the association request command buffer in | ||
740 | * the form of a Marvell extended IEEE IE. | ||
741 | */ | ||
742 | u32 | ||
743 | mwifiex_wmm_process_association_req(struct mwifiex_private *priv, | ||
744 | u8 **assoc_buf, | ||
745 | struct ieee_types_wmm_parameter *wmm_ie, | ||
746 | struct ieee80211_ht_cap *ht_cap) | ||
747 | { | ||
748 | struct mwifiex_ie_types_wmm_param_set *wmm_tlv; | ||
749 | u32 ret_len = 0; | ||
750 | |||
751 | /* Null checks */ | ||
752 | if (!assoc_buf) | ||
753 | return 0; | ||
754 | if (!(*assoc_buf)) | ||
755 | return 0; | ||
756 | |||
757 | if (!wmm_ie) | ||
758 | return 0; | ||
759 | |||
760 | dev_dbg(priv->adapter->dev, "info: WMM: process assoc req:" | ||
761 | "bss->wmmIe=0x%x\n", | ||
762 | wmm_ie->vend_hdr.element_id); | ||
763 | |||
764 | if ((priv->wmm_required | ||
765 | || (ht_cap && (priv->adapter->config_bands & BAND_GN | ||
766 | || priv->adapter->config_bands & BAND_AN)) | ||
767 | ) | ||
768 | && wmm_ie->vend_hdr.element_id == WLAN_EID_VENDOR_SPECIFIC) { | ||
769 | wmm_tlv = (struct mwifiex_ie_types_wmm_param_set *) *assoc_buf; | ||
770 | wmm_tlv->header.type = cpu_to_le16((u16) wmm_info_ie[0]); | ||
771 | wmm_tlv->header.len = cpu_to_le16((u16) wmm_info_ie[1]); | ||
772 | memcpy(wmm_tlv->wmm_ie, &wmm_info_ie[2], | ||
773 | le16_to_cpu(wmm_tlv->header.len)); | ||
774 | if (wmm_ie->qos_info_bitmap & IEEE80211_WMM_IE_AP_QOSINFO_UAPSD) | ||
775 | memcpy((u8 *) (wmm_tlv->wmm_ie | ||
776 | + le16_to_cpu(wmm_tlv->header.len) | ||
777 | - sizeof(priv->wmm_qosinfo)), | ||
778 | &priv->wmm_qosinfo, | ||
779 | sizeof(priv->wmm_qosinfo)); | ||
780 | |||
781 | ret_len = sizeof(wmm_tlv->header) | ||
782 | + le16_to_cpu(wmm_tlv->header.len); | ||
783 | |||
784 | *assoc_buf += ret_len; | ||
785 | } | ||
786 | |||
787 | return ret_len; | ||
788 | } | ||
789 | |||
790 | /* | ||
791 | * This function computes the time delay in the driver queues for a | ||
792 | * given packet. | ||
793 | * | ||
794 | * When the packet is received at the OS/Driver interface, the current | ||
795 | * time is set in the packet structure. The difference between the present | ||
796 | * time and that received time is computed in this function and limited | ||
797 | * based on pre-compiled limits in the driver. | ||
798 | */ | ||
799 | u8 | ||
800 | mwifiex_wmm_compute_drv_pkt_delay(struct mwifiex_private *priv, | ||
801 | const struct sk_buff *skb) | ||
802 | { | ||
803 | u8 ret_val = 0; | ||
804 | struct timeval out_tstamp, in_tstamp; | ||
805 | u32 queue_delay; | ||
806 | |||
807 | do_gettimeofday(&out_tstamp); | ||
808 | in_tstamp = ktime_to_timeval(skb->tstamp); | ||
809 | |||
810 | queue_delay = (out_tstamp.tv_sec - in_tstamp.tv_sec) * 1000; | ||
811 | queue_delay += (out_tstamp.tv_usec - in_tstamp.tv_usec) / 1000; | ||
812 | |||
813 | /* | ||
814 | * Queue delay is passed as a uint8 in units of 2ms (ms shifted | ||
815 | * by 1). Min value (other than 0) is therefore 2ms, max is 510ms. | ||
816 | * | ||
817 | * Pass max value if queue_delay is beyond the uint8 range | ||
818 | */ | ||
819 | ret_val = (u8) (min(queue_delay, priv->wmm.drv_pkt_delay_max) >> 1); | ||
820 | |||
821 | dev_dbg(priv->adapter->dev, "data: WMM: Pkt Delay: %d ms," | ||
822 | " %d ms sent to FW\n", queue_delay, ret_val); | ||
823 | |||
824 | return ret_val; | ||
825 | } | ||
826 | |||
827 | /* | ||
828 | * This function retrieves the highest priority RA list table pointer. | ||
829 | */ | ||
830 | static struct mwifiex_ra_list_tbl * | ||
831 | mwifiex_wmm_get_highest_priolist_ptr(struct mwifiex_adapter *adapter, | ||
832 | struct mwifiex_private **priv, int *tid) | ||
833 | { | ||
834 | struct mwifiex_private *priv_tmp; | ||
835 | struct mwifiex_ra_list_tbl *ptr, *head; | ||
836 | struct mwifiex_bss_prio_node *bssprio_node, *bssprio_head; | ||
837 | struct mwifiex_tid_tbl *tid_ptr; | ||
838 | int is_list_empty; | ||
839 | unsigned long flags; | ||
840 | int i, j; | ||
841 | |||
842 | for (j = adapter->priv_num - 1; j >= 0; --j) { | ||
843 | spin_lock_irqsave(&adapter->bss_prio_tbl[j].bss_prio_lock, | ||
844 | flags); | ||
845 | is_list_empty = list_empty(&adapter->bss_prio_tbl[j] | ||
846 | .bss_prio_head); | ||
847 | spin_unlock_irqrestore(&adapter->bss_prio_tbl[j].bss_prio_lock, | ||
848 | flags); | ||
849 | if (is_list_empty) | ||
850 | continue; | ||
851 | |||
852 | if (adapter->bss_prio_tbl[j].bss_prio_cur == | ||
853 | (struct mwifiex_bss_prio_node *) | ||
854 | &adapter->bss_prio_tbl[j].bss_prio_head) { | ||
855 | bssprio_node = | ||
856 | list_first_entry(&adapter->bss_prio_tbl[j] | ||
857 | .bss_prio_head, | ||
858 | struct mwifiex_bss_prio_node, | ||
859 | list); | ||
860 | bssprio_head = bssprio_node; | ||
861 | } else { | ||
862 | bssprio_node = adapter->bss_prio_tbl[j].bss_prio_cur; | ||
863 | bssprio_head = bssprio_node; | ||
864 | } | ||
865 | |||
866 | do { | ||
867 | priv_tmp = bssprio_node->priv; | ||
868 | |||
869 | for (i = HIGH_PRIO_TID; i >= LOW_PRIO_TID; --i) { | ||
870 | |||
871 | tid_ptr = &(priv_tmp)->wmm. | ||
872 | tid_tbl_ptr[tos_to_tid[i]]; | ||
873 | |||
874 | spin_lock_irqsave(&tid_ptr->tid_tbl_lock, | ||
875 | flags); | ||
876 | is_list_empty = | ||
877 | list_empty(&adapter->bss_prio_tbl[j] | ||
878 | .bss_prio_head); | ||
879 | spin_unlock_irqrestore(&tid_ptr->tid_tbl_lock, | ||
880 | flags); | ||
881 | if (is_list_empty) | ||
882 | continue; | ||
883 | |||
884 | /* | ||
885 | * Always choose the next ra we transmitted | ||
886 | * last time, this way we pick the ra's in | ||
887 | * round robin fashion. | ||
888 | */ | ||
889 | ptr = list_first_entry( | ||
890 | &tid_ptr->ra_list_curr->list, | ||
891 | struct mwifiex_ra_list_tbl, | ||
892 | list); | ||
893 | |||
894 | head = ptr; | ||
895 | if (ptr == (struct mwifiex_ra_list_tbl *) | ||
896 | &tid_ptr->ra_list) { | ||
897 | /* Get next ra */ | ||
898 | ptr = list_first_entry(&ptr->list, | ||
899 | struct mwifiex_ra_list_tbl, list); | ||
900 | head = ptr; | ||
901 | } | ||
902 | |||
903 | do { | ||
904 | is_list_empty = | ||
905 | skb_queue_empty(&ptr->skb_head); | ||
906 | if (!is_list_empty) { | ||
907 | *priv = priv_tmp; | ||
908 | *tid = tos_to_tid[i]; | ||
909 | return ptr; | ||
910 | } | ||
911 | /* Get next ra */ | ||
912 | ptr = list_first_entry(&ptr->list, | ||
913 | struct mwifiex_ra_list_tbl, | ||
914 | list); | ||
915 | if (ptr == | ||
916 | (struct mwifiex_ra_list_tbl *) | ||
917 | &tid_ptr->ra_list) | ||
918 | ptr = list_first_entry( | ||
919 | &ptr->list, | ||
920 | struct mwifiex_ra_list_tbl, | ||
921 | list); | ||
922 | } while (ptr != head); | ||
923 | } | ||
924 | |||
925 | /* Get next bss priority node */ | ||
926 | bssprio_node = list_first_entry(&bssprio_node->list, | ||
927 | struct mwifiex_bss_prio_node, | ||
928 | list); | ||
929 | |||
930 | if (bssprio_node == | ||
931 | (struct mwifiex_bss_prio_node *) | ||
932 | &adapter->bss_prio_tbl[j].bss_prio_head) | ||
933 | /* Get next bss priority node */ | ||
934 | bssprio_node = list_first_entry( | ||
935 | &bssprio_node->list, | ||
936 | struct mwifiex_bss_prio_node, | ||
937 | list); | ||
938 | } while (bssprio_node != bssprio_head); | ||
939 | } | ||
940 | return NULL; | ||
941 | } | ||
942 | |||
943 | /* | ||
944 | * This function gets the number of packets in the Tx queue of a | ||
945 | * particular RA list. | ||
946 | */ | ||
947 | static int | ||
948 | mwifiex_num_pkts_in_txq(struct mwifiex_private *priv, | ||
949 | struct mwifiex_ra_list_tbl *ptr, int max_buf_size) | ||
950 | { | ||
951 | int count = 0, total_size = 0; | ||
952 | struct sk_buff *skb, *tmp; | ||
953 | |||
954 | skb_queue_walk_safe(&ptr->skb_head, skb, tmp) { | ||
955 | total_size += skb->len; | ||
956 | if (total_size < max_buf_size) | ||
957 | ++count; | ||
958 | else | ||
959 | break; | ||
960 | } | ||
961 | |||
962 | return count; | ||
963 | } | ||
964 | |||
965 | /* | ||
966 | * This function sends a single packet to firmware for transmission. | ||
967 | */ | ||
968 | static void | ||
969 | mwifiex_send_single_packet(struct mwifiex_private *priv, | ||
970 | struct mwifiex_ra_list_tbl *ptr, int ptr_index, | ||
971 | unsigned long ra_list_flags) | ||
972 | __releases(&priv->wmm.ra_list_spinlock) | ||
973 | { | ||
974 | struct sk_buff *skb, *skb_next; | ||
975 | struct mwifiex_tx_param tx_param; | ||
976 | struct mwifiex_adapter *adapter = priv->adapter; | ||
977 | int status = 0; | ||
978 | struct mwifiex_txinfo *tx_info; | ||
979 | |||
980 | if (skb_queue_empty(&ptr->skb_head)) { | ||
981 | spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, | ||
982 | ra_list_flags); | ||
983 | dev_dbg(adapter->dev, "data: nothing to send\n"); | ||
984 | return; | ||
985 | } | ||
986 | |||
987 | skb = skb_dequeue(&ptr->skb_head); | ||
988 | |||
989 | tx_info = MWIFIEX_SKB_TXCB(skb); | ||
990 | dev_dbg(adapter->dev, "data: dequeuing the packet %p %p\n", ptr, skb); | ||
991 | |||
992 | ptr->total_pkts_size -= skb->len; | ||
993 | |||
994 | if (!skb_queue_empty(&ptr->skb_head)) | ||
995 | skb_next = skb_peek(&ptr->skb_head); | ||
996 | else | ||
997 | skb_next = NULL; | ||
998 | |||
999 | spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ra_list_flags); | ||
1000 | |||
1001 | tx_param.next_pkt_len = ((skb_next) ? skb_next->len + | ||
1002 | sizeof(struct txpd) : 0); | ||
1003 | |||
1004 | status = mwifiex_process_tx(priv, skb, &tx_param); | ||
1005 | |||
1006 | if (status == -EBUSY) { | ||
1007 | /* Queue the packet back at the head */ | ||
1008 | spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags); | ||
1009 | |||
1010 | if (!mwifiex_is_ralist_valid(priv, ptr, ptr_index)) { | ||
1011 | spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, | ||
1012 | ra_list_flags); | ||
1013 | mwifiex_write_data_complete(adapter, skb, -1); | ||
1014 | return; | ||
1015 | } | ||
1016 | |||
1017 | skb_queue_tail(&ptr->skb_head, skb); | ||
1018 | |||
1019 | ptr->total_pkts_size += skb->len; | ||
1020 | tx_info->flags |= MWIFIEX_BUF_FLAG_REQUEUED_PKT; | ||
1021 | spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, | ||
1022 | ra_list_flags); | ||
1023 | } else { | ||
1024 | spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags); | ||
1025 | if (mwifiex_is_ralist_valid(priv, ptr, ptr_index)) { | ||
1026 | priv->wmm.packets_out[ptr_index]++; | ||
1027 | priv->wmm.tid_tbl_ptr[ptr_index].ra_list_curr = ptr; | ||
1028 | } | ||
1029 | adapter->bss_prio_tbl[priv->bss_priority].bss_prio_cur = | ||
1030 | list_first_entry( | ||
1031 | &adapter->bss_prio_tbl[priv->bss_priority] | ||
1032 | .bss_prio_cur->list, | ||
1033 | struct mwifiex_bss_prio_node, | ||
1034 | list); | ||
1035 | spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, | ||
1036 | ra_list_flags); | ||
1037 | } | ||
1038 | } | ||
1039 | |||
1040 | /* | ||
1041 | * This function checks if the first packet in the given RA list | ||
1042 | * is already processed or not. | ||
1043 | */ | ||
1044 | static int | ||
1045 | mwifiex_is_ptr_processed(struct mwifiex_private *priv, | ||
1046 | struct mwifiex_ra_list_tbl *ptr) | ||
1047 | { | ||
1048 | struct sk_buff *skb; | ||
1049 | struct mwifiex_txinfo *tx_info; | ||
1050 | |||
1051 | if (skb_queue_empty(&ptr->skb_head)) | ||
1052 | return false; | ||
1053 | |||
1054 | skb = skb_peek(&ptr->skb_head); | ||
1055 | |||
1056 | tx_info = MWIFIEX_SKB_TXCB(skb); | ||
1057 | if (tx_info->flags & MWIFIEX_BUF_FLAG_REQUEUED_PKT) | ||
1058 | return true; | ||
1059 | |||
1060 | return false; | ||
1061 | } | ||
1062 | |||
1063 | /* | ||
1064 | * This function sends a single processed packet to firmware for | ||
1065 | * transmission. | ||
1066 | */ | ||
1067 | static void | ||
1068 | mwifiex_send_processed_packet(struct mwifiex_private *priv, | ||
1069 | struct mwifiex_ra_list_tbl *ptr, int ptr_index, | ||
1070 | unsigned long ra_list_flags) | ||
1071 | __releases(&priv->wmm.ra_list_spinlock) | ||
1072 | { | ||
1073 | struct mwifiex_tx_param tx_param; | ||
1074 | struct mwifiex_adapter *adapter = priv->adapter; | ||
1075 | int ret = -1; | ||
1076 | struct sk_buff *skb, *skb_next; | ||
1077 | struct mwifiex_txinfo *tx_info; | ||
1078 | |||
1079 | if (skb_queue_empty(&ptr->skb_head)) { | ||
1080 | spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, | ||
1081 | ra_list_flags); | ||
1082 | return; | ||
1083 | } | ||
1084 | |||
1085 | skb = skb_dequeue(&ptr->skb_head); | ||
1086 | |||
1087 | if (!skb_queue_empty(&ptr->skb_head)) | ||
1088 | skb_next = skb_peek(&ptr->skb_head); | ||
1089 | else | ||
1090 | skb_next = NULL; | ||
1091 | |||
1092 | tx_info = MWIFIEX_SKB_TXCB(skb); | ||
1093 | |||
1094 | spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ra_list_flags); | ||
1095 | tx_param.next_pkt_len = | ||
1096 | ((skb_next) ? skb_next->len + | ||
1097 | sizeof(struct txpd) : 0); | ||
1098 | ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA, | ||
1099 | skb->data, skb->len, &tx_param); | ||
1100 | switch (ret) { | ||
1101 | case -EBUSY: | ||
1102 | dev_dbg(adapter->dev, "data: -EBUSY is returned\n"); | ||
1103 | spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags); | ||
1104 | |||
1105 | if (!mwifiex_is_ralist_valid(priv, ptr, ptr_index)) { | ||
1106 | spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, | ||
1107 | ra_list_flags); | ||
1108 | mwifiex_write_data_complete(adapter, skb, -1); | ||
1109 | return; | ||
1110 | } | ||
1111 | |||
1112 | skb_queue_tail(&ptr->skb_head, skb); | ||
1113 | |||
1114 | tx_info->flags |= MWIFIEX_BUF_FLAG_REQUEUED_PKT; | ||
1115 | spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, | ||
1116 | ra_list_flags); | ||
1117 | break; | ||
1118 | case -1: | ||
1119 | adapter->data_sent = false; | ||
1120 | dev_err(adapter->dev, "host_to_card failed: %#x\n", ret); | ||
1121 | adapter->dbg.num_tx_host_to_card_failure++; | ||
1122 | mwifiex_write_data_complete(adapter, skb, ret); | ||
1123 | break; | ||
1124 | case -EINPROGRESS: | ||
1125 | adapter->data_sent = false; | ||
1126 | default: | ||
1127 | break; | ||
1128 | } | ||
1129 | if (ret != -EBUSY) { | ||
1130 | spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags); | ||
1131 | if (mwifiex_is_ralist_valid(priv, ptr, ptr_index)) { | ||
1132 | priv->wmm.packets_out[ptr_index]++; | ||
1133 | priv->wmm.tid_tbl_ptr[ptr_index].ra_list_curr = ptr; | ||
1134 | } | ||
1135 | adapter->bss_prio_tbl[priv->bss_priority].bss_prio_cur = | ||
1136 | list_first_entry( | ||
1137 | &adapter->bss_prio_tbl[priv->bss_priority] | ||
1138 | .bss_prio_cur->list, | ||
1139 | struct mwifiex_bss_prio_node, | ||
1140 | list); | ||
1141 | spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, | ||
1142 | ra_list_flags); | ||
1143 | } | ||
1144 | } | ||
1145 | |||
1146 | /* | ||
1147 | * This function dequeues a packet from the highest priority list | ||
1148 | * and transmits it. | ||
1149 | */ | ||
1150 | static int | ||
1151 | mwifiex_dequeue_tx_packet(struct mwifiex_adapter *adapter) | ||
1152 | { | ||
1153 | struct mwifiex_ra_list_tbl *ptr; | ||
1154 | struct mwifiex_private *priv = NULL; | ||
1155 | int ptr_index = 0; | ||
1156 | u8 ra[ETH_ALEN]; | ||
1157 | int tid_del = 0, tid = 0; | ||
1158 | unsigned long flags; | ||
1159 | |||
1160 | ptr = mwifiex_wmm_get_highest_priolist_ptr(adapter, &priv, &ptr_index); | ||
1161 | if (!ptr) | ||
1162 | return -1; | ||
1163 | |||
1164 | tid = mwifiex_get_tid(priv->adapter, ptr); | ||
1165 | |||
1166 | dev_dbg(adapter->dev, "data: tid=%d\n", tid); | ||
1167 | |||
1168 | spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags); | ||
1169 | if (!mwifiex_is_ralist_valid(priv, ptr, ptr_index)) { | ||
1170 | spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags); | ||
1171 | return -1; | ||
1172 | } | ||
1173 | |||
1174 | if (mwifiex_is_ptr_processed(priv, ptr)) { | ||
1175 | mwifiex_send_processed_packet(priv, ptr, ptr_index, flags); | ||
1176 | /* ra_list_spinlock has been freed in | ||
1177 | mwifiex_send_processed_packet() */ | ||
1178 | return 0; | ||
1179 | } | ||
1180 | |||
1181 | if (!ptr->is_11n_enabled || mwifiex_is_ba_stream_setup(priv, ptr, tid) | ||
1182 | || ((priv->sec_info.wpa_enabled | ||
1183 | || priv->sec_info.wpa2_enabled) && !priv->wpa_is_gtk_set) | ||
1184 | ) { | ||
1185 | mwifiex_send_single_packet(priv, ptr, ptr_index, flags); | ||
1186 | /* ra_list_spinlock has been freed in | ||
1187 | mwifiex_send_single_packet() */ | ||
1188 | } else { | ||
1189 | if (mwifiex_is_ampdu_allowed(priv, ptr, tid)) { | ||
1190 | if (mwifiex_is_ba_stream_avail(priv)) { | ||
1191 | mwifiex_11n_create_tx_ba_stream_tbl(priv, | ||
1192 | ptr->ra, tid, | ||
1193 | BA_STREAM_SETUP_INPROGRESS); | ||
1194 | mwifiex_send_addba(priv, tid, ptr->ra); | ||
1195 | } else if (mwifiex_find_stream_to_delete | ||
1196 | (priv, ptr, tid, &tid_del, ra)) { | ||
1197 | mwifiex_11n_create_tx_ba_stream_tbl(priv, | ||
1198 | ptr->ra, tid, | ||
1199 | BA_STREAM_SETUP_INPROGRESS); | ||
1200 | mwifiex_send_delba(priv, tid_del, ra, 1); | ||
1201 | } | ||
1202 | } | ||
1203 | /* Minimum number of AMSDU */ | ||
1204 | #define MIN_NUM_AMSDU 2 | ||
1205 | if (mwifiex_is_amsdu_allowed(priv, ptr, tid) && | ||
1206 | (mwifiex_num_pkts_in_txq(priv, ptr, adapter->tx_buf_size) >= | ||
1207 | MIN_NUM_AMSDU)) | ||
1208 | mwifiex_11n_aggregate_pkt(priv, ptr, INTF_HEADER_LEN, | ||
1209 | ptr_index, flags); | ||
1210 | /* ra_list_spinlock has been freed in | ||
1211 | mwifiex_11n_aggregate_pkt() */ | ||
1212 | else | ||
1213 | mwifiex_send_single_packet(priv, ptr, ptr_index, flags); | ||
1214 | /* ra_list_spinlock has been freed in | ||
1215 | mwifiex_send_single_packet() */ | ||
1216 | } | ||
1217 | return 0; | ||
1218 | } | ||
1219 | |||
1220 | /* | ||
1221 | * This function transmits the highest priority packet awaiting in the | ||
1222 | * WMM Queues. | ||
1223 | */ | ||
1224 | void | ||
1225 | mwifiex_wmm_process_tx(struct mwifiex_adapter *adapter) | ||
1226 | { | ||
1227 | do { | ||
1228 | /* Check if busy */ | ||
1229 | if (adapter->data_sent || adapter->tx_lock_flag) | ||
1230 | break; | ||
1231 | |||
1232 | if (mwifiex_dequeue_tx_packet(adapter)) | ||
1233 | break; | ||
1234 | } while (true); | ||
1235 | |||
1236 | return; | ||
1237 | } | ||
diff --git a/drivers/net/wireless/mwifiex/wmm.h b/drivers/net/wireless/mwifiex/wmm.h new file mode 100644 index 000000000000..241f1b0b77f9 --- /dev/null +++ b/drivers/net/wireless/mwifiex/wmm.h | |||
@@ -0,0 +1,112 @@ | |||
1 | /* | ||
2 | * Marvell Wireless LAN device driver: WMM | ||
3 | * | ||
4 | * Copyright (C) 2011, Marvell International Ltd. | ||
5 | * | ||
6 | * This software file (the "File") is distributed by Marvell International | ||
7 | * Ltd. under the terms of the GNU General Public License Version 2, June 1991 | ||
8 | * (the "License"). You may use, redistribute and/or modify this File in | ||
9 | * accordance with the terms and conditions of the License, a copy of which | ||
10 | * is available by writing to the Free Software Foundation, Inc., | ||
11 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the | ||
12 | * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. | ||
13 | * | ||
14 | * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE | ||
15 | * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE | ||
16 | * ARE EXPRESSLY DISCLAIMED. The License provides additional details about | ||
17 | * this warranty disclaimer. | ||
18 | */ | ||
19 | |||
20 | #ifndef _MWIFIEX_WMM_H_ | ||
21 | #define _MWIFIEX_WMM_H_ | ||
22 | |||
23 | enum ieee_types_wmm_aciaifsn_bitmasks { | ||
24 | MWIFIEX_AIFSN = (BIT(0) | BIT(1) | BIT(2) | BIT(3)), | ||
25 | MWIFIEX_ACM = BIT(4), | ||
26 | MWIFIEX_ACI = (BIT(5) | BIT(6)), | ||
27 | }; | ||
28 | |||
29 | enum ieee_types_wmm_ecw_bitmasks { | ||
30 | MWIFIEX_ECW_MIN = (BIT(0) | BIT(1) | BIT(2) | BIT(3)), | ||
31 | MWIFIEX_ECW_MAX = (BIT(4) | BIT(5) | BIT(6) | BIT(7)), | ||
32 | }; | ||
33 | |||
34 | /* | ||
35 | * This function retrieves the TID of the given RA list. | ||
36 | */ | ||
37 | static inline int | ||
38 | mwifiex_get_tid(struct mwifiex_adapter *adapter, | ||
39 | struct mwifiex_ra_list_tbl *ptr) | ||
40 | { | ||
41 | struct sk_buff *skb; | ||
42 | |||
43 | if (skb_queue_empty(&ptr->skb_head)) | ||
44 | return 0; | ||
45 | |||
46 | skb = skb_peek(&ptr->skb_head); | ||
47 | |||
48 | return skb->priority; | ||
49 | } | ||
50 | |||
51 | /* | ||
52 | * This function gets the length of a list. | ||
53 | */ | ||
54 | static inline int | ||
55 | mwifiex_wmm_list_len(struct mwifiex_adapter *adapter, struct list_head *head) | ||
56 | { | ||
57 | struct list_head *pos; | ||
58 | int count = 0; | ||
59 | |||
60 | list_for_each(pos, head) | ||
61 | ++count; | ||
62 | |||
63 | return count; | ||
64 | } | ||
65 | |||
66 | /* | ||
67 | * This function checks if a RA list is empty or not. | ||
68 | */ | ||
69 | static inline u8 | ||
70 | mwifiex_wmm_is_ra_list_empty(struct mwifiex_adapter *adapter, | ||
71 | struct list_head *ra_list_hhead) | ||
72 | { | ||
73 | struct mwifiex_ra_list_tbl *ra_list; | ||
74 | int is_list_empty; | ||
75 | |||
76 | list_for_each_entry(ra_list, ra_list_hhead, list) { | ||
77 | is_list_empty = skb_queue_empty(&ra_list->skb_head); | ||
78 | if (!is_list_empty) | ||
79 | return false; | ||
80 | } | ||
81 | |||
82 | return true; | ||
83 | } | ||
84 | |||
85 | void mwifiex_wmm_add_buf_txqueue(struct mwifiex_adapter *adapter, | ||
86 | struct sk_buff *skb); | ||
87 | void mwifiex_ralist_add(struct mwifiex_private *priv, u8 *ra); | ||
88 | |||
89 | int mwifiex_wmm_lists_empty(struct mwifiex_adapter *adapter); | ||
90 | void mwifiex_wmm_process_tx(struct mwifiex_adapter *adapter); | ||
91 | int mwifiex_is_ralist_valid(struct mwifiex_private *priv, | ||
92 | struct mwifiex_ra_list_tbl *ra_list, int tid); | ||
93 | |||
94 | u8 mwifiex_wmm_compute_drv_pkt_delay(struct mwifiex_private *priv, | ||
95 | const struct sk_buff *skb); | ||
96 | void mwifiex_wmm_init(struct mwifiex_adapter *adapter); | ||
97 | |||
98 | extern u32 mwifiex_wmm_process_association_req(struct mwifiex_private *priv, | ||
99 | u8 **assoc_buf, | ||
100 | struct ieee_types_wmm_parameter | ||
101 | *wmmie, | ||
102 | struct ieee80211_ht_cap | ||
103 | *htcap); | ||
104 | |||
105 | void mwifiex_wmm_setup_queue_priorities(struct mwifiex_private *priv, | ||
106 | struct ieee_types_wmm_parameter | ||
107 | *wmm_ie); | ||
108 | void mwifiex_wmm_setup_ac_downgrade(struct mwifiex_private *priv); | ||
109 | extern int mwifiex_ret_wmm_get_status(struct mwifiex_private *priv, | ||
110 | const struct host_cmd_ds_command *resp); | ||
111 | |||
112 | #endif /* !_MWIFIEX_WMM_H_ */ | ||
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index c1ceb4b23971..8913180a7bd3 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c | |||
@@ -63,6 +63,7 @@ MODULE_PARM_DESC(ap_mode_default, | |||
63 | #define MWL8K_HIU_A2H_INTERRUPT_CLEAR_SEL 0x00000c38 | 63 | #define MWL8K_HIU_A2H_INTERRUPT_CLEAR_SEL 0x00000c38 |
64 | #define MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK 0x00000c3c | 64 | #define MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK 0x00000c3c |
65 | #define MWL8K_A2H_INT_DUMMY (1 << 20) | 65 | #define MWL8K_A2H_INT_DUMMY (1 << 20) |
66 | #define MWL8K_A2H_INT_BA_WATCHDOG (1 << 14) | ||
66 | #define MWL8K_A2H_INT_CHNL_SWITCHED (1 << 11) | 67 | #define MWL8K_A2H_INT_CHNL_SWITCHED (1 << 11) |
67 | #define MWL8K_A2H_INT_QUEUE_EMPTY (1 << 10) | 68 | #define MWL8K_A2H_INT_QUEUE_EMPTY (1 << 10) |
68 | #define MWL8K_A2H_INT_RADAR_DETECT (1 << 7) | 69 | #define MWL8K_A2H_INT_RADAR_DETECT (1 << 7) |
@@ -82,10 +83,14 @@ MODULE_PARM_DESC(ap_mode_default, | |||
82 | MWL8K_A2H_INT_MAC_EVENT | \ | 83 | MWL8K_A2H_INT_MAC_EVENT | \ |
83 | MWL8K_A2H_INT_OPC_DONE | \ | 84 | MWL8K_A2H_INT_OPC_DONE | \ |
84 | MWL8K_A2H_INT_RX_READY | \ | 85 | MWL8K_A2H_INT_RX_READY | \ |
85 | MWL8K_A2H_INT_TX_DONE) | 86 | MWL8K_A2H_INT_TX_DONE | \ |
87 | MWL8K_A2H_INT_BA_WATCHDOG) | ||
86 | 88 | ||
87 | #define MWL8K_RX_QUEUES 1 | 89 | #define MWL8K_RX_QUEUES 1 |
88 | #define MWL8K_TX_QUEUES 4 | 90 | #define MWL8K_TX_WMM_QUEUES 4 |
91 | #define MWL8K_MAX_AMPDU_QUEUES 8 | ||
92 | #define MWL8K_MAX_TX_QUEUES (MWL8K_TX_WMM_QUEUES + MWL8K_MAX_AMPDU_QUEUES) | ||
93 | #define mwl8k_tx_queues(priv) (MWL8K_TX_WMM_QUEUES + (priv)->num_ampdu_queues) | ||
89 | 94 | ||
90 | struct rxd_ops { | 95 | struct rxd_ops { |
91 | int rxd_size; | 96 | int rxd_size; |
@@ -134,6 +139,21 @@ struct mwl8k_tx_queue { | |||
134 | struct sk_buff **skb; | 139 | struct sk_buff **skb; |
135 | }; | 140 | }; |
136 | 141 | ||
142 | enum { | ||
143 | AMPDU_NO_STREAM, | ||
144 | AMPDU_STREAM_NEW, | ||
145 | AMPDU_STREAM_IN_PROGRESS, | ||
146 | AMPDU_STREAM_ACTIVE, | ||
147 | }; | ||
148 | |||
149 | struct mwl8k_ampdu_stream { | ||
150 | struct ieee80211_sta *sta; | ||
151 | u8 tid; | ||
152 | u8 state; | ||
153 | u8 idx; | ||
154 | u8 txq_idx; /* index of this stream in priv->txq */ | ||
155 | }; | ||
156 | |||
137 | struct mwl8k_priv { | 157 | struct mwl8k_priv { |
138 | struct ieee80211_hw *hw; | 158 | struct ieee80211_hw *hw; |
139 | struct pci_dev *pdev; | 159 | struct pci_dev *pdev; |
@@ -160,6 +180,12 @@ struct mwl8k_priv { | |||
160 | u32 ap_macids_supported; | 180 | u32 ap_macids_supported; |
161 | u32 sta_macids_supported; | 181 | u32 sta_macids_supported; |
162 | 182 | ||
183 | /* Ampdu stream information */ | ||
184 | u8 num_ampdu_queues; | ||
185 | spinlock_t stream_lock; | ||
186 | struct mwl8k_ampdu_stream ampdu[MWL8K_MAX_AMPDU_QUEUES]; | ||
187 | struct work_struct watchdog_ba_handle; | ||
188 | |||
163 | /* firmware access */ | 189 | /* firmware access */ |
164 | struct mutex fw_mutex; | 190 | struct mutex fw_mutex; |
165 | struct task_struct *fw_mutex_owner; | 191 | struct task_struct *fw_mutex_owner; |
@@ -191,7 +217,8 @@ struct mwl8k_priv { | |||
191 | int pending_tx_pkts; | 217 | int pending_tx_pkts; |
192 | 218 | ||
193 | struct mwl8k_rx_queue rxq[MWL8K_RX_QUEUES]; | 219 | struct mwl8k_rx_queue rxq[MWL8K_RX_QUEUES]; |
194 | struct mwl8k_tx_queue txq[MWL8K_TX_QUEUES]; | 220 | struct mwl8k_tx_queue txq[MWL8K_MAX_TX_QUEUES]; |
221 | u32 txq_offset[MWL8K_MAX_TX_QUEUES]; | ||
195 | 222 | ||
196 | bool radio_on; | 223 | bool radio_on; |
197 | bool radio_short_preamble; | 224 | bool radio_short_preamble; |
@@ -224,7 +251,7 @@ struct mwl8k_priv { | |||
224 | * preserve the queue configurations so they can be restored if/when | 251 | * preserve the queue configurations so they can be restored if/when |
225 | * the firmware image is swapped. | 252 | * the firmware image is swapped. |
226 | */ | 253 | */ |
227 | struct ieee80211_tx_queue_params wmm_params[MWL8K_TX_QUEUES]; | 254 | struct ieee80211_tx_queue_params wmm_params[MWL8K_TX_WMM_QUEUES]; |
228 | 255 | ||
229 | /* async firmware loading state */ | 256 | /* async firmware loading state */ |
230 | unsigned fw_state; | 257 | unsigned fw_state; |
@@ -265,6 +292,7 @@ struct mwl8k_vif { | |||
265 | struct mwl8k_sta { | 292 | struct mwl8k_sta { |
266 | /* Index into station database. Returned by UPDATE_STADB. */ | 293 | /* Index into station database. Returned by UPDATE_STADB. */ |
267 | u8 peer_id; | 294 | u8 peer_id; |
295 | u8 is_ampdu_allowed; | ||
268 | }; | 296 | }; |
269 | #define MWL8K_STA(_sta) ((struct mwl8k_sta *)&((_sta)->drv_priv)) | 297 | #define MWL8K_STA(_sta) ((struct mwl8k_sta *)&((_sta)->drv_priv)) |
270 | 298 | ||
@@ -352,10 +380,12 @@ static const struct ieee80211_rate mwl8k_rates_50[] = { | |||
352 | #define MWL8K_CMD_ENABLE_SNIFFER 0x0150 | 380 | #define MWL8K_CMD_ENABLE_SNIFFER 0x0150 |
353 | #define MWL8K_CMD_SET_MAC_ADDR 0x0202 /* per-vif */ | 381 | #define MWL8K_CMD_SET_MAC_ADDR 0x0202 /* per-vif */ |
354 | #define MWL8K_CMD_SET_RATEADAPT_MODE 0x0203 | 382 | #define MWL8K_CMD_SET_RATEADAPT_MODE 0x0203 |
383 | #define MWL8K_CMD_GET_WATCHDOG_BITMAP 0x0205 | ||
355 | #define MWL8K_CMD_BSS_START 0x1100 /* per-vif */ | 384 | #define MWL8K_CMD_BSS_START 0x1100 /* per-vif */ |
356 | #define MWL8K_CMD_SET_NEW_STN 0x1111 /* per-vif */ | 385 | #define MWL8K_CMD_SET_NEW_STN 0x1111 /* per-vif */ |
357 | #define MWL8K_CMD_UPDATE_ENCRYPTION 0x1122 /* per-vif */ | 386 | #define MWL8K_CMD_UPDATE_ENCRYPTION 0x1122 /* per-vif */ |
358 | #define MWL8K_CMD_UPDATE_STADB 0x1123 | 387 | #define MWL8K_CMD_UPDATE_STADB 0x1123 |
388 | #define MWL8K_CMD_BASTREAM 0x1125 | ||
359 | 389 | ||
360 | static const char *mwl8k_cmd_name(__le16 cmd, char *buf, int bufsize) | 390 | static const char *mwl8k_cmd_name(__le16 cmd, char *buf, int bufsize) |
361 | { | 391 | { |
@@ -395,6 +425,8 @@ static const char *mwl8k_cmd_name(__le16 cmd, char *buf, int bufsize) | |||
395 | MWL8K_CMDNAME(SET_NEW_STN); | 425 | MWL8K_CMDNAME(SET_NEW_STN); |
396 | MWL8K_CMDNAME(UPDATE_ENCRYPTION); | 426 | MWL8K_CMDNAME(UPDATE_ENCRYPTION); |
397 | MWL8K_CMDNAME(UPDATE_STADB); | 427 | MWL8K_CMDNAME(UPDATE_STADB); |
428 | MWL8K_CMDNAME(BASTREAM); | ||
429 | MWL8K_CMDNAME(GET_WATCHDOG_BITMAP); | ||
398 | default: | 430 | default: |
399 | snprintf(buf, bufsize, "0x%x", cmd); | 431 | snprintf(buf, bufsize, "0x%x", cmd); |
400 | } | 432 | } |
@@ -1127,6 +1159,9 @@ static void mwl8k_rxq_deinit(struct ieee80211_hw *hw, int index) | |||
1127 | struct mwl8k_rx_queue *rxq = priv->rxq + index; | 1159 | struct mwl8k_rx_queue *rxq = priv->rxq + index; |
1128 | int i; | 1160 | int i; |
1129 | 1161 | ||
1162 | if (rxq->rxd == NULL) | ||
1163 | return; | ||
1164 | |||
1130 | for (i = 0; i < MWL8K_RX_DESCS; i++) { | 1165 | for (i = 0; i < MWL8K_RX_DESCS; i++) { |
1131 | if (rxq->buf[i].skb != NULL) { | 1166 | if (rxq->buf[i].skb != NULL) { |
1132 | pci_unmap_single(priv->pdev, | 1167 | pci_unmap_single(priv->pdev, |
@@ -1319,7 +1354,7 @@ struct mwl8k_tx_desc { | |||
1319 | __le16 pkt_len; | 1354 | __le16 pkt_len; |
1320 | __u8 dest_MAC_addr[ETH_ALEN]; | 1355 | __u8 dest_MAC_addr[ETH_ALEN]; |
1321 | __le32 next_txd_phys_addr; | 1356 | __le32 next_txd_phys_addr; |
1322 | __le32 reserved; | 1357 | __le32 timestamp; |
1323 | __le16 rate_info; | 1358 | __le16 rate_info; |
1324 | __u8 peer_id; | 1359 | __u8 peer_id; |
1325 | __u8 tx_frag_cnt; | 1360 | __u8 tx_frag_cnt; |
@@ -1383,7 +1418,7 @@ static void mwl8k_dump_tx_rings(struct ieee80211_hw *hw) | |||
1383 | struct mwl8k_priv *priv = hw->priv; | 1418 | struct mwl8k_priv *priv = hw->priv; |
1384 | int i; | 1419 | int i; |
1385 | 1420 | ||
1386 | for (i = 0; i < MWL8K_TX_QUEUES; i++) { | 1421 | for (i = 0; i < mwl8k_tx_queues(priv); i++) { |
1387 | struct mwl8k_tx_queue *txq = priv->txq + i; | 1422 | struct mwl8k_tx_queue *txq = priv->txq + i; |
1388 | int fw_owned = 0; | 1423 | int fw_owned = 0; |
1389 | int drv_owned = 0; | 1424 | int drv_owned = 0; |
@@ -1484,6 +1519,54 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw) | |||
1484 | MWL8K_TXD_STATUS_OK_RETRY | \ | 1519 | MWL8K_TXD_STATUS_OK_RETRY | \ |
1485 | MWL8K_TXD_STATUS_OK_MORE_RETRY)) | 1520 | MWL8K_TXD_STATUS_OK_MORE_RETRY)) |
1486 | 1521 | ||
1522 | static int mwl8k_tid_queue_mapping(u8 tid) | ||
1523 | { | ||
1524 | BUG_ON(tid > 7); | ||
1525 | |||
1526 | switch (tid) { | ||
1527 | case 0: | ||
1528 | case 3: | ||
1529 | return IEEE80211_AC_BE; | ||
1530 | break; | ||
1531 | case 1: | ||
1532 | case 2: | ||
1533 | return IEEE80211_AC_BK; | ||
1534 | break; | ||
1535 | case 4: | ||
1536 | case 5: | ||
1537 | return IEEE80211_AC_VI; | ||
1538 | break; | ||
1539 | case 6: | ||
1540 | case 7: | ||
1541 | return IEEE80211_AC_VO; | ||
1542 | break; | ||
1543 | default: | ||
1544 | return -1; | ||
1545 | break; | ||
1546 | } | ||
1547 | } | ||
1548 | |||
1549 | /* The firmware will fill in the rate information | ||
1550 | * for each packet that gets queued in the hardware | ||
1551 | * in this structure | ||
1552 | */ | ||
1553 | |||
1554 | struct rateinfo { | ||
1555 | __le16 format:1; | ||
1556 | __le16 short_gi:1; | ||
1557 | __le16 band_width:1; | ||
1558 | __le16 rate_id_mcs:6; | ||
1559 | __le16 adv_coding:2; | ||
1560 | __le16 antenna:2; | ||
1561 | __le16 act_sub_chan:2; | ||
1562 | __le16 preamble_type:1; | ||
1563 | __le16 power_id:4; | ||
1564 | __le16 antenna2:1; | ||
1565 | __le16 reserved:1; | ||
1566 | __le16 tx_bf_frame:1; | ||
1567 | __le16 green_field:1; | ||
1568 | } __packed; | ||
1569 | |||
1487 | static int | 1570 | static int |
1488 | mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int limit, int force) | 1571 | mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int limit, int force) |
1489 | { | 1572 | { |
@@ -1500,6 +1583,11 @@ mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int limit, int force) | |||
1500 | struct sk_buff *skb; | 1583 | struct sk_buff *skb; |
1501 | struct ieee80211_tx_info *info; | 1584 | struct ieee80211_tx_info *info; |
1502 | u32 status; | 1585 | u32 status; |
1586 | struct ieee80211_sta *sta; | ||
1587 | struct mwl8k_sta *sta_info = NULL; | ||
1588 | u16 rate_info; | ||
1589 | struct rateinfo *rate; | ||
1590 | struct ieee80211_hdr *wh; | ||
1503 | 1591 | ||
1504 | tx = txq->head; | 1592 | tx = txq->head; |
1505 | tx_desc = txq->txd + tx; | 1593 | tx_desc = txq->txd + tx; |
@@ -1528,11 +1616,34 @@ mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int limit, int force) | |||
1528 | 1616 | ||
1529 | mwl8k_remove_dma_header(skb, tx_desc->qos_control); | 1617 | mwl8k_remove_dma_header(skb, tx_desc->qos_control); |
1530 | 1618 | ||
1619 | wh = (struct ieee80211_hdr *) skb->data; | ||
1620 | |||
1531 | /* Mark descriptor as unused */ | 1621 | /* Mark descriptor as unused */ |
1532 | tx_desc->pkt_phys_addr = 0; | 1622 | tx_desc->pkt_phys_addr = 0; |
1533 | tx_desc->pkt_len = 0; | 1623 | tx_desc->pkt_len = 0; |
1534 | 1624 | ||
1535 | info = IEEE80211_SKB_CB(skb); | 1625 | info = IEEE80211_SKB_CB(skb); |
1626 | if (ieee80211_is_data(wh->frame_control)) { | ||
1627 | sta = info->control.sta; | ||
1628 | if (sta) { | ||
1629 | sta_info = MWL8K_STA(sta); | ||
1630 | BUG_ON(sta_info == NULL); | ||
1631 | rate_info = le16_to_cpu(tx_desc->rate_info); | ||
1632 | rate = (struct rateinfo *)&rate_info; | ||
1633 | /* If rate is < 6.5 Mpbs for an ht station | ||
1634 | * do not form an ampdu. If the station is a | ||
1635 | * legacy station (format = 0), do not form an | ||
1636 | * ampdu | ||
1637 | */ | ||
1638 | if (rate->rate_id_mcs < 1 || | ||
1639 | rate->format == 0) { | ||
1640 | sta_info->is_ampdu_allowed = false; | ||
1641 | } else { | ||
1642 | sta_info->is_ampdu_allowed = true; | ||
1643 | } | ||
1644 | } | ||
1645 | } | ||
1646 | |||
1536 | ieee80211_tx_info_clear_status(info); | 1647 | ieee80211_tx_info_clear_status(info); |
1537 | 1648 | ||
1538 | /* Rate control is happening in the firmware. | 1649 | /* Rate control is happening in the firmware. |
@@ -1549,7 +1660,8 @@ mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int limit, int force) | |||
1549 | processed++; | 1660 | processed++; |
1550 | } | 1661 | } |
1551 | 1662 | ||
1552 | if (processed && priv->radio_on && !mutex_is_locked(&priv->fw_mutex)) | 1663 | if (index < MWL8K_TX_WMM_QUEUES && processed && priv->radio_on && |
1664 | !mutex_is_locked(&priv->fw_mutex)) | ||
1553 | ieee80211_wake_queue(hw, index); | 1665 | ieee80211_wake_queue(hw, index); |
1554 | 1666 | ||
1555 | return processed; | 1667 | return processed; |
@@ -1561,6 +1673,9 @@ static void mwl8k_txq_deinit(struct ieee80211_hw *hw, int index) | |||
1561 | struct mwl8k_priv *priv = hw->priv; | 1673 | struct mwl8k_priv *priv = hw->priv; |
1562 | struct mwl8k_tx_queue *txq = priv->txq + index; | 1674 | struct mwl8k_tx_queue *txq = priv->txq + index; |
1563 | 1675 | ||
1676 | if (txq->txd == NULL) | ||
1677 | return; | ||
1678 | |||
1564 | mwl8k_txq_reclaim(hw, index, INT_MAX, 1); | 1679 | mwl8k_txq_reclaim(hw, index, INT_MAX, 1); |
1565 | 1680 | ||
1566 | kfree(txq->skb); | 1681 | kfree(txq->skb); |
@@ -1572,12 +1687,81 @@ static void mwl8k_txq_deinit(struct ieee80211_hw *hw, int index) | |||
1572 | txq->txd = NULL; | 1687 | txq->txd = NULL; |
1573 | } | 1688 | } |
1574 | 1689 | ||
1690 | /* caller must hold priv->stream_lock when calling the stream functions */ | ||
1691 | struct mwl8k_ampdu_stream * | ||
1692 | mwl8k_add_stream(struct ieee80211_hw *hw, struct ieee80211_sta *sta, u8 tid) | ||
1693 | { | ||
1694 | struct mwl8k_ampdu_stream *stream; | ||
1695 | struct mwl8k_priv *priv = hw->priv; | ||
1696 | int i; | ||
1697 | |||
1698 | for (i = 0; i < priv->num_ampdu_queues; i++) { | ||
1699 | stream = &priv->ampdu[i]; | ||
1700 | if (stream->state == AMPDU_NO_STREAM) { | ||
1701 | stream->sta = sta; | ||
1702 | stream->state = AMPDU_STREAM_NEW; | ||
1703 | stream->tid = tid; | ||
1704 | stream->idx = i; | ||
1705 | stream->txq_idx = MWL8K_TX_WMM_QUEUES + i; | ||
1706 | wiphy_debug(hw->wiphy, "Added a new stream for %pM %d", | ||
1707 | sta->addr, tid); | ||
1708 | return stream; | ||
1709 | } | ||
1710 | } | ||
1711 | return NULL; | ||
1712 | } | ||
1713 | |||
1714 | static int | ||
1715 | mwl8k_start_stream(struct ieee80211_hw *hw, struct mwl8k_ampdu_stream *stream) | ||
1716 | { | ||
1717 | int ret; | ||
1718 | |||
1719 | /* if the stream has already been started, don't start it again */ | ||
1720 | if (stream->state != AMPDU_STREAM_NEW) | ||
1721 | return 0; | ||
1722 | ret = ieee80211_start_tx_ba_session(stream->sta, stream->tid, 0); | ||
1723 | if (ret) | ||
1724 | wiphy_debug(hw->wiphy, "Failed to start stream for %pM %d: " | ||
1725 | "%d\n", stream->sta->addr, stream->tid, ret); | ||
1726 | else | ||
1727 | wiphy_debug(hw->wiphy, "Started stream for %pM %d\n", | ||
1728 | stream->sta->addr, stream->tid); | ||
1729 | return ret; | ||
1730 | } | ||
1731 | |||
1732 | static void | ||
1733 | mwl8k_remove_stream(struct ieee80211_hw *hw, struct mwl8k_ampdu_stream *stream) | ||
1734 | { | ||
1735 | wiphy_debug(hw->wiphy, "Remove stream for %pM %d\n", stream->sta->addr, | ||
1736 | stream->tid); | ||
1737 | memset(stream, 0, sizeof(*stream)); | ||
1738 | } | ||
1739 | |||
1740 | static struct mwl8k_ampdu_stream * | ||
1741 | mwl8k_lookup_stream(struct ieee80211_hw *hw, u8 *addr, u8 tid) | ||
1742 | { | ||
1743 | struct mwl8k_priv *priv = hw->priv; | ||
1744 | int i; | ||
1745 | |||
1746 | for (i = 0 ; i < priv->num_ampdu_queues; i++) { | ||
1747 | struct mwl8k_ampdu_stream *stream; | ||
1748 | stream = &priv->ampdu[i]; | ||
1749 | if (stream->state == AMPDU_NO_STREAM) | ||
1750 | continue; | ||
1751 | if (!memcmp(stream->sta->addr, addr, ETH_ALEN) && | ||
1752 | stream->tid == tid) | ||
1753 | return stream; | ||
1754 | } | ||
1755 | return NULL; | ||
1756 | } | ||
1757 | |||
1575 | static void | 1758 | static void |
1576 | mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) | 1759 | mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) |
1577 | { | 1760 | { |
1578 | struct mwl8k_priv *priv = hw->priv; | 1761 | struct mwl8k_priv *priv = hw->priv; |
1579 | struct ieee80211_tx_info *tx_info; | 1762 | struct ieee80211_tx_info *tx_info; |
1580 | struct mwl8k_vif *mwl8k_vif; | 1763 | struct mwl8k_vif *mwl8k_vif; |
1764 | struct ieee80211_sta *sta; | ||
1581 | struct ieee80211_hdr *wh; | 1765 | struct ieee80211_hdr *wh; |
1582 | struct mwl8k_tx_queue *txq; | 1766 | struct mwl8k_tx_queue *txq; |
1583 | struct mwl8k_tx_desc *tx; | 1767 | struct mwl8k_tx_desc *tx; |
@@ -1585,6 +1769,11 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) | |||
1585 | u32 txstatus; | 1769 | u32 txstatus; |
1586 | u8 txdatarate; | 1770 | u8 txdatarate; |
1587 | u16 qos; | 1771 | u16 qos; |
1772 | int txpriority; | ||
1773 | u8 tid = 0; | ||
1774 | struct mwl8k_ampdu_stream *stream = NULL; | ||
1775 | bool start_ba_session = false; | ||
1776 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; | ||
1588 | 1777 | ||
1589 | wh = (struct ieee80211_hdr *)skb->data; | 1778 | wh = (struct ieee80211_hdr *)skb->data; |
1590 | if (ieee80211_is_data_qos(wh->frame_control)) | 1779 | if (ieee80211_is_data_qos(wh->frame_control)) |
@@ -1600,6 +1789,7 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) | |||
1600 | wh = &((struct mwl8k_dma_data *)skb->data)->wh; | 1789 | wh = &((struct mwl8k_dma_data *)skb->data)->wh; |
1601 | 1790 | ||
1602 | tx_info = IEEE80211_SKB_CB(skb); | 1791 | tx_info = IEEE80211_SKB_CB(skb); |
1792 | sta = tx_info->control.sta; | ||
1603 | mwl8k_vif = MWL8K_VIF(tx_info->control.vif); | 1793 | mwl8k_vif = MWL8K_VIF(tx_info->control.vif); |
1604 | 1794 | ||
1605 | if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { | 1795 | if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { |
@@ -1627,12 +1817,90 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) | |||
1627 | qos |= MWL8K_QOS_ACK_POLICY_NORMAL; | 1817 | qos |= MWL8K_QOS_ACK_POLICY_NORMAL; |
1628 | } | 1818 | } |
1629 | 1819 | ||
1820 | /* Queue ADDBA request in the respective data queue. While setting up | ||
1821 | * the ampdu stream, mac80211 queues further packets for that | ||
1822 | * particular ra/tid pair. However, packets piled up in the hardware | ||
1823 | * for that ra/tid pair will still go out. ADDBA request and the | ||
1824 | * related data packets going out from different queues asynchronously | ||
1825 | * will cause a shift in the receiver window which might result in | ||
1826 | * ampdu packets getting dropped at the receiver after the stream has | ||
1827 | * been setup. | ||
1828 | */ | ||
1829 | if (unlikely(ieee80211_is_action(wh->frame_control) && | ||
1830 | mgmt->u.action.category == WLAN_CATEGORY_BACK && | ||
1831 | mgmt->u.action.u.addba_req.action_code == WLAN_ACTION_ADDBA_REQ && | ||
1832 | priv->ap_fw)) { | ||
1833 | u16 capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab); | ||
1834 | tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2; | ||
1835 | index = mwl8k_tid_queue_mapping(tid); | ||
1836 | } | ||
1837 | |||
1838 | txpriority = index; | ||
1839 | |||
1840 | if (ieee80211_is_data_qos(wh->frame_control) && | ||
1841 | skb->protocol != cpu_to_be16(ETH_P_PAE) && | ||
1842 | sta->ht_cap.ht_supported && priv->ap_fw) { | ||
1843 | tid = qos & 0xf; | ||
1844 | spin_lock(&priv->stream_lock); | ||
1845 | stream = mwl8k_lookup_stream(hw, sta->addr, tid); | ||
1846 | if (stream != NULL) { | ||
1847 | if (stream->state == AMPDU_STREAM_ACTIVE) { | ||
1848 | txpriority = stream->txq_idx; | ||
1849 | index = stream->txq_idx; | ||
1850 | } else if (stream->state == AMPDU_STREAM_NEW) { | ||
1851 | /* We get here if the driver sends us packets | ||
1852 | * after we've initiated a stream, but before | ||
1853 | * our ampdu_action routine has been called | ||
1854 | * with IEEE80211_AMPDU_TX_START to get the SSN | ||
1855 | * for the ADDBA request. So this packet can | ||
1856 | * go out with no risk of sequence number | ||
1857 | * mismatch. No special handling is required. | ||
1858 | */ | ||
1859 | } else { | ||
1860 | /* Drop packets that would go out after the | ||
1861 | * ADDBA request was sent but before the ADDBA | ||
1862 | * response is received. If we don't do this, | ||
1863 | * the recipient would probably receive it | ||
1864 | * after the ADDBA request with SSN 0. This | ||
1865 | * will cause the recipient's BA receive window | ||
1866 | * to shift, which would cause the subsequent | ||
1867 | * packets in the BA stream to be discarded. | ||
1868 | * mac80211 queues our packets for us in this | ||
1869 | * case, so this is really just a safety check. | ||
1870 | */ | ||
1871 | wiphy_warn(hw->wiphy, | ||
1872 | "Cannot send packet while ADDBA " | ||
1873 | "dialog is underway.\n"); | ||
1874 | spin_unlock(&priv->stream_lock); | ||
1875 | dev_kfree_skb(skb); | ||
1876 | return; | ||
1877 | } | ||
1878 | } else { | ||
1879 | /* Defer calling mwl8k_start_stream so that the current | ||
1880 | * skb can go out before the ADDBA request. This | ||
1881 | * prevents sequence number mismatch at the recepient | ||
1882 | * as described above. | ||
1883 | */ | ||
1884 | if (MWL8K_STA(sta)->is_ampdu_allowed) { | ||
1885 | stream = mwl8k_add_stream(hw, sta, tid); | ||
1886 | if (stream != NULL) | ||
1887 | start_ba_session = true; | ||
1888 | } | ||
1889 | } | ||
1890 | spin_unlock(&priv->stream_lock); | ||
1891 | } | ||
1892 | |||
1630 | dma = pci_map_single(priv->pdev, skb->data, | 1893 | dma = pci_map_single(priv->pdev, skb->data, |
1631 | skb->len, PCI_DMA_TODEVICE); | 1894 | skb->len, PCI_DMA_TODEVICE); |
1632 | 1895 | ||
1633 | if (pci_dma_mapping_error(priv->pdev, dma)) { | 1896 | if (pci_dma_mapping_error(priv->pdev, dma)) { |
1634 | wiphy_debug(hw->wiphy, | 1897 | wiphy_debug(hw->wiphy, |
1635 | "failed to dma map skb, dropping TX frame.\n"); | 1898 | "failed to dma map skb, dropping TX frame.\n"); |
1899 | if (start_ba_session) { | ||
1900 | spin_lock(&priv->stream_lock); | ||
1901 | mwl8k_remove_stream(hw, stream); | ||
1902 | spin_unlock(&priv->stream_lock); | ||
1903 | } | ||
1636 | dev_kfree_skb(skb); | 1904 | dev_kfree_skb(skb); |
1637 | return; | 1905 | return; |
1638 | } | 1906 | } |
@@ -1641,12 +1909,22 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) | |||
1641 | 1909 | ||
1642 | txq = priv->txq + index; | 1910 | txq = priv->txq + index; |
1643 | 1911 | ||
1912 | if (index >= MWL8K_TX_WMM_QUEUES && txq->len >= MWL8K_TX_DESCS) { | ||
1913 | /* This is the case in which the tx packet is destined for an | ||
1914 | * AMPDU queue and that AMPDU queue is full. Because we don't | ||
1915 | * start and stop the AMPDU queues, we must drop these packets. | ||
1916 | */ | ||
1917 | dev_kfree_skb(skb); | ||
1918 | spin_unlock_bh(&priv->tx_lock); | ||
1919 | return; | ||
1920 | } | ||
1921 | |||
1644 | BUG_ON(txq->skb[txq->tail] != NULL); | 1922 | BUG_ON(txq->skb[txq->tail] != NULL); |
1645 | txq->skb[txq->tail] = skb; | 1923 | txq->skb[txq->tail] = skb; |
1646 | 1924 | ||
1647 | tx = txq->txd + txq->tail; | 1925 | tx = txq->txd + txq->tail; |
1648 | tx->data_rate = txdatarate; | 1926 | tx->data_rate = txdatarate; |
1649 | tx->tx_priority = index; | 1927 | tx->tx_priority = txpriority; |
1650 | tx->qos_control = cpu_to_le16(qos); | 1928 | tx->qos_control = cpu_to_le16(qos); |
1651 | tx->pkt_phys_addr = cpu_to_le32(dma); | 1929 | tx->pkt_phys_addr = cpu_to_le32(dma); |
1652 | tx->pkt_len = cpu_to_le16(skb->len); | 1930 | tx->pkt_len = cpu_to_le16(skb->len); |
@@ -1665,12 +1943,20 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) | |||
1665 | if (txq->tail == MWL8K_TX_DESCS) | 1943 | if (txq->tail == MWL8K_TX_DESCS) |
1666 | txq->tail = 0; | 1944 | txq->tail = 0; |
1667 | 1945 | ||
1668 | if (txq->head == txq->tail) | 1946 | if (txq->head == txq->tail && index < MWL8K_TX_WMM_QUEUES) |
1669 | ieee80211_stop_queue(hw, index); | 1947 | ieee80211_stop_queue(hw, index); |
1670 | 1948 | ||
1671 | mwl8k_tx_start(priv); | 1949 | mwl8k_tx_start(priv); |
1672 | 1950 | ||
1673 | spin_unlock_bh(&priv->tx_lock); | 1951 | spin_unlock_bh(&priv->tx_lock); |
1952 | |||
1953 | /* Initiate the ampdu session here */ | ||
1954 | if (start_ba_session) { | ||
1955 | spin_lock(&priv->stream_lock); | ||
1956 | if (mwl8k_start_stream(hw, stream)) | ||
1957 | mwl8k_remove_stream(hw, stream); | ||
1958 | spin_unlock(&priv->stream_lock); | ||
1959 | } | ||
1674 | } | 1960 | } |
1675 | 1961 | ||
1676 | 1962 | ||
@@ -1868,7 +2154,7 @@ struct mwl8k_cmd_get_hw_spec_sta { | |||
1868 | __u8 mcs_bitmap[16]; | 2154 | __u8 mcs_bitmap[16]; |
1869 | __le32 rx_queue_ptr; | 2155 | __le32 rx_queue_ptr; |
1870 | __le32 num_tx_queues; | 2156 | __le32 num_tx_queues; |
1871 | __le32 tx_queue_ptrs[MWL8K_TX_QUEUES]; | 2157 | __le32 tx_queue_ptrs[MWL8K_TX_WMM_QUEUES]; |
1872 | __le32 caps2; | 2158 | __le32 caps2; |
1873 | __le32 num_tx_desc_per_queue; | 2159 | __le32 num_tx_desc_per_queue; |
1874 | __le32 total_rxd; | 2160 | __le32 total_rxd; |
@@ -1974,8 +2260,8 @@ static int mwl8k_cmd_get_hw_spec_sta(struct ieee80211_hw *hw) | |||
1974 | memset(cmd->perm_addr, 0xff, sizeof(cmd->perm_addr)); | 2260 | memset(cmd->perm_addr, 0xff, sizeof(cmd->perm_addr)); |
1975 | cmd->ps_cookie = cpu_to_le32(priv->cookie_dma); | 2261 | cmd->ps_cookie = cpu_to_le32(priv->cookie_dma); |
1976 | cmd->rx_queue_ptr = cpu_to_le32(priv->rxq[0].rxd_dma); | 2262 | cmd->rx_queue_ptr = cpu_to_le32(priv->rxq[0].rxd_dma); |
1977 | cmd->num_tx_queues = cpu_to_le32(MWL8K_TX_QUEUES); | 2263 | cmd->num_tx_queues = cpu_to_le32(mwl8k_tx_queues(priv)); |
1978 | for (i = 0; i < MWL8K_TX_QUEUES; i++) | 2264 | for (i = 0; i < mwl8k_tx_queues(priv); i++) |
1979 | cmd->tx_queue_ptrs[i] = cpu_to_le32(priv->txq[i].txd_dma); | 2265 | cmd->tx_queue_ptrs[i] = cpu_to_le32(priv->txq[i].txd_dma); |
1980 | cmd->num_tx_desc_per_queue = cpu_to_le32(MWL8K_TX_DESCS); | 2266 | cmd->num_tx_desc_per_queue = cpu_to_le32(MWL8K_TX_DESCS); |
1981 | cmd->total_rxd = cpu_to_le32(MWL8K_RX_DESCS); | 2267 | cmd->total_rxd = cpu_to_le32(MWL8K_RX_DESCS); |
@@ -2017,13 +2303,16 @@ struct mwl8k_cmd_get_hw_spec_ap { | |||
2017 | __le32 wcbbase2; | 2303 | __le32 wcbbase2; |
2018 | __le32 wcbbase3; | 2304 | __le32 wcbbase3; |
2019 | __le32 fw_api_version; | 2305 | __le32 fw_api_version; |
2306 | __le32 caps; | ||
2307 | __le32 num_of_ampdu_queues; | ||
2308 | __le32 wcbbase_ampdu[MWL8K_MAX_AMPDU_QUEUES]; | ||
2020 | } __packed; | 2309 | } __packed; |
2021 | 2310 | ||
2022 | static int mwl8k_cmd_get_hw_spec_ap(struct ieee80211_hw *hw) | 2311 | static int mwl8k_cmd_get_hw_spec_ap(struct ieee80211_hw *hw) |
2023 | { | 2312 | { |
2024 | struct mwl8k_priv *priv = hw->priv; | 2313 | struct mwl8k_priv *priv = hw->priv; |
2025 | struct mwl8k_cmd_get_hw_spec_ap *cmd; | 2314 | struct mwl8k_cmd_get_hw_spec_ap *cmd; |
2026 | int rc; | 2315 | int rc, i; |
2027 | u32 api_version; | 2316 | u32 api_version; |
2028 | 2317 | ||
2029 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | 2318 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); |
@@ -2055,27 +2344,31 @@ static int mwl8k_cmd_get_hw_spec_ap(struct ieee80211_hw *hw) | |||
2055 | priv->num_mcaddrs = le16_to_cpu(cmd->num_mcaddrs); | 2344 | priv->num_mcaddrs = le16_to_cpu(cmd->num_mcaddrs); |
2056 | priv->fw_rev = le32_to_cpu(cmd->fw_rev); | 2345 | priv->fw_rev = le32_to_cpu(cmd->fw_rev); |
2057 | priv->hw_rev = cmd->hw_rev; | 2346 | priv->hw_rev = cmd->hw_rev; |
2058 | mwl8k_setup_2ghz_band(hw); | 2347 | mwl8k_set_caps(hw, le32_to_cpu(cmd->caps)); |
2059 | priv->ap_macids_supported = 0x000000ff; | 2348 | priv->ap_macids_supported = 0x000000ff; |
2060 | priv->sta_macids_supported = 0x00000000; | 2349 | priv->sta_macids_supported = 0x00000000; |
2061 | 2350 | priv->num_ampdu_queues = le32_to_cpu(cmd->num_of_ampdu_queues); | |
2062 | off = le32_to_cpu(cmd->wcbbase0) & 0xffff; | 2351 | if (priv->num_ampdu_queues > MWL8K_MAX_AMPDU_QUEUES) { |
2063 | iowrite32(priv->txq[0].txd_dma, priv->sram + off); | 2352 | wiphy_warn(hw->wiphy, "fw reported %d ampdu queues" |
2064 | 2353 | " but we only support %d.\n", | |
2354 | priv->num_ampdu_queues, | ||
2355 | MWL8K_MAX_AMPDU_QUEUES); | ||
2356 | priv->num_ampdu_queues = MWL8K_MAX_AMPDU_QUEUES; | ||
2357 | } | ||
2065 | off = le32_to_cpu(cmd->rxwrptr) & 0xffff; | 2358 | off = le32_to_cpu(cmd->rxwrptr) & 0xffff; |
2066 | iowrite32(priv->rxq[0].rxd_dma, priv->sram + off); | 2359 | iowrite32(priv->rxq[0].rxd_dma, priv->sram + off); |
2067 | 2360 | ||
2068 | off = le32_to_cpu(cmd->rxrdptr) & 0xffff; | 2361 | off = le32_to_cpu(cmd->rxrdptr) & 0xffff; |
2069 | iowrite32(priv->rxq[0].rxd_dma, priv->sram + off); | 2362 | iowrite32(priv->rxq[0].rxd_dma, priv->sram + off); |
2070 | 2363 | ||
2071 | off = le32_to_cpu(cmd->wcbbase1) & 0xffff; | 2364 | priv->txq_offset[0] = le32_to_cpu(cmd->wcbbase0) & 0xffff; |
2072 | iowrite32(priv->txq[1].txd_dma, priv->sram + off); | 2365 | priv->txq_offset[1] = le32_to_cpu(cmd->wcbbase1) & 0xffff; |
2366 | priv->txq_offset[2] = le32_to_cpu(cmd->wcbbase2) & 0xffff; | ||
2367 | priv->txq_offset[3] = le32_to_cpu(cmd->wcbbase3) & 0xffff; | ||
2073 | 2368 | ||
2074 | off = le32_to_cpu(cmd->wcbbase2) & 0xffff; | 2369 | for (i = 0; i < priv->num_ampdu_queues; i++) |
2075 | iowrite32(priv->txq[2].txd_dma, priv->sram + off); | 2370 | priv->txq_offset[i + MWL8K_TX_WMM_QUEUES] = |
2076 | 2371 | le32_to_cpu(cmd->wcbbase_ampdu[i]) & 0xffff; | |
2077 | off = le32_to_cpu(cmd->wcbbase3) & 0xffff; | ||
2078 | iowrite32(priv->txq[3].txd_dma, priv->sram + off); | ||
2079 | } | 2372 | } |
2080 | 2373 | ||
2081 | done: | 2374 | done: |
@@ -2098,12 +2391,20 @@ struct mwl8k_cmd_set_hw_spec { | |||
2098 | __le32 caps; | 2391 | __le32 caps; |
2099 | __le32 rx_queue_ptr; | 2392 | __le32 rx_queue_ptr; |
2100 | __le32 num_tx_queues; | 2393 | __le32 num_tx_queues; |
2101 | __le32 tx_queue_ptrs[MWL8K_TX_QUEUES]; | 2394 | __le32 tx_queue_ptrs[MWL8K_MAX_TX_QUEUES]; |
2102 | __le32 flags; | 2395 | __le32 flags; |
2103 | __le32 num_tx_desc_per_queue; | 2396 | __le32 num_tx_desc_per_queue; |
2104 | __le32 total_rxd; | 2397 | __le32 total_rxd; |
2105 | } __packed; | 2398 | } __packed; |
2106 | 2399 | ||
2400 | /* If enabled, MWL8K_SET_HW_SPEC_FLAG_ENABLE_LIFE_TIME_EXPIRY will cause | ||
2401 | * packets to expire 500 ms after the timestamp in the tx descriptor. That is, | ||
2402 | * the packets that are queued for more than 500ms, will be dropped in the | ||
2403 | * hardware. This helps minimizing the issues caused due to head-of-line | ||
2404 | * blocking where a slow client can hog the bandwidth and affect traffic to a | ||
2405 | * faster client. | ||
2406 | */ | ||
2407 | #define MWL8K_SET_HW_SPEC_FLAG_ENABLE_LIFE_TIME_EXPIRY 0x00000400 | ||
2107 | #define MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT 0x00000080 | 2408 | #define MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT 0x00000080 |
2108 | #define MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_PROBERESP 0x00000020 | 2409 | #define MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_PROBERESP 0x00000020 |
2109 | #define MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_BEACON 0x00000010 | 2410 | #define MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_BEACON 0x00000010 |
@@ -2124,7 +2425,7 @@ static int mwl8k_cmd_set_hw_spec(struct ieee80211_hw *hw) | |||
2124 | 2425 | ||
2125 | cmd->ps_cookie = cpu_to_le32(priv->cookie_dma); | 2426 | cmd->ps_cookie = cpu_to_le32(priv->cookie_dma); |
2126 | cmd->rx_queue_ptr = cpu_to_le32(priv->rxq[0].rxd_dma); | 2427 | cmd->rx_queue_ptr = cpu_to_le32(priv->rxq[0].rxd_dma); |
2127 | cmd->num_tx_queues = cpu_to_le32(MWL8K_TX_QUEUES); | 2428 | cmd->num_tx_queues = cpu_to_le32(mwl8k_tx_queues(priv)); |
2128 | 2429 | ||
2129 | /* | 2430 | /* |
2130 | * Mac80211 stack has Q0 as highest priority and Q3 as lowest in | 2431 | * Mac80211 stack has Q0 as highest priority and Q3 as lowest in |
@@ -2132,8 +2433,8 @@ static int mwl8k_cmd_set_hw_spec(struct ieee80211_hw *hw) | |||
2132 | * in that order. Map Q3 of mac80211 to Q0 of firmware so that the | 2433 | * in that order. Map Q3 of mac80211 to Q0 of firmware so that the |
2133 | * priority is interpreted the right way in firmware. | 2434 | * priority is interpreted the right way in firmware. |
2134 | */ | 2435 | */ |
2135 | for (i = 0; i < MWL8K_TX_QUEUES; i++) { | 2436 | for (i = 0; i < mwl8k_tx_queues(priv); i++) { |
2136 | int j = MWL8K_TX_QUEUES - 1 - i; | 2437 | int j = mwl8k_tx_queues(priv) - 1 - i; |
2137 | cmd->tx_queue_ptrs[i] = cpu_to_le32(priv->txq[j].txd_dma); | 2438 | cmd->tx_queue_ptrs[i] = cpu_to_le32(priv->txq[j].txd_dma); |
2138 | } | 2439 | } |
2139 | 2440 | ||
@@ -3123,6 +3424,65 @@ static int mwl8k_cmd_set_rateadapt_mode(struct ieee80211_hw *hw, __u16 mode) | |||
3123 | } | 3424 | } |
3124 | 3425 | ||
3125 | /* | 3426 | /* |
3427 | * CMD_GET_WATCHDOG_BITMAP. | ||
3428 | */ | ||
3429 | struct mwl8k_cmd_get_watchdog_bitmap { | ||
3430 | struct mwl8k_cmd_pkt header; | ||
3431 | u8 bitmap; | ||
3432 | } __packed; | ||
3433 | |||
3434 | static int mwl8k_cmd_get_watchdog_bitmap(struct ieee80211_hw *hw, u8 *bitmap) | ||
3435 | { | ||
3436 | struct mwl8k_cmd_get_watchdog_bitmap *cmd; | ||
3437 | int rc; | ||
3438 | |||
3439 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
3440 | if (cmd == NULL) | ||
3441 | return -ENOMEM; | ||
3442 | |||
3443 | cmd->header.code = cpu_to_le16(MWL8K_CMD_GET_WATCHDOG_BITMAP); | ||
3444 | cmd->header.length = cpu_to_le16(sizeof(*cmd)); | ||
3445 | |||
3446 | rc = mwl8k_post_cmd(hw, &cmd->header); | ||
3447 | if (!rc) | ||
3448 | *bitmap = cmd->bitmap; | ||
3449 | |||
3450 | kfree(cmd); | ||
3451 | |||
3452 | return rc; | ||
3453 | } | ||
3454 | |||
3455 | #define INVALID_BA 0xAA | ||
3456 | static void mwl8k_watchdog_ba_events(struct work_struct *work) | ||
3457 | { | ||
3458 | int rc; | ||
3459 | u8 bitmap = 0, stream_index; | ||
3460 | struct mwl8k_ampdu_stream *streams; | ||
3461 | struct mwl8k_priv *priv = | ||
3462 | container_of(work, struct mwl8k_priv, watchdog_ba_handle); | ||
3463 | |||
3464 | rc = mwl8k_cmd_get_watchdog_bitmap(priv->hw, &bitmap); | ||
3465 | if (rc) | ||
3466 | return; | ||
3467 | |||
3468 | if (bitmap == INVALID_BA) | ||
3469 | return; | ||
3470 | |||
3471 | /* the bitmap is the hw queue number. Map it to the ampdu queue. */ | ||
3472 | stream_index = bitmap - MWL8K_TX_WMM_QUEUES; | ||
3473 | |||
3474 | BUG_ON(stream_index >= priv->num_ampdu_queues); | ||
3475 | |||
3476 | streams = &priv->ampdu[stream_index]; | ||
3477 | |||
3478 | if (streams->state == AMPDU_STREAM_ACTIVE) | ||
3479 | ieee80211_stop_tx_ba_session(streams->sta, streams->tid); | ||
3480 | |||
3481 | return; | ||
3482 | } | ||
3483 | |||
3484 | |||
3485 | /* | ||
3126 | * CMD_BSS_START. | 3486 | * CMD_BSS_START. |
3127 | */ | 3487 | */ |
3128 | struct mwl8k_cmd_bss_start { | 3488 | struct mwl8k_cmd_bss_start { |
@@ -3151,6 +3511,152 @@ static int mwl8k_cmd_bss_start(struct ieee80211_hw *hw, | |||
3151 | } | 3511 | } |
3152 | 3512 | ||
3153 | /* | 3513 | /* |
3514 | * CMD_BASTREAM. | ||
3515 | */ | ||
3516 | |||
3517 | /* | ||
3518 | * UPSTREAM is tx direction | ||
3519 | */ | ||
3520 | #define BASTREAM_FLAG_DIRECTION_UPSTREAM 0x00 | ||
3521 | #define BASTREAM_FLAG_IMMEDIATE_TYPE 0x01 | ||
3522 | |||
3523 | enum { | ||
3524 | MWL8K_BA_CREATE, | ||
3525 | MWL8K_BA_UPDATE, | ||
3526 | MWL8K_BA_DESTROY, | ||
3527 | MWL8K_BA_FLUSH, | ||
3528 | MWL8K_BA_CHECK, | ||
3529 | } ba_stream_action_type; | ||
3530 | |||
3531 | |||
3532 | struct mwl8k_create_ba_stream { | ||
3533 | __le32 flags; | ||
3534 | __le32 idle_thrs; | ||
3535 | __le32 bar_thrs; | ||
3536 | __le32 window_size; | ||
3537 | u8 peer_mac_addr[6]; | ||
3538 | u8 dialog_token; | ||
3539 | u8 tid; | ||
3540 | u8 queue_id; | ||
3541 | u8 param_info; | ||
3542 | __le32 ba_context; | ||
3543 | u8 reset_seq_no_flag; | ||
3544 | __le16 curr_seq_no; | ||
3545 | u8 sta_src_mac_addr[6]; | ||
3546 | } __packed; | ||
3547 | |||
3548 | struct mwl8k_destroy_ba_stream { | ||
3549 | __le32 flags; | ||
3550 | __le32 ba_context; | ||
3551 | } __packed; | ||
3552 | |||
3553 | struct mwl8k_cmd_bastream { | ||
3554 | struct mwl8k_cmd_pkt header; | ||
3555 | __le32 action; | ||
3556 | union { | ||
3557 | struct mwl8k_create_ba_stream create_params; | ||
3558 | struct mwl8k_destroy_ba_stream destroy_params; | ||
3559 | }; | ||
3560 | } __packed; | ||
3561 | |||
3562 | static int | ||
3563 | mwl8k_check_ba(struct ieee80211_hw *hw, struct mwl8k_ampdu_stream *stream) | ||
3564 | { | ||
3565 | struct mwl8k_cmd_bastream *cmd; | ||
3566 | int rc; | ||
3567 | |||
3568 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
3569 | if (cmd == NULL) | ||
3570 | return -ENOMEM; | ||
3571 | |||
3572 | cmd->header.code = cpu_to_le16(MWL8K_CMD_BASTREAM); | ||
3573 | cmd->header.length = cpu_to_le16(sizeof(*cmd)); | ||
3574 | |||
3575 | cmd->action = cpu_to_le32(MWL8K_BA_CHECK); | ||
3576 | |||
3577 | cmd->create_params.queue_id = stream->idx; | ||
3578 | memcpy(&cmd->create_params.peer_mac_addr[0], stream->sta->addr, | ||
3579 | ETH_ALEN); | ||
3580 | cmd->create_params.tid = stream->tid; | ||
3581 | |||
3582 | cmd->create_params.flags = | ||
3583 | cpu_to_le32(BASTREAM_FLAG_IMMEDIATE_TYPE) | | ||
3584 | cpu_to_le32(BASTREAM_FLAG_DIRECTION_UPSTREAM); | ||
3585 | |||
3586 | rc = mwl8k_post_cmd(hw, &cmd->header); | ||
3587 | |||
3588 | kfree(cmd); | ||
3589 | |||
3590 | return rc; | ||
3591 | } | ||
3592 | |||
3593 | static int | ||
3594 | mwl8k_create_ba(struct ieee80211_hw *hw, struct mwl8k_ampdu_stream *stream, | ||
3595 | u8 buf_size) | ||
3596 | { | ||
3597 | struct mwl8k_cmd_bastream *cmd; | ||
3598 | int rc; | ||
3599 | |||
3600 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
3601 | if (cmd == NULL) | ||
3602 | return -ENOMEM; | ||
3603 | |||
3604 | |||
3605 | cmd->header.code = cpu_to_le16(MWL8K_CMD_BASTREAM); | ||
3606 | cmd->header.length = cpu_to_le16(sizeof(*cmd)); | ||
3607 | |||
3608 | cmd->action = cpu_to_le32(MWL8K_BA_CREATE); | ||
3609 | |||
3610 | cmd->create_params.bar_thrs = cpu_to_le32((u32)buf_size); | ||
3611 | cmd->create_params.window_size = cpu_to_le32((u32)buf_size); | ||
3612 | cmd->create_params.queue_id = stream->idx; | ||
3613 | |||
3614 | memcpy(cmd->create_params.peer_mac_addr, stream->sta->addr, ETH_ALEN); | ||
3615 | cmd->create_params.tid = stream->tid; | ||
3616 | cmd->create_params.curr_seq_no = cpu_to_le16(0); | ||
3617 | cmd->create_params.reset_seq_no_flag = 1; | ||
3618 | |||
3619 | cmd->create_params.param_info = | ||
3620 | (stream->sta->ht_cap.ampdu_factor & | ||
3621 | IEEE80211_HT_AMPDU_PARM_FACTOR) | | ||
3622 | ((stream->sta->ht_cap.ampdu_density << 2) & | ||
3623 | IEEE80211_HT_AMPDU_PARM_DENSITY); | ||
3624 | |||
3625 | cmd->create_params.flags = | ||
3626 | cpu_to_le32(BASTREAM_FLAG_IMMEDIATE_TYPE | | ||
3627 | BASTREAM_FLAG_DIRECTION_UPSTREAM); | ||
3628 | |||
3629 | rc = mwl8k_post_cmd(hw, &cmd->header); | ||
3630 | |||
3631 | wiphy_debug(hw->wiphy, "Created a BA stream for %pM : tid %d\n", | ||
3632 | stream->sta->addr, stream->tid); | ||
3633 | kfree(cmd); | ||
3634 | |||
3635 | return rc; | ||
3636 | } | ||
3637 | |||
3638 | static void mwl8k_destroy_ba(struct ieee80211_hw *hw, | ||
3639 | struct mwl8k_ampdu_stream *stream) | ||
3640 | { | ||
3641 | struct mwl8k_cmd_bastream *cmd; | ||
3642 | |||
3643 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
3644 | if (cmd == NULL) | ||
3645 | return; | ||
3646 | |||
3647 | cmd->header.code = cpu_to_le16(MWL8K_CMD_BASTREAM); | ||
3648 | cmd->header.length = cpu_to_le16(sizeof(*cmd)); | ||
3649 | cmd->action = cpu_to_le32(MWL8K_BA_DESTROY); | ||
3650 | |||
3651 | cmd->destroy_params.ba_context = cpu_to_le32(stream->idx); | ||
3652 | mwl8k_post_cmd(hw, &cmd->header); | ||
3653 | |||
3654 | wiphy_debug(hw->wiphy, "Deleted BA stream index %d\n", stream->idx); | ||
3655 | |||
3656 | kfree(cmd); | ||
3657 | } | ||
3658 | |||
3659 | /* | ||
3154 | * CMD_SET_NEW_STN. | 3660 | * CMD_SET_NEW_STN. |
3155 | */ | 3661 | */ |
3156 | struct mwl8k_cmd_set_new_stn { | 3662 | struct mwl8k_cmd_set_new_stn { |
@@ -3671,6 +4177,11 @@ static irqreturn_t mwl8k_interrupt(int irq, void *dev_id) | |||
3671 | tasklet_schedule(&priv->poll_rx_task); | 4177 | tasklet_schedule(&priv->poll_rx_task); |
3672 | } | 4178 | } |
3673 | 4179 | ||
4180 | if (status & MWL8K_A2H_INT_BA_WATCHDOG) { | ||
4181 | status &= ~MWL8K_A2H_INT_BA_WATCHDOG; | ||
4182 | ieee80211_queue_work(hw, &priv->watchdog_ba_handle); | ||
4183 | } | ||
4184 | |||
3674 | if (status) | 4185 | if (status) |
3675 | iowrite32(~status, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); | 4186 | iowrite32(~status, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); |
3676 | 4187 | ||
@@ -3699,7 +4210,7 @@ static void mwl8k_tx_poll(unsigned long data) | |||
3699 | 4210 | ||
3700 | spin_lock_bh(&priv->tx_lock); | 4211 | spin_lock_bh(&priv->tx_lock); |
3701 | 4212 | ||
3702 | for (i = 0; i < MWL8K_TX_QUEUES; i++) | 4213 | for (i = 0; i < mwl8k_tx_queues(priv); i++) |
3703 | limit -= mwl8k_txq_reclaim(hw, i, limit, 0); | 4214 | limit -= mwl8k_txq_reclaim(hw, i, limit, 0); |
3704 | 4215 | ||
3705 | if (!priv->pending_tx_pkts && priv->tx_wait != NULL) { | 4216 | if (!priv->pending_tx_pkts && priv->tx_wait != NULL) { |
@@ -3829,6 +4340,7 @@ static void mwl8k_stop(struct ieee80211_hw *hw) | |||
3829 | 4340 | ||
3830 | /* Stop finalize join worker */ | 4341 | /* Stop finalize join worker */ |
3831 | cancel_work_sync(&priv->finalize_join_worker); | 4342 | cancel_work_sync(&priv->finalize_join_worker); |
4343 | cancel_work_sync(&priv->watchdog_ba_handle); | ||
3832 | if (priv->beacon_skb != NULL) | 4344 | if (priv->beacon_skb != NULL) |
3833 | dev_kfree_skb(priv->beacon_skb); | 4345 | dev_kfree_skb(priv->beacon_skb); |
3834 | 4346 | ||
@@ -3837,7 +4349,7 @@ static void mwl8k_stop(struct ieee80211_hw *hw) | |||
3837 | tasklet_disable(&priv->poll_rx_task); | 4349 | tasklet_disable(&priv->poll_rx_task); |
3838 | 4350 | ||
3839 | /* Return all skbs to mac80211 */ | 4351 | /* Return all skbs to mac80211 */ |
3840 | for (i = 0; i < MWL8K_TX_QUEUES; i++) | 4352 | for (i = 0; i < mwl8k_tx_queues(priv); i++) |
3841 | mwl8k_txq_reclaim(hw, i, INT_MAX, 1); | 4353 | mwl8k_txq_reclaim(hw, i, INT_MAX, 1); |
3842 | } | 4354 | } |
3843 | 4355 | ||
@@ -3958,9 +4470,12 @@ static int mwl8k_config(struct ieee80211_hw *hw, u32 changed) | |||
3958 | conf->power_level = 18; | 4470 | conf->power_level = 18; |
3959 | 4471 | ||
3960 | if (priv->ap_fw) { | 4472 | if (priv->ap_fw) { |
3961 | rc = mwl8k_cmd_tx_power(hw, conf, conf->power_level); | 4473 | |
3962 | if (rc) | 4474 | if (conf->flags & IEEE80211_CONF_CHANGE_POWER) { |
3963 | goto out; | 4475 | rc = mwl8k_cmd_tx_power(hw, conf, conf->power_level); |
4476 | if (rc) | ||
4477 | goto out; | ||
4478 | } | ||
3964 | 4479 | ||
3965 | rc = mwl8k_cmd_rf_antenna(hw, MWL8K_RF_ANTENNA_RX, 0x3); | 4480 | rc = mwl8k_cmd_rf_antenna(hw, MWL8K_RF_ANTENNA_RX, 0x3); |
3966 | if (rc) | 4481 | if (rc) |
@@ -4312,6 +4827,8 @@ static int mwl8k_sta_add(struct ieee80211_hw *hw, | |||
4312 | ret = mwl8k_cmd_update_stadb_add(hw, vif, sta); | 4827 | ret = mwl8k_cmd_update_stadb_add(hw, vif, sta); |
4313 | if (ret >= 0) { | 4828 | if (ret >= 0) { |
4314 | MWL8K_STA(sta)->peer_id = ret; | 4829 | MWL8K_STA(sta)->peer_id = ret; |
4830 | if (sta->ht_cap.ht_supported) | ||
4831 | MWL8K_STA(sta)->is_ampdu_allowed = true; | ||
4315 | ret = 0; | 4832 | ret = 0; |
4316 | } | 4833 | } |
4317 | 4834 | ||
@@ -4335,14 +4852,14 @@ static int mwl8k_conf_tx(struct ieee80211_hw *hw, u16 queue, | |||
4335 | 4852 | ||
4336 | rc = mwl8k_fw_lock(hw); | 4853 | rc = mwl8k_fw_lock(hw); |
4337 | if (!rc) { | 4854 | if (!rc) { |
4338 | BUG_ON(queue > MWL8K_TX_QUEUES - 1); | 4855 | BUG_ON(queue > MWL8K_TX_WMM_QUEUES - 1); |
4339 | memcpy(&priv->wmm_params[queue], params, sizeof(*params)); | 4856 | memcpy(&priv->wmm_params[queue], params, sizeof(*params)); |
4340 | 4857 | ||
4341 | if (!priv->wmm_enabled) | 4858 | if (!priv->wmm_enabled) |
4342 | rc = mwl8k_cmd_set_wmm_mode(hw, 1); | 4859 | rc = mwl8k_cmd_set_wmm_mode(hw, 1); |
4343 | 4860 | ||
4344 | if (!rc) { | 4861 | if (!rc) { |
4345 | int q = MWL8K_TX_QUEUES - 1 - queue; | 4862 | int q = MWL8K_TX_WMM_QUEUES - 1 - queue; |
4346 | rc = mwl8k_cmd_set_edca_params(hw, q, | 4863 | rc = mwl8k_cmd_set_edca_params(hw, q, |
4347 | params->cw_min, | 4864 | params->cw_min, |
4348 | params->cw_max, | 4865 | params->cw_max, |
@@ -4378,21 +4895,118 @@ static int mwl8k_get_survey(struct ieee80211_hw *hw, int idx, | |||
4378 | return 0; | 4895 | return 0; |
4379 | } | 4896 | } |
4380 | 4897 | ||
4898 | #define MAX_AMPDU_ATTEMPTS 5 | ||
4899 | |||
4381 | static int | 4900 | static int |
4382 | mwl8k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | 4901 | mwl8k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
4383 | enum ieee80211_ampdu_mlme_action action, | 4902 | enum ieee80211_ampdu_mlme_action action, |
4384 | struct ieee80211_sta *sta, u16 tid, u16 *ssn, | 4903 | struct ieee80211_sta *sta, u16 tid, u16 *ssn, |
4385 | u8 buf_size) | 4904 | u8 buf_size) |
4386 | { | 4905 | { |
4906 | |||
4907 | int i, rc = 0; | ||
4908 | struct mwl8k_priv *priv = hw->priv; | ||
4909 | struct mwl8k_ampdu_stream *stream; | ||
4910 | u8 *addr = sta->addr; | ||
4911 | |||
4912 | if (!(hw->flags & IEEE80211_HW_AMPDU_AGGREGATION)) | ||
4913 | return -ENOTSUPP; | ||
4914 | |||
4915 | spin_lock(&priv->stream_lock); | ||
4916 | stream = mwl8k_lookup_stream(hw, addr, tid); | ||
4917 | |||
4387 | switch (action) { | 4918 | switch (action) { |
4388 | case IEEE80211_AMPDU_RX_START: | 4919 | case IEEE80211_AMPDU_RX_START: |
4389 | case IEEE80211_AMPDU_RX_STOP: | 4920 | case IEEE80211_AMPDU_RX_STOP: |
4390 | if (!(hw->flags & IEEE80211_HW_AMPDU_AGGREGATION)) | 4921 | break; |
4391 | return -ENOTSUPP; | 4922 | case IEEE80211_AMPDU_TX_START: |
4392 | return 0; | 4923 | /* By the time we get here the hw queues may contain outgoing |
4924 | * packets for this RA/TID that are not part of this BA | ||
4925 | * session. The hw will assign sequence numbers to these | ||
4926 | * packets as they go out. So if we query the hw for its next | ||
4927 | * sequence number and use that for the SSN here, it may end up | ||
4928 | * being wrong, which will lead to sequence number mismatch at | ||
4929 | * the recipient. To avoid this, we reset the sequence number | ||
4930 | * to O for the first MPDU in this BA stream. | ||
4931 | */ | ||
4932 | *ssn = 0; | ||
4933 | if (stream == NULL) { | ||
4934 | /* This means that somebody outside this driver called | ||
4935 | * ieee80211_start_tx_ba_session. This is unexpected | ||
4936 | * because we do our own rate control. Just warn and | ||
4937 | * move on. | ||
4938 | */ | ||
4939 | wiphy_warn(hw->wiphy, "Unexpected call to %s. " | ||
4940 | "Proceeding anyway.\n", __func__); | ||
4941 | stream = mwl8k_add_stream(hw, sta, tid); | ||
4942 | } | ||
4943 | if (stream == NULL) { | ||
4944 | wiphy_debug(hw->wiphy, "no free AMPDU streams\n"); | ||
4945 | rc = -EBUSY; | ||
4946 | break; | ||
4947 | } | ||
4948 | stream->state = AMPDU_STREAM_IN_PROGRESS; | ||
4949 | |||
4950 | /* Release the lock before we do the time consuming stuff */ | ||
4951 | spin_unlock(&priv->stream_lock); | ||
4952 | for (i = 0; i < MAX_AMPDU_ATTEMPTS; i++) { | ||
4953 | rc = mwl8k_check_ba(hw, stream); | ||
4954 | |||
4955 | if (!rc) | ||
4956 | break; | ||
4957 | /* | ||
4958 | * HW queues take time to be flushed, give them | ||
4959 | * sufficient time | ||
4960 | */ | ||
4961 | |||
4962 | msleep(1000); | ||
4963 | } | ||
4964 | spin_lock(&priv->stream_lock); | ||
4965 | if (rc) { | ||
4966 | wiphy_err(hw->wiphy, "Stream for tid %d busy after %d" | ||
4967 | " attempts\n", tid, MAX_AMPDU_ATTEMPTS); | ||
4968 | mwl8k_remove_stream(hw, stream); | ||
4969 | rc = -EBUSY; | ||
4970 | break; | ||
4971 | } | ||
4972 | ieee80211_start_tx_ba_cb_irqsafe(vif, addr, tid); | ||
4973 | break; | ||
4974 | case IEEE80211_AMPDU_TX_STOP: | ||
4975 | if (stream == NULL) | ||
4976 | break; | ||
4977 | if (stream->state == AMPDU_STREAM_ACTIVE) { | ||
4978 | spin_unlock(&priv->stream_lock); | ||
4979 | mwl8k_destroy_ba(hw, stream); | ||
4980 | spin_lock(&priv->stream_lock); | ||
4981 | } | ||
4982 | mwl8k_remove_stream(hw, stream); | ||
4983 | ieee80211_stop_tx_ba_cb_irqsafe(vif, addr, tid); | ||
4984 | break; | ||
4985 | case IEEE80211_AMPDU_TX_OPERATIONAL: | ||
4986 | BUG_ON(stream == NULL); | ||
4987 | BUG_ON(stream->state != AMPDU_STREAM_IN_PROGRESS); | ||
4988 | spin_unlock(&priv->stream_lock); | ||
4989 | rc = mwl8k_create_ba(hw, stream, buf_size); | ||
4990 | spin_lock(&priv->stream_lock); | ||
4991 | if (!rc) | ||
4992 | stream->state = AMPDU_STREAM_ACTIVE; | ||
4993 | else { | ||
4994 | spin_unlock(&priv->stream_lock); | ||
4995 | mwl8k_destroy_ba(hw, stream); | ||
4996 | spin_lock(&priv->stream_lock); | ||
4997 | wiphy_debug(hw->wiphy, | ||
4998 | "Failed adding stream for sta %pM tid %d\n", | ||
4999 | addr, tid); | ||
5000 | mwl8k_remove_stream(hw, stream); | ||
5001 | } | ||
5002 | break; | ||
5003 | |||
4393 | default: | 5004 | default: |
4394 | return -ENOTSUPP; | 5005 | rc = -ENOTSUPP; |
4395 | } | 5006 | } |
5007 | |||
5008 | spin_unlock(&priv->stream_lock); | ||
5009 | return rc; | ||
4396 | } | 5010 | } |
4397 | 5011 | ||
4398 | static const struct ieee80211_ops mwl8k_ops = { | 5012 | static const struct ieee80211_ops mwl8k_ops = { |
@@ -4441,7 +5055,7 @@ enum { | |||
4441 | MWL8366, | 5055 | MWL8366, |
4442 | }; | 5056 | }; |
4443 | 5057 | ||
4444 | #define MWL8K_8366_AP_FW_API 1 | 5058 | #define MWL8K_8366_AP_FW_API 2 |
4445 | #define _MWL8K_8366_AP_FW(api) "mwl8k/fmimage_8366_ap-" #api ".fw" | 5059 | #define _MWL8K_8366_AP_FW(api) "mwl8k/fmimage_8366_ap-" #api ".fw" |
4446 | #define MWL8K_8366_AP_FW(api) _MWL8K_8366_AP_FW(api) | 5060 | #define MWL8K_8366_AP_FW(api) _MWL8K_8366_AP_FW(api) |
4447 | 5061 | ||
@@ -4607,6 +5221,23 @@ static int mwl8k_init_firmware(struct ieee80211_hw *hw, char *fw_image, | |||
4607 | return rc; | 5221 | return rc; |
4608 | } | 5222 | } |
4609 | 5223 | ||
5224 | static int mwl8k_init_txqs(struct ieee80211_hw *hw) | ||
5225 | { | ||
5226 | struct mwl8k_priv *priv = hw->priv; | ||
5227 | int rc = 0; | ||
5228 | int i; | ||
5229 | |||
5230 | for (i = 0; i < mwl8k_tx_queues(priv); i++) { | ||
5231 | rc = mwl8k_txq_init(hw, i); | ||
5232 | if (rc) | ||
5233 | break; | ||
5234 | if (priv->ap_fw) | ||
5235 | iowrite32(priv->txq[i].txd_dma, | ||
5236 | priv->sram + priv->txq_offset[i]); | ||
5237 | } | ||
5238 | return rc; | ||
5239 | } | ||
5240 | |||
4610 | /* initialize hw after successfully loading a firmware image */ | 5241 | /* initialize hw after successfully loading a firmware image */ |
4611 | static int mwl8k_probe_hw(struct ieee80211_hw *hw) | 5242 | static int mwl8k_probe_hw(struct ieee80211_hw *hw) |
4612 | { | 5243 | { |
@@ -4634,15 +5265,23 @@ static int mwl8k_probe_hw(struct ieee80211_hw *hw) | |||
4634 | goto err_stop_firmware; | 5265 | goto err_stop_firmware; |
4635 | rxq_refill(hw, 0, INT_MAX); | 5266 | rxq_refill(hw, 0, INT_MAX); |
4636 | 5267 | ||
4637 | for (i = 0; i < MWL8K_TX_QUEUES; i++) { | 5268 | /* For the sta firmware, we need to know the dma addresses of tx queues |
4638 | rc = mwl8k_txq_init(hw, i); | 5269 | * before sending MWL8K_CMD_GET_HW_SPEC. So we must initialize them |
5270 | * prior to issuing this command. But for the AP case, we learn the | ||
5271 | * total number of queues from the result CMD_GET_HW_SPEC, so for this | ||
5272 | * case we must initialize the tx queues after. | ||
5273 | */ | ||
5274 | priv->num_ampdu_queues = 0; | ||
5275 | if (!priv->ap_fw) { | ||
5276 | rc = mwl8k_init_txqs(hw); | ||
4639 | if (rc) | 5277 | if (rc) |
4640 | goto err_free_queues; | 5278 | goto err_free_queues; |
4641 | } | 5279 | } |
4642 | 5280 | ||
4643 | iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); | 5281 | iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); |
4644 | iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); | 5282 | iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); |
4645 | iowrite32(MWL8K_A2H_INT_TX_DONE | MWL8K_A2H_INT_RX_READY, | 5283 | iowrite32(MWL8K_A2H_INT_TX_DONE|MWL8K_A2H_INT_RX_READY| |
5284 | MWL8K_A2H_INT_BA_WATCHDOG, | ||
4646 | priv->regs + MWL8K_HIU_A2H_INTERRUPT_CLEAR_SEL); | 5285 | priv->regs + MWL8K_HIU_A2H_INTERRUPT_CLEAR_SEL); |
4647 | iowrite32(0xffffffff, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK); | 5286 | iowrite32(0xffffffff, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK); |
4648 | 5287 | ||
@@ -4653,6 +5292,8 @@ static int mwl8k_probe_hw(struct ieee80211_hw *hw) | |||
4653 | goto err_free_queues; | 5292 | goto err_free_queues; |
4654 | } | 5293 | } |
4655 | 5294 | ||
5295 | memset(priv->ampdu, 0, sizeof(priv->ampdu)); | ||
5296 | |||
4656 | /* | 5297 | /* |
4657 | * Temporarily enable interrupts. Initial firmware host | 5298 | * Temporarily enable interrupts. Initial firmware host |
4658 | * commands use interrupts and avoid polling. Disable | 5299 | * commands use interrupts and avoid polling. Disable |
@@ -4664,6 +5305,8 @@ static int mwl8k_probe_hw(struct ieee80211_hw *hw) | |||
4664 | if (priv->ap_fw) { | 5305 | if (priv->ap_fw) { |
4665 | rc = mwl8k_cmd_get_hw_spec_ap(hw); | 5306 | rc = mwl8k_cmd_get_hw_spec_ap(hw); |
4666 | if (!rc) | 5307 | if (!rc) |
5308 | rc = mwl8k_init_txqs(hw); | ||
5309 | if (!rc) | ||
4667 | rc = mwl8k_cmd_set_hw_spec(hw); | 5310 | rc = mwl8k_cmd_set_hw_spec(hw); |
4668 | } else { | 5311 | } else { |
4669 | rc = mwl8k_cmd_get_hw_spec_sta(hw); | 5312 | rc = mwl8k_cmd_get_hw_spec_sta(hw); |
@@ -4705,7 +5348,7 @@ err_free_irq: | |||
4705 | free_irq(priv->pdev->irq, hw); | 5348 | free_irq(priv->pdev->irq, hw); |
4706 | 5349 | ||
4707 | err_free_queues: | 5350 | err_free_queues: |
4708 | for (i = 0; i < MWL8K_TX_QUEUES; i++) | 5351 | for (i = 0; i < mwl8k_tx_queues(priv); i++) |
4709 | mwl8k_txq_deinit(hw, i); | 5352 | mwl8k_txq_deinit(hw, i); |
4710 | mwl8k_rxq_deinit(hw, 0); | 5353 | mwl8k_rxq_deinit(hw, 0); |
4711 | 5354 | ||
@@ -4727,7 +5370,7 @@ static int mwl8k_reload_firmware(struct ieee80211_hw *hw, char *fw_image) | |||
4727 | mwl8k_stop(hw); | 5370 | mwl8k_stop(hw); |
4728 | mwl8k_rxq_deinit(hw, 0); | 5371 | mwl8k_rxq_deinit(hw, 0); |
4729 | 5372 | ||
4730 | for (i = 0; i < MWL8K_TX_QUEUES; i++) | 5373 | for (i = 0; i < mwl8k_tx_queues(priv); i++) |
4731 | mwl8k_txq_deinit(hw, i); | 5374 | mwl8k_txq_deinit(hw, i); |
4732 | 5375 | ||
4733 | rc = mwl8k_init_firmware(hw, fw_image, false); | 5376 | rc = mwl8k_init_firmware(hw, fw_image, false); |
@@ -4746,7 +5389,7 @@ static int mwl8k_reload_firmware(struct ieee80211_hw *hw, char *fw_image) | |||
4746 | if (rc) | 5389 | if (rc) |
4747 | goto fail; | 5390 | goto fail; |
4748 | 5391 | ||
4749 | for (i = 0; i < MWL8K_TX_QUEUES; i++) { | 5392 | for (i = 0; i < MWL8K_TX_WMM_QUEUES; i++) { |
4750 | rc = mwl8k_conf_tx(hw, i, &priv->wmm_params[i]); | 5393 | rc = mwl8k_conf_tx(hw, i, &priv->wmm_params[i]); |
4751 | if (rc) | 5394 | if (rc) |
4752 | goto fail; | 5395 | goto fail; |
@@ -4780,7 +5423,7 @@ static int mwl8k_firmware_load_success(struct mwl8k_priv *priv) | |||
4780 | 5423 | ||
4781 | hw->channel_change_time = 10; | 5424 | hw->channel_change_time = 10; |
4782 | 5425 | ||
4783 | hw->queues = MWL8K_TX_QUEUES; | 5426 | hw->queues = MWL8K_TX_WMM_QUEUES; |
4784 | 5427 | ||
4785 | /* Set rssi values to dBm */ | 5428 | /* Set rssi values to dBm */ |
4786 | hw->flags |= IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_HAS_RATE_CONTROL; | 5429 | hw->flags |= IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_HAS_RATE_CONTROL; |
@@ -4796,6 +5439,8 @@ static int mwl8k_firmware_load_success(struct mwl8k_priv *priv) | |||
4796 | 5439 | ||
4797 | /* Finalize join worker */ | 5440 | /* Finalize join worker */ |
4798 | INIT_WORK(&priv->finalize_join_worker, mwl8k_finalize_join_worker); | 5441 | INIT_WORK(&priv->finalize_join_worker, mwl8k_finalize_join_worker); |
5442 | /* Handle watchdog ba events */ | ||
5443 | INIT_WORK(&priv->watchdog_ba_handle, mwl8k_watchdog_ba_events); | ||
4799 | 5444 | ||
4800 | /* TX reclaim and RX tasklets. */ | 5445 | /* TX reclaim and RX tasklets. */ |
4801 | tasklet_init(&priv->poll_tx_task, mwl8k_tx_poll, (unsigned long)hw); | 5446 | tasklet_init(&priv->poll_tx_task, mwl8k_tx_poll, (unsigned long)hw); |
@@ -4815,6 +5460,8 @@ static int mwl8k_firmware_load_success(struct mwl8k_priv *priv) | |||
4815 | 5460 | ||
4816 | spin_lock_init(&priv->tx_lock); | 5461 | spin_lock_init(&priv->tx_lock); |
4817 | 5462 | ||
5463 | spin_lock_init(&priv->stream_lock); | ||
5464 | |||
4818 | priv->tx_wait = NULL; | 5465 | priv->tx_wait = NULL; |
4819 | 5466 | ||
4820 | rc = mwl8k_probe_hw(hw); | 5467 | rc = mwl8k_probe_hw(hw); |
@@ -4836,7 +5483,7 @@ static int mwl8k_firmware_load_success(struct mwl8k_priv *priv) | |||
4836 | return 0; | 5483 | return 0; |
4837 | 5484 | ||
4838 | err_unprobe_hw: | 5485 | err_unprobe_hw: |
4839 | for (i = 0; i < MWL8K_TX_QUEUES; i++) | 5486 | for (i = 0; i < mwl8k_tx_queues(priv); i++) |
4840 | mwl8k_txq_deinit(hw, i); | 5487 | mwl8k_txq_deinit(hw, i); |
4841 | mwl8k_rxq_deinit(hw, 0); | 5488 | mwl8k_rxq_deinit(hw, 0); |
4842 | 5489 | ||
@@ -4995,10 +5642,10 @@ static void __devexit mwl8k_remove(struct pci_dev *pdev) | |||
4995 | mwl8k_hw_reset(priv); | 5642 | mwl8k_hw_reset(priv); |
4996 | 5643 | ||
4997 | /* Return all skbs to mac80211 */ | 5644 | /* Return all skbs to mac80211 */ |
4998 | for (i = 0; i < MWL8K_TX_QUEUES; i++) | 5645 | for (i = 0; i < mwl8k_tx_queues(priv); i++) |
4999 | mwl8k_txq_reclaim(hw, i, INT_MAX, 1); | 5646 | mwl8k_txq_reclaim(hw, i, INT_MAX, 1); |
5000 | 5647 | ||
5001 | for (i = 0; i < MWL8K_TX_QUEUES; i++) | 5648 | for (i = 0; i < mwl8k_tx_queues(priv); i++) |
5002 | mwl8k_txq_deinit(hw, i); | 5649 | mwl8k_txq_deinit(hw, i); |
5003 | 5650 | ||
5004 | mwl8k_rxq_deinit(hw, 0); | 5651 | mwl8k_rxq_deinit(hw, 0); |
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 329f3283697b..137a24e520da 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c | |||
@@ -1368,8 +1368,10 @@ static void rt2400pci_tbtt_tasklet(unsigned long data) | |||
1368 | static void rt2400pci_rxdone_tasklet(unsigned long data) | 1368 | static void rt2400pci_rxdone_tasklet(unsigned long data) |
1369 | { | 1369 | { |
1370 | struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; | 1370 | struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; |
1371 | rt2x00pci_rxdone(rt2x00dev); | 1371 | if (rt2x00pci_rxdone(rt2x00dev)) |
1372 | rt2400pci_enable_interrupt(rt2x00dev, CSR8_RXDONE); | 1372 | tasklet_schedule(&rt2x00dev->rxdone_tasklet); |
1373 | else | ||
1374 | rt2400pci_enable_interrupt(rt2x00dev, CSR8_RXDONE); | ||
1373 | } | 1375 | } |
1374 | 1376 | ||
1375 | static irqreturn_t rt2400pci_interrupt(int irq, void *dev_instance) | 1377 | static irqreturn_t rt2400pci_interrupt(int irq, void *dev_instance) |
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 58277878889e..198fc0a0d77c 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c | |||
@@ -1500,8 +1500,10 @@ static void rt2500pci_tbtt_tasklet(unsigned long data) | |||
1500 | static void rt2500pci_rxdone_tasklet(unsigned long data) | 1500 | static void rt2500pci_rxdone_tasklet(unsigned long data) |
1501 | { | 1501 | { |
1502 | struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; | 1502 | struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; |
1503 | rt2x00pci_rxdone(rt2x00dev); | 1503 | if (rt2x00pci_rxdone(rt2x00dev)) |
1504 | rt2500pci_enable_interrupt(rt2x00dev, CSR8_RXDONE); | 1504 | tasklet_schedule(&rt2x00dev->rxdone_tasklet); |
1505 | else | ||
1506 | rt2500pci_enable_interrupt(rt2x00dev, CSR8_RXDONE); | ||
1505 | } | 1507 | } |
1506 | 1508 | ||
1507 | static irqreturn_t rt2500pci_interrupt(int irq, void *dev_instance) | 1509 | static irqreturn_t rt2500pci_interrupt(int irq, void *dev_instance) |
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 979fe6596a2d..eac788160f55 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c | |||
@@ -1796,7 +1796,6 @@ static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev) | |||
1796 | __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags); | 1796 | __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags); |
1797 | __set_bit(DRIVER_REQUIRE_COPY_IV, &rt2x00dev->flags); | 1797 | __set_bit(DRIVER_REQUIRE_COPY_IV, &rt2x00dev->flags); |
1798 | } | 1798 | } |
1799 | __set_bit(DRIVER_SUPPORT_WATCHDOG, &rt2x00dev->flags); | ||
1800 | __set_bit(DRIVER_REQUIRE_SW_SEQNO, &rt2x00dev->flags); | 1799 | __set_bit(DRIVER_REQUIRE_SW_SEQNO, &rt2x00dev->flags); |
1801 | 1800 | ||
1802 | /* | 1801 | /* |
@@ -1910,13 +1909,10 @@ static struct usb_device_id rt2500usb_device_table[] = { | |||
1910 | /* Belkin */ | 1909 | /* Belkin */ |
1911 | { USB_DEVICE(0x050d, 0x7050), USB_DEVICE_DATA(&rt2500usb_ops) }, | 1910 | { USB_DEVICE(0x050d, 0x7050), USB_DEVICE_DATA(&rt2500usb_ops) }, |
1912 | { USB_DEVICE(0x050d, 0x7051), USB_DEVICE_DATA(&rt2500usb_ops) }, | 1911 | { USB_DEVICE(0x050d, 0x7051), USB_DEVICE_DATA(&rt2500usb_ops) }, |
1913 | { USB_DEVICE(0x050d, 0x705a), USB_DEVICE_DATA(&rt2500usb_ops) }, | ||
1914 | /* Cisco Systems */ | 1912 | /* Cisco Systems */ |
1915 | { USB_DEVICE(0x13b1, 0x000d), USB_DEVICE_DATA(&rt2500usb_ops) }, | 1913 | { USB_DEVICE(0x13b1, 0x000d), USB_DEVICE_DATA(&rt2500usb_ops) }, |
1916 | { USB_DEVICE(0x13b1, 0x0011), USB_DEVICE_DATA(&rt2500usb_ops) }, | 1914 | { USB_DEVICE(0x13b1, 0x0011), USB_DEVICE_DATA(&rt2500usb_ops) }, |
1917 | { USB_DEVICE(0x13b1, 0x001a), USB_DEVICE_DATA(&rt2500usb_ops) }, | 1915 | { USB_DEVICE(0x13b1, 0x001a), USB_DEVICE_DATA(&rt2500usb_ops) }, |
1918 | /* CNet */ | ||
1919 | { USB_DEVICE(0x1371, 0x9022), USB_DEVICE_DATA(&rt2500usb_ops) }, | ||
1920 | /* Conceptronic */ | 1916 | /* Conceptronic */ |
1921 | { USB_DEVICE(0x14b2, 0x3c02), USB_DEVICE_DATA(&rt2500usb_ops) }, | 1917 | { USB_DEVICE(0x14b2, 0x3c02), USB_DEVICE_DATA(&rt2500usb_ops) }, |
1922 | /* D-LINK */ | 1918 | /* D-LINK */ |
@@ -1939,7 +1935,6 @@ static struct usb_device_id rt2500usb_device_table[] = { | |||
1939 | /* Ralink */ | 1935 | /* Ralink */ |
1940 | { USB_DEVICE(0x148f, 0x1706), USB_DEVICE_DATA(&rt2500usb_ops) }, | 1936 | { USB_DEVICE(0x148f, 0x1706), USB_DEVICE_DATA(&rt2500usb_ops) }, |
1941 | { USB_DEVICE(0x148f, 0x2570), USB_DEVICE_DATA(&rt2500usb_ops) }, | 1937 | { USB_DEVICE(0x148f, 0x2570), USB_DEVICE_DATA(&rt2500usb_ops) }, |
1942 | { USB_DEVICE(0x148f, 0x2573), USB_DEVICE_DATA(&rt2500usb_ops) }, | ||
1943 | { USB_DEVICE(0x148f, 0x9020), USB_DEVICE_DATA(&rt2500usb_ops) }, | 1938 | { USB_DEVICE(0x148f, 0x9020), USB_DEVICE_DATA(&rt2500usb_ops) }, |
1944 | /* Sagem */ | 1939 | /* Sagem */ |
1945 | { USB_DEVICE(0x079b, 0x004b), USB_DEVICE_DATA(&rt2500usb_ops) }, | 1940 | { USB_DEVICE(0x079b, 0x004b), USB_DEVICE_DATA(&rt2500usb_ops) }, |
diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h index 8fbc5fa965e0..ce2010952886 100644 --- a/drivers/net/wireless/rt2x00/rt2800.h +++ b/drivers/net/wireless/rt2x00/rt2800.h | |||
@@ -2104,6 +2104,59 @@ struct mac_iveiv_entry { | |||
2104 | #define EEPROM_TXPOWER_BG_2 FIELD16(0xff00) | 2104 | #define EEPROM_TXPOWER_BG_2 FIELD16(0xff00) |
2105 | 2105 | ||
2106 | /* | 2106 | /* |
2107 | * EEPROM temperature compensation boundaries 802.11BG | ||
2108 | * MINUS4: If the actual TSSI is below this boundary, tx power needs to be | ||
2109 | * reduced by (agc_step * -4) | ||
2110 | * MINUS3: If the actual TSSI is below this boundary, tx power needs to be | ||
2111 | * reduced by (agc_step * -3) | ||
2112 | */ | ||
2113 | #define EEPROM_TSSI_BOUND_BG1 0x0037 | ||
2114 | #define EEPROM_TSSI_BOUND_BG1_MINUS4 FIELD16(0x00ff) | ||
2115 | #define EEPROM_TSSI_BOUND_BG1_MINUS3 FIELD16(0xff00) | ||
2116 | |||
2117 | /* | ||
2118 | * EEPROM temperature compensation boundaries 802.11BG | ||
2119 | * MINUS2: If the actual TSSI is below this boundary, tx power needs to be | ||
2120 | * reduced by (agc_step * -2) | ||
2121 | * MINUS1: If the actual TSSI is below this boundary, tx power needs to be | ||
2122 | * reduced by (agc_step * -1) | ||
2123 | */ | ||
2124 | #define EEPROM_TSSI_BOUND_BG2 0x0038 | ||
2125 | #define EEPROM_TSSI_BOUND_BG2_MINUS2 FIELD16(0x00ff) | ||
2126 | #define EEPROM_TSSI_BOUND_BG2_MINUS1 FIELD16(0xff00) | ||
2127 | |||
2128 | /* | ||
2129 | * EEPROM temperature compensation boundaries 802.11BG | ||
2130 | * REF: Reference TSSI value, no tx power changes needed | ||
2131 | * PLUS1: If the actual TSSI is above this boundary, tx power needs to be | ||
2132 | * increased by (agc_step * 1) | ||
2133 | */ | ||
2134 | #define EEPROM_TSSI_BOUND_BG3 0x0039 | ||
2135 | #define EEPROM_TSSI_BOUND_BG3_REF FIELD16(0x00ff) | ||
2136 | #define EEPROM_TSSI_BOUND_BG3_PLUS1 FIELD16(0xff00) | ||
2137 | |||
2138 | /* | ||
2139 | * EEPROM temperature compensation boundaries 802.11BG | ||
2140 | * PLUS2: If the actual TSSI is above this boundary, tx power needs to be | ||
2141 | * increased by (agc_step * 2) | ||
2142 | * PLUS3: If the actual TSSI is above this boundary, tx power needs to be | ||
2143 | * increased by (agc_step * 3) | ||
2144 | */ | ||
2145 | #define EEPROM_TSSI_BOUND_BG4 0x003a | ||
2146 | #define EEPROM_TSSI_BOUND_BG4_PLUS2 FIELD16(0x00ff) | ||
2147 | #define EEPROM_TSSI_BOUND_BG4_PLUS3 FIELD16(0xff00) | ||
2148 | |||
2149 | /* | ||
2150 | * EEPROM temperature compensation boundaries 802.11BG | ||
2151 | * PLUS4: If the actual TSSI is above this boundary, tx power needs to be | ||
2152 | * increased by (agc_step * 4) | ||
2153 | * AGC_STEP: Temperature compensation step. | ||
2154 | */ | ||
2155 | #define EEPROM_TSSI_BOUND_BG5 0x003b | ||
2156 | #define EEPROM_TSSI_BOUND_BG5_PLUS4 FIELD16(0x00ff) | ||
2157 | #define EEPROM_TSSI_BOUND_BG5_AGC_STEP FIELD16(0xff00) | ||
2158 | |||
2159 | /* | ||
2107 | * EEPROM TXPOWER 802.11A | 2160 | * EEPROM TXPOWER 802.11A |
2108 | */ | 2161 | */ |
2109 | #define EEPROM_TXPOWER_A1 0x003c | 2162 | #define EEPROM_TXPOWER_A1 0x003c |
@@ -2113,6 +2166,59 @@ struct mac_iveiv_entry { | |||
2113 | #define EEPROM_TXPOWER_A_2 FIELD16(0xff00) | 2166 | #define EEPROM_TXPOWER_A_2 FIELD16(0xff00) |
2114 | 2167 | ||
2115 | /* | 2168 | /* |
2169 | * EEPROM temperature compensation boundaries 802.11A | ||
2170 | * MINUS4: If the actual TSSI is below this boundary, tx power needs to be | ||
2171 | * reduced by (agc_step * -4) | ||
2172 | * MINUS3: If the actual TSSI is below this boundary, tx power needs to be | ||
2173 | * reduced by (agc_step * -3) | ||
2174 | */ | ||
2175 | #define EEPROM_TSSI_BOUND_A1 0x006a | ||
2176 | #define EEPROM_TSSI_BOUND_A1_MINUS4 FIELD16(0x00ff) | ||
2177 | #define EEPROM_TSSI_BOUND_A1_MINUS3 FIELD16(0xff00) | ||
2178 | |||
2179 | /* | ||
2180 | * EEPROM temperature compensation boundaries 802.11A | ||
2181 | * MINUS2: If the actual TSSI is below this boundary, tx power needs to be | ||
2182 | * reduced by (agc_step * -2) | ||
2183 | * MINUS1: If the actual TSSI is below this boundary, tx power needs to be | ||
2184 | * reduced by (agc_step * -1) | ||
2185 | */ | ||
2186 | #define EEPROM_TSSI_BOUND_A2 0x006b | ||
2187 | #define EEPROM_TSSI_BOUND_A2_MINUS2 FIELD16(0x00ff) | ||
2188 | #define EEPROM_TSSI_BOUND_A2_MINUS1 FIELD16(0xff00) | ||
2189 | |||
2190 | /* | ||
2191 | * EEPROM temperature compensation boundaries 802.11A | ||
2192 | * REF: Reference TSSI value, no tx power changes needed | ||
2193 | * PLUS1: If the actual TSSI is above this boundary, tx power needs to be | ||
2194 | * increased by (agc_step * 1) | ||
2195 | */ | ||
2196 | #define EEPROM_TSSI_BOUND_A3 0x006c | ||
2197 | #define EEPROM_TSSI_BOUND_A3_REF FIELD16(0x00ff) | ||
2198 | #define EEPROM_TSSI_BOUND_A3_PLUS1 FIELD16(0xff00) | ||
2199 | |||
2200 | /* | ||
2201 | * EEPROM temperature compensation boundaries 802.11A | ||
2202 | * PLUS2: If the actual TSSI is above this boundary, tx power needs to be | ||
2203 | * increased by (agc_step * 2) | ||
2204 | * PLUS3: If the actual TSSI is above this boundary, tx power needs to be | ||
2205 | * increased by (agc_step * 3) | ||
2206 | */ | ||
2207 | #define EEPROM_TSSI_BOUND_A4 0x006d | ||
2208 | #define EEPROM_TSSI_BOUND_A4_PLUS2 FIELD16(0x00ff) | ||
2209 | #define EEPROM_TSSI_BOUND_A4_PLUS3 FIELD16(0xff00) | ||
2210 | |||
2211 | /* | ||
2212 | * EEPROM temperature compensation boundaries 802.11A | ||
2213 | * PLUS4: If the actual TSSI is above this boundary, tx power needs to be | ||
2214 | * increased by (agc_step * 4) | ||
2215 | * AGC_STEP: Temperature compensation step. | ||
2216 | */ | ||
2217 | #define EEPROM_TSSI_BOUND_A5 0x006e | ||
2218 | #define EEPROM_TSSI_BOUND_A5_PLUS4 FIELD16(0x00ff) | ||
2219 | #define EEPROM_TSSI_BOUND_A5_AGC_STEP FIELD16(0xff00) | ||
2220 | |||
2221 | /* | ||
2116 | * EEPROM TXPOWER by rate: tx power per tx rate for HT20 mode | 2222 | * EEPROM TXPOWER by rate: tx power per tx rate for HT20 mode |
2117 | */ | 2223 | */ |
2118 | #define EEPROM_TXPOWER_BYRATE 0x006f | 2224 | #define EEPROM_TXPOWER_BYRATE 0x006f |
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index dbf74d07d947..6331c61957a3 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c | |||
@@ -687,6 +687,9 @@ void rt2800_txdone_entry(struct queue_entry *entry, u32 status) | |||
687 | mcs = real_mcs; | 687 | mcs = real_mcs; |
688 | } | 688 | } |
689 | 689 | ||
690 | if (aggr == 1 || ampdu == 1) | ||
691 | __set_bit(TXDONE_AMPDU, &txdesc.flags); | ||
692 | |||
690 | /* | 693 | /* |
691 | * Ralink has a retry mechanism using a global fallback | 694 | * Ralink has a retry mechanism using a global fallback |
692 | * table. We setup this fallback table to try the immediate | 695 | * table. We setup this fallback table to try the immediate |
@@ -1813,17 +1816,131 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, | |||
1813 | rt2800_register_read(rt2x00dev, CH_BUSY_STA_SEC, ®); | 1816 | rt2800_register_read(rt2x00dev, CH_BUSY_STA_SEC, ®); |
1814 | } | 1817 | } |
1815 | 1818 | ||
1819 | static int rt2800_get_gain_calibration_delta(struct rt2x00_dev *rt2x00dev) | ||
1820 | { | ||
1821 | u8 tssi_bounds[9]; | ||
1822 | u8 current_tssi; | ||
1823 | u16 eeprom; | ||
1824 | u8 step; | ||
1825 | int i; | ||
1826 | |||
1827 | /* | ||
1828 | * Read TSSI boundaries for temperature compensation from | ||
1829 | * the EEPROM. | ||
1830 | * | ||
1831 | * Array idx 0 1 2 3 4 5 6 7 8 | ||
1832 | * Matching Delta value -4 -3 -2 -1 0 +1 +2 +3 +4 | ||
1833 | * Example TSSI bounds 0xF0 0xD0 0xB5 0xA0 0x88 0x45 0x25 0x15 0x00 | ||
1834 | */ | ||
1835 | if (rt2x00dev->curr_band == IEEE80211_BAND_2GHZ) { | ||
1836 | rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG1, &eeprom); | ||
1837 | tssi_bounds[0] = rt2x00_get_field16(eeprom, | ||
1838 | EEPROM_TSSI_BOUND_BG1_MINUS4); | ||
1839 | tssi_bounds[1] = rt2x00_get_field16(eeprom, | ||
1840 | EEPROM_TSSI_BOUND_BG1_MINUS3); | ||
1841 | |||
1842 | rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG2, &eeprom); | ||
1843 | tssi_bounds[2] = rt2x00_get_field16(eeprom, | ||
1844 | EEPROM_TSSI_BOUND_BG2_MINUS2); | ||
1845 | tssi_bounds[3] = rt2x00_get_field16(eeprom, | ||
1846 | EEPROM_TSSI_BOUND_BG2_MINUS1); | ||
1847 | |||
1848 | rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG3, &eeprom); | ||
1849 | tssi_bounds[4] = rt2x00_get_field16(eeprom, | ||
1850 | EEPROM_TSSI_BOUND_BG3_REF); | ||
1851 | tssi_bounds[5] = rt2x00_get_field16(eeprom, | ||
1852 | EEPROM_TSSI_BOUND_BG3_PLUS1); | ||
1853 | |||
1854 | rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG4, &eeprom); | ||
1855 | tssi_bounds[6] = rt2x00_get_field16(eeprom, | ||
1856 | EEPROM_TSSI_BOUND_BG4_PLUS2); | ||
1857 | tssi_bounds[7] = rt2x00_get_field16(eeprom, | ||
1858 | EEPROM_TSSI_BOUND_BG4_PLUS3); | ||
1859 | |||
1860 | rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG5, &eeprom); | ||
1861 | tssi_bounds[8] = rt2x00_get_field16(eeprom, | ||
1862 | EEPROM_TSSI_BOUND_BG5_PLUS4); | ||
1863 | |||
1864 | step = rt2x00_get_field16(eeprom, | ||
1865 | EEPROM_TSSI_BOUND_BG5_AGC_STEP); | ||
1866 | } else { | ||
1867 | rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A1, &eeprom); | ||
1868 | tssi_bounds[0] = rt2x00_get_field16(eeprom, | ||
1869 | EEPROM_TSSI_BOUND_A1_MINUS4); | ||
1870 | tssi_bounds[1] = rt2x00_get_field16(eeprom, | ||
1871 | EEPROM_TSSI_BOUND_A1_MINUS3); | ||
1872 | |||
1873 | rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A2, &eeprom); | ||
1874 | tssi_bounds[2] = rt2x00_get_field16(eeprom, | ||
1875 | EEPROM_TSSI_BOUND_A2_MINUS2); | ||
1876 | tssi_bounds[3] = rt2x00_get_field16(eeprom, | ||
1877 | EEPROM_TSSI_BOUND_A2_MINUS1); | ||
1878 | |||
1879 | rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A3, &eeprom); | ||
1880 | tssi_bounds[4] = rt2x00_get_field16(eeprom, | ||
1881 | EEPROM_TSSI_BOUND_A3_REF); | ||
1882 | tssi_bounds[5] = rt2x00_get_field16(eeprom, | ||
1883 | EEPROM_TSSI_BOUND_A3_PLUS1); | ||
1884 | |||
1885 | rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A4, &eeprom); | ||
1886 | tssi_bounds[6] = rt2x00_get_field16(eeprom, | ||
1887 | EEPROM_TSSI_BOUND_A4_PLUS2); | ||
1888 | tssi_bounds[7] = rt2x00_get_field16(eeprom, | ||
1889 | EEPROM_TSSI_BOUND_A4_PLUS3); | ||
1890 | |||
1891 | rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A5, &eeprom); | ||
1892 | tssi_bounds[8] = rt2x00_get_field16(eeprom, | ||
1893 | EEPROM_TSSI_BOUND_A5_PLUS4); | ||
1894 | |||
1895 | step = rt2x00_get_field16(eeprom, | ||
1896 | EEPROM_TSSI_BOUND_A5_AGC_STEP); | ||
1897 | } | ||
1898 | |||
1899 | /* | ||
1900 | * Check if temperature compensation is supported. | ||
1901 | */ | ||
1902 | if (tssi_bounds[4] == 0xff) | ||
1903 | return 0; | ||
1904 | |||
1905 | /* | ||
1906 | * Read current TSSI (BBP 49). | ||
1907 | */ | ||
1908 | rt2800_bbp_read(rt2x00dev, 49, ¤t_tssi); | ||
1909 | |||
1910 | /* | ||
1911 | * Compare TSSI value (BBP49) with the compensation boundaries | ||
1912 | * from the EEPROM and increase or decrease tx power. | ||
1913 | */ | ||
1914 | for (i = 0; i <= 3; i++) { | ||
1915 | if (current_tssi > tssi_bounds[i]) | ||
1916 | break; | ||
1917 | } | ||
1918 | |||
1919 | if (i == 4) { | ||
1920 | for (i = 8; i >= 5; i--) { | ||
1921 | if (current_tssi < tssi_bounds[i]) | ||
1922 | break; | ||
1923 | } | ||
1924 | } | ||
1925 | |||
1926 | return (i - 4) * step; | ||
1927 | } | ||
1928 | |||
1816 | static int rt2800_get_txpower_bw_comp(struct rt2x00_dev *rt2x00dev, | 1929 | static int rt2800_get_txpower_bw_comp(struct rt2x00_dev *rt2x00dev, |
1817 | enum ieee80211_band band) | 1930 | enum ieee80211_band band) |
1818 | { | 1931 | { |
1819 | u16 eeprom; | 1932 | u16 eeprom; |
1820 | u8 comp_en; | 1933 | u8 comp_en; |
1821 | u8 comp_type; | 1934 | u8 comp_type; |
1822 | int comp_value; | 1935 | int comp_value = 0; |
1823 | 1936 | ||
1824 | rt2x00_eeprom_read(rt2x00dev, EEPROM_TXPOWER_DELTA, &eeprom); | 1937 | rt2x00_eeprom_read(rt2x00dev, EEPROM_TXPOWER_DELTA, &eeprom); |
1825 | 1938 | ||
1826 | if (eeprom == 0xffff) | 1939 | /* |
1940 | * HT40 compensation not required. | ||
1941 | */ | ||
1942 | if (eeprom == 0xffff || | ||
1943 | !test_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags)) | ||
1827 | return 0; | 1944 | return 0; |
1828 | 1945 | ||
1829 | if (band == IEEE80211_BAND_2GHZ) { | 1946 | if (band == IEEE80211_BAND_2GHZ) { |
@@ -1853,11 +1970,9 @@ static int rt2800_get_txpower_bw_comp(struct rt2x00_dev *rt2x00dev, | |||
1853 | return comp_value; | 1970 | return comp_value; |
1854 | } | 1971 | } |
1855 | 1972 | ||
1856 | static u8 rt2800_compesate_txpower(struct rt2x00_dev *rt2x00dev, | 1973 | static u8 rt2800_compensate_txpower(struct rt2x00_dev *rt2x00dev, int is_rate_b, |
1857 | int is_rate_b, | 1974 | enum ieee80211_band band, int power_level, |
1858 | enum ieee80211_band band, | 1975 | u8 txpower, int delta) |
1859 | int power_level, | ||
1860 | u8 txpower) | ||
1861 | { | 1976 | { |
1862 | u32 reg; | 1977 | u32 reg; |
1863 | u16 eeprom; | 1978 | u16 eeprom; |
@@ -1865,14 +1980,10 @@ static u8 rt2800_compesate_txpower(struct rt2x00_dev *rt2x00dev, | |||
1865 | u8 eirp_txpower; | 1980 | u8 eirp_txpower; |
1866 | u8 eirp_txpower_criterion; | 1981 | u8 eirp_txpower_criterion; |
1867 | u8 reg_limit; | 1982 | u8 reg_limit; |
1868 | int bw_comp = 0; | ||
1869 | 1983 | ||
1870 | if (!((band == IEEE80211_BAND_5GHZ) && is_rate_b)) | 1984 | if (!((band == IEEE80211_BAND_5GHZ) && is_rate_b)) |
1871 | return txpower; | 1985 | return txpower; |
1872 | 1986 | ||
1873 | if (test_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags)) | ||
1874 | bw_comp = rt2800_get_txpower_bw_comp(rt2x00dev, band); | ||
1875 | |||
1876 | if (test_bit(CONFIG_SUPPORT_POWER_LIMIT, &rt2x00dev->flags)) { | 1987 | if (test_bit(CONFIG_SUPPORT_POWER_LIMIT, &rt2x00dev->flags)) { |
1877 | /* | 1988 | /* |
1878 | * Check if eirp txpower exceed txpower_limit. | 1989 | * Check if eirp txpower exceed txpower_limit. |
@@ -1895,18 +2006,19 @@ static u8 rt2800_compesate_txpower(struct rt2x00_dev *rt2x00dev, | |||
1895 | EEPROM_EIRP_MAX_TX_POWER_5GHZ); | 2006 | EEPROM_EIRP_MAX_TX_POWER_5GHZ); |
1896 | 2007 | ||
1897 | eirp_txpower = eirp_txpower_criterion + (txpower - criterion) + | 2008 | eirp_txpower = eirp_txpower_criterion + (txpower - criterion) + |
1898 | (is_rate_b ? 4 : 0) + bw_comp; | 2009 | (is_rate_b ? 4 : 0) + delta; |
1899 | 2010 | ||
1900 | reg_limit = (eirp_txpower > power_level) ? | 2011 | reg_limit = (eirp_txpower > power_level) ? |
1901 | (eirp_txpower - power_level) : 0; | 2012 | (eirp_txpower - power_level) : 0; |
1902 | } else | 2013 | } else |
1903 | reg_limit = 0; | 2014 | reg_limit = 0; |
1904 | 2015 | ||
1905 | return txpower + bw_comp - reg_limit; | 2016 | return txpower + delta - reg_limit; |
1906 | } | 2017 | } |
1907 | 2018 | ||
1908 | static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev, | 2019 | static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev, |
1909 | struct ieee80211_conf *conf) | 2020 | enum ieee80211_band band, |
2021 | int power_level) | ||
1910 | { | 2022 | { |
1911 | u8 txpower; | 2023 | u8 txpower; |
1912 | u16 eeprom; | 2024 | u16 eeprom; |
@@ -1914,8 +2026,17 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev, | |||
1914 | u32 reg; | 2026 | u32 reg; |
1915 | u8 r1; | 2027 | u8 r1; |
1916 | u32 offset; | 2028 | u32 offset; |
1917 | enum ieee80211_band band = conf->channel->band; | 2029 | int delta; |
1918 | int power_level = conf->power_level; | 2030 | |
2031 | /* | ||
2032 | * Calculate HT40 compensation delta | ||
2033 | */ | ||
2034 | delta = rt2800_get_txpower_bw_comp(rt2x00dev, band); | ||
2035 | |||
2036 | /* | ||
2037 | * calculate temperature compensation delta | ||
2038 | */ | ||
2039 | delta += rt2800_get_gain_calibration_delta(rt2x00dev); | ||
1919 | 2040 | ||
1920 | /* | 2041 | /* |
1921 | * set to normal bbp tx power control mode: +/- 0dBm | 2042 | * set to normal bbp tx power control mode: +/- 0dBm |
@@ -1944,8 +2065,8 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev, | |||
1944 | */ | 2065 | */ |
1945 | txpower = rt2x00_get_field16(eeprom, | 2066 | txpower = rt2x00_get_field16(eeprom, |
1946 | EEPROM_TXPOWER_BYRATE_RATE0); | 2067 | EEPROM_TXPOWER_BYRATE_RATE0); |
1947 | txpower = rt2800_compesate_txpower(rt2x00dev, is_rate_b, band, | 2068 | txpower = rt2800_compensate_txpower(rt2x00dev, is_rate_b, band, |
1948 | power_level, txpower); | 2069 | power_level, txpower, delta); |
1949 | rt2x00_set_field32(®, TX_PWR_CFG_RATE0, txpower); | 2070 | rt2x00_set_field32(®, TX_PWR_CFG_RATE0, txpower); |
1950 | 2071 | ||
1951 | /* | 2072 | /* |
@@ -1955,8 +2076,8 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev, | |||
1955 | */ | 2076 | */ |
1956 | txpower = rt2x00_get_field16(eeprom, | 2077 | txpower = rt2x00_get_field16(eeprom, |
1957 | EEPROM_TXPOWER_BYRATE_RATE1); | 2078 | EEPROM_TXPOWER_BYRATE_RATE1); |
1958 | txpower = rt2800_compesate_txpower(rt2x00dev, is_rate_b, band, | 2079 | txpower = rt2800_compensate_txpower(rt2x00dev, is_rate_b, band, |
1959 | power_level, txpower); | 2080 | power_level, txpower, delta); |
1960 | rt2x00_set_field32(®, TX_PWR_CFG_RATE1, txpower); | 2081 | rt2x00_set_field32(®, TX_PWR_CFG_RATE1, txpower); |
1961 | 2082 | ||
1962 | /* | 2083 | /* |
@@ -1966,8 +2087,8 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev, | |||
1966 | */ | 2087 | */ |
1967 | txpower = rt2x00_get_field16(eeprom, | 2088 | txpower = rt2x00_get_field16(eeprom, |
1968 | EEPROM_TXPOWER_BYRATE_RATE2); | 2089 | EEPROM_TXPOWER_BYRATE_RATE2); |
1969 | txpower = rt2800_compesate_txpower(rt2x00dev, is_rate_b, band, | 2090 | txpower = rt2800_compensate_txpower(rt2x00dev, is_rate_b, band, |
1970 | power_level, txpower); | 2091 | power_level, txpower, delta); |
1971 | rt2x00_set_field32(®, TX_PWR_CFG_RATE2, txpower); | 2092 | rt2x00_set_field32(®, TX_PWR_CFG_RATE2, txpower); |
1972 | 2093 | ||
1973 | /* | 2094 | /* |
@@ -1977,8 +2098,8 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev, | |||
1977 | */ | 2098 | */ |
1978 | txpower = rt2x00_get_field16(eeprom, | 2099 | txpower = rt2x00_get_field16(eeprom, |
1979 | EEPROM_TXPOWER_BYRATE_RATE3); | 2100 | EEPROM_TXPOWER_BYRATE_RATE3); |
1980 | txpower = rt2800_compesate_txpower(rt2x00dev, is_rate_b, band, | 2101 | txpower = rt2800_compensate_txpower(rt2x00dev, is_rate_b, band, |
1981 | power_level, txpower); | 2102 | power_level, txpower, delta); |
1982 | rt2x00_set_field32(®, TX_PWR_CFG_RATE3, txpower); | 2103 | rt2x00_set_field32(®, TX_PWR_CFG_RATE3, txpower); |
1983 | 2104 | ||
1984 | /* read the next four txpower values */ | 2105 | /* read the next four txpower values */ |
@@ -1993,8 +2114,8 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev, | |||
1993 | */ | 2114 | */ |
1994 | txpower = rt2x00_get_field16(eeprom, | 2115 | txpower = rt2x00_get_field16(eeprom, |
1995 | EEPROM_TXPOWER_BYRATE_RATE0); | 2116 | EEPROM_TXPOWER_BYRATE_RATE0); |
1996 | txpower = rt2800_compesate_txpower(rt2x00dev, is_rate_b, band, | 2117 | txpower = rt2800_compensate_txpower(rt2x00dev, is_rate_b, band, |
1997 | power_level, txpower); | 2118 | power_level, txpower, delta); |
1998 | rt2x00_set_field32(®, TX_PWR_CFG_RATE4, txpower); | 2119 | rt2x00_set_field32(®, TX_PWR_CFG_RATE4, txpower); |
1999 | 2120 | ||
2000 | /* | 2121 | /* |
@@ -2004,8 +2125,8 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev, | |||
2004 | */ | 2125 | */ |
2005 | txpower = rt2x00_get_field16(eeprom, | 2126 | txpower = rt2x00_get_field16(eeprom, |
2006 | EEPROM_TXPOWER_BYRATE_RATE1); | 2127 | EEPROM_TXPOWER_BYRATE_RATE1); |
2007 | txpower = rt2800_compesate_txpower(rt2x00dev, is_rate_b, band, | 2128 | txpower = rt2800_compensate_txpower(rt2x00dev, is_rate_b, band, |
2008 | power_level, txpower); | 2129 | power_level, txpower, delta); |
2009 | rt2x00_set_field32(®, TX_PWR_CFG_RATE5, txpower); | 2130 | rt2x00_set_field32(®, TX_PWR_CFG_RATE5, txpower); |
2010 | 2131 | ||
2011 | /* | 2132 | /* |
@@ -2015,8 +2136,8 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev, | |||
2015 | */ | 2136 | */ |
2016 | txpower = rt2x00_get_field16(eeprom, | 2137 | txpower = rt2x00_get_field16(eeprom, |
2017 | EEPROM_TXPOWER_BYRATE_RATE2); | 2138 | EEPROM_TXPOWER_BYRATE_RATE2); |
2018 | txpower = rt2800_compesate_txpower(rt2x00dev, is_rate_b, band, | 2139 | txpower = rt2800_compensate_txpower(rt2x00dev, is_rate_b, band, |
2019 | power_level, txpower); | 2140 | power_level, txpower, delta); |
2020 | rt2x00_set_field32(®, TX_PWR_CFG_RATE6, txpower); | 2141 | rt2x00_set_field32(®, TX_PWR_CFG_RATE6, txpower); |
2021 | 2142 | ||
2022 | /* | 2143 | /* |
@@ -2026,8 +2147,8 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev, | |||
2026 | */ | 2147 | */ |
2027 | txpower = rt2x00_get_field16(eeprom, | 2148 | txpower = rt2x00_get_field16(eeprom, |
2028 | EEPROM_TXPOWER_BYRATE_RATE3); | 2149 | EEPROM_TXPOWER_BYRATE_RATE3); |
2029 | txpower = rt2800_compesate_txpower(rt2x00dev, is_rate_b, band, | 2150 | txpower = rt2800_compensate_txpower(rt2x00dev, is_rate_b, band, |
2030 | power_level, txpower); | 2151 | power_level, txpower, delta); |
2031 | rt2x00_set_field32(®, TX_PWR_CFG_RATE7, txpower); | 2152 | rt2x00_set_field32(®, TX_PWR_CFG_RATE7, txpower); |
2032 | 2153 | ||
2033 | rt2800_register_write(rt2x00dev, offset, reg); | 2154 | rt2800_register_write(rt2x00dev, offset, reg); |
@@ -2037,6 +2158,13 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev, | |||
2037 | } | 2158 | } |
2038 | } | 2159 | } |
2039 | 2160 | ||
2161 | void rt2800_gain_calibration(struct rt2x00_dev *rt2x00dev) | ||
2162 | { | ||
2163 | rt2800_config_txpower(rt2x00dev, rt2x00dev->curr_band, | ||
2164 | rt2x00dev->tx_power); | ||
2165 | } | ||
2166 | EXPORT_SYMBOL_GPL(rt2800_gain_calibration); | ||
2167 | |||
2040 | static void rt2800_config_retry_limit(struct rt2x00_dev *rt2x00dev, | 2168 | static void rt2800_config_retry_limit(struct rt2x00_dev *rt2x00dev, |
2041 | struct rt2x00lib_conf *libconf) | 2169 | struct rt2x00lib_conf *libconf) |
2042 | { | 2170 | { |
@@ -2090,10 +2218,12 @@ void rt2800_config(struct rt2x00_dev *rt2x00dev, | |||
2090 | if (flags & IEEE80211_CONF_CHANGE_CHANNEL) { | 2218 | if (flags & IEEE80211_CONF_CHANGE_CHANNEL) { |
2091 | rt2800_config_channel(rt2x00dev, libconf->conf, | 2219 | rt2800_config_channel(rt2x00dev, libconf->conf, |
2092 | &libconf->rf, &libconf->channel); | 2220 | &libconf->rf, &libconf->channel); |
2093 | rt2800_config_txpower(rt2x00dev, libconf->conf); | 2221 | rt2800_config_txpower(rt2x00dev, libconf->conf->channel->band, |
2222 | libconf->conf->power_level); | ||
2094 | } | 2223 | } |
2095 | if (flags & IEEE80211_CONF_CHANGE_POWER) | 2224 | if (flags & IEEE80211_CONF_CHANGE_POWER) |
2096 | rt2800_config_txpower(rt2x00dev, libconf->conf); | 2225 | rt2800_config_txpower(rt2x00dev, libconf->conf->channel->band, |
2226 | libconf->conf->power_level); | ||
2097 | if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS) | 2227 | if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS) |
2098 | rt2800_config_retry_limit(rt2x00dev, libconf); | 2228 | rt2800_config_retry_limit(rt2x00dev, libconf); |
2099 | if (flags & IEEE80211_CONF_CHANGE_PS) | 2229 | if (flags & IEEE80211_CONF_CHANGE_PS) |
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.h b/drivers/net/wireless/rt2x00/rt2800lib.h index 0c92d86a36f4..f2d15941c71a 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.h +++ b/drivers/net/wireless/rt2x00/rt2800lib.h | |||
@@ -181,6 +181,7 @@ void rt2800_link_stats(struct rt2x00_dev *rt2x00dev, struct link_qual *qual); | |||
181 | void rt2800_reset_tuner(struct rt2x00_dev *rt2x00dev, struct link_qual *qual); | 181 | void rt2800_reset_tuner(struct rt2x00_dev *rt2x00dev, struct link_qual *qual); |
182 | void rt2800_link_tuner(struct rt2x00_dev *rt2x00dev, struct link_qual *qual, | 182 | void rt2800_link_tuner(struct rt2x00_dev *rt2x00dev, struct link_qual *qual, |
183 | const u32 count); | 183 | const u32 count); |
184 | void rt2800_gain_calibration(struct rt2x00_dev *rt2x00dev); | ||
184 | 185 | ||
185 | int rt2800_enable_radio(struct rt2x00_dev *rt2x00dev); | 186 | int rt2800_enable_radio(struct rt2x00_dev *rt2x00dev); |
186 | void rt2800_disable_radio(struct rt2x00_dev *rt2x00dev); | 187 | void rt2800_disable_radio(struct rt2x00_dev *rt2x00dev); |
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 808073aa9dcc..adc3534254df 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c | |||
@@ -717,12 +717,13 @@ static void rt2800pci_wakeup(struct rt2x00_dev *rt2x00dev) | |||
717 | rt2800_config(rt2x00dev, &libconf, IEEE80211_CONF_CHANGE_PS); | 717 | rt2800_config(rt2x00dev, &libconf, IEEE80211_CONF_CHANGE_PS); |
718 | } | 718 | } |
719 | 719 | ||
720 | static void rt2800pci_txdone(struct rt2x00_dev *rt2x00dev) | 720 | static bool rt2800pci_txdone(struct rt2x00_dev *rt2x00dev) |
721 | { | 721 | { |
722 | struct data_queue *queue; | 722 | struct data_queue *queue; |
723 | struct queue_entry *entry; | 723 | struct queue_entry *entry; |
724 | u32 status; | 724 | u32 status; |
725 | u8 qid; | 725 | u8 qid; |
726 | int max_tx_done = 16; | ||
726 | 727 | ||
727 | while (kfifo_get(&rt2x00dev->txstatus_fifo, &status)) { | 728 | while (kfifo_get(&rt2x00dev->txstatus_fifo, &status)) { |
728 | qid = rt2x00_get_field32(status, TX_STA_FIFO_PID_QUEUE); | 729 | qid = rt2x00_get_field32(status, TX_STA_FIFO_PID_QUEUE); |
@@ -759,7 +760,12 @@ static void rt2800pci_txdone(struct rt2x00_dev *rt2x00dev) | |||
759 | 760 | ||
760 | entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); | 761 | entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); |
761 | rt2800_txdone_entry(entry, status); | 762 | rt2800_txdone_entry(entry, status); |
763 | |||
764 | if (--max_tx_done == 0) | ||
765 | break; | ||
762 | } | 766 | } |
767 | |||
768 | return !max_tx_done; | ||
763 | } | 769 | } |
764 | 770 | ||
765 | static void rt2800pci_enable_interrupt(struct rt2x00_dev *rt2x00dev, | 771 | static void rt2800pci_enable_interrupt(struct rt2x00_dev *rt2x00dev, |
@@ -780,7 +786,9 @@ static void rt2800pci_enable_interrupt(struct rt2x00_dev *rt2x00dev, | |||
780 | 786 | ||
781 | static void rt2800pci_txstatus_tasklet(unsigned long data) | 787 | static void rt2800pci_txstatus_tasklet(unsigned long data) |
782 | { | 788 | { |
783 | rt2800pci_txdone((struct rt2x00_dev *)data); | 789 | struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; |
790 | if (rt2800pci_txdone(rt2x00dev)) | ||
791 | tasklet_schedule(&rt2x00dev->txstatus_tasklet); | ||
784 | 792 | ||
785 | /* | 793 | /* |
786 | * No need to enable the tx status interrupt here as we always | 794 | * No need to enable the tx status interrupt here as we always |
@@ -806,8 +814,10 @@ static void rt2800pci_tbtt_tasklet(unsigned long data) | |||
806 | static void rt2800pci_rxdone_tasklet(unsigned long data) | 814 | static void rt2800pci_rxdone_tasklet(unsigned long data) |
807 | { | 815 | { |
808 | struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; | 816 | struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; |
809 | rt2x00pci_rxdone(rt2x00dev); | 817 | if (rt2x00pci_rxdone(rt2x00dev)) |
810 | rt2800pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_RX_DONE); | 818 | tasklet_schedule(&rt2x00dev->rxdone_tasklet); |
819 | else | ||
820 | rt2800pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_RX_DONE); | ||
811 | } | 821 | } |
812 | 822 | ||
813 | static void rt2800pci_autowake_tasklet(unsigned long data) | 823 | static void rt2800pci_autowake_tasklet(unsigned long data) |
@@ -1043,6 +1053,7 @@ static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = { | |||
1043 | .link_stats = rt2800_link_stats, | 1053 | .link_stats = rt2800_link_stats, |
1044 | .reset_tuner = rt2800_reset_tuner, | 1054 | .reset_tuner = rt2800_reset_tuner, |
1045 | .link_tuner = rt2800_link_tuner, | 1055 | .link_tuner = rt2800_link_tuner, |
1056 | .gain_calibration = rt2800_gain_calibration, | ||
1046 | .start_queue = rt2800pci_start_queue, | 1057 | .start_queue = rt2800pci_start_queue, |
1047 | .kick_queue = rt2800pci_kick_queue, | 1058 | .kick_queue = rt2800pci_kick_queue, |
1048 | .stop_queue = rt2800pci_stop_queue, | 1059 | .stop_queue = rt2800pci_stop_queue, |
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 37509d019910..6ba31a0e8f78 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c | |||
@@ -564,7 +564,6 @@ static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev) | |||
564 | if (!modparam_nohwcrypt) | 564 | if (!modparam_nohwcrypt) |
565 | __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags); | 565 | __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags); |
566 | __set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags); | 566 | __set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags); |
567 | __set_bit(DRIVER_SUPPORT_WATCHDOG, &rt2x00dev->flags); | ||
568 | __set_bit(DRIVER_REQUIRE_HT_TX_DESC, &rt2x00dev->flags); | 567 | __set_bit(DRIVER_REQUIRE_HT_TX_DESC, &rt2x00dev->flags); |
569 | 568 | ||
570 | /* | 569 | /* |
@@ -630,6 +629,7 @@ static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = { | |||
630 | .link_stats = rt2800_link_stats, | 629 | .link_stats = rt2800_link_stats, |
631 | .reset_tuner = rt2800_reset_tuner, | 630 | .reset_tuner = rt2800_reset_tuner, |
632 | .link_tuner = rt2800_link_tuner, | 631 | .link_tuner = rt2800_link_tuner, |
632 | .gain_calibration = rt2800_gain_calibration, | ||
633 | .watchdog = rt2800usb_watchdog, | 633 | .watchdog = rt2800usb_watchdog, |
634 | .start_queue = rt2800usb_start_queue, | 634 | .start_queue = rt2800usb_start_queue, |
635 | .kick_queue = rt2x00usb_kick_queue, | 635 | .kick_queue = rt2x00usb_kick_queue, |
@@ -882,6 +882,7 @@ static struct usb_device_id rt2800usb_device_table[] = { | |||
882 | { USB_DEVICE(0x5a57, 0x5257), USB_DEVICE_DATA(&rt2800usb_ops) }, | 882 | { USB_DEVICE(0x5a57, 0x5257), USB_DEVICE_DATA(&rt2800usb_ops) }, |
883 | /* Zyxel */ | 883 | /* Zyxel */ |
884 | { USB_DEVICE(0x0586, 0x3416), USB_DEVICE_DATA(&rt2800usb_ops) }, | 884 | { USB_DEVICE(0x0586, 0x3416), USB_DEVICE_DATA(&rt2800usb_ops) }, |
885 | { USB_DEVICE(0x0586, 0x3418), USB_DEVICE_DATA(&rt2800usb_ops) }, | ||
885 | #ifdef CONFIG_RT2800USB_RT33XX | 886 | #ifdef CONFIG_RT2800USB_RT33XX |
886 | /* Ralink */ | 887 | /* Ralink */ |
887 | { USB_DEVICE(0x148f, 0x3370), USB_DEVICE_DATA(&rt2800usb_ops) }, | 888 | { USB_DEVICE(0x148f, 0x3370), USB_DEVICE_DATA(&rt2800usb_ops) }, |
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 7f10239f56a8..a2bd5feb9d5c 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h | |||
@@ -348,6 +348,11 @@ struct link { | |||
348 | * to bring the device/driver back into the desired state. | 348 | * to bring the device/driver back into the desired state. |
349 | */ | 349 | */ |
350 | struct delayed_work watchdog_work; | 350 | struct delayed_work watchdog_work; |
351 | |||
352 | /* | ||
353 | * Work structure for scheduling periodic AGC adjustments. | ||
354 | */ | ||
355 | struct delayed_work agc_work; | ||
351 | }; | 356 | }; |
352 | 357 | ||
353 | enum rt2x00_delayed_flags { | 358 | enum rt2x00_delayed_flags { |
@@ -556,6 +561,7 @@ struct rt2x00lib_ops { | |||
556 | struct link_qual *qual); | 561 | struct link_qual *qual); |
557 | void (*link_tuner) (struct rt2x00_dev *rt2x00dev, | 562 | void (*link_tuner) (struct rt2x00_dev *rt2x00dev, |
558 | struct link_qual *qual, const u32 count); | 563 | struct link_qual *qual, const u32 count); |
564 | void (*gain_calibration) (struct rt2x00_dev *rt2x00dev); | ||
559 | 565 | ||
560 | /* | 566 | /* |
561 | * Data queue handlers. | 567 | * Data queue handlers. |
@@ -674,7 +680,6 @@ enum rt2x00_flags { | |||
674 | DRIVER_SUPPORT_CONTROL_FILTER_PSPOLL, | 680 | DRIVER_SUPPORT_CONTROL_FILTER_PSPOLL, |
675 | DRIVER_SUPPORT_PRE_TBTT_INTERRUPT, | 681 | DRIVER_SUPPORT_PRE_TBTT_INTERRUPT, |
676 | DRIVER_SUPPORT_LINK_TUNING, | 682 | DRIVER_SUPPORT_LINK_TUNING, |
677 | DRIVER_SUPPORT_WATCHDOG, | ||
678 | 683 | ||
679 | /* | 684 | /* |
680 | * Driver configuration | 685 | * Driver configuration |
diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c index c92db3264741..66166ef037f5 100644 --- a/drivers/net/wireless/rt2x00/rt2x00debug.c +++ b/drivers/net/wireless/rt2x00/rt2x00debug.c | |||
@@ -568,7 +568,6 @@ static struct dentry *rt2x00debug_create_file_driver(const char *name, | |||
568 | blob->data = data; | 568 | blob->data = data; |
569 | data += sprintf(data, "driver:\t%s\n", intf->rt2x00dev->ops->name); | 569 | data += sprintf(data, "driver:\t%s\n", intf->rt2x00dev->ops->name); |
570 | data += sprintf(data, "version:\t%s\n", DRV_VERSION); | 570 | data += sprintf(data, "version:\t%s\n", DRV_VERSION); |
571 | data += sprintf(data, "compiled:\t%s %s\n", __DATE__, __TIME__); | ||
572 | blob->size = strlen(blob->data); | 571 | blob->size = strlen(blob->data); |
573 | 572 | ||
574 | return debugfs_create_blob(name, S_IRUSR, intf->driver_folder, blob); | 573 | return debugfs_create_blob(name, S_IRUSR, intf->driver_folder, blob); |
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 84eb6ad36377..9bffe8438d1f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <linux/kernel.h> | 27 | #include <linux/kernel.h> |
28 | #include <linux/module.h> | 28 | #include <linux/module.h> |
29 | #include <linux/slab.h> | 29 | #include <linux/slab.h> |
30 | #include <linux/log2.h> | ||
30 | 31 | ||
31 | #include "rt2x00.h" | 32 | #include "rt2x00.h" |
32 | #include "rt2x00lib.h" | 33 | #include "rt2x00lib.h" |
@@ -70,6 +71,7 @@ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev) | |||
70 | */ | 71 | */ |
71 | rt2x00queue_start_queues(rt2x00dev); | 72 | rt2x00queue_start_queues(rt2x00dev); |
72 | rt2x00link_start_tuner(rt2x00dev); | 73 | rt2x00link_start_tuner(rt2x00dev); |
74 | rt2x00link_start_agc(rt2x00dev); | ||
73 | 75 | ||
74 | /* | 76 | /* |
75 | * Start watchdog monitoring. | 77 | * Start watchdog monitoring. |
@@ -92,6 +94,7 @@ void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev) | |||
92 | /* | 94 | /* |
93 | * Stop all queues | 95 | * Stop all queues |
94 | */ | 96 | */ |
97 | rt2x00link_stop_agc(rt2x00dev); | ||
95 | rt2x00link_stop_tuner(rt2x00dev); | 98 | rt2x00link_stop_tuner(rt2x00dev); |
96 | rt2x00queue_stop_queues(rt2x00dev); | 99 | rt2x00queue_stop_queues(rt2x00dev); |
97 | rt2x00queue_flush_queues(rt2x00dev, true); | 100 | rt2x00queue_flush_queues(rt2x00dev, true); |
@@ -350,10 +353,14 @@ void rt2x00lib_txdone(struct queue_entry *entry, | |||
350 | * which would allow the rc algorithm to better decide on | 353 | * which would allow the rc algorithm to better decide on |
351 | * which rates are suitable. | 354 | * which rates are suitable. |
352 | */ | 355 | */ |
353 | if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) { | 356 | if (test_bit(TXDONE_AMPDU, &txdesc->flags) || |
357 | tx_info->flags & IEEE80211_TX_CTL_AMPDU) { | ||
354 | tx_info->flags |= IEEE80211_TX_STAT_AMPDU; | 358 | tx_info->flags |= IEEE80211_TX_STAT_AMPDU; |
355 | tx_info->status.ampdu_len = 1; | 359 | tx_info->status.ampdu_len = 1; |
356 | tx_info->status.ampdu_ack_len = success ? 1 : 0; | 360 | tx_info->status.ampdu_ack_len = success ? 1 : 0; |
361 | |||
362 | if (!success) | ||
363 | tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; | ||
357 | } | 364 | } |
358 | 365 | ||
359 | if (rate_flags & IEEE80211_TX_RC_USE_RTS_CTS) { | 366 | if (rate_flags & IEEE80211_TX_RC_USE_RTS_CTS) { |
@@ -511,8 +518,6 @@ void rt2x00lib_rxdone(struct queue_entry *entry) | |||
511 | (rxdesc.size > header_length) && | 518 | (rxdesc.size > header_length) && |
512 | (rxdesc.dev_flags & RXDONE_L2PAD)) | 519 | (rxdesc.dev_flags & RXDONE_L2PAD)) |
513 | rt2x00queue_remove_l2pad(entry->skb, header_length); | 520 | rt2x00queue_remove_l2pad(entry->skb, header_length); |
514 | else | ||
515 | rt2x00queue_align_payload(entry->skb, header_length); | ||
516 | 521 | ||
517 | /* Trim buffer to correct size */ | 522 | /* Trim buffer to correct size */ |
518 | skb_trim(entry->skb, rxdesc.size); | 523 | skb_trim(entry->skb, rxdesc.size); |
@@ -811,13 +816,18 @@ static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev) | |||
811 | */ | 816 | */ |
812 | if (test_bit(DRIVER_REQUIRE_TXSTATUS_FIFO, &rt2x00dev->flags)) { | 817 | if (test_bit(DRIVER_REQUIRE_TXSTATUS_FIFO, &rt2x00dev->flags)) { |
813 | /* | 818 | /* |
814 | * Allocate txstatus fifo and tasklet, we use a size of 512 | 819 | * Allocate the txstatus fifo. In the worst case the tx |
815 | * for the kfifo which is big enough to store 512/4=128 tx | 820 | * status fifo has to hold the tx status of all entries |
816 | * status reports. In the worst case (tx status for all tx | 821 | * in all tx queues. Hence, calculate the kfifo size as |
817 | * queues gets reported before we've got a chance to handle | 822 | * tx_queues * entry_num and round up to the nearest |
818 | * them) 24*4=384 tx status reports need to be cached. | 823 | * power of 2. |
819 | */ | 824 | */ |
820 | status = kfifo_alloc(&rt2x00dev->txstatus_fifo, 512, | 825 | int kfifo_size = |
826 | roundup_pow_of_two(rt2x00dev->ops->tx_queues * | ||
827 | rt2x00dev->ops->tx->entry_num * | ||
828 | sizeof(u32)); | ||
829 | |||
830 | status = kfifo_alloc(&rt2x00dev->txstatus_fifo, kfifo_size, | ||
821 | GFP_KERNEL); | 831 | GFP_KERNEL); |
822 | if (status) | 832 | if (status) |
823 | return status; | 833 | return status; |
diff --git a/drivers/net/wireless/rt2x00/rt2x00ht.c b/drivers/net/wireless/rt2x00/rt2x00ht.c index ae1219dffaae..e8c0c3e92c2f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00ht.c +++ b/drivers/net/wireless/rt2x00/rt2x00ht.c | |||
@@ -43,8 +43,11 @@ void rt2x00ht_create_tx_descriptor(struct queue_entry *entry, | |||
43 | 43 | ||
44 | txdesc->u.ht.ba_size = 7; /* FIXME: What value is needed? */ | 44 | txdesc->u.ht.ba_size = 7; /* FIXME: What value is needed? */ |
45 | 45 | ||
46 | txdesc->u.ht.stbc = | 46 | /* |
47 | (tx_info->flags & IEEE80211_TX_CTL_STBC) >> IEEE80211_TX_CTL_STBC_SHIFT; | 47 | * Only one STBC stream is supported for now. |
48 | */ | ||
49 | if (tx_info->flags & IEEE80211_TX_CTL_STBC) | ||
50 | txdesc->u.ht.stbc = 1; | ||
48 | 51 | ||
49 | /* | 52 | /* |
50 | * If IEEE80211_TX_RC_MCS is set txrate->idx just contains the | 53 | * If IEEE80211_TX_RC_MCS is set txrate->idx just contains the |
diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index 2d94cbaf5f4a..88f2f9275528 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h | |||
@@ -32,6 +32,7 @@ | |||
32 | */ | 32 | */ |
33 | #define WATCHDOG_INTERVAL round_jiffies_relative(HZ) | 33 | #define WATCHDOG_INTERVAL round_jiffies_relative(HZ) |
34 | #define LINK_TUNE_INTERVAL round_jiffies_relative(HZ) | 34 | #define LINK_TUNE_INTERVAL round_jiffies_relative(HZ) |
35 | #define AGC_INTERVAL round_jiffies_relative(4 * HZ) | ||
35 | 36 | ||
36 | /* | 37 | /* |
37 | * rt2x00_rate: Per rate device information | 38 | * rt2x00_rate: Per rate device information |
@@ -119,16 +120,6 @@ void rt2x00queue_free_skb(struct queue_entry *entry); | |||
119 | void rt2x00queue_align_frame(struct sk_buff *skb); | 120 | void rt2x00queue_align_frame(struct sk_buff *skb); |
120 | 121 | ||
121 | /** | 122 | /** |
122 | * rt2x00queue_align_payload - Align 802.11 payload to 4-byte boundary | ||
123 | * @skb: The skb to align | ||
124 | * @header_length: Length of 802.11 header | ||
125 | * | ||
126 | * Align the 802.11 payload to a 4-byte boundary, this could | ||
127 | * mean the header is not aligned properly though. | ||
128 | */ | ||
129 | void rt2x00queue_align_payload(struct sk_buff *skb, unsigned int header_length); | ||
130 | |||
131 | /** | ||
132 | * rt2x00queue_insert_l2pad - Align 802.11 header & payload to 4-byte boundary | 123 | * rt2x00queue_insert_l2pad - Align 802.11 header & payload to 4-byte boundary |
133 | * @skb: The skb to align | 124 | * @skb: The skb to align |
134 | * @header_length: Length of 802.11 header | 125 | * @header_length: Length of 802.11 header |
@@ -281,6 +272,18 @@ void rt2x00link_start_watchdog(struct rt2x00_dev *rt2x00dev); | |||
281 | void rt2x00link_stop_watchdog(struct rt2x00_dev *rt2x00dev); | 272 | void rt2x00link_stop_watchdog(struct rt2x00_dev *rt2x00dev); |
282 | 273 | ||
283 | /** | 274 | /** |
275 | * rt2x00link_start_agc - Start periodic gain calibration | ||
276 | * @rt2x00dev: Pointer to &struct rt2x00_dev. | ||
277 | */ | ||
278 | void rt2x00link_start_agc(struct rt2x00_dev *rt2x00dev); | ||
279 | |||
280 | /** | ||
281 | * rt2x00link_stop_agc - Stop periodic gain calibration | ||
282 | * @rt2x00dev: Pointer to &struct rt2x00_dev. | ||
283 | */ | ||
284 | void rt2x00link_stop_agc(struct rt2x00_dev *rt2x00dev); | ||
285 | |||
286 | /** | ||
284 | * rt2x00link_register - Initialize link tuning & watchdog functionality | 287 | * rt2x00link_register - Initialize link tuning & watchdog functionality |
285 | * @rt2x00dev: Pointer to &struct rt2x00_dev. | 288 | * @rt2x00dev: Pointer to &struct rt2x00_dev. |
286 | * | 289 | * |
diff --git a/drivers/net/wireless/rt2x00/rt2x00link.c b/drivers/net/wireless/rt2x00/rt2x00link.c index 29abfdeb0b65..1435976b8779 100644 --- a/drivers/net/wireless/rt2x00/rt2x00link.c +++ b/drivers/net/wireless/rt2x00/rt2x00link.c | |||
@@ -413,12 +413,11 @@ void rt2x00link_start_watchdog(struct rt2x00_dev *rt2x00dev) | |||
413 | { | 413 | { |
414 | struct link *link = &rt2x00dev->link; | 414 | struct link *link = &rt2x00dev->link; |
415 | 415 | ||
416 | if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) || | 416 | if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) && |
417 | !test_bit(DRIVER_SUPPORT_WATCHDOG, &rt2x00dev->flags)) | 417 | rt2x00dev->ops->lib->watchdog) |
418 | return; | 418 | ieee80211_queue_delayed_work(rt2x00dev->hw, |
419 | 419 | &link->watchdog_work, | |
420 | ieee80211_queue_delayed_work(rt2x00dev->hw, | 420 | WATCHDOG_INTERVAL); |
421 | &link->watchdog_work, WATCHDOG_INTERVAL); | ||
422 | } | 421 | } |
423 | 422 | ||
424 | void rt2x00link_stop_watchdog(struct rt2x00_dev *rt2x00dev) | 423 | void rt2x00link_stop_watchdog(struct rt2x00_dev *rt2x00dev) |
@@ -447,8 +446,46 @@ static void rt2x00link_watchdog(struct work_struct *work) | |||
447 | WATCHDOG_INTERVAL); | 446 | WATCHDOG_INTERVAL); |
448 | } | 447 | } |
449 | 448 | ||
449 | void rt2x00link_start_agc(struct rt2x00_dev *rt2x00dev) | ||
450 | { | ||
451 | struct link *link = &rt2x00dev->link; | ||
452 | |||
453 | if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) && | ||
454 | rt2x00dev->ops->lib->gain_calibration) | ||
455 | ieee80211_queue_delayed_work(rt2x00dev->hw, | ||
456 | &link->agc_work, | ||
457 | AGC_INTERVAL); | ||
458 | } | ||
459 | |||
460 | void rt2x00link_stop_agc(struct rt2x00_dev *rt2x00dev) | ||
461 | { | ||
462 | cancel_delayed_work_sync(&rt2x00dev->link.agc_work); | ||
463 | } | ||
464 | |||
465 | static void rt2x00link_agc(struct work_struct *work) | ||
466 | { | ||
467 | struct rt2x00_dev *rt2x00dev = | ||
468 | container_of(work, struct rt2x00_dev, link.agc_work.work); | ||
469 | struct link *link = &rt2x00dev->link; | ||
470 | |||
471 | /* | ||
472 | * When the radio is shutting down we should | ||
473 | * immediately cease the watchdog monitoring. | ||
474 | */ | ||
475 | if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) | ||
476 | return; | ||
477 | |||
478 | rt2x00dev->ops->lib->gain_calibration(rt2x00dev); | ||
479 | |||
480 | if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) | ||
481 | ieee80211_queue_delayed_work(rt2x00dev->hw, | ||
482 | &link->agc_work, | ||
483 | AGC_INTERVAL); | ||
484 | } | ||
485 | |||
450 | void rt2x00link_register(struct rt2x00_dev *rt2x00dev) | 486 | void rt2x00link_register(struct rt2x00_dev *rt2x00dev) |
451 | { | 487 | { |
488 | INIT_DELAYED_WORK(&rt2x00dev->link.agc_work, rt2x00link_agc); | ||
452 | INIT_DELAYED_WORK(&rt2x00dev->link.watchdog_work, rt2x00link_watchdog); | 489 | INIT_DELAYED_WORK(&rt2x00dev->link.watchdog_work, rt2x00link_watchdog); |
453 | INIT_DELAYED_WORK(&rt2x00dev->link.work, rt2x00link_tuner); | 490 | INIT_DELAYED_WORK(&rt2x00dev->link.work, rt2x00link_tuner); |
454 | } | 491 | } |
diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c index 4dd82b0b0520..9649bd0cd718 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.c +++ b/drivers/net/wireless/rt2x00/rt2x00pci.c | |||
@@ -60,14 +60,15 @@ int rt2x00pci_regbusy_read(struct rt2x00_dev *rt2x00dev, | |||
60 | } | 60 | } |
61 | EXPORT_SYMBOL_GPL(rt2x00pci_regbusy_read); | 61 | EXPORT_SYMBOL_GPL(rt2x00pci_regbusy_read); |
62 | 62 | ||
63 | void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev) | 63 | bool rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev) |
64 | { | 64 | { |
65 | struct data_queue *queue = rt2x00dev->rx; | 65 | struct data_queue *queue = rt2x00dev->rx; |
66 | struct queue_entry *entry; | 66 | struct queue_entry *entry; |
67 | struct queue_entry_priv_pci *entry_priv; | 67 | struct queue_entry_priv_pci *entry_priv; |
68 | struct skb_frame_desc *skbdesc; | 68 | struct skb_frame_desc *skbdesc; |
69 | int max_rx = 16; | ||
69 | 70 | ||
70 | while (1) { | 71 | while (--max_rx) { |
71 | entry = rt2x00queue_get_entry(queue, Q_INDEX); | 72 | entry = rt2x00queue_get_entry(queue, Q_INDEX); |
72 | entry_priv = entry->priv_data; | 73 | entry_priv = entry->priv_data; |
73 | 74 | ||
@@ -93,6 +94,8 @@ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev) | |||
93 | */ | 94 | */ |
94 | rt2x00lib_rxdone(entry); | 95 | rt2x00lib_rxdone(entry); |
95 | } | 96 | } |
97 | |||
98 | return !max_rx; | ||
96 | } | 99 | } |
97 | EXPORT_SYMBOL_GPL(rt2x00pci_rxdone); | 100 | EXPORT_SYMBOL_GPL(rt2x00pci_rxdone); |
98 | 101 | ||
diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.h b/drivers/net/wireless/rt2x00/rt2x00pci.h index 746ce8fe8cf4..07961b8b369a 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.h +++ b/drivers/net/wireless/rt2x00/rt2x00pci.h | |||
@@ -101,8 +101,11 @@ struct queue_entry_priv_pci { | |||
101 | /** | 101 | /** |
102 | * rt2x00pci_rxdone - Handle RX done events | 102 | * rt2x00pci_rxdone - Handle RX done events |
103 | * @rt2x00dev: Device pointer, see &struct rt2x00_dev. | 103 | * @rt2x00dev: Device pointer, see &struct rt2x00_dev. |
104 | * | ||
105 | * Returns true if there are still rx frames pending and false if all | ||
106 | * pending rx frames were processed. | ||
104 | */ | 107 | */ |
105 | void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev); | 108 | bool rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev); |
106 | 109 | ||
107 | /* | 110 | /* |
108 | * Device initialization handlers. | 111 | * Device initialization handlers. |
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 4358051bfe1a..94b8bbb7ad80 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c | |||
@@ -148,19 +148,6 @@ void rt2x00queue_align_frame(struct sk_buff *skb) | |||
148 | skb_trim(skb, frame_length); | 148 | skb_trim(skb, frame_length); |
149 | } | 149 | } |
150 | 150 | ||
151 | void rt2x00queue_align_payload(struct sk_buff *skb, unsigned int header_length) | ||
152 | { | ||
153 | unsigned int frame_length = skb->len; | ||
154 | unsigned int align = ALIGN_SIZE(skb, header_length); | ||
155 | |||
156 | if (!align) | ||
157 | return; | ||
158 | |||
159 | skb_push(skb, align); | ||
160 | memmove(skb->data, skb->data + align, frame_length); | ||
161 | skb_trim(skb, frame_length); | ||
162 | } | ||
163 | |||
164 | void rt2x00queue_insert_l2pad(struct sk_buff *skb, unsigned int header_length) | 151 | void rt2x00queue_insert_l2pad(struct sk_buff *skb, unsigned int header_length) |
165 | { | 152 | { |
166 | unsigned int payload_length = skb->len - header_length; | 153 | unsigned int payload_length = skb->len - header_length; |
@@ -495,8 +482,11 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb, | |||
495 | struct skb_frame_desc *skbdesc; | 482 | struct skb_frame_desc *skbdesc; |
496 | u8 rate_idx, rate_flags; | 483 | u8 rate_idx, rate_flags; |
497 | 484 | ||
498 | if (unlikely(rt2x00queue_full(queue))) | 485 | if (unlikely(rt2x00queue_full(queue))) { |
486 | ERROR(queue->rt2x00dev, | ||
487 | "Dropping frame due to full tx queue %d.\n", queue->qid); | ||
499 | return -ENOBUFS; | 488 | return -ENOBUFS; |
489 | } | ||
500 | 490 | ||
501 | if (unlikely(test_and_set_bit(ENTRY_OWNER_DEVICE_DATA, | 491 | if (unlikely(test_and_set_bit(ENTRY_OWNER_DEVICE_DATA, |
502 | &entry->flags))) { | 492 | &entry->flags))) { |
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index 217861f8d95f..5db6a99fce7d 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h | |||
@@ -217,6 +217,7 @@ enum txdone_entry_desc_flags { | |||
217 | TXDONE_FALLBACK, | 217 | TXDONE_FALLBACK, |
218 | TXDONE_FAILURE, | 218 | TXDONE_FAILURE, |
219 | TXDONE_EXCESSIVE_RETRY, | 219 | TXDONE_EXCESSIVE_RETRY, |
220 | TXDONE_AMPDU, | ||
220 | }; | 221 | }; |
221 | 222 | ||
222 | /** | 223 | /** |
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 77e8113b91e1..8ee1514a7943 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c | |||
@@ -2313,8 +2313,10 @@ static void rt61pci_tbtt_tasklet(unsigned long data) | |||
2313 | static void rt61pci_rxdone_tasklet(unsigned long data) | 2313 | static void rt61pci_rxdone_tasklet(unsigned long data) |
2314 | { | 2314 | { |
2315 | struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; | 2315 | struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; |
2316 | rt2x00pci_rxdone(rt2x00dev); | 2316 | if (rt2x00pci_rxdone(rt2x00dev)) |
2317 | rt61pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_RXDONE); | 2317 | rt2x00pci_rxdone(rt2x00dev); |
2318 | else | ||
2319 | rt61pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_RXDONE); | ||
2318 | } | 2320 | } |
2319 | 2321 | ||
2320 | static void rt61pci_autowake_tasklet(unsigned long data) | 2322 | static void rt61pci_autowake_tasklet(unsigned long data) |
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 02f1148c577e..6593059f9c7e 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c | |||
@@ -2209,7 +2209,6 @@ static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev) | |||
2209 | if (!modparam_nohwcrypt) | 2209 | if (!modparam_nohwcrypt) |
2210 | __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags); | 2210 | __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags); |
2211 | __set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags); | 2211 | __set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags); |
2212 | __set_bit(DRIVER_SUPPORT_WATCHDOG, &rt2x00dev->flags); | ||
2213 | 2212 | ||
2214 | /* | 2213 | /* |
2215 | * Set the rssi offset. | 2214 | * Set the rssi offset. |
@@ -2407,7 +2406,6 @@ static struct usb_device_id rt73usb_device_table[] = { | |||
2407 | { USB_DEVICE(0x0b05, 0x1723), USB_DEVICE_DATA(&rt73usb_ops) }, | 2406 | { USB_DEVICE(0x0b05, 0x1723), USB_DEVICE_DATA(&rt73usb_ops) }, |
2408 | { USB_DEVICE(0x0b05, 0x1724), USB_DEVICE_DATA(&rt73usb_ops) }, | 2407 | { USB_DEVICE(0x0b05, 0x1724), USB_DEVICE_DATA(&rt73usb_ops) }, |
2409 | /* Belkin */ | 2408 | /* Belkin */ |
2410 | { USB_DEVICE(0x050d, 0x7050), USB_DEVICE_DATA(&rt73usb_ops) }, | ||
2411 | { USB_DEVICE(0x050d, 0x705a), USB_DEVICE_DATA(&rt73usb_ops) }, | 2409 | { USB_DEVICE(0x050d, 0x705a), USB_DEVICE_DATA(&rt73usb_ops) }, |
2412 | { USB_DEVICE(0x050d, 0x905b), USB_DEVICE_DATA(&rt73usb_ops) }, | 2410 | { USB_DEVICE(0x050d, 0x905b), USB_DEVICE_DATA(&rt73usb_ops) }, |
2413 | { USB_DEVICE(0x050d, 0x905c), USB_DEVICE_DATA(&rt73usb_ops) }, | 2411 | { USB_DEVICE(0x050d, 0x905c), USB_DEVICE_DATA(&rt73usb_ops) }, |
diff --git a/drivers/net/wireless/rtlwifi/base.c b/drivers/net/wireless/rtlwifi/base.c index 0d7d93e1d398..4803f54842e4 100644 --- a/drivers/net/wireless/rtlwifi/base.c +++ b/drivers/net/wireless/rtlwifi/base.c | |||
@@ -432,7 +432,7 @@ static void _rtl_txrate_selectmode(struct ieee80211_hw *hw, | |||
432 | } | 432 | } |
433 | 433 | ||
434 | if (rtlpriv->dm.useramask) { | 434 | if (rtlpriv->dm.useramask) { |
435 | /* TODO we will differentiate adhoc and station futrue */ | 435 | /* TODO adhoc and station handled differently in the future */ |
436 | tcb_desc->mac_id = 0; | 436 | tcb_desc->mac_id = 0; |
437 | 437 | ||
438 | if ((mac->mode == WIRELESS_MODE_N_24G) || | 438 | if ((mac->mode == WIRELESS_MODE_N_24G) || |
@@ -630,7 +630,7 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx) | |||
630 | const struct iphdr *ip; | 630 | const struct iphdr *ip; |
631 | 631 | ||
632 | if (!ieee80211_is_data(fc)) | 632 | if (!ieee80211_is_data(fc)) |
633 | goto end; | 633 | return false; |
634 | 634 | ||
635 | if (ieee80211_is_nullfunc(fc)) | 635 | if (ieee80211_is_nullfunc(fc)) |
636 | return true; | 636 | return true; |
@@ -686,7 +686,6 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx) | |||
686 | return true; | 686 | return true; |
687 | } | 687 | } |
688 | 688 | ||
689 | end: | ||
690 | return false; | 689 | return false; |
691 | } | 690 | } |
692 | 691 | ||
diff --git a/drivers/net/wireless/rtlwifi/core.c b/drivers/net/wireless/rtlwifi/core.c index e4f4aee8f298..8fed3c687619 100644 --- a/drivers/net/wireless/rtlwifi/core.c +++ b/drivers/net/wireless/rtlwifi/core.c | |||
@@ -35,7 +35,7 @@ | |||
35 | /*mutex for start & stop is must here. */ | 35 | /*mutex for start & stop is must here. */ |
36 | static int rtl_op_start(struct ieee80211_hw *hw) | 36 | static int rtl_op_start(struct ieee80211_hw *hw) |
37 | { | 37 | { |
38 | int err = 0; | 38 | int err; |
39 | struct rtl_priv *rtlpriv = rtl_priv(hw); | 39 | struct rtl_priv *rtlpriv = rtl_priv(hw); |
40 | struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); | 40 | struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); |
41 | 41 | ||
@@ -45,10 +45,8 @@ static int rtl_op_start(struct ieee80211_hw *hw) | |||
45 | return 0; | 45 | return 0; |
46 | mutex_lock(&rtlpriv->locks.conf_mutex); | 46 | mutex_lock(&rtlpriv->locks.conf_mutex); |
47 | err = rtlpriv->intf_ops->adapter_start(hw); | 47 | err = rtlpriv->intf_ops->adapter_start(hw); |
48 | if (err) | 48 | if (!err) |
49 | goto out; | 49 | rtl_watch_dog_timer_callback((unsigned long)hw); |
50 | rtl_watch_dog_timer_callback((unsigned long)hw); | ||
51 | out: | ||
52 | mutex_unlock(&rtlpriv->locks.conf_mutex); | 50 | mutex_unlock(&rtlpriv->locks.conf_mutex); |
53 | return err; | 51 | return err; |
54 | } | 52 | } |
diff --git a/drivers/net/wireless/rtlwifi/efuse.c b/drivers/net/wireless/rtlwifi/efuse.c index 590f14f45a89..5d73c0f7012c 100644 --- a/drivers/net/wireless/rtlwifi/efuse.c +++ b/drivers/net/wireless/rtlwifi/efuse.c | |||
@@ -338,11 +338,11 @@ bool efuse_shadow_update_chk(struct ieee80211_hw *hw) | |||
338 | struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); | 338 | struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); |
339 | u8 section_idx, i, Base; | 339 | u8 section_idx, i, Base; |
340 | u16 words_need = 0, hdr_num = 0, totalbytes, efuse_used; | 340 | u16 words_need = 0, hdr_num = 0, totalbytes, efuse_used; |
341 | bool bwordchanged, bresult = true; | 341 | bool wordchanged, result = true; |
342 | 342 | ||
343 | for (section_idx = 0; section_idx < 16; section_idx++) { | 343 | for (section_idx = 0; section_idx < 16; section_idx++) { |
344 | Base = section_idx * 8; | 344 | Base = section_idx * 8; |
345 | bwordchanged = false; | 345 | wordchanged = false; |
346 | 346 | ||
347 | for (i = 0; i < 8; i = i + 2) { | 347 | for (i = 0; i < 8; i = i + 2) { |
348 | if ((rtlefuse->efuse_map[EFUSE_INIT_MAP][Base + i] != | 348 | if ((rtlefuse->efuse_map[EFUSE_INIT_MAP][Base + i] != |
@@ -351,11 +351,11 @@ bool efuse_shadow_update_chk(struct ieee80211_hw *hw) | |||
351 | rtlefuse->efuse_map[EFUSE_MODIFY_MAP][Base + i + | 351 | rtlefuse->efuse_map[EFUSE_MODIFY_MAP][Base + i + |
352 | 1])) { | 352 | 1])) { |
353 | words_need++; | 353 | words_need++; |
354 | bwordchanged = true; | 354 | wordchanged = true; |
355 | } | 355 | } |
356 | } | 356 | } |
357 | 357 | ||
358 | if (bwordchanged == true) | 358 | if (wordchanged == true) |
359 | hdr_num++; | 359 | hdr_num++; |
360 | } | 360 | } |
361 | 361 | ||
@@ -364,14 +364,14 @@ bool efuse_shadow_update_chk(struct ieee80211_hw *hw) | |||
364 | 364 | ||
365 | if ((totalbytes + efuse_used) >= | 365 | if ((totalbytes + efuse_used) >= |
366 | (EFUSE_MAX_SIZE - EFUSE_OOB_PROTECT_BYTES)) | 366 | (EFUSE_MAX_SIZE - EFUSE_OOB_PROTECT_BYTES)) |
367 | bresult = false; | 367 | result = false; |
368 | 368 | ||
369 | RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD, | 369 | RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD, |
370 | ("efuse_shadow_update_chk(): totalbytes(%#x), " | 370 | ("efuse_shadow_update_chk(): totalbytes(%#x), " |
371 | "hdr_num(%#x), words_need(%#x), efuse_used(%d)\n", | 371 | "hdr_num(%#x), words_need(%#x), efuse_used(%d)\n", |
372 | totalbytes, hdr_num, words_need, efuse_used)); | 372 | totalbytes, hdr_num, words_need, efuse_used)); |
373 | 373 | ||
374 | return bresult; | 374 | return result; |
375 | } | 375 | } |
376 | 376 | ||
377 | void efuse_shadow_read(struct ieee80211_hw *hw, u8 type, | 377 | void efuse_shadow_read(struct ieee80211_hw *hw, u8 type, |
@@ -394,7 +394,7 @@ void efuse_shadow_write(struct ieee80211_hw *hw, u8 type, u16 offset, | |||
394 | else if (type == 2) | 394 | else if (type == 2) |
395 | efuse_shadow_write_2byte(hw, offset, (u16) value); | 395 | efuse_shadow_write_2byte(hw, offset, (u16) value); |
396 | else if (type == 4) | 396 | else if (type == 4) |
397 | efuse_shadow_write_4byte(hw, offset, (u32) value); | 397 | efuse_shadow_write_4byte(hw, offset, value); |
398 | 398 | ||
399 | } | 399 | } |
400 | 400 | ||
@@ -572,7 +572,7 @@ static int efuse_one_byte_read(struct ieee80211_hw *hw, u16 addr, u8 *data) | |||
572 | { | 572 | { |
573 | struct rtl_priv *rtlpriv = rtl_priv(hw); | 573 | struct rtl_priv *rtlpriv = rtl_priv(hw); |
574 | u8 tmpidx = 0; | 574 | u8 tmpidx = 0; |
575 | int bresult; | 575 | int result; |
576 | 576 | ||
577 | rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 1, | 577 | rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 1, |
578 | (u8) (addr & 0xff)); | 578 | (u8) (addr & 0xff)); |
@@ -592,19 +592,18 @@ static int efuse_one_byte_read(struct ieee80211_hw *hw, u16 addr, u8 *data) | |||
592 | 592 | ||
593 | if (tmpidx < 100) { | 593 | if (tmpidx < 100) { |
594 | *data = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL]); | 594 | *data = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL]); |
595 | bresult = true; | 595 | result = true; |
596 | } else { | 596 | } else { |
597 | *data = 0xff; | 597 | *data = 0xff; |
598 | bresult = false; | 598 | result = false; |
599 | } | 599 | } |
600 | return bresult; | 600 | return result; |
601 | } | 601 | } |
602 | 602 | ||
603 | static int efuse_one_byte_write(struct ieee80211_hw *hw, u16 addr, u8 data) | 603 | static int efuse_one_byte_write(struct ieee80211_hw *hw, u16 addr, u8 data) |
604 | { | 604 | { |
605 | struct rtl_priv *rtlpriv = rtl_priv(hw); | 605 | struct rtl_priv *rtlpriv = rtl_priv(hw); |
606 | u8 tmpidx = 0; | 606 | u8 tmpidx = 0; |
607 | bool bresult; | ||
608 | 607 | ||
609 | RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD, | 608 | RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD, |
610 | ("Addr = %x Data=%x\n", addr, data)); | 609 | ("Addr = %x Data=%x\n", addr, data)); |
@@ -626,11 +625,9 @@ static int efuse_one_byte_write(struct ieee80211_hw *hw, u16 addr, u8 data) | |||
626 | } | 625 | } |
627 | 626 | ||
628 | if (tmpidx < 100) | 627 | if (tmpidx < 100) |
629 | bresult = true; | 628 | return true; |
630 | else | ||
631 | bresult = false; | ||
632 | 629 | ||
633 | return bresult; | 630 | return false; |
634 | } | 631 | } |
635 | 632 | ||
636 | static void efuse_read_all_map(struct ieee80211_hw *hw, u8 * efuse) | 633 | static void efuse_read_all_map(struct ieee80211_hw *hw, u8 * efuse) |
@@ -681,11 +678,10 @@ static int efuse_pg_packet_read(struct ieee80211_hw *hw, u8 offset, u8 *data) | |||
681 | { | 678 | { |
682 | u8 readstate = PG_STATE_HEADER; | 679 | u8 readstate = PG_STATE_HEADER; |
683 | 680 | ||
684 | bool bcontinual = true; | 681 | bool continual = true; |
685 | 682 | ||
686 | u8 efuse_data, word_cnts = 0; | 683 | u8 efuse_data, word_cnts = 0; |
687 | u16 efuse_addr = 0; | 684 | u16 efuse_addr = 0; |
688 | u8 hworden = 0; | ||
689 | u8 tmpdata[8]; | 685 | u8 tmpdata[8]; |
690 | 686 | ||
691 | if (data == NULL) | 687 | if (data == NULL) |
@@ -696,7 +692,7 @@ static int efuse_pg_packet_read(struct ieee80211_hw *hw, u8 offset, u8 *data) | |||
696 | memset(data, 0xff, PGPKT_DATA_SIZE * sizeof(u8)); | 692 | memset(data, 0xff, PGPKT_DATA_SIZE * sizeof(u8)); |
697 | memset(tmpdata, 0xff, PGPKT_DATA_SIZE * sizeof(u8)); | 693 | memset(tmpdata, 0xff, PGPKT_DATA_SIZE * sizeof(u8)); |
698 | 694 | ||
699 | while (bcontinual && (efuse_addr < EFUSE_MAX_SIZE)) { | 695 | while (continual && (efuse_addr < EFUSE_MAX_SIZE)) { |
700 | if (readstate & PG_STATE_HEADER) { | 696 | if (readstate & PG_STATE_HEADER) { |
701 | if (efuse_one_byte_read(hw, efuse_addr, &efuse_data) | 697 | if (efuse_one_byte_read(hw, efuse_addr, &efuse_data) |
702 | && (efuse_data != 0xFF)) | 698 | && (efuse_data != 0xFF)) |
@@ -705,9 +701,9 @@ static int efuse_pg_packet_read(struct ieee80211_hw *hw, u8 offset, u8 *data) | |||
705 | offset, tmpdata, | 701 | offset, tmpdata, |
706 | &readstate); | 702 | &readstate); |
707 | else | 703 | else |
708 | bcontinual = false; | 704 | continual = false; |
709 | } else if (readstate & PG_STATE_DATA) { | 705 | } else if (readstate & PG_STATE_DATA) { |
710 | efuse_word_enable_data_read(hworden, tmpdata, data); | 706 | efuse_word_enable_data_read(0, tmpdata, data); |
711 | efuse_addr = efuse_addr + (word_cnts * 2) + 1; | 707 | efuse_addr = efuse_addr + (word_cnts * 2) + 1; |
712 | readstate = PG_STATE_HEADER; | 708 | readstate = PG_STATE_HEADER; |
713 | } | 709 | } |
@@ -725,13 +721,13 @@ static int efuse_pg_packet_read(struct ieee80211_hw *hw, u8 offset, u8 *data) | |||
725 | } | 721 | } |
726 | 722 | ||
727 | static void efuse_write_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr, | 723 | static void efuse_write_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr, |
728 | u8 efuse_data, u8 offset, int *bcontinual, | 724 | u8 efuse_data, u8 offset, int *continual, |
729 | u8 *write_state, struct pgpkt_struct *target_pkt, | 725 | u8 *write_state, struct pgpkt_struct *target_pkt, |
730 | int *repeat_times, int *bresult, u8 word_en) | 726 | int *repeat_times, int *result, u8 word_en) |
731 | { | 727 | { |
732 | struct rtl_priv *rtlpriv = rtl_priv(hw); | 728 | struct rtl_priv *rtlpriv = rtl_priv(hw); |
733 | struct pgpkt_struct tmp_pkt; | 729 | struct pgpkt_struct tmp_pkt; |
734 | int bdataempty = true; | 730 | bool dataempty = true; |
735 | u8 originaldata[8 * sizeof(u8)]; | 731 | u8 originaldata[8 * sizeof(u8)]; |
736 | u8 badworden = 0x0F; | 732 | u8 badworden = 0x0F; |
737 | u8 match_word_en, tmp_word_en; | 733 | u8 match_word_en, tmp_word_en; |
@@ -751,10 +747,10 @@ static void efuse_write_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr, | |||
751 | u16 address = *efuse_addr + 1 + tmpindex; | 747 | u16 address = *efuse_addr + 1 + tmpindex; |
752 | if (efuse_one_byte_read(hw, address, | 748 | if (efuse_one_byte_read(hw, address, |
753 | &efuse_data) && (efuse_data != 0xFF)) | 749 | &efuse_data) && (efuse_data != 0xFF)) |
754 | bdataempty = false; | 750 | dataempty = false; |
755 | } | 751 | } |
756 | 752 | ||
757 | if (bdataempty == false) { | 753 | if (dataempty == false) { |
758 | *efuse_addr = *efuse_addr + (tmp_word_cnts * 2) + 1; | 754 | *efuse_addr = *efuse_addr + (tmp_word_cnts * 2) + 1; |
759 | *write_state = PG_STATE_HEADER; | 755 | *write_state = PG_STATE_HEADER; |
760 | } else { | 756 | } else { |
@@ -811,12 +807,12 @@ static void efuse_write_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr, | |||
811 | target_pkt->offset = offset; | 807 | target_pkt->offset = offset; |
812 | target_pkt->word_en = tmp_word_en; | 808 | target_pkt->word_en = tmp_word_en; |
813 | } else | 809 | } else |
814 | *bcontinual = false; | 810 | *continual = false; |
815 | *write_state = PG_STATE_HEADER; | 811 | *write_state = PG_STATE_HEADER; |
816 | *repeat_times += 1; | 812 | *repeat_times += 1; |
817 | if (*repeat_times > EFUSE_REPEAT_THRESHOLD_) { | 813 | if (*repeat_times > EFUSE_REPEAT_THRESHOLD_) { |
818 | *bcontinual = false; | 814 | *continual = false; |
819 | *bresult = false; | 815 | *result = false; |
820 | } | 816 | } |
821 | } else { | 817 | } else { |
822 | *efuse_addr += (2 * tmp_word_cnts) + 1; | 818 | *efuse_addr += (2 * tmp_word_cnts) + 1; |
@@ -830,9 +826,9 @@ static void efuse_write_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr, | |||
830 | } | 826 | } |
831 | 827 | ||
832 | static void efuse_write_data_case2(struct ieee80211_hw *hw, u16 *efuse_addr, | 828 | static void efuse_write_data_case2(struct ieee80211_hw *hw, u16 *efuse_addr, |
833 | int *bcontinual, u8 *write_state, | 829 | int *continual, u8 *write_state, |
834 | struct pgpkt_struct target_pkt, | 830 | struct pgpkt_struct target_pkt, |
835 | int *repeat_times, int *bresult) | 831 | int *repeat_times, int *result) |
836 | { | 832 | { |
837 | struct rtl_priv *rtlpriv = rtl_priv(hw); | 833 | struct rtl_priv *rtlpriv = rtl_priv(hw); |
838 | struct pgpkt_struct tmp_pkt; | 834 | struct pgpkt_struct tmp_pkt; |
@@ -852,8 +848,8 @@ static void efuse_write_data_case2(struct ieee80211_hw *hw, u16 *efuse_addr, | |||
852 | *write_state = PG_STATE_HEADER; | 848 | *write_state = PG_STATE_HEADER; |
853 | *repeat_times += 1; | 849 | *repeat_times += 1; |
854 | if (*repeat_times > EFUSE_REPEAT_THRESHOLD_) { | 850 | if (*repeat_times > EFUSE_REPEAT_THRESHOLD_) { |
855 | *bcontinual = false; | 851 | *continual = false; |
856 | *bresult = false; | 852 | *result = false; |
857 | } | 853 | } |
858 | } else { | 854 | } else { |
859 | tmp_pkt.offset = (tmp_header >> 4) & 0x0F; | 855 | tmp_pkt.offset = (tmp_header >> 4) & 0x0F; |
@@ -884,8 +880,8 @@ static void efuse_write_data_case2(struct ieee80211_hw *hw, u16 *efuse_addr, | |||
884 | *write_state = PG_STATE_HEADER; | 880 | *write_state = PG_STATE_HEADER; |
885 | *repeat_times += 1; | 881 | *repeat_times += 1; |
886 | if (*repeat_times > EFUSE_REPEAT_THRESHOLD_) { | 882 | if (*repeat_times > EFUSE_REPEAT_THRESHOLD_) { |
887 | *bcontinual = false; | 883 | *continual = false; |
888 | *bresult = false; | 884 | *result = false; |
889 | } | 885 | } |
890 | 886 | ||
891 | RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, | 887 | RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, |
@@ -899,7 +895,7 @@ static int efuse_pg_packet_write(struct ieee80211_hw *hw, | |||
899 | struct rtl_priv *rtlpriv = rtl_priv(hw); | 895 | struct rtl_priv *rtlpriv = rtl_priv(hw); |
900 | struct pgpkt_struct target_pkt; | 896 | struct pgpkt_struct target_pkt; |
901 | u8 write_state = PG_STATE_HEADER; | 897 | u8 write_state = PG_STATE_HEADER; |
902 | int bcontinual = true, bdataempty = true, bresult = true; | 898 | int continual = true, dataempty = true, result = true; |
903 | u16 efuse_addr = 0; | 899 | u16 efuse_addr = 0; |
904 | u8 efuse_data; | 900 | u8 efuse_data; |
905 | u8 target_word_cnts = 0; | 901 | u8 target_word_cnts = 0; |
@@ -923,11 +919,11 @@ static int efuse_pg_packet_write(struct ieee80211_hw *hw, | |||
923 | 919 | ||
924 | RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, ("efuse Power ON\n")); | 920 | RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, ("efuse Power ON\n")); |
925 | 921 | ||
926 | while (bcontinual && (efuse_addr < | 922 | while (continual && (efuse_addr < |
927 | (EFUSE_MAX_SIZE - EFUSE_OOB_PROTECT_BYTES))) { | 923 | (EFUSE_MAX_SIZE - EFUSE_OOB_PROTECT_BYTES))) { |
928 | 924 | ||
929 | if (write_state == PG_STATE_HEADER) { | 925 | if (write_state == PG_STATE_HEADER) { |
930 | bdataempty = true; | 926 | dataempty = true; |
931 | badworden = 0x0F; | 927 | badworden = 0x0F; |
932 | RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, | 928 | RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, |
933 | ("efuse PG_STATE_HEADER\n")); | 929 | ("efuse PG_STATE_HEADER\n")); |
@@ -936,32 +932,30 @@ static int efuse_pg_packet_write(struct ieee80211_hw *hw, | |||
936 | (efuse_data != 0xFF)) | 932 | (efuse_data != 0xFF)) |
937 | efuse_write_data_case1(hw, &efuse_addr, | 933 | efuse_write_data_case1(hw, &efuse_addr, |
938 | efuse_data, offset, | 934 | efuse_data, offset, |
939 | &bcontinual, | 935 | &continual, |
940 | &write_state, &target_pkt, | 936 | &write_state, &target_pkt, |
941 | &repeat_times, &bresult, | 937 | &repeat_times, &result, |
942 | word_en); | 938 | word_en); |
943 | else | 939 | else |
944 | efuse_write_data_case2(hw, &efuse_addr, | 940 | efuse_write_data_case2(hw, &efuse_addr, |
945 | &bcontinual, | 941 | &continual, |
946 | &write_state, | 942 | &write_state, |
947 | target_pkt, | 943 | target_pkt, |
948 | &repeat_times, | 944 | &repeat_times, |
949 | &bresult); | 945 | &result); |
950 | 946 | ||
951 | } else if (write_state == PG_STATE_DATA) { | 947 | } else if (write_state == PG_STATE_DATA) { |
952 | RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, | 948 | RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, |
953 | ("efuse PG_STATE_DATA\n")); | 949 | ("efuse PG_STATE_DATA\n")); |
954 | badworden = 0x0f; | ||
955 | badworden = | 950 | badworden = |
956 | efuse_word_enable_data_write(hw, efuse_addr + 1, | 951 | efuse_word_enable_data_write(hw, efuse_addr + 1, |
957 | target_pkt.word_en, | 952 | target_pkt.word_en, |
958 | target_pkt.data); | 953 | target_pkt.data); |
959 | 954 | ||
960 | if ((badworden & 0x0F) == 0x0F) { | 955 | if ((badworden & 0x0F) == 0x0F) { |
961 | bcontinual = false; | 956 | continual = false; |
962 | } else { | 957 | } else { |
963 | efuse_addr = | 958 | efuse_addr += (2 * target_word_cnts) + 1; |
964 | efuse_addr + (2 * target_word_cnts) + 1; | ||
965 | 959 | ||
966 | target_pkt.offset = offset; | 960 | target_pkt.offset = offset; |
967 | target_pkt.word_en = badworden; | 961 | target_pkt.word_en = badworden; |
@@ -971,8 +965,8 @@ static int efuse_pg_packet_write(struct ieee80211_hw *hw, | |||
971 | write_state = PG_STATE_HEADER; | 965 | write_state = PG_STATE_HEADER; |
972 | repeat_times++; | 966 | repeat_times++; |
973 | if (repeat_times > EFUSE_REPEAT_THRESHOLD_) { | 967 | if (repeat_times > EFUSE_REPEAT_THRESHOLD_) { |
974 | bcontinual = false; | 968 | continual = false; |
975 | bresult = false; | 969 | result = false; |
976 | } | 970 | } |
977 | RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, | 971 | RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, |
978 | ("efuse PG_STATE_HEADER-3\n")); | 972 | ("efuse PG_STATE_HEADER-3\n")); |
@@ -1072,13 +1066,13 @@ static u8 efuse_word_enable_data_write(struct ieee80211_hw *hw, | |||
1072 | return badworden; | 1066 | return badworden; |
1073 | } | 1067 | } |
1074 | 1068 | ||
1075 | static void efuse_power_switch(struct ieee80211_hw *hw, u8 bwrite, u8 pwrstate) | 1069 | static void efuse_power_switch(struct ieee80211_hw *hw, u8 write, u8 pwrstate) |
1076 | { | 1070 | { |
1077 | struct rtl_priv *rtlpriv = rtl_priv(hw); | 1071 | struct rtl_priv *rtlpriv = rtl_priv(hw); |
1078 | u8 tempval; | 1072 | u8 tempval; |
1079 | u16 tmpV16; | 1073 | u16 tmpV16; |
1080 | 1074 | ||
1081 | if (pwrstate == true) { | 1075 | if (pwrstate) { |
1082 | tmpV16 = rtl_read_word(rtlpriv, | 1076 | tmpV16 = rtl_read_word(rtlpriv, |
1083 | rtlpriv->cfg->maps[SYS_ISO_CTRL]); | 1077 | rtlpriv->cfg->maps[SYS_ISO_CTRL]); |
1084 | if (!(tmpV16 & rtlpriv->cfg->maps[EFUSE_PWC_EV12V])) { | 1078 | if (!(tmpV16 & rtlpriv->cfg->maps[EFUSE_PWC_EV12V])) { |
@@ -1106,8 +1100,8 @@ static void efuse_power_switch(struct ieee80211_hw *hw, u8 bwrite, u8 pwrstate) | |||
1106 | } | 1100 | } |
1107 | } | 1101 | } |
1108 | 1102 | ||
1109 | if (pwrstate == true) { | 1103 | if (pwrstate) { |
1110 | if (bwrite == true) { | 1104 | if (write) { |
1111 | tempval = rtl_read_byte(rtlpriv, | 1105 | tempval = rtl_read_byte(rtlpriv, |
1112 | rtlpriv->cfg->maps[EFUSE_TEST] + | 1106 | rtlpriv->cfg->maps[EFUSE_TEST] + |
1113 | 3); | 1107 | 3); |
@@ -1119,7 +1113,7 @@ static void efuse_power_switch(struct ieee80211_hw *hw, u8 bwrite, u8 pwrstate) | |||
1119 | } | 1113 | } |
1120 | 1114 | ||
1121 | } else { | 1115 | } else { |
1122 | if (bwrite == true) { | 1116 | if (write) { |
1123 | tempval = rtl_read_byte(rtlpriv, | 1117 | tempval = rtl_read_byte(rtlpriv, |
1124 | rtlpriv->cfg->maps[EFUSE_TEST] + | 1118 | rtlpriv->cfg->maps[EFUSE_TEST] + |
1125 | 3); | 1119 | 3); |
@@ -1134,12 +1128,12 @@ static void efuse_power_switch(struct ieee80211_hw *hw, u8 bwrite, u8 pwrstate) | |||
1134 | 1128 | ||
1135 | static u16 efuse_get_current_size(struct ieee80211_hw *hw) | 1129 | static u16 efuse_get_current_size(struct ieee80211_hw *hw) |
1136 | { | 1130 | { |
1137 | int bcontinual = true; | 1131 | int continual = true; |
1138 | u16 efuse_addr = 0; | 1132 | u16 efuse_addr = 0; |
1139 | u8 hoffset, hworden; | 1133 | u8 hoffset, hworden; |
1140 | u8 efuse_data, word_cnts; | 1134 | u8 efuse_data, word_cnts; |
1141 | 1135 | ||
1142 | while (bcontinual && efuse_one_byte_read(hw, efuse_addr, &efuse_data) | 1136 | while (continual && efuse_one_byte_read(hw, efuse_addr, &efuse_data) |
1143 | && (efuse_addr < EFUSE_MAX_SIZE)) { | 1137 | && (efuse_addr < EFUSE_MAX_SIZE)) { |
1144 | if (efuse_data != 0xFF) { | 1138 | if (efuse_data != 0xFF) { |
1145 | hoffset = (efuse_data >> 4) & 0x0F; | 1139 | hoffset = (efuse_data >> 4) & 0x0F; |
@@ -1147,7 +1141,7 @@ static u16 efuse_get_current_size(struct ieee80211_hw *hw) | |||
1147 | word_cnts = efuse_calculate_word_cnts(hworden); | 1141 | word_cnts = efuse_calculate_word_cnts(hworden); |
1148 | efuse_addr = efuse_addr + (word_cnts * 2) + 1; | 1142 | efuse_addr = efuse_addr + (word_cnts * 2) + 1; |
1149 | } else { | 1143 | } else { |
1150 | bcontinual = false; | 1144 | continual = false; |
1151 | } | 1145 | } |
1152 | } | 1146 | } |
1153 | 1147 | ||
diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c index 5938f6ee21e4..fbde52d83424 100644 --- a/drivers/net/wireless/rtlwifi/pci.c +++ b/drivers/net/wireless/rtlwifi/pci.c | |||
@@ -113,32 +113,19 @@ static void _rtl_pci_update_default_setting(struct ieee80211_hw *hw) | |||
113 | 113 | ||
114 | /*Set HW definition to determine if it supports ASPM. */ | 114 | /*Set HW definition to determine if it supports ASPM. */ |
115 | switch (rtlpci->const_support_pciaspm) { | 115 | switch (rtlpci->const_support_pciaspm) { |
116 | case 0:{ | 116 | case 0: |
117 | /*Not support ASPM. */ | 117 | /*Not support ASPM. */ |
118 | bool support_aspm = false; | 118 | ppsc->support_aspm = false; |
119 | ppsc->support_aspm = support_aspm; | 119 | break; |
120 | break; | 120 | case 1: |
121 | } | 121 | /*Support ASPM. */ |
122 | case 1:{ | 122 | ppsc->support_aspm = true; |
123 | /*Support ASPM. */ | 123 | ppsc->support_backdoor = true; |
124 | bool support_aspm = true; | 124 | break; |
125 | bool support_backdoor = true; | ||
126 | ppsc->support_aspm = support_aspm; | ||
127 | |||
128 | /*if(priv->oem_id == RT_CID_TOSHIBA && | ||
129 | !priv->ndis_adapter.amd_l1_patch) | ||
130 | support_backdoor = false; */ | ||
131 | |||
132 | ppsc->support_backdoor = support_backdoor; | ||
133 | |||
134 | break; | ||
135 | } | ||
136 | case 2: | 125 | case 2: |
137 | /*ASPM value set by chipset. */ | 126 | /*ASPM value set by chipset. */ |
138 | if (pcibridge_vendor == PCI_BRIDGE_VENDOR_INTEL) { | 127 | if (pcibridge_vendor == PCI_BRIDGE_VENDOR_INTEL) |
139 | bool support_aspm = true; | 128 | ppsc->support_aspm = true; |
140 | ppsc->support_aspm = support_aspm; | ||
141 | } | ||
142 | break; | 129 | break; |
143 | default: | 130 | default: |
144 | RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, | 131 | RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, |
@@ -152,13 +139,11 @@ static bool _rtl_pci_platform_switch_device_pci_aspm( | |||
152 | u8 value) | 139 | u8 value) |
153 | { | 140 | { |
154 | struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); | 141 | struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); |
155 | bool bresult = false; | ||
156 | 142 | ||
157 | value |= 0x40; | 143 | value |= 0x40; |
158 | |||
159 | pci_write_config_byte(rtlpci->pdev, 0x80, value); | 144 | pci_write_config_byte(rtlpci->pdev, 0x80, value); |
160 | 145 | ||
161 | return bresult; | 146 | return false; |
162 | } | 147 | } |
163 | 148 | ||
164 | /*When we set 0x01 to enable clk request. Set 0x0 to disable clk req.*/ | 149 | /*When we set 0x01 to enable clk request. Set 0x0 to disable clk req.*/ |
@@ -166,14 +151,11 @@ static bool _rtl_pci_switch_clk_req(struct ieee80211_hw *hw, u8 value) | |||
166 | { | 151 | { |
167 | struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); | 152 | struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); |
168 | u8 buffer; | 153 | u8 buffer; |
169 | bool bresult = false; | ||
170 | 154 | ||
171 | buffer = value; | 155 | buffer = value; |
172 | |||
173 | pci_write_config_byte(rtlpci->pdev, 0x81, value); | 156 | pci_write_config_byte(rtlpci->pdev, 0x81, value); |
174 | bresult = true; | ||
175 | 157 | ||
176 | return bresult; | 158 | return true; |
177 | } | 159 | } |
178 | 160 | ||
179 | /*Disable RTL8192SE ASPM & Disable Pci Bridge ASPM*/ | 161 | /*Disable RTL8192SE ASPM & Disable Pci Bridge ASPM*/ |
@@ -191,6 +173,7 @@ static void rtl_pci_disable_aspm(struct ieee80211_hw *hw) | |||
191 | u16 pcibridge_linkctrlreg = pcipriv->ndis_adapter. | 173 | u16 pcibridge_linkctrlreg = pcipriv->ndis_adapter. |
192 | pcibridge_linkctrlreg; | 174 | pcibridge_linkctrlreg; |
193 | u16 aspmlevel = 0; | 175 | u16 aspmlevel = 0; |
176 | u8 tmp_u1b = 0; | ||
194 | 177 | ||
195 | if (pcibridge_vendor == PCI_BRIDGE_VENDOR_UNKNOWN) { | 178 | if (pcibridge_vendor == PCI_BRIDGE_VENDOR_UNKNOWN) { |
196 | RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE, | 179 | RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE, |
@@ -204,11 +187,8 @@ static void rtl_pci_disable_aspm(struct ieee80211_hw *hw) | |||
204 | _rtl_pci_switch_clk_req(hw, 0x0); | 187 | _rtl_pci_switch_clk_req(hw, 0x0); |
205 | } | 188 | } |
206 | 189 | ||
207 | if (1) { | 190 | /*for promising device will in L0 state after an I/O. */ |
208 | /*for promising device will in L0 state after an I/O. */ | 191 | pci_read_config_byte(rtlpci->pdev, 0x80, &tmp_u1b); |
209 | u8 tmp_u1b; | ||
210 | pci_read_config_byte(rtlpci->pdev, 0x80, &tmp_u1b); | ||
211 | } | ||
212 | 192 | ||
213 | /*Set corresponding value. */ | 193 | /*Set corresponding value. */ |
214 | aspmlevel |= BIT(0) | BIT(1); | 194 | aspmlevel |= BIT(0) | BIT(1); |
@@ -224,7 +204,6 @@ static void rtl_pci_disable_aspm(struct ieee80211_hw *hw) | |||
224 | rtl_pci_raw_write_port_uchar(PCI_CONF_DATA, pcibridge_linkctrlreg); | 204 | rtl_pci_raw_write_port_uchar(PCI_CONF_DATA, pcibridge_linkctrlreg); |
225 | 205 | ||
226 | udelay(50); | 206 | udelay(50); |
227 | |||
228 | } | 207 | } |
229 | 208 | ||
230 | /* | 209 | /* |
diff --git a/drivers/net/wireless/rtlwifi/pci.h b/drivers/net/wireless/rtlwifi/pci.h index 0caa81429726..12747b9c71e1 100644 --- a/drivers/net/wireless/rtlwifi/pci.h +++ b/drivers/net/wireless/rtlwifi/pci.h | |||
@@ -192,8 +192,8 @@ struct rtl_pci { | |||
192 | u8 const_devicepci_aspm_setting; | 192 | u8 const_devicepci_aspm_setting; |
193 | /*If it supports ASPM, Offset[560h] = 0x40, | 193 | /*If it supports ASPM, Offset[560h] = 0x40, |
194 | otherwise Offset[560h] = 0x00. */ | 194 | otherwise Offset[560h] = 0x00. */ |
195 | bool b_support_aspm; | 195 | bool support_aspm; |
196 | bool b_support_backdoor; | 196 | bool support_backdoor; |
197 | 197 | ||
198 | /*QOS & EDCA */ | 198 | /*QOS & EDCA */ |
199 | enum acm_method acm_method; | 199 | enum acm_method acm_method; |
diff --git a/drivers/net/wireless/rtlwifi/ps.c b/drivers/net/wireless/rtlwifi/ps.c index 6b7e217b6b89..c8395fb0c050 100644 --- a/drivers/net/wireless/rtlwifi/ps.c +++ b/drivers/net/wireless/rtlwifi/ps.c | |||
@@ -63,7 +63,6 @@ EXPORT_SYMBOL(rtl_ps_enable_nic); | |||
63 | 63 | ||
64 | bool rtl_ps_disable_nic(struct ieee80211_hw *hw) | 64 | bool rtl_ps_disable_nic(struct ieee80211_hw *hw) |
65 | { | 65 | { |
66 | bool status = true; | ||
67 | struct rtl_priv *rtlpriv = rtl_priv(hw); | 66 | struct rtl_priv *rtlpriv = rtl_priv(hw); |
68 | 67 | ||
69 | /*<1> Stop all timer */ | 68 | /*<1> Stop all timer */ |
@@ -75,7 +74,7 @@ bool rtl_ps_disable_nic(struct ieee80211_hw *hw) | |||
75 | /*<3> Disable Adapter */ | 74 | /*<3> Disable Adapter */ |
76 | rtlpriv->cfg->ops->hw_disable(hw); | 75 | rtlpriv->cfg->ops->hw_disable(hw); |
77 | 76 | ||
78 | return status; | 77 | return true; |
79 | } | 78 | } |
80 | EXPORT_SYMBOL(rtl_ps_disable_nic); | 79 | EXPORT_SYMBOL(rtl_ps_disable_nic); |
81 | 80 | ||
diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c index 28a6ce3bc239..f107660f545d 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c +++ b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c | |||
@@ -171,7 +171,6 @@ static void _rtl92c_write_fw(struct ieee80211_hw *hw, | |||
171 | static int _rtl92c_fw_free_to_go(struct ieee80211_hw *hw) | 171 | static int _rtl92c_fw_free_to_go(struct ieee80211_hw *hw) |
172 | { | 172 | { |
173 | struct rtl_priv *rtlpriv = rtl_priv(hw); | 173 | struct rtl_priv *rtlpriv = rtl_priv(hw); |
174 | int err = -EIO; | ||
175 | u32 counter = 0; | 174 | u32 counter = 0; |
176 | u32 value32; | 175 | u32 value32; |
177 | 176 | ||
@@ -184,7 +183,7 @@ static int _rtl92c_fw_free_to_go(struct ieee80211_hw *hw) | |||
184 | RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, | 183 | RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, |
185 | ("chksum report faill ! REG_MCUFWDL:0x%08x .\n", | 184 | ("chksum report faill ! REG_MCUFWDL:0x%08x .\n", |
186 | value32)); | 185 | value32)); |
187 | goto exit; | 186 | return -EIO; |
188 | } | 187 | } |
189 | 188 | ||
190 | RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, | 189 | RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, |
@@ -204,8 +203,7 @@ static int _rtl92c_fw_free_to_go(struct ieee80211_hw *hw) | |||
204 | ("Polling FW ready success!!" | 203 | ("Polling FW ready success!!" |
205 | " REG_MCUFWDL:0x%08x .\n", | 204 | " REG_MCUFWDL:0x%08x .\n", |
206 | value32)); | 205 | value32)); |
207 | err = 0; | 206 | return 0; |
208 | goto exit; | ||
209 | } | 207 | } |
210 | 208 | ||
211 | mdelay(FW_8192C_POLLING_DELAY); | 209 | mdelay(FW_8192C_POLLING_DELAY); |
@@ -214,9 +212,7 @@ static int _rtl92c_fw_free_to_go(struct ieee80211_hw *hw) | |||
214 | 212 | ||
215 | RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, | 213 | RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, |
216 | ("Polling FW ready fail!! REG_MCUFWDL:0x%08x .\n", value32)); | 214 | ("Polling FW ready fail!! REG_MCUFWDL:0x%08x .\n", value32)); |
217 | 215 | return -EIO; | |
218 | exit: | ||
219 | return err; | ||
220 | } | 216 | } |
221 | 217 | ||
222 | int rtl92c_download_fw(struct ieee80211_hw *hw) | 218 | int rtl92c_download_fw(struct ieee80211_hw *hw) |
@@ -226,16 +222,14 @@ int rtl92c_download_fw(struct ieee80211_hw *hw) | |||
226 | struct rtl92c_firmware_header *pfwheader; | 222 | struct rtl92c_firmware_header *pfwheader; |
227 | u8 *pfwdata; | 223 | u8 *pfwdata; |
228 | u32 fwsize; | 224 | u32 fwsize; |
229 | int err; | ||
230 | enum version_8192c version = rtlhal->version; | 225 | enum version_8192c version = rtlhal->version; |
231 | const struct firmware *firmware; | 226 | const struct firmware *firmware; |
232 | 227 | ||
233 | printk(KERN_INFO "rtl8192cu: Loading firmware file %s\n", | 228 | printk(KERN_INFO "rtl8192c: Loading firmware file %s\n", |
234 | rtlpriv->cfg->fw_name); | 229 | rtlpriv->cfg->fw_name); |
235 | err = request_firmware(&firmware, rtlpriv->cfg->fw_name, | 230 | if (request_firmware(&firmware, rtlpriv->cfg->fw_name, |
236 | rtlpriv->io.dev); | 231 | rtlpriv->io.dev)) { |
237 | if (err) { | 232 | printk(KERN_ERR "rtl8192c: Firmware loading failed\n"); |
238 | printk(KERN_ERR "rtl8192cu: Firmware loading failed\n"); | ||
239 | return 1; | 233 | return 1; |
240 | } | 234 | } |
241 | 235 | ||
@@ -267,8 +261,7 @@ int rtl92c_download_fw(struct ieee80211_hw *hw) | |||
267 | _rtl92c_write_fw(hw, version, pfwdata, fwsize); | 261 | _rtl92c_write_fw(hw, version, pfwdata, fwsize); |
268 | _rtl92c_enable_fw_download(hw, false); | 262 | _rtl92c_enable_fw_download(hw, false); |
269 | 263 | ||
270 | err = _rtl92c_fw_free_to_go(hw); | 264 | if (_rtl92c_fw_free_to_go(hw)) { |
271 | if (err) { | ||
272 | RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, | 265 | RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, |
273 | ("Firmware is not ready to run!\n")); | 266 | ("Firmware is not ready to run!\n")); |
274 | } else { | 267 | } else { |
@@ -303,7 +296,6 @@ static void _rtl92c_fill_h2c_command(struct ieee80211_hw *hw, | |||
303 | u16 box_reg, box_extreg; | 296 | u16 box_reg, box_extreg; |
304 | u8 u1b_tmp; | 297 | u8 u1b_tmp; |
305 | bool isfw_read = false; | 298 | bool isfw_read = false; |
306 | u8 buf_index = 0; | ||
307 | bool bwrite_sucess = false; | 299 | bool bwrite_sucess = false; |
308 | u8 wait_h2c_limmit = 100; | 300 | u8 wait_h2c_limmit = 100; |
309 | u8 wait_writeh2c_limmit = 100; | 301 | u8 wait_writeh2c_limmit = 100; |
@@ -414,7 +406,7 @@ static void _rtl92c_fill_h2c_command(struct ieee80211_hw *hw, | |||
414 | case 1: | 406 | case 1: |
415 | boxcontent[0] &= ~(BIT(7)); | 407 | boxcontent[0] &= ~(BIT(7)); |
416 | memcpy((u8 *) (boxcontent) + 1, | 408 | memcpy((u8 *) (boxcontent) + 1, |
417 | p_cmdbuffer + buf_index, 1); | 409 | p_cmdbuffer, 1); |
418 | 410 | ||
419 | for (idx = 0; idx < 4; idx++) { | 411 | for (idx = 0; idx < 4; idx++) { |
420 | rtl_write_byte(rtlpriv, box_reg + idx, | 412 | rtl_write_byte(rtlpriv, box_reg + idx, |
@@ -424,7 +416,7 @@ static void _rtl92c_fill_h2c_command(struct ieee80211_hw *hw, | |||
424 | case 2: | 416 | case 2: |
425 | boxcontent[0] &= ~(BIT(7)); | 417 | boxcontent[0] &= ~(BIT(7)); |
426 | memcpy((u8 *) (boxcontent) + 1, | 418 | memcpy((u8 *) (boxcontent) + 1, |
427 | p_cmdbuffer + buf_index, 2); | 419 | p_cmdbuffer, 2); |
428 | 420 | ||
429 | for (idx = 0; idx < 4; idx++) { | 421 | for (idx = 0; idx < 4; idx++) { |
430 | rtl_write_byte(rtlpriv, box_reg + idx, | 422 | rtl_write_byte(rtlpriv, box_reg + idx, |
@@ -434,7 +426,7 @@ static void _rtl92c_fill_h2c_command(struct ieee80211_hw *hw, | |||
434 | case 3: | 426 | case 3: |
435 | boxcontent[0] &= ~(BIT(7)); | 427 | boxcontent[0] &= ~(BIT(7)); |
436 | memcpy((u8 *) (boxcontent) + 1, | 428 | memcpy((u8 *) (boxcontent) + 1, |
437 | p_cmdbuffer + buf_index, 3); | 429 | p_cmdbuffer, 3); |
438 | 430 | ||
439 | for (idx = 0; idx < 4; idx++) { | 431 | for (idx = 0; idx < 4; idx++) { |
440 | rtl_write_byte(rtlpriv, box_reg + idx, | 432 | rtl_write_byte(rtlpriv, box_reg + idx, |
@@ -444,9 +436,9 @@ static void _rtl92c_fill_h2c_command(struct ieee80211_hw *hw, | |||
444 | case 4: | 436 | case 4: |
445 | boxcontent[0] |= (BIT(7)); | 437 | boxcontent[0] |= (BIT(7)); |
446 | memcpy((u8 *) (boxextcontent), | 438 | memcpy((u8 *) (boxextcontent), |
447 | p_cmdbuffer + buf_index, 2); | 439 | p_cmdbuffer, 2); |
448 | memcpy((u8 *) (boxcontent) + 1, | 440 | memcpy((u8 *) (boxcontent) + 1, |
449 | p_cmdbuffer + buf_index + 2, 2); | 441 | p_cmdbuffer + 2, 2); |
450 | 442 | ||
451 | for (idx = 0; idx < 2; idx++) { | 443 | for (idx = 0; idx < 2; idx++) { |
452 | rtl_write_byte(rtlpriv, box_extreg + idx, | 444 | rtl_write_byte(rtlpriv, box_extreg + idx, |
@@ -461,9 +453,9 @@ static void _rtl92c_fill_h2c_command(struct ieee80211_hw *hw, | |||
461 | case 5: | 453 | case 5: |
462 | boxcontent[0] |= (BIT(7)); | 454 | boxcontent[0] |= (BIT(7)); |
463 | memcpy((u8 *) (boxextcontent), | 455 | memcpy((u8 *) (boxextcontent), |
464 | p_cmdbuffer + buf_index, 2); | 456 | p_cmdbuffer, 2); |
465 | memcpy((u8 *) (boxcontent) + 1, | 457 | memcpy((u8 *) (boxcontent) + 1, |
466 | p_cmdbuffer + buf_index + 2, 3); | 458 | p_cmdbuffer + 2, 3); |
467 | 459 | ||
468 | for (idx = 0; idx < 2; idx++) { | 460 | for (idx = 0; idx < 2; idx++) { |
469 | rtl_write_byte(rtlpriv, box_extreg + idx, | 461 | rtl_write_byte(rtlpriv, box_extreg + idx, |
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h index 803adcc80c96..b0b0b13dd0ae 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h | |||
@@ -532,9 +532,9 @@ | |||
532 | #define CLEAR_PCI_TX_DESC_CONTENT(__pdesc, _size) \ | 532 | #define CLEAR_PCI_TX_DESC_CONTENT(__pdesc, _size) \ |
533 | do { \ | 533 | do { \ |
534 | if (_size > TX_DESC_NEXT_DESC_OFFSET) \ | 534 | if (_size > TX_DESC_NEXT_DESC_OFFSET) \ |
535 | memset((void *)__pdesc, 0, TX_DESC_NEXT_DESC_OFFSET); \ | 535 | memset(__pdesc, 0, TX_DESC_NEXT_DESC_OFFSET); \ |
536 | else \ | 536 | else \ |
537 | memset((void *)__pdesc, 0, _size); \ | 537 | memset(__pdesc, 0, _size); \ |
538 | } while (0); | 538 | } while (0); |
539 | 539 | ||
540 | #define RX_HAL_IS_CCK_RATE(_pdesc)\ | 540 | #define RX_HAL_IS_CCK_RATE(_pdesc)\ |
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c index d0b0d43b9a6d..3f0cb81c424f 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c | |||
@@ -656,7 +656,7 @@ void rtl92cu_tx_fill_cmddesc(struct ieee80211_hw *hw, | |||
656 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data); | 656 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data); |
657 | __le16 fc = hdr->frame_control; | 657 | __le16 fc = hdr->frame_control; |
658 | 658 | ||
659 | memset((void *)pdesc, 0, RTL_TX_HEADER_SIZE); | 659 | memset(pdesc, 0, RTL_TX_HEADER_SIZE); |
660 | if (firstseg) | 660 | if (firstseg) |
661 | SET_TX_DESC_OFFSET(pdesc, RTL_TX_HEADER_SIZE); | 661 | SET_TX_DESC_OFFSET(pdesc, RTL_TX_HEADER_SIZE); |
662 | SET_TX_DESC_TX_RATE(pdesc, DESC92C_RATE1M); | 662 | SET_TX_DESC_TX_RATE(pdesc, DESC92C_RATE1M); |
diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h index 07db95ff9bc5..2713efe07ce5 100644 --- a/drivers/net/wireless/rtlwifi/wifi.h +++ b/drivers/net/wireless/rtlwifi/wifi.h | |||
@@ -766,7 +766,7 @@ struct rtl_rfkill { | |||
766 | #define IQK_MATRIX_REG_NUM 8 | 766 | #define IQK_MATRIX_REG_NUM 8 |
767 | #define IQK_MATRIX_SETTINGS_NUM (1 + 24 + 21) | 767 | #define IQK_MATRIX_SETTINGS_NUM (1 + 24 + 21) |
768 | struct iqk_matrix_regs { | 768 | struct iqk_matrix_regs { |
769 | bool b_iqk_done; | 769 | bool iqk_done; |
770 | long value[1][IQK_MATRIX_REG_NUM]; | 770 | long value[1][IQK_MATRIX_REG_NUM]; |
771 | }; | 771 | }; |
772 | 772 | ||
@@ -1621,19 +1621,19 @@ struct bt_coexist_info { | |||
1621 | u32 bt_edca_ul; | 1621 | u32 bt_edca_ul; |
1622 | u32 bt_edca_dl; | 1622 | u32 bt_edca_dl; |
1623 | 1623 | ||
1624 | bool b_init_set; | 1624 | bool init_set; |
1625 | bool b_bt_busy_traffic; | 1625 | bool bt_busy_traffic; |
1626 | bool b_bt_traffic_mode_set; | 1626 | bool bt_traffic_mode_set; |
1627 | bool b_bt_non_traffic_mode_set; | 1627 | bool bt_non_traffic_mode_set; |
1628 | 1628 | ||
1629 | bool b_fw_coexist_all_off; | 1629 | bool fw_coexist_all_off; |
1630 | bool b_sw_coexist_all_off; | 1630 | bool sw_coexist_all_off; |
1631 | u32 current_state; | 1631 | u32 current_state; |
1632 | u32 previous_state; | 1632 | u32 previous_state; |
1633 | u8 bt_pre_rssi_state; | 1633 | u8 bt_pre_rssi_state; |
1634 | 1634 | ||
1635 | u8 b_reg_bt_iso; | 1635 | u8 reg_bt_iso; |
1636 | u8 b_reg_bt_sco; | 1636 | u8 reg_bt_sco; |
1637 | 1637 | ||
1638 | }; | 1638 | }; |
1639 | 1639 | ||
diff --git a/drivers/net/wireless/wl1251/cmd.h b/drivers/net/wireless/wl1251/cmd.h index e5c74c631374..79ca5273c9e9 100644 --- a/drivers/net/wireless/wl1251/cmd.h +++ b/drivers/net/wireless/wl1251/cmd.h | |||
@@ -313,8 +313,8 @@ struct wl1251_cmd_vbm_update { | |||
313 | } __packed; | 313 | } __packed; |
314 | 314 | ||
315 | enum wl1251_cmd_ps_mode { | 315 | enum wl1251_cmd_ps_mode { |
316 | STATION_ACTIVE_MODE, | 316 | CHIP_ACTIVE_MODE, |
317 | STATION_POWER_SAVE_MODE | 317 | CHIP_POWER_SAVE_MODE |
318 | }; | 318 | }; |
319 | 319 | ||
320 | struct wl1251_cmd_ps_params { | 320 | struct wl1251_cmd_ps_params { |
diff --git a/drivers/net/wireless/wl1251/event.c b/drivers/net/wireless/wl1251/event.c index dfc4579acb06..9f15ccaf8f05 100644 --- a/drivers/net/wireless/wl1251/event.c +++ b/drivers/net/wireless/wl1251/event.c | |||
@@ -68,14 +68,16 @@ static int wl1251_event_process(struct wl1251 *wl, struct event_mailbox *mbox) | |||
68 | if (vector & BSS_LOSE_EVENT_ID) { | 68 | if (vector & BSS_LOSE_EVENT_ID) { |
69 | wl1251_debug(DEBUG_EVENT, "BSS_LOSE_EVENT"); | 69 | wl1251_debug(DEBUG_EVENT, "BSS_LOSE_EVENT"); |
70 | 70 | ||
71 | if (wl->psm_requested && wl->psm) { | 71 | if (wl->psm_requested && |
72 | wl->station_mode != STATION_ACTIVE_MODE) { | ||
72 | ret = wl1251_ps_set_mode(wl, STATION_ACTIVE_MODE); | 73 | ret = wl1251_ps_set_mode(wl, STATION_ACTIVE_MODE); |
73 | if (ret < 0) | 74 | if (ret < 0) |
74 | return ret; | 75 | return ret; |
75 | } | 76 | } |
76 | } | 77 | } |
77 | 78 | ||
78 | if (vector & SYNCHRONIZATION_TIMEOUT_EVENT_ID && wl->psm) { | 79 | if (vector & SYNCHRONIZATION_TIMEOUT_EVENT_ID && |
80 | wl->station_mode != STATION_ACTIVE_MODE) { | ||
79 | wl1251_debug(DEBUG_EVENT, "SYNCHRONIZATION_TIMEOUT_EVENT"); | 81 | wl1251_debug(DEBUG_EVENT, "SYNCHRONIZATION_TIMEOUT_EVENT"); |
80 | 82 | ||
81 | /* indicate to the stack, that beacons have been lost */ | 83 | /* indicate to the stack, that beacons have been lost */ |
diff --git a/drivers/net/wireless/wl1251/main.c b/drivers/net/wireless/wl1251/main.c index 12c9e635a6d6..a14a48c99cdc 100644 --- a/drivers/net/wireless/wl1251/main.c +++ b/drivers/net/wireless/wl1251/main.c | |||
@@ -497,7 +497,7 @@ static void wl1251_op_stop(struct ieee80211_hw *hw) | |||
497 | wl->rx_last_id = 0; | 497 | wl->rx_last_id = 0; |
498 | wl->next_tx_complete = 0; | 498 | wl->next_tx_complete = 0; |
499 | wl->elp = false; | 499 | wl->elp = false; |
500 | wl->psm = 0; | 500 | wl->station_mode = STATION_ACTIVE_MODE; |
501 | wl->tx_queue_stopped = false; | 501 | wl->tx_queue_stopped = false; |
502 | wl->power_level = WL1251_DEFAULT_POWER_LEVEL; | 502 | wl->power_level = WL1251_DEFAULT_POWER_LEVEL; |
503 | wl->rssi_thold = 0; | 503 | wl->rssi_thold = 0; |
@@ -632,13 +632,29 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed) | |||
632 | 632 | ||
633 | wl->psm_requested = false; | 633 | wl->psm_requested = false; |
634 | 634 | ||
635 | if (wl->psm) { | 635 | if (wl->station_mode != STATION_ACTIVE_MODE) { |
636 | ret = wl1251_ps_set_mode(wl, STATION_ACTIVE_MODE); | 636 | ret = wl1251_ps_set_mode(wl, STATION_ACTIVE_MODE); |
637 | if (ret < 0) | 637 | if (ret < 0) |
638 | goto out_sleep; | 638 | goto out_sleep; |
639 | } | 639 | } |
640 | } | 640 | } |
641 | 641 | ||
642 | if (changed & IEEE80211_CONF_CHANGE_IDLE) { | ||
643 | if (conf->flags & IEEE80211_CONF_IDLE) { | ||
644 | ret = wl1251_ps_set_mode(wl, STATION_IDLE); | ||
645 | if (ret < 0) | ||
646 | goto out_sleep; | ||
647 | } else { | ||
648 | ret = wl1251_ps_set_mode(wl, STATION_ACTIVE_MODE); | ||
649 | if (ret < 0) | ||
650 | goto out_sleep; | ||
651 | ret = wl1251_join(wl, wl->bss_type, wl->channel, | ||
652 | wl->beacon_int, wl->dtim_period); | ||
653 | if (ret < 0) | ||
654 | goto out_sleep; | ||
655 | } | ||
656 | } | ||
657 | |||
642 | if (conf->power_level != wl->power_level) { | 658 | if (conf->power_level != wl->power_level) { |
643 | ret = wl1251_acx_tx_power(wl, conf->power_level); | 659 | ret = wl1251_acx_tx_power(wl, conf->power_level); |
644 | if (ret < 0) | 660 | if (ret < 0) |
@@ -1384,7 +1400,7 @@ struct ieee80211_hw *wl1251_alloc_hw(void) | |||
1384 | wl->rx_config = WL1251_DEFAULT_RX_CONFIG; | 1400 | wl->rx_config = WL1251_DEFAULT_RX_CONFIG; |
1385 | wl->rx_filter = WL1251_DEFAULT_RX_FILTER; | 1401 | wl->rx_filter = WL1251_DEFAULT_RX_FILTER; |
1386 | wl->elp = false; | 1402 | wl->elp = false; |
1387 | wl->psm = 0; | 1403 | wl->station_mode = STATION_ACTIVE_MODE; |
1388 | wl->psm_requested = false; | 1404 | wl->psm_requested = false; |
1389 | wl->tx_queue_stopped = false; | 1405 | wl->tx_queue_stopped = false; |
1390 | wl->power_level = WL1251_DEFAULT_POWER_LEVEL; | 1406 | wl->power_level = WL1251_DEFAULT_POWER_LEVEL; |
diff --git a/drivers/net/wireless/wl1251/ps.c b/drivers/net/wireless/wl1251/ps.c index 9cc514703d2a..db719f7d2692 100644 --- a/drivers/net/wireless/wl1251/ps.c +++ b/drivers/net/wireless/wl1251/ps.c | |||
@@ -39,7 +39,7 @@ void wl1251_elp_work(struct work_struct *work) | |||
39 | 39 | ||
40 | mutex_lock(&wl->mutex); | 40 | mutex_lock(&wl->mutex); |
41 | 41 | ||
42 | if (wl->elp || !wl->psm) | 42 | if (wl->elp || wl->station_mode == STATION_ACTIVE_MODE) |
43 | goto out; | 43 | goto out; |
44 | 44 | ||
45 | wl1251_debug(DEBUG_PSM, "chip to elp"); | 45 | wl1251_debug(DEBUG_PSM, "chip to elp"); |
@@ -57,7 +57,7 @@ void wl1251_ps_elp_sleep(struct wl1251 *wl) | |||
57 | { | 57 | { |
58 | unsigned long delay; | 58 | unsigned long delay; |
59 | 59 | ||
60 | if (wl->psm) { | 60 | if (wl->station_mode != STATION_ACTIVE_MODE) { |
61 | delay = msecs_to_jiffies(ELP_ENTRY_DELAY); | 61 | delay = msecs_to_jiffies(ELP_ENTRY_DELAY); |
62 | ieee80211_queue_delayed_work(wl->hw, &wl->elp_work, delay); | 62 | ieee80211_queue_delayed_work(wl->hw, &wl->elp_work, delay); |
63 | } | 63 | } |
@@ -104,7 +104,7 @@ int wl1251_ps_elp_wakeup(struct wl1251 *wl) | |||
104 | return 0; | 104 | return 0; |
105 | } | 105 | } |
106 | 106 | ||
107 | int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode) | 107 | int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_station_mode mode) |
108 | { | 108 | { |
109 | int ret; | 109 | int ret; |
110 | 110 | ||
@@ -128,15 +128,24 @@ int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode) | |||
128 | if (ret < 0) | 128 | if (ret < 0) |
129 | return ret; | 129 | return ret; |
130 | 130 | ||
131 | ret = wl1251_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE); | 131 | ret = wl1251_cmd_ps_mode(wl, CHIP_POWER_SAVE_MODE); |
132 | if (ret < 0) | 132 | if (ret < 0) |
133 | return ret; | 133 | return ret; |
134 | 134 | ||
135 | ret = wl1251_acx_sleep_auth(wl, WL1251_PSM_ELP); | 135 | ret = wl1251_acx_sleep_auth(wl, WL1251_PSM_ELP); |
136 | if (ret < 0) | 136 | if (ret < 0) |
137 | return ret; | 137 | return ret; |
138 | break; | ||
139 | case STATION_IDLE: | ||
140 | wl1251_debug(DEBUG_PSM, "entering idle"); | ||
138 | 141 | ||
139 | wl->psm = 1; | 142 | ret = wl1251_acx_sleep_auth(wl, WL1251_PSM_ELP); |
143 | if (ret < 0) | ||
144 | return ret; | ||
145 | |||
146 | ret = wl1251_cmd_template_set(wl, CMD_DISCONNECT, NULL, 0); | ||
147 | if (ret < 0) | ||
148 | return ret; | ||
140 | break; | 149 | break; |
141 | case STATION_ACTIVE_MODE: | 150 | case STATION_ACTIVE_MODE: |
142 | default: | 151 | default: |
@@ -163,13 +172,13 @@ int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode) | |||
163 | if (ret < 0) | 172 | if (ret < 0) |
164 | return ret; | 173 | return ret; |
165 | 174 | ||
166 | ret = wl1251_cmd_ps_mode(wl, STATION_ACTIVE_MODE); | 175 | ret = wl1251_cmd_ps_mode(wl, CHIP_ACTIVE_MODE); |
167 | if (ret < 0) | 176 | if (ret < 0) |
168 | return ret; | 177 | return ret; |
169 | 178 | ||
170 | wl->psm = 0; | ||
171 | break; | 179 | break; |
172 | } | 180 | } |
181 | wl->station_mode = mode; | ||
173 | 182 | ||
174 | return ret; | 183 | return ret; |
175 | } | 184 | } |
diff --git a/drivers/net/wireless/wl1251/ps.h b/drivers/net/wireless/wl1251/ps.h index 55c3dda75e69..75efad246d67 100644 --- a/drivers/net/wireless/wl1251/ps.h +++ b/drivers/net/wireless/wl1251/ps.h | |||
@@ -26,7 +26,7 @@ | |||
26 | #include "wl1251.h" | 26 | #include "wl1251.h" |
27 | #include "acx.h" | 27 | #include "acx.h" |
28 | 28 | ||
29 | int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode); | 29 | int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_station_mode mode); |
30 | void wl1251_ps_elp_sleep(struct wl1251 *wl); | 30 | void wl1251_ps_elp_sleep(struct wl1251 *wl); |
31 | int wl1251_ps_elp_wakeup(struct wl1251 *wl); | 31 | int wl1251_ps_elp_wakeup(struct wl1251 *wl); |
32 | void wl1251_elp_work(struct work_struct *work); | 32 | void wl1251_elp_work(struct work_struct *work); |
diff --git a/drivers/net/wireless/wl1251/wl1251.h b/drivers/net/wireless/wl1251/wl1251.h index bb23cd522b22..a77f1bbbed0a 100644 --- a/drivers/net/wireless/wl1251/wl1251.h +++ b/drivers/net/wireless/wl1251/wl1251.h | |||
@@ -129,6 +129,12 @@ enum wl1251_partition_type { | |||
129 | PART_TABLE_LEN | 129 | PART_TABLE_LEN |
130 | }; | 130 | }; |
131 | 131 | ||
132 | enum wl1251_station_mode { | ||
133 | STATION_ACTIVE_MODE, | ||
134 | STATION_POWER_SAVE_MODE, | ||
135 | STATION_IDLE, | ||
136 | }; | ||
137 | |||
132 | struct wl1251_partition { | 138 | struct wl1251_partition { |
133 | u32 size; | 139 | u32 size; |
134 | u32 start; | 140 | u32 start; |
@@ -358,8 +364,7 @@ struct wl1251 { | |||
358 | 364 | ||
359 | struct delayed_work elp_work; | 365 | struct delayed_work elp_work; |
360 | 366 | ||
361 | /* we can be in psm, but not in elp, we have to differentiate */ | 367 | enum wl1251_station_mode station_mode; |
362 | bool psm; | ||
363 | 368 | ||
364 | /* PSM mode requested */ | 369 | /* PSM mode requested */ |
365 | bool psm_requested; | 370 | bool psm_requested; |
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c index a73a305d3cba..ff306d763e37 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.c +++ b/drivers/net/wireless/zd1211rw/zd_chip.c | |||
@@ -557,7 +557,7 @@ int zd_chip_unlock_phy_regs(struct zd_chip *chip) | |||
557 | return r; | 557 | return r; |
558 | } | 558 | } |
559 | 559 | ||
560 | /* CR157 can be optionally patched by the EEPROM for original ZD1211 */ | 560 | /* ZD_CR157 can be optionally patched by the EEPROM for original ZD1211 */ |
561 | static int patch_cr157(struct zd_chip *chip) | 561 | static int patch_cr157(struct zd_chip *chip) |
562 | { | 562 | { |
563 | int r; | 563 | int r; |
@@ -571,7 +571,7 @@ static int patch_cr157(struct zd_chip *chip) | |||
571 | return r; | 571 | return r; |
572 | 572 | ||
573 | dev_dbg_f(zd_chip_dev(chip), "patching value %x\n", value >> 8); | 573 | dev_dbg_f(zd_chip_dev(chip), "patching value %x\n", value >> 8); |
574 | return zd_iowrite32_locked(chip, value >> 8, CR157); | 574 | return zd_iowrite32_locked(chip, value >> 8, ZD_CR157); |
575 | } | 575 | } |
576 | 576 | ||
577 | /* | 577 | /* |
@@ -593,8 +593,8 @@ static int patch_6m_band_edge(struct zd_chip *chip, u8 channel) | |||
593 | int zd_chip_generic_patch_6m_band(struct zd_chip *chip, int channel) | 593 | int zd_chip_generic_patch_6m_band(struct zd_chip *chip, int channel) |
594 | { | 594 | { |
595 | struct zd_ioreq16 ioreqs[] = { | 595 | struct zd_ioreq16 ioreqs[] = { |
596 | { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 }, | 596 | { ZD_CR128, 0x14 }, { ZD_CR129, 0x12 }, { ZD_CR130, 0x10 }, |
597 | { CR47, 0x1e }, | 597 | { ZD_CR47, 0x1e }, |
598 | }; | 598 | }; |
599 | 599 | ||
600 | /* FIXME: Channel 11 is not the edge for all regulatory domains. */ | 600 | /* FIXME: Channel 11 is not the edge for all regulatory domains. */ |
@@ -608,69 +608,69 @@ int zd_chip_generic_patch_6m_band(struct zd_chip *chip, int channel) | |||
608 | static int zd1211_hw_reset_phy(struct zd_chip *chip) | 608 | static int zd1211_hw_reset_phy(struct zd_chip *chip) |
609 | { | 609 | { |
610 | static const struct zd_ioreq16 ioreqs[] = { | 610 | static const struct zd_ioreq16 ioreqs[] = { |
611 | { CR0, 0x0a }, { CR1, 0x06 }, { CR2, 0x26 }, | 611 | { ZD_CR0, 0x0a }, { ZD_CR1, 0x06 }, { ZD_CR2, 0x26 }, |
612 | { CR3, 0x38 }, { CR4, 0x80 }, { CR9, 0xa0 }, | 612 | { ZD_CR3, 0x38 }, { ZD_CR4, 0x80 }, { ZD_CR9, 0xa0 }, |
613 | { CR10, 0x81 }, { CR11, 0x00 }, { CR12, 0x7f }, | 613 | { ZD_CR10, 0x81 }, { ZD_CR11, 0x00 }, { ZD_CR12, 0x7f }, |
614 | { CR13, 0x8c }, { CR14, 0x80 }, { CR15, 0x3d }, | 614 | { ZD_CR13, 0x8c }, { ZD_CR14, 0x80 }, { ZD_CR15, 0x3d }, |
615 | { CR16, 0x20 }, { CR17, 0x1e }, { CR18, 0x0a }, | 615 | { ZD_CR16, 0x20 }, { ZD_CR17, 0x1e }, { ZD_CR18, 0x0a }, |
616 | { CR19, 0x48 }, { CR20, 0x0c }, { CR21, 0x0c }, | 616 | { ZD_CR19, 0x48 }, { ZD_CR20, 0x0c }, { ZD_CR21, 0x0c }, |
617 | { CR22, 0x23 }, { CR23, 0x90 }, { CR24, 0x14 }, | 617 | { ZD_CR22, 0x23 }, { ZD_CR23, 0x90 }, { ZD_CR24, 0x14 }, |
618 | { CR25, 0x40 }, { CR26, 0x10 }, { CR27, 0x19 }, | 618 | { ZD_CR25, 0x40 }, { ZD_CR26, 0x10 }, { ZD_CR27, 0x19 }, |
619 | { CR28, 0x7f }, { CR29, 0x80 }, { CR30, 0x4b }, | 619 | { ZD_CR28, 0x7f }, { ZD_CR29, 0x80 }, { ZD_CR30, 0x4b }, |
620 | { CR31, 0x60 }, { CR32, 0x43 }, { CR33, 0x08 }, | 620 | { ZD_CR31, 0x60 }, { ZD_CR32, 0x43 }, { ZD_CR33, 0x08 }, |
621 | { CR34, 0x06 }, { CR35, 0x0a }, { CR36, 0x00 }, | 621 | { ZD_CR34, 0x06 }, { ZD_CR35, 0x0a }, { ZD_CR36, 0x00 }, |
622 | { CR37, 0x00 }, { CR38, 0x38 }, { CR39, 0x0c }, | 622 | { ZD_CR37, 0x00 }, { ZD_CR38, 0x38 }, { ZD_CR39, 0x0c }, |
623 | { CR40, 0x84 }, { CR41, 0x2a }, { CR42, 0x80 }, | 623 | { ZD_CR40, 0x84 }, { ZD_CR41, 0x2a }, { ZD_CR42, 0x80 }, |
624 | { CR43, 0x10 }, { CR44, 0x12 }, { CR46, 0xff }, | 624 | { ZD_CR43, 0x10 }, { ZD_CR44, 0x12 }, { ZD_CR46, 0xff }, |
625 | { CR47, 0x1E }, { CR48, 0x26 }, { CR49, 0x5b }, | 625 | { ZD_CR47, 0x1E }, { ZD_CR48, 0x26 }, { ZD_CR49, 0x5b }, |
626 | { CR64, 0xd0 }, { CR65, 0x04 }, { CR66, 0x58 }, | 626 | { ZD_CR64, 0xd0 }, { ZD_CR65, 0x04 }, { ZD_CR66, 0x58 }, |
627 | { CR67, 0xc9 }, { CR68, 0x88 }, { CR69, 0x41 }, | 627 | { ZD_CR67, 0xc9 }, { ZD_CR68, 0x88 }, { ZD_CR69, 0x41 }, |
628 | { CR70, 0x23 }, { CR71, 0x10 }, { CR72, 0xff }, | 628 | { ZD_CR70, 0x23 }, { ZD_CR71, 0x10 }, { ZD_CR72, 0xff }, |
629 | { CR73, 0x32 }, { CR74, 0x30 }, { CR75, 0x65 }, | 629 | { ZD_CR73, 0x32 }, { ZD_CR74, 0x30 }, { ZD_CR75, 0x65 }, |
630 | { CR76, 0x41 }, { CR77, 0x1b }, { CR78, 0x30 }, | 630 | { ZD_CR76, 0x41 }, { ZD_CR77, 0x1b }, { ZD_CR78, 0x30 }, |
631 | { CR79, 0x68 }, { CR80, 0x64 }, { CR81, 0x64 }, | 631 | { ZD_CR79, 0x68 }, { ZD_CR80, 0x64 }, { ZD_CR81, 0x64 }, |
632 | { CR82, 0x00 }, { CR83, 0x00 }, { CR84, 0x00 }, | 632 | { ZD_CR82, 0x00 }, { ZD_CR83, 0x00 }, { ZD_CR84, 0x00 }, |
633 | { CR85, 0x02 }, { CR86, 0x00 }, { CR87, 0x00 }, | 633 | { ZD_CR85, 0x02 }, { ZD_CR86, 0x00 }, { ZD_CR87, 0x00 }, |
634 | { CR88, 0xff }, { CR89, 0xfc }, { CR90, 0x00 }, | 634 | { ZD_CR88, 0xff }, { ZD_CR89, 0xfc }, { ZD_CR90, 0x00 }, |
635 | { CR91, 0x00 }, { CR92, 0x00 }, { CR93, 0x08 }, | 635 | { ZD_CR91, 0x00 }, { ZD_CR92, 0x00 }, { ZD_CR93, 0x08 }, |
636 | { CR94, 0x00 }, { CR95, 0x00 }, { CR96, 0xff }, | 636 | { ZD_CR94, 0x00 }, { ZD_CR95, 0x00 }, { ZD_CR96, 0xff }, |
637 | { CR97, 0xe7 }, { CR98, 0x00 }, { CR99, 0x00 }, | 637 | { ZD_CR97, 0xe7 }, { ZD_CR98, 0x00 }, { ZD_CR99, 0x00 }, |
638 | { CR100, 0x00 }, { CR101, 0xae }, { CR102, 0x02 }, | 638 | { ZD_CR100, 0x00 }, { ZD_CR101, 0xae }, { ZD_CR102, 0x02 }, |
639 | { CR103, 0x00 }, { CR104, 0x03 }, { CR105, 0x65 }, | 639 | { ZD_CR103, 0x00 }, { ZD_CR104, 0x03 }, { ZD_CR105, 0x65 }, |
640 | { CR106, 0x04 }, { CR107, 0x00 }, { CR108, 0x0a }, | 640 | { ZD_CR106, 0x04 }, { ZD_CR107, 0x00 }, { ZD_CR108, 0x0a }, |
641 | { CR109, 0xaa }, { CR110, 0xaa }, { CR111, 0x25 }, | 641 | { ZD_CR109, 0xaa }, { ZD_CR110, 0xaa }, { ZD_CR111, 0x25 }, |
642 | { CR112, 0x25 }, { CR113, 0x00 }, { CR119, 0x1e }, | 642 | { ZD_CR112, 0x25 }, { ZD_CR113, 0x00 }, { ZD_CR119, 0x1e }, |
643 | { CR125, 0x90 }, { CR126, 0x00 }, { CR127, 0x00 }, | 643 | { ZD_CR125, 0x90 }, { ZD_CR126, 0x00 }, { ZD_CR127, 0x00 }, |
644 | { }, | 644 | { }, |
645 | { CR5, 0x00 }, { CR6, 0x00 }, { CR7, 0x00 }, | 645 | { ZD_CR5, 0x00 }, { ZD_CR6, 0x00 }, { ZD_CR7, 0x00 }, |
646 | { CR8, 0x00 }, { CR9, 0x20 }, { CR12, 0xf0 }, | 646 | { ZD_CR8, 0x00 }, { ZD_CR9, 0x20 }, { ZD_CR12, 0xf0 }, |
647 | { CR20, 0x0e }, { CR21, 0x0e }, { CR27, 0x10 }, | 647 | { ZD_CR20, 0x0e }, { ZD_CR21, 0x0e }, { ZD_CR27, 0x10 }, |
648 | { CR44, 0x33 }, { CR47, 0x1E }, { CR83, 0x24 }, | 648 | { ZD_CR44, 0x33 }, { ZD_CR47, 0x1E }, { ZD_CR83, 0x24 }, |
649 | { CR84, 0x04 }, { CR85, 0x00 }, { CR86, 0x0C }, | 649 | { ZD_CR84, 0x04 }, { ZD_CR85, 0x00 }, { ZD_CR86, 0x0C }, |
650 | { CR87, 0x12 }, { CR88, 0x0C }, { CR89, 0x00 }, | 650 | { ZD_CR87, 0x12 }, { ZD_CR88, 0x0C }, { ZD_CR89, 0x00 }, |
651 | { CR90, 0x10 }, { CR91, 0x08 }, { CR93, 0x00 }, | 651 | { ZD_CR90, 0x10 }, { ZD_CR91, 0x08 }, { ZD_CR93, 0x00 }, |
652 | { CR94, 0x01 }, { CR95, 0x00 }, { CR96, 0x50 }, | 652 | { ZD_CR94, 0x01 }, { ZD_CR95, 0x00 }, { ZD_CR96, 0x50 }, |
653 | { CR97, 0x37 }, { CR98, 0x35 }, { CR101, 0x13 }, | 653 | { ZD_CR97, 0x37 }, { ZD_CR98, 0x35 }, { ZD_CR101, 0x13 }, |
654 | { CR102, 0x27 }, { CR103, 0x27 }, { CR104, 0x18 }, | 654 | { ZD_CR102, 0x27 }, { ZD_CR103, 0x27 }, { ZD_CR104, 0x18 }, |
655 | { CR105, 0x12 }, { CR109, 0x27 }, { CR110, 0x27 }, | 655 | { ZD_CR105, 0x12 }, { ZD_CR109, 0x27 }, { ZD_CR110, 0x27 }, |
656 | { CR111, 0x27 }, { CR112, 0x27 }, { CR113, 0x27 }, | 656 | { ZD_CR111, 0x27 }, { ZD_CR112, 0x27 }, { ZD_CR113, 0x27 }, |
657 | { CR114, 0x27 }, { CR115, 0x26 }, { CR116, 0x24 }, | 657 | { ZD_CR114, 0x27 }, { ZD_CR115, 0x26 }, { ZD_CR116, 0x24 }, |
658 | { CR117, 0xfc }, { CR118, 0xfa }, { CR120, 0x4f }, | 658 | { ZD_CR117, 0xfc }, { ZD_CR118, 0xfa }, { ZD_CR120, 0x4f }, |
659 | { CR125, 0xaa }, { CR127, 0x03 }, { CR128, 0x14 }, | 659 | { ZD_CR125, 0xaa }, { ZD_CR127, 0x03 }, { ZD_CR128, 0x14 }, |
660 | { CR129, 0x12 }, { CR130, 0x10 }, { CR131, 0x0C }, | 660 | { ZD_CR129, 0x12 }, { ZD_CR130, 0x10 }, { ZD_CR131, 0x0C }, |
661 | { CR136, 0xdf }, { CR137, 0x40 }, { CR138, 0xa0 }, | 661 | { ZD_CR136, 0xdf }, { ZD_CR137, 0x40 }, { ZD_CR138, 0xa0 }, |
662 | { CR139, 0xb0 }, { CR140, 0x99 }, { CR141, 0x82 }, | 662 | { ZD_CR139, 0xb0 }, { ZD_CR140, 0x99 }, { ZD_CR141, 0x82 }, |
663 | { CR142, 0x54 }, { CR143, 0x1c }, { CR144, 0x6c }, | 663 | { ZD_CR142, 0x54 }, { ZD_CR143, 0x1c }, { ZD_CR144, 0x6c }, |
664 | { CR147, 0x07 }, { CR148, 0x4c }, { CR149, 0x50 }, | 664 | { ZD_CR147, 0x07 }, { ZD_CR148, 0x4c }, { ZD_CR149, 0x50 }, |
665 | { CR150, 0x0e }, { CR151, 0x18 }, { CR160, 0xfe }, | 665 | { ZD_CR150, 0x0e }, { ZD_CR151, 0x18 }, { ZD_CR160, 0xfe }, |
666 | { CR161, 0xee }, { CR162, 0xaa }, { CR163, 0xfa }, | 666 | { ZD_CR161, 0xee }, { ZD_CR162, 0xaa }, { ZD_CR163, 0xfa }, |
667 | { CR164, 0xfa }, { CR165, 0xea }, { CR166, 0xbe }, | 667 | { ZD_CR164, 0xfa }, { ZD_CR165, 0xea }, { ZD_CR166, 0xbe }, |
668 | { CR167, 0xbe }, { CR168, 0x6a }, { CR169, 0xba }, | 668 | { ZD_CR167, 0xbe }, { ZD_CR168, 0x6a }, { ZD_CR169, 0xba }, |
669 | { CR170, 0xba }, { CR171, 0xba }, | 669 | { ZD_CR170, 0xba }, { ZD_CR171, 0xba }, |
670 | /* Note: CR204 must lead the CR203 */ | 670 | /* Note: ZD_CR204 must lead the ZD_CR203 */ |
671 | { CR204, 0x7d }, | 671 | { ZD_CR204, 0x7d }, |
672 | { }, | 672 | { }, |
673 | { CR203, 0x30 }, | 673 | { ZD_CR203, 0x30 }, |
674 | }; | 674 | }; |
675 | 675 | ||
676 | int r, t; | 676 | int r, t; |
@@ -697,62 +697,62 @@ out: | |||
697 | static int zd1211b_hw_reset_phy(struct zd_chip *chip) | 697 | static int zd1211b_hw_reset_phy(struct zd_chip *chip) |
698 | { | 698 | { |
699 | static const struct zd_ioreq16 ioreqs[] = { | 699 | static const struct zd_ioreq16 ioreqs[] = { |
700 | { CR0, 0x14 }, { CR1, 0x06 }, { CR2, 0x26 }, | 700 | { ZD_CR0, 0x14 }, { ZD_CR1, 0x06 }, { ZD_CR2, 0x26 }, |
701 | { CR3, 0x38 }, { CR4, 0x80 }, { CR9, 0xe0 }, | 701 | { ZD_CR3, 0x38 }, { ZD_CR4, 0x80 }, { ZD_CR9, 0xe0 }, |
702 | { CR10, 0x81 }, | 702 | { ZD_CR10, 0x81 }, |
703 | /* power control { { CR11, 1 << 6 }, */ | 703 | /* power control { { ZD_CR11, 1 << 6 }, */ |
704 | { CR11, 0x00 }, | 704 | { ZD_CR11, 0x00 }, |
705 | { CR12, 0xf0 }, { CR13, 0x8c }, { CR14, 0x80 }, | 705 | { ZD_CR12, 0xf0 }, { ZD_CR13, 0x8c }, { ZD_CR14, 0x80 }, |
706 | { CR15, 0x3d }, { CR16, 0x20 }, { CR17, 0x1e }, | 706 | { ZD_CR15, 0x3d }, { ZD_CR16, 0x20 }, { ZD_CR17, 0x1e }, |
707 | { CR18, 0x0a }, { CR19, 0x48 }, | 707 | { ZD_CR18, 0x0a }, { ZD_CR19, 0x48 }, |
708 | { CR20, 0x10 }, /* Org:0x0E, ComTrend:RalLink AP */ | 708 | { ZD_CR20, 0x10 }, /* Org:0x0E, ComTrend:RalLink AP */ |
709 | { CR21, 0x0e }, { CR22, 0x23 }, { CR23, 0x90 }, | 709 | { ZD_CR21, 0x0e }, { ZD_CR22, 0x23 }, { ZD_CR23, 0x90 }, |
710 | { CR24, 0x14 }, { CR25, 0x40 }, { CR26, 0x10 }, | 710 | { ZD_CR24, 0x14 }, { ZD_CR25, 0x40 }, { ZD_CR26, 0x10 }, |
711 | { CR27, 0x10 }, { CR28, 0x7f }, { CR29, 0x80 }, | 711 | { ZD_CR27, 0x10 }, { ZD_CR28, 0x7f }, { ZD_CR29, 0x80 }, |
712 | { CR30, 0x4b }, /* ASIC/FWT, no jointly decoder */ | 712 | { ZD_CR30, 0x4b }, /* ASIC/FWT, no jointly decoder */ |
713 | { CR31, 0x60 }, { CR32, 0x43 }, { CR33, 0x08 }, | 713 | { ZD_CR31, 0x60 }, { ZD_CR32, 0x43 }, { ZD_CR33, 0x08 }, |
714 | { CR34, 0x06 }, { CR35, 0x0a }, { CR36, 0x00 }, | 714 | { ZD_CR34, 0x06 }, { ZD_CR35, 0x0a }, { ZD_CR36, 0x00 }, |
715 | { CR37, 0x00 }, { CR38, 0x38 }, { CR39, 0x0c }, | 715 | { ZD_CR37, 0x00 }, { ZD_CR38, 0x38 }, { ZD_CR39, 0x0c }, |
716 | { CR40, 0x84 }, { CR41, 0x2a }, { CR42, 0x80 }, | 716 | { ZD_CR40, 0x84 }, { ZD_CR41, 0x2a }, { ZD_CR42, 0x80 }, |
717 | { CR43, 0x10 }, { CR44, 0x33 }, { CR46, 0xff }, | 717 | { ZD_CR43, 0x10 }, { ZD_CR44, 0x33 }, { ZD_CR46, 0xff }, |
718 | { CR47, 0x1E }, { CR48, 0x26 }, { CR49, 0x5b }, | 718 | { ZD_CR47, 0x1E }, { ZD_CR48, 0x26 }, { ZD_CR49, 0x5b }, |
719 | { CR64, 0xd0 }, { CR65, 0x04 }, { CR66, 0x58 }, | 719 | { ZD_CR64, 0xd0 }, { ZD_CR65, 0x04 }, { ZD_CR66, 0x58 }, |
720 | { CR67, 0xc9 }, { CR68, 0x88 }, { CR69, 0x41 }, | 720 | { ZD_CR67, 0xc9 }, { ZD_CR68, 0x88 }, { ZD_CR69, 0x41 }, |
721 | { CR70, 0x23 }, { CR71, 0x10 }, { CR72, 0xff }, | 721 | { ZD_CR70, 0x23 }, { ZD_CR71, 0x10 }, { ZD_CR72, 0xff }, |
722 | { CR73, 0x32 }, { CR74, 0x30 }, { CR75, 0x65 }, | 722 | { ZD_CR73, 0x32 }, { ZD_CR74, 0x30 }, { ZD_CR75, 0x65 }, |
723 | { CR76, 0x41 }, { CR77, 0x1b }, { CR78, 0x30 }, | 723 | { ZD_CR76, 0x41 }, { ZD_CR77, 0x1b }, { ZD_CR78, 0x30 }, |
724 | { CR79, 0xf0 }, { CR80, 0x64 }, { CR81, 0x64 }, | 724 | { ZD_CR79, 0xf0 }, { ZD_CR80, 0x64 }, { ZD_CR81, 0x64 }, |
725 | { CR82, 0x00 }, { CR83, 0x24 }, { CR84, 0x04 }, | 725 | { ZD_CR82, 0x00 }, { ZD_CR83, 0x24 }, { ZD_CR84, 0x04 }, |
726 | { CR85, 0x00 }, { CR86, 0x0c }, { CR87, 0x12 }, | 726 | { ZD_CR85, 0x00 }, { ZD_CR86, 0x0c }, { ZD_CR87, 0x12 }, |
727 | { CR88, 0x0c }, { CR89, 0x00 }, { CR90, 0x58 }, | 727 | { ZD_CR88, 0x0c }, { ZD_CR89, 0x00 }, { ZD_CR90, 0x58 }, |
728 | { CR91, 0x04 }, { CR92, 0x00 }, { CR93, 0x00 }, | 728 | { ZD_CR91, 0x04 }, { ZD_CR92, 0x00 }, { ZD_CR93, 0x00 }, |
729 | { CR94, 0x01 }, | 729 | { ZD_CR94, 0x01 }, |
730 | { CR95, 0x20 }, /* ZD1211B */ | 730 | { ZD_CR95, 0x20 }, /* ZD1211B */ |
731 | { CR96, 0x50 }, { CR97, 0x37 }, { CR98, 0x35 }, | 731 | { ZD_CR96, 0x50 }, { ZD_CR97, 0x37 }, { ZD_CR98, 0x35 }, |
732 | { CR99, 0x00 }, { CR100, 0x01 }, { CR101, 0x13 }, | 732 | { ZD_CR99, 0x00 }, { ZD_CR100, 0x01 }, { ZD_CR101, 0x13 }, |
733 | { CR102, 0x27 }, { CR103, 0x27 }, { CR104, 0x18 }, | 733 | { ZD_CR102, 0x27 }, { ZD_CR103, 0x27 }, { ZD_CR104, 0x18 }, |
734 | { CR105, 0x12 }, { CR106, 0x04 }, { CR107, 0x00 }, | 734 | { ZD_CR105, 0x12 }, { ZD_CR106, 0x04 }, { ZD_CR107, 0x00 }, |
735 | { CR108, 0x0a }, { CR109, 0x27 }, { CR110, 0x27 }, | 735 | { ZD_CR108, 0x0a }, { ZD_CR109, 0x27 }, { ZD_CR110, 0x27 }, |
736 | { CR111, 0x27 }, { CR112, 0x27 }, { CR113, 0x27 }, | 736 | { ZD_CR111, 0x27 }, { ZD_CR112, 0x27 }, { ZD_CR113, 0x27 }, |
737 | { CR114, 0x27 }, { CR115, 0x26 }, { CR116, 0x24 }, | 737 | { ZD_CR114, 0x27 }, { ZD_CR115, 0x26 }, { ZD_CR116, 0x24 }, |
738 | { CR117, 0xfc }, { CR118, 0xfa }, { CR119, 0x1e }, | 738 | { ZD_CR117, 0xfc }, { ZD_CR118, 0xfa }, { ZD_CR119, 0x1e }, |
739 | { CR125, 0x90 }, { CR126, 0x00 }, { CR127, 0x00 }, | 739 | { ZD_CR125, 0x90 }, { ZD_CR126, 0x00 }, { ZD_CR127, 0x00 }, |
740 | { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 }, | 740 | { ZD_CR128, 0x14 }, { ZD_CR129, 0x12 }, { ZD_CR130, 0x10 }, |
741 | { CR131, 0x0c }, { CR136, 0xdf }, { CR137, 0xa0 }, | 741 | { ZD_CR131, 0x0c }, { ZD_CR136, 0xdf }, { ZD_CR137, 0xa0 }, |
742 | { CR138, 0xa8 }, { CR139, 0xb4 }, { CR140, 0x98 }, | 742 | { ZD_CR138, 0xa8 }, { ZD_CR139, 0xb4 }, { ZD_CR140, 0x98 }, |
743 | { CR141, 0x82 }, { CR142, 0x53 }, { CR143, 0x1c }, | 743 | { ZD_CR141, 0x82 }, { ZD_CR142, 0x53 }, { ZD_CR143, 0x1c }, |
744 | { CR144, 0x6c }, { CR147, 0x07 }, { CR148, 0x40 }, | 744 | { ZD_CR144, 0x6c }, { ZD_CR147, 0x07 }, { ZD_CR148, 0x40 }, |
745 | { CR149, 0x40 }, /* Org:0x50 ComTrend:RalLink AP */ | 745 | { ZD_CR149, 0x40 }, /* Org:0x50 ComTrend:RalLink AP */ |
746 | { CR150, 0x14 }, /* Org:0x0E ComTrend:RalLink AP */ | 746 | { ZD_CR150, 0x14 }, /* Org:0x0E ComTrend:RalLink AP */ |
747 | { CR151, 0x18 }, { CR159, 0x70 }, { CR160, 0xfe }, | 747 | { ZD_CR151, 0x18 }, { ZD_CR159, 0x70 }, { ZD_CR160, 0xfe }, |
748 | { CR161, 0xee }, { CR162, 0xaa }, { CR163, 0xfa }, | 748 | { ZD_CR161, 0xee }, { ZD_CR162, 0xaa }, { ZD_CR163, 0xfa }, |
749 | { CR164, 0xfa }, { CR165, 0xea }, { CR166, 0xbe }, | 749 | { ZD_CR164, 0xfa }, { ZD_CR165, 0xea }, { ZD_CR166, 0xbe }, |
750 | { CR167, 0xbe }, { CR168, 0x6a }, { CR169, 0xba }, | 750 | { ZD_CR167, 0xbe }, { ZD_CR168, 0x6a }, { ZD_CR169, 0xba }, |
751 | { CR170, 0xba }, { CR171, 0xba }, | 751 | { ZD_CR170, 0xba }, { ZD_CR171, 0xba }, |
752 | /* Note: CR204 must lead the CR203 */ | 752 | /* Note: ZD_CR204 must lead the ZD_CR203 */ |
753 | { CR204, 0x7d }, | 753 | { ZD_CR204, 0x7d }, |
754 | {}, | 754 | {}, |
755 | { CR203, 0x30 }, | 755 | { ZD_CR203, 0x30 }, |
756 | }; | 756 | }; |
757 | 757 | ||
758 | int r, t; | 758 | int r, t; |
@@ -1200,24 +1200,24 @@ out: | |||
1200 | static int update_pwr_int(struct zd_chip *chip, u8 channel) | 1200 | static int update_pwr_int(struct zd_chip *chip, u8 channel) |
1201 | { | 1201 | { |
1202 | u8 value = chip->pwr_int_values[channel - 1]; | 1202 | u8 value = chip->pwr_int_values[channel - 1]; |
1203 | return zd_iowrite16_locked(chip, value, CR31); | 1203 | return zd_iowrite16_locked(chip, value, ZD_CR31); |
1204 | } | 1204 | } |
1205 | 1205 | ||
1206 | static int update_pwr_cal(struct zd_chip *chip, u8 channel) | 1206 | static int update_pwr_cal(struct zd_chip *chip, u8 channel) |
1207 | { | 1207 | { |
1208 | u8 value = chip->pwr_cal_values[channel-1]; | 1208 | u8 value = chip->pwr_cal_values[channel-1]; |
1209 | return zd_iowrite16_locked(chip, value, CR68); | 1209 | return zd_iowrite16_locked(chip, value, ZD_CR68); |
1210 | } | 1210 | } |
1211 | 1211 | ||
1212 | static int update_ofdm_cal(struct zd_chip *chip, u8 channel) | 1212 | static int update_ofdm_cal(struct zd_chip *chip, u8 channel) |
1213 | { | 1213 | { |
1214 | struct zd_ioreq16 ioreqs[3]; | 1214 | struct zd_ioreq16 ioreqs[3]; |
1215 | 1215 | ||
1216 | ioreqs[0].addr = CR67; | 1216 | ioreqs[0].addr = ZD_CR67; |
1217 | ioreqs[0].value = chip->ofdm_cal_values[OFDM_36M_INDEX][channel-1]; | 1217 | ioreqs[0].value = chip->ofdm_cal_values[OFDM_36M_INDEX][channel-1]; |
1218 | ioreqs[1].addr = CR66; | 1218 | ioreqs[1].addr = ZD_CR66; |
1219 | ioreqs[1].value = chip->ofdm_cal_values[OFDM_48M_INDEX][channel-1]; | 1219 | ioreqs[1].value = chip->ofdm_cal_values[OFDM_48M_INDEX][channel-1]; |
1220 | ioreqs[2].addr = CR65; | 1220 | ioreqs[2].addr = ZD_CR65; |
1221 | ioreqs[2].value = chip->ofdm_cal_values[OFDM_54M_INDEX][channel-1]; | 1221 | ioreqs[2].value = chip->ofdm_cal_values[OFDM_54M_INDEX][channel-1]; |
1222 | 1222 | ||
1223 | return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); | 1223 | return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); |
@@ -1236,9 +1236,9 @@ static int update_channel_integration_and_calibration(struct zd_chip *chip, | |||
1236 | return r; | 1236 | return r; |
1237 | if (zd_chip_is_zd1211b(chip)) { | 1237 | if (zd_chip_is_zd1211b(chip)) { |
1238 | static const struct zd_ioreq16 ioreqs[] = { | 1238 | static const struct zd_ioreq16 ioreqs[] = { |
1239 | { CR69, 0x28 }, | 1239 | { ZD_CR69, 0x28 }, |
1240 | {}, | 1240 | {}, |
1241 | { CR69, 0x2a }, | 1241 | { ZD_CR69, 0x2a }, |
1242 | }; | 1242 | }; |
1243 | 1243 | ||
1244 | r = update_ofdm_cal(chip, channel); | 1244 | r = update_ofdm_cal(chip, channel); |
@@ -1269,7 +1269,7 @@ static int patch_cck_gain(struct zd_chip *chip) | |||
1269 | if (r) | 1269 | if (r) |
1270 | return r; | 1270 | return r; |
1271 | dev_dbg_f(zd_chip_dev(chip), "patching value %x\n", value & 0xff); | 1271 | dev_dbg_f(zd_chip_dev(chip), "patching value %x\n", value & 0xff); |
1272 | return zd_iowrite16_locked(chip, value & 0xff, CR47); | 1272 | return zd_iowrite16_locked(chip, value & 0xff, ZD_CR47); |
1273 | } | 1273 | } |
1274 | 1274 | ||
1275 | int zd_chip_set_channel(struct zd_chip *chip, u8 channel) | 1275 | int zd_chip_set_channel(struct zd_chip *chip, u8 channel) |
@@ -1505,9 +1505,9 @@ int zd_rfwritev_locked(struct zd_chip *chip, | |||
1505 | int zd_rfwrite_cr_locked(struct zd_chip *chip, u32 value) | 1505 | int zd_rfwrite_cr_locked(struct zd_chip *chip, u32 value) |
1506 | { | 1506 | { |
1507 | const struct zd_ioreq16 ioreqs[] = { | 1507 | const struct zd_ioreq16 ioreqs[] = { |
1508 | { CR244, (value >> 16) & 0xff }, | 1508 | { ZD_CR244, (value >> 16) & 0xff }, |
1509 | { CR243, (value >> 8) & 0xff }, | 1509 | { ZD_CR243, (value >> 8) & 0xff }, |
1510 | { CR242, value & 0xff }, | 1510 | { ZD_CR242, value & 0xff }, |
1511 | }; | 1511 | }; |
1512 | ZD_ASSERT(mutex_is_locked(&chip->mutex)); | 1512 | ZD_ASSERT(mutex_is_locked(&chip->mutex)); |
1513 | return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); | 1513 | return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); |
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.h b/drivers/net/wireless/zd1211rw/zd_chip.h index 14e4402a6111..4be7c3b5b265 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.h +++ b/drivers/net/wireless/zd1211rw/zd_chip.h | |||
@@ -61,277 +61,288 @@ enum { | |||
61 | #define FWRAW_DATA(offset) ((zd_addr_t)(FW_START + (offset))) | 61 | #define FWRAW_DATA(offset) ((zd_addr_t)(FW_START + (offset))) |
62 | 62 | ||
63 | /* 8-bit hardware registers */ | 63 | /* 8-bit hardware registers */ |
64 | #define CR0 CTL_REG(0x0000) | 64 | #define ZD_CR0 CTL_REG(0x0000) |
65 | #define CR1 CTL_REG(0x0004) | 65 | #define ZD_CR1 CTL_REG(0x0004) |
66 | #define CR2 CTL_REG(0x0008) | 66 | #define ZD_CR2 CTL_REG(0x0008) |
67 | #define CR3 CTL_REG(0x000C) | 67 | #define ZD_CR3 CTL_REG(0x000C) |
68 | 68 | ||
69 | #define CR5 CTL_REG(0x0010) | 69 | #define ZD_CR5 CTL_REG(0x0010) |
70 | /* bit 5: if set short preamble used | 70 | /* bit 5: if set short preamble used |
71 | * bit 6: filter band - Japan channel 14 on, else off | 71 | * bit 6: filter band - Japan channel 14 on, else off |
72 | */ | 72 | */ |
73 | #define CR6 CTL_REG(0x0014) | 73 | #define ZD_CR6 CTL_REG(0x0014) |
74 | #define CR7 CTL_REG(0x0018) | 74 | #define ZD_CR7 CTL_REG(0x0018) |
75 | #define CR8 CTL_REG(0x001C) | 75 | #define ZD_CR8 CTL_REG(0x001C) |
76 | 76 | ||
77 | #define CR4 CTL_REG(0x0020) | 77 | #define ZD_CR4 CTL_REG(0x0020) |
78 | 78 | ||
79 | #define CR9 CTL_REG(0x0024) | 79 | #define ZD_CR9 CTL_REG(0x0024) |
80 | /* bit 2: antenna switch (together with CR10) */ | 80 | /* bit 2: antenna switch (together with ZD_CR10) */ |
81 | #define CR10 CTL_REG(0x0028) | 81 | #define ZD_CR10 CTL_REG(0x0028) |
82 | /* bit 1: antenna switch (together with CR9) | 82 | /* bit 1: antenna switch (together with ZD_CR9) |
83 | * RF2959 controls with CR11 radion on and off | 83 | * RF2959 controls with ZD_CR11 radion on and off |
84 | */ | 84 | */ |
85 | #define CR11 CTL_REG(0x002C) | 85 | #define ZD_CR11 CTL_REG(0x002C) |
86 | /* bit 6: TX power control for OFDM | 86 | /* bit 6: TX power control for OFDM |
87 | * RF2959 controls with CR10 radio on and off | 87 | * RF2959 controls with ZD_CR10 radio on and off |
88 | */ | 88 | */ |
89 | #define CR12 CTL_REG(0x0030) | 89 | #define ZD_CR12 CTL_REG(0x0030) |
90 | #define CR13 CTL_REG(0x0034) | 90 | #define ZD_CR13 CTL_REG(0x0034) |
91 | #define CR14 CTL_REG(0x0038) | 91 | #define ZD_CR14 CTL_REG(0x0038) |
92 | #define CR15 CTL_REG(0x003C) | 92 | #define ZD_CR15 CTL_REG(0x003C) |
93 | #define CR16 CTL_REG(0x0040) | 93 | #define ZD_CR16 CTL_REG(0x0040) |
94 | #define CR17 CTL_REG(0x0044) | 94 | #define ZD_CR17 CTL_REG(0x0044) |
95 | #define CR18 CTL_REG(0x0048) | 95 | #define ZD_CR18 CTL_REG(0x0048) |
96 | #define CR19 CTL_REG(0x004C) | 96 | #define ZD_CR19 CTL_REG(0x004C) |
97 | #define CR20 CTL_REG(0x0050) | 97 | #define ZD_CR20 CTL_REG(0x0050) |
98 | #define CR21 CTL_REG(0x0054) | 98 | #define ZD_CR21 CTL_REG(0x0054) |
99 | #define CR22 CTL_REG(0x0058) | 99 | #define ZD_CR22 CTL_REG(0x0058) |
100 | #define CR23 CTL_REG(0x005C) | 100 | #define ZD_CR23 CTL_REG(0x005C) |
101 | #define CR24 CTL_REG(0x0060) /* CCA threshold */ | 101 | #define ZD_CR24 CTL_REG(0x0060) /* CCA threshold */ |
102 | #define CR25 CTL_REG(0x0064) | 102 | #define ZD_CR25 CTL_REG(0x0064) |
103 | #define CR26 CTL_REG(0x0068) | 103 | #define ZD_CR26 CTL_REG(0x0068) |
104 | #define CR27 CTL_REG(0x006C) | 104 | #define ZD_CR27 CTL_REG(0x006C) |
105 | #define CR28 CTL_REG(0x0070) | 105 | #define ZD_CR28 CTL_REG(0x0070) |
106 | #define CR29 CTL_REG(0x0074) | 106 | #define ZD_CR29 CTL_REG(0x0074) |
107 | #define CR30 CTL_REG(0x0078) | 107 | #define ZD_CR30 CTL_REG(0x0078) |
108 | #define CR31 CTL_REG(0x007C) /* TX power control for RF in CCK mode */ | 108 | #define ZD_CR31 CTL_REG(0x007C) /* TX power control for RF in |
109 | #define CR32 CTL_REG(0x0080) | 109 | * CCK mode |
110 | #define CR33 CTL_REG(0x0084) | 110 | */ |
111 | #define CR34 CTL_REG(0x0088) | 111 | #define ZD_CR32 CTL_REG(0x0080) |
112 | #define CR35 CTL_REG(0x008C) | 112 | #define ZD_CR33 CTL_REG(0x0084) |
113 | #define CR36 CTL_REG(0x0090) | 113 | #define ZD_CR34 CTL_REG(0x0088) |
114 | #define CR37 CTL_REG(0x0094) | 114 | #define ZD_CR35 CTL_REG(0x008C) |
115 | #define CR38 CTL_REG(0x0098) | 115 | #define ZD_CR36 CTL_REG(0x0090) |
116 | #define CR39 CTL_REG(0x009C) | 116 | #define ZD_CR37 CTL_REG(0x0094) |
117 | #define CR40 CTL_REG(0x00A0) | 117 | #define ZD_CR38 CTL_REG(0x0098) |
118 | #define CR41 CTL_REG(0x00A4) | 118 | #define ZD_CR39 CTL_REG(0x009C) |
119 | #define CR42 CTL_REG(0x00A8) | 119 | #define ZD_CR40 CTL_REG(0x00A0) |
120 | #define CR43 CTL_REG(0x00AC) | 120 | #define ZD_CR41 CTL_REG(0x00A4) |
121 | #define CR44 CTL_REG(0x00B0) | 121 | #define ZD_CR42 CTL_REG(0x00A8) |
122 | #define CR45 CTL_REG(0x00B4) | 122 | #define ZD_CR43 CTL_REG(0x00AC) |
123 | #define CR46 CTL_REG(0x00B8) | 123 | #define ZD_CR44 CTL_REG(0x00B0) |
124 | #define CR47 CTL_REG(0x00BC) /* CCK baseband gain | 124 | #define ZD_CR45 CTL_REG(0x00B4) |
125 | * (patch value might be in EEPROM) | 125 | #define ZD_CR46 CTL_REG(0x00B8) |
126 | */ | 126 | #define ZD_CR47 CTL_REG(0x00BC) /* CCK baseband gain |
127 | #define CR48 CTL_REG(0x00C0) | 127 | * (patch value might be in EEPROM) |
128 | #define CR49 CTL_REG(0x00C4) | 128 | */ |
129 | #define CR50 CTL_REG(0x00C8) | 129 | #define ZD_CR48 CTL_REG(0x00C0) |
130 | #define CR51 CTL_REG(0x00CC) /* TX power control for RF in 6-36M modes */ | 130 | #define ZD_CR49 CTL_REG(0x00C4) |
131 | #define CR52 CTL_REG(0x00D0) /* TX power control for RF in 48M mode */ | 131 | #define ZD_CR50 CTL_REG(0x00C8) |
132 | #define CR53 CTL_REG(0x00D4) /* TX power control for RF in 54M mode */ | 132 | #define ZD_CR51 CTL_REG(0x00CC) /* TX power control for RF in |
133 | #define CR54 CTL_REG(0x00D8) | 133 | * 6-36M modes |
134 | #define CR55 CTL_REG(0x00DC) | 134 | */ |
135 | #define CR56 CTL_REG(0x00E0) | 135 | #define ZD_CR52 CTL_REG(0x00D0) /* TX power control for RF in |
136 | #define CR57 CTL_REG(0x00E4) | 136 | * 48M mode |
137 | #define CR58 CTL_REG(0x00E8) | 137 | */ |
138 | #define CR59 CTL_REG(0x00EC) | 138 | #define ZD_CR53 CTL_REG(0x00D4) /* TX power control for RF in |
139 | #define CR60 CTL_REG(0x00F0) | 139 | * 54M mode |
140 | #define CR61 CTL_REG(0x00F4) | 140 | */ |
141 | #define CR62 CTL_REG(0x00F8) | 141 | #define ZD_CR54 CTL_REG(0x00D8) |
142 | #define CR63 CTL_REG(0x00FC) | 142 | #define ZD_CR55 CTL_REG(0x00DC) |
143 | #define CR64 CTL_REG(0x0100) | 143 | #define ZD_CR56 CTL_REG(0x00E0) |
144 | #define CR65 CTL_REG(0x0104) /* OFDM 54M calibration */ | 144 | #define ZD_CR57 CTL_REG(0x00E4) |
145 | #define CR66 CTL_REG(0x0108) /* OFDM 48M calibration */ | 145 | #define ZD_CR58 CTL_REG(0x00E8) |
146 | #define CR67 CTL_REG(0x010C) /* OFDM 36M calibration */ | 146 | #define ZD_CR59 CTL_REG(0x00EC) |
147 | #define CR68 CTL_REG(0x0110) /* CCK calibration */ | 147 | #define ZD_CR60 CTL_REG(0x00F0) |
148 | #define CR69 CTL_REG(0x0114) | 148 | #define ZD_CR61 CTL_REG(0x00F4) |
149 | #define CR70 CTL_REG(0x0118) | 149 | #define ZD_CR62 CTL_REG(0x00F8) |
150 | #define CR71 CTL_REG(0x011C) | 150 | #define ZD_CR63 CTL_REG(0x00FC) |
151 | #define CR72 CTL_REG(0x0120) | 151 | #define ZD_CR64 CTL_REG(0x0100) |
152 | #define CR73 CTL_REG(0x0124) | 152 | #define ZD_CR65 CTL_REG(0x0104) /* OFDM 54M calibration */ |
153 | #define CR74 CTL_REG(0x0128) | 153 | #define ZD_CR66 CTL_REG(0x0108) /* OFDM 48M calibration */ |
154 | #define CR75 CTL_REG(0x012C) | 154 | #define ZD_CR67 CTL_REG(0x010C) /* OFDM 36M calibration */ |
155 | #define CR76 CTL_REG(0x0130) | 155 | #define ZD_CR68 CTL_REG(0x0110) /* CCK calibration */ |
156 | #define CR77 CTL_REG(0x0134) | 156 | #define ZD_CR69 CTL_REG(0x0114) |
157 | #define CR78 CTL_REG(0x0138) | 157 | #define ZD_CR70 CTL_REG(0x0118) |
158 | #define CR79 CTL_REG(0x013C) | 158 | #define ZD_CR71 CTL_REG(0x011C) |
159 | #define CR80 CTL_REG(0x0140) | 159 | #define ZD_CR72 CTL_REG(0x0120) |
160 | #define CR81 CTL_REG(0x0144) | 160 | #define ZD_CR73 CTL_REG(0x0124) |
161 | #define CR82 CTL_REG(0x0148) | 161 | #define ZD_CR74 CTL_REG(0x0128) |
162 | #define CR83 CTL_REG(0x014C) | 162 | #define ZD_CR75 CTL_REG(0x012C) |
163 | #define CR84 CTL_REG(0x0150) | 163 | #define ZD_CR76 CTL_REG(0x0130) |
164 | #define CR85 CTL_REG(0x0154) | 164 | #define ZD_CR77 CTL_REG(0x0134) |
165 | #define CR86 CTL_REG(0x0158) | 165 | #define ZD_CR78 CTL_REG(0x0138) |
166 | #define CR87 CTL_REG(0x015C) | 166 | #define ZD_CR79 CTL_REG(0x013C) |
167 | #define CR88 CTL_REG(0x0160) | 167 | #define ZD_CR80 CTL_REG(0x0140) |
168 | #define CR89 CTL_REG(0x0164) | 168 | #define ZD_CR81 CTL_REG(0x0144) |
169 | #define CR90 CTL_REG(0x0168) | 169 | #define ZD_CR82 CTL_REG(0x0148) |
170 | #define CR91 CTL_REG(0x016C) | 170 | #define ZD_CR83 CTL_REG(0x014C) |
171 | #define CR92 CTL_REG(0x0170) | 171 | #define ZD_CR84 CTL_REG(0x0150) |
172 | #define CR93 CTL_REG(0x0174) | 172 | #define ZD_CR85 CTL_REG(0x0154) |
173 | #define CR94 CTL_REG(0x0178) | 173 | #define ZD_CR86 CTL_REG(0x0158) |
174 | #define CR95 CTL_REG(0x017C) | 174 | #define ZD_CR87 CTL_REG(0x015C) |
175 | #define CR96 CTL_REG(0x0180) | 175 | #define ZD_CR88 CTL_REG(0x0160) |
176 | #define CR97 CTL_REG(0x0184) | 176 | #define ZD_CR89 CTL_REG(0x0164) |
177 | #define CR98 CTL_REG(0x0188) | 177 | #define ZD_CR90 CTL_REG(0x0168) |
178 | #define CR99 CTL_REG(0x018C) | 178 | #define ZD_CR91 CTL_REG(0x016C) |
179 | #define CR100 CTL_REG(0x0190) | 179 | #define ZD_CR92 CTL_REG(0x0170) |
180 | #define CR101 CTL_REG(0x0194) | 180 | #define ZD_CR93 CTL_REG(0x0174) |
181 | #define CR102 CTL_REG(0x0198) | 181 | #define ZD_CR94 CTL_REG(0x0178) |
182 | #define CR103 CTL_REG(0x019C) | 182 | #define ZD_CR95 CTL_REG(0x017C) |
183 | #define CR104 CTL_REG(0x01A0) | 183 | #define ZD_CR96 CTL_REG(0x0180) |
184 | #define CR105 CTL_REG(0x01A4) | 184 | #define ZD_CR97 CTL_REG(0x0184) |
185 | #define CR106 CTL_REG(0x01A8) | 185 | #define ZD_CR98 CTL_REG(0x0188) |
186 | #define CR107 CTL_REG(0x01AC) | 186 | #define ZD_CR99 CTL_REG(0x018C) |
187 | #define CR108 CTL_REG(0x01B0) | 187 | #define ZD_CR100 CTL_REG(0x0190) |
188 | #define CR109 CTL_REG(0x01B4) | 188 | #define ZD_CR101 CTL_REG(0x0194) |
189 | #define CR110 CTL_REG(0x01B8) | 189 | #define ZD_CR102 CTL_REG(0x0198) |
190 | #define CR111 CTL_REG(0x01BC) | 190 | #define ZD_CR103 CTL_REG(0x019C) |
191 | #define CR112 CTL_REG(0x01C0) | 191 | #define ZD_CR104 CTL_REG(0x01A0) |
192 | #define CR113 CTL_REG(0x01C4) | 192 | #define ZD_CR105 CTL_REG(0x01A4) |
193 | #define CR114 CTL_REG(0x01C8) | 193 | #define ZD_CR106 CTL_REG(0x01A8) |
194 | #define CR115 CTL_REG(0x01CC) | 194 | #define ZD_CR107 CTL_REG(0x01AC) |
195 | #define CR116 CTL_REG(0x01D0) | 195 | #define ZD_CR108 CTL_REG(0x01B0) |
196 | #define CR117 CTL_REG(0x01D4) | 196 | #define ZD_CR109 CTL_REG(0x01B4) |
197 | #define CR118 CTL_REG(0x01D8) | 197 | #define ZD_CR110 CTL_REG(0x01B8) |
198 | #define CR119 CTL_REG(0x01DC) | 198 | #define ZD_CR111 CTL_REG(0x01BC) |
199 | #define CR120 CTL_REG(0x01E0) | 199 | #define ZD_CR112 CTL_REG(0x01C0) |
200 | #define CR121 CTL_REG(0x01E4) | 200 | #define ZD_CR113 CTL_REG(0x01C4) |
201 | #define CR122 CTL_REG(0x01E8) | 201 | #define ZD_CR114 CTL_REG(0x01C8) |
202 | #define CR123 CTL_REG(0x01EC) | 202 | #define ZD_CR115 CTL_REG(0x01CC) |
203 | #define CR124 CTL_REG(0x01F0) | 203 | #define ZD_CR116 CTL_REG(0x01D0) |
204 | #define CR125 CTL_REG(0x01F4) | 204 | #define ZD_CR117 CTL_REG(0x01D4) |
205 | #define CR126 CTL_REG(0x01F8) | 205 | #define ZD_CR118 CTL_REG(0x01D8) |
206 | #define CR127 CTL_REG(0x01FC) | 206 | #define ZD_CR119 CTL_REG(0x01DC) |
207 | #define CR128 CTL_REG(0x0200) | 207 | #define ZD_CR120 CTL_REG(0x01E0) |
208 | #define CR129 CTL_REG(0x0204) | 208 | #define ZD_CR121 CTL_REG(0x01E4) |
209 | #define CR130 CTL_REG(0x0208) | 209 | #define ZD_CR122 CTL_REG(0x01E8) |
210 | #define CR131 CTL_REG(0x020C) | 210 | #define ZD_CR123 CTL_REG(0x01EC) |
211 | #define CR132 CTL_REG(0x0210) | 211 | #define ZD_CR124 CTL_REG(0x01F0) |
212 | #define CR133 CTL_REG(0x0214) | 212 | #define ZD_CR125 CTL_REG(0x01F4) |
213 | #define CR134 CTL_REG(0x0218) | 213 | #define ZD_CR126 CTL_REG(0x01F8) |
214 | #define CR135 CTL_REG(0x021C) | 214 | #define ZD_CR127 CTL_REG(0x01FC) |
215 | #define CR136 CTL_REG(0x0220) | 215 | #define ZD_CR128 CTL_REG(0x0200) |
216 | #define CR137 CTL_REG(0x0224) | 216 | #define ZD_CR129 CTL_REG(0x0204) |
217 | #define CR138 CTL_REG(0x0228) | 217 | #define ZD_CR130 CTL_REG(0x0208) |
218 | #define CR139 CTL_REG(0x022C) | 218 | #define ZD_CR131 CTL_REG(0x020C) |
219 | #define CR140 CTL_REG(0x0230) | 219 | #define ZD_CR132 CTL_REG(0x0210) |
220 | #define CR141 CTL_REG(0x0234) | 220 | #define ZD_CR133 CTL_REG(0x0214) |
221 | #define CR142 CTL_REG(0x0238) | 221 | #define ZD_CR134 CTL_REG(0x0218) |
222 | #define CR143 CTL_REG(0x023C) | 222 | #define ZD_CR135 CTL_REG(0x021C) |
223 | #define CR144 CTL_REG(0x0240) | 223 | #define ZD_CR136 CTL_REG(0x0220) |
224 | #define CR145 CTL_REG(0x0244) | 224 | #define ZD_CR137 CTL_REG(0x0224) |
225 | #define CR146 CTL_REG(0x0248) | 225 | #define ZD_CR138 CTL_REG(0x0228) |
226 | #define CR147 CTL_REG(0x024C) | 226 | #define ZD_CR139 CTL_REG(0x022C) |
227 | #define CR148 CTL_REG(0x0250) | 227 | #define ZD_CR140 CTL_REG(0x0230) |
228 | #define CR149 CTL_REG(0x0254) | 228 | #define ZD_CR141 CTL_REG(0x0234) |
229 | #define CR150 CTL_REG(0x0258) | 229 | #define ZD_CR142 CTL_REG(0x0238) |
230 | #define CR151 CTL_REG(0x025C) | 230 | #define ZD_CR143 CTL_REG(0x023C) |
231 | #define CR152 CTL_REG(0x0260) | 231 | #define ZD_CR144 CTL_REG(0x0240) |
232 | #define CR153 CTL_REG(0x0264) | 232 | #define ZD_CR145 CTL_REG(0x0244) |
233 | #define CR154 CTL_REG(0x0268) | 233 | #define ZD_CR146 CTL_REG(0x0248) |
234 | #define CR155 CTL_REG(0x026C) | 234 | #define ZD_CR147 CTL_REG(0x024C) |
235 | #define CR156 CTL_REG(0x0270) | 235 | #define ZD_CR148 CTL_REG(0x0250) |
236 | #define CR157 CTL_REG(0x0274) | 236 | #define ZD_CR149 CTL_REG(0x0254) |
237 | #define CR158 CTL_REG(0x0278) | 237 | #define ZD_CR150 CTL_REG(0x0258) |
238 | #define CR159 CTL_REG(0x027C) | 238 | #define ZD_CR151 CTL_REG(0x025C) |
239 | #define CR160 CTL_REG(0x0280) | 239 | #define ZD_CR152 CTL_REG(0x0260) |
240 | #define CR161 CTL_REG(0x0284) | 240 | #define ZD_CR153 CTL_REG(0x0264) |
241 | #define CR162 CTL_REG(0x0288) | 241 | #define ZD_CR154 CTL_REG(0x0268) |
242 | #define CR163 CTL_REG(0x028C) | 242 | #define ZD_CR155 CTL_REG(0x026C) |
243 | #define CR164 CTL_REG(0x0290) | 243 | #define ZD_CR156 CTL_REG(0x0270) |
244 | #define CR165 CTL_REG(0x0294) | 244 | #define ZD_CR157 CTL_REG(0x0274) |
245 | #define CR166 CTL_REG(0x0298) | 245 | #define ZD_CR158 CTL_REG(0x0278) |
246 | #define CR167 CTL_REG(0x029C) | 246 | #define ZD_CR159 CTL_REG(0x027C) |
247 | #define CR168 CTL_REG(0x02A0) | 247 | #define ZD_CR160 CTL_REG(0x0280) |
248 | #define CR169 CTL_REG(0x02A4) | 248 | #define ZD_CR161 CTL_REG(0x0284) |
249 | #define CR170 CTL_REG(0x02A8) | 249 | #define ZD_CR162 CTL_REG(0x0288) |
250 | #define CR171 CTL_REG(0x02AC) | 250 | #define ZD_CR163 CTL_REG(0x028C) |
251 | #define CR172 CTL_REG(0x02B0) | 251 | #define ZD_CR164 CTL_REG(0x0290) |
252 | #define CR173 CTL_REG(0x02B4) | 252 | #define ZD_CR165 CTL_REG(0x0294) |
253 | #define CR174 CTL_REG(0x02B8) | 253 | #define ZD_CR166 CTL_REG(0x0298) |
254 | #define CR175 CTL_REG(0x02BC) | 254 | #define ZD_CR167 CTL_REG(0x029C) |
255 | #define CR176 CTL_REG(0x02C0) | 255 | #define ZD_CR168 CTL_REG(0x02A0) |
256 | #define CR177 CTL_REG(0x02C4) | 256 | #define ZD_CR169 CTL_REG(0x02A4) |
257 | #define CR178 CTL_REG(0x02C8) | 257 | #define ZD_CR170 CTL_REG(0x02A8) |
258 | #define CR179 CTL_REG(0x02CC) | 258 | #define ZD_CR171 CTL_REG(0x02AC) |
259 | #define CR180 CTL_REG(0x02D0) | 259 | #define ZD_CR172 CTL_REG(0x02B0) |
260 | #define CR181 CTL_REG(0x02D4) | 260 | #define ZD_CR173 CTL_REG(0x02B4) |
261 | #define CR182 CTL_REG(0x02D8) | 261 | #define ZD_CR174 CTL_REG(0x02B8) |
262 | #define CR183 CTL_REG(0x02DC) | 262 | #define ZD_CR175 CTL_REG(0x02BC) |
263 | #define CR184 CTL_REG(0x02E0) | 263 | #define ZD_CR176 CTL_REG(0x02C0) |
264 | #define CR185 CTL_REG(0x02E4) | 264 | #define ZD_CR177 CTL_REG(0x02C4) |
265 | #define CR186 CTL_REG(0x02E8) | 265 | #define ZD_CR178 CTL_REG(0x02C8) |
266 | #define CR187 CTL_REG(0x02EC) | 266 | #define ZD_CR179 CTL_REG(0x02CC) |
267 | #define CR188 CTL_REG(0x02F0) | 267 | #define ZD_CR180 CTL_REG(0x02D0) |
268 | #define CR189 CTL_REG(0x02F4) | 268 | #define ZD_CR181 CTL_REG(0x02D4) |
269 | #define CR190 CTL_REG(0x02F8) | 269 | #define ZD_CR182 CTL_REG(0x02D8) |
270 | #define CR191 CTL_REG(0x02FC) | 270 | #define ZD_CR183 CTL_REG(0x02DC) |
271 | #define CR192 CTL_REG(0x0300) | 271 | #define ZD_CR184 CTL_REG(0x02E0) |
272 | #define CR193 CTL_REG(0x0304) | 272 | #define ZD_CR185 CTL_REG(0x02E4) |
273 | #define CR194 CTL_REG(0x0308) | 273 | #define ZD_CR186 CTL_REG(0x02E8) |
274 | #define CR195 CTL_REG(0x030C) | 274 | #define ZD_CR187 CTL_REG(0x02EC) |
275 | #define CR196 CTL_REG(0x0310) | 275 | #define ZD_CR188 CTL_REG(0x02F0) |
276 | #define CR197 CTL_REG(0x0314) | 276 | #define ZD_CR189 CTL_REG(0x02F4) |
277 | #define CR198 CTL_REG(0x0318) | 277 | #define ZD_CR190 CTL_REG(0x02F8) |
278 | #define CR199 CTL_REG(0x031C) | 278 | #define ZD_CR191 CTL_REG(0x02FC) |
279 | #define CR200 CTL_REG(0x0320) | 279 | #define ZD_CR192 CTL_REG(0x0300) |
280 | #define CR201 CTL_REG(0x0324) | 280 | #define ZD_CR193 CTL_REG(0x0304) |
281 | #define CR202 CTL_REG(0x0328) | 281 | #define ZD_CR194 CTL_REG(0x0308) |
282 | #define CR203 CTL_REG(0x032C) /* I2C bus template value & flash control */ | 282 | #define ZD_CR195 CTL_REG(0x030C) |
283 | #define CR204 CTL_REG(0x0330) | 283 | #define ZD_CR196 CTL_REG(0x0310) |
284 | #define CR205 CTL_REG(0x0334) | 284 | #define ZD_CR197 CTL_REG(0x0314) |
285 | #define CR206 CTL_REG(0x0338) | 285 | #define ZD_CR198 CTL_REG(0x0318) |
286 | #define CR207 CTL_REG(0x033C) | 286 | #define ZD_CR199 CTL_REG(0x031C) |
287 | #define CR208 CTL_REG(0x0340) | 287 | #define ZD_CR200 CTL_REG(0x0320) |
288 | #define CR209 CTL_REG(0x0344) | 288 | #define ZD_CR201 CTL_REG(0x0324) |
289 | #define CR210 CTL_REG(0x0348) | 289 | #define ZD_CR202 CTL_REG(0x0328) |
290 | #define CR211 CTL_REG(0x034C) | 290 | #define ZD_CR203 CTL_REG(0x032C) /* I2C bus template value & flash |
291 | #define CR212 CTL_REG(0x0350) | 291 | * control |
292 | #define CR213 CTL_REG(0x0354) | 292 | */ |
293 | #define CR214 CTL_REG(0x0358) | 293 | #define ZD_CR204 CTL_REG(0x0330) |
294 | #define CR215 CTL_REG(0x035C) | 294 | #define ZD_CR205 CTL_REG(0x0334) |
295 | #define CR216 CTL_REG(0x0360) | 295 | #define ZD_CR206 CTL_REG(0x0338) |
296 | #define CR217 CTL_REG(0x0364) | 296 | #define ZD_CR207 CTL_REG(0x033C) |
297 | #define CR218 CTL_REG(0x0368) | 297 | #define ZD_CR208 CTL_REG(0x0340) |
298 | #define CR219 CTL_REG(0x036C) | 298 | #define ZD_CR209 CTL_REG(0x0344) |
299 | #define CR220 CTL_REG(0x0370) | 299 | #define ZD_CR210 CTL_REG(0x0348) |
300 | #define CR221 CTL_REG(0x0374) | 300 | #define ZD_CR211 CTL_REG(0x034C) |
301 | #define CR222 CTL_REG(0x0378) | 301 | #define ZD_CR212 CTL_REG(0x0350) |
302 | #define CR223 CTL_REG(0x037C) | 302 | #define ZD_CR213 CTL_REG(0x0354) |
303 | #define CR224 CTL_REG(0x0380) | 303 | #define ZD_CR214 CTL_REG(0x0358) |
304 | #define CR225 CTL_REG(0x0384) | 304 | #define ZD_CR215 CTL_REG(0x035C) |
305 | #define CR226 CTL_REG(0x0388) | 305 | #define ZD_CR216 CTL_REG(0x0360) |
306 | #define CR227 CTL_REG(0x038C) | 306 | #define ZD_CR217 CTL_REG(0x0364) |
307 | #define CR228 CTL_REG(0x0390) | 307 | #define ZD_CR218 CTL_REG(0x0368) |
308 | #define CR229 CTL_REG(0x0394) | 308 | #define ZD_CR219 CTL_REG(0x036C) |
309 | #define CR230 CTL_REG(0x0398) | 309 | #define ZD_CR220 CTL_REG(0x0370) |
310 | #define CR231 CTL_REG(0x039C) | 310 | #define ZD_CR221 CTL_REG(0x0374) |
311 | #define CR232 CTL_REG(0x03A0) | 311 | #define ZD_CR222 CTL_REG(0x0378) |
312 | #define CR233 CTL_REG(0x03A4) | 312 | #define ZD_CR223 CTL_REG(0x037C) |
313 | #define CR234 CTL_REG(0x03A8) | 313 | #define ZD_CR224 CTL_REG(0x0380) |
314 | #define CR235 CTL_REG(0x03AC) | 314 | #define ZD_CR225 CTL_REG(0x0384) |
315 | #define CR236 CTL_REG(0x03B0) | 315 | #define ZD_CR226 CTL_REG(0x0388) |
316 | 316 | #define ZD_CR227 CTL_REG(0x038C) | |
317 | #define CR240 CTL_REG(0x03C0) | 317 | #define ZD_CR228 CTL_REG(0x0390) |
318 | /* bit 7: host-controlled RF register writes | 318 | #define ZD_CR229 CTL_REG(0x0394) |
319 | * CR241-CR245: for hardware controlled writing of RF bits, not needed for | 319 | #define ZD_CR230 CTL_REG(0x0398) |
320 | * USB | 320 | #define ZD_CR231 CTL_REG(0x039C) |
321 | #define ZD_CR232 CTL_REG(0x03A0) | ||
322 | #define ZD_CR233 CTL_REG(0x03A4) | ||
323 | #define ZD_CR234 CTL_REG(0x03A8) | ||
324 | #define ZD_CR235 CTL_REG(0x03AC) | ||
325 | #define ZD_CR236 CTL_REG(0x03B0) | ||
326 | |||
327 | #define ZD_CR240 CTL_REG(0x03C0) | ||
328 | /* bit 7: host-controlled RF register writes | ||
329 | * ZD_CR241-ZD_CR245: for hardware controlled writing of RF bits, not needed for | ||
330 | * USB | ||
321 | */ | 331 | */ |
322 | #define CR241 CTL_REG(0x03C4) | 332 | #define ZD_CR241 CTL_REG(0x03C4) |
323 | #define CR242 CTL_REG(0x03C8) | 333 | #define ZD_CR242 CTL_REG(0x03C8) |
324 | #define CR243 CTL_REG(0x03CC) | 334 | #define ZD_CR243 CTL_REG(0x03CC) |
325 | #define CR244 CTL_REG(0x03D0) | 335 | #define ZD_CR244 CTL_REG(0x03D0) |
326 | #define CR245 CTL_REG(0x03D4) | 336 | #define ZD_CR245 CTL_REG(0x03D4) |
327 | 337 | ||
328 | #define CR251 CTL_REG(0x03EC) /* only used for activation and deactivation of | 338 | #define ZD_CR251 CTL_REG(0x03EC) /* only used for activation and |
329 | * Airoha RFs AL2230 and AL7230B | 339 | * deactivation of Airoha RFs AL2230 |
330 | */ | 340 | * and AL7230B |
331 | #define CR252 CTL_REG(0x03F0) | 341 | */ |
332 | #define CR253 CTL_REG(0x03F4) | 342 | #define ZD_CR252 CTL_REG(0x03F0) |
333 | #define CR254 CTL_REG(0x03F8) | 343 | #define ZD_CR253 CTL_REG(0x03F4) |
334 | #define CR255 CTL_REG(0x03FC) | 344 | #define ZD_CR254 CTL_REG(0x03F8) |
345 | #define ZD_CR255 CTL_REG(0x03FC) | ||
335 | 346 | ||
336 | #define CR_MAX_PHY_REG 255 | 347 | #define CR_MAX_PHY_REG 255 |
337 | 348 | ||
diff --git a/drivers/net/wireless/zd1211rw/zd_rf.h b/drivers/net/wireless/zd1211rw/zd_rf.h index 79dc1035592d..725b7c99b23d 100644 --- a/drivers/net/wireless/zd1211rw/zd_rf.h +++ b/drivers/net/wireless/zd1211rw/zd_rf.h | |||
@@ -55,7 +55,7 @@ struct zd_rf { | |||
55 | * defaults to 1 (yes) */ | 55 | * defaults to 1 (yes) */ |
56 | u8 update_channel_int:1; | 56 | u8 update_channel_int:1; |
57 | 57 | ||
58 | /* whether CR47 should be patched from the EEPROM, if the appropriate | 58 | /* whether ZD_CR47 should be patched from the EEPROM, if the appropriate |
59 | * flag is set in the POD. The vendor driver suggests that this should | 59 | * flag is set in the POD. The vendor driver suggests that this should |
60 | * be done for all RF's, but a bug in their code prevents but their | 60 | * be done for all RF's, but a bug in their code prevents but their |
61 | * HW_OverWritePhyRegFromE2P() routine from ever taking effect. */ | 61 | * HW_OverWritePhyRegFromE2P() routine from ever taking effect. */ |
diff --git a/drivers/net/wireless/zd1211rw/zd_rf_al2230.c b/drivers/net/wireless/zd1211rw/zd_rf_al2230.c index 74a8f7a55591..12babcb633c3 100644 --- a/drivers/net/wireless/zd1211rw/zd_rf_al2230.c +++ b/drivers/net/wireless/zd1211rw/zd_rf_al2230.c | |||
@@ -61,31 +61,31 @@ static const u32 zd1211b_al2230_table[][3] = { | |||
61 | }; | 61 | }; |
62 | 62 | ||
63 | static const struct zd_ioreq16 zd1211b_ioreqs_shared_1[] = { | 63 | static const struct zd_ioreq16 zd1211b_ioreqs_shared_1[] = { |
64 | { CR240, 0x57 }, { CR9, 0xe0 }, | 64 | { ZD_CR240, 0x57 }, { ZD_CR9, 0xe0 }, |
65 | }; | 65 | }; |
66 | 66 | ||
67 | static const struct zd_ioreq16 ioreqs_init_al2230s[] = { | 67 | static const struct zd_ioreq16 ioreqs_init_al2230s[] = { |
68 | { CR47, 0x1e }, /* MARK_002 */ | 68 | { ZD_CR47, 0x1e }, /* MARK_002 */ |
69 | { CR106, 0x22 }, | 69 | { ZD_CR106, 0x22 }, |
70 | { CR107, 0x2a }, /* MARK_002 */ | 70 | { ZD_CR107, 0x2a }, /* MARK_002 */ |
71 | { CR109, 0x13 }, /* MARK_002 */ | 71 | { ZD_CR109, 0x13 }, /* MARK_002 */ |
72 | { CR118, 0xf8 }, /* MARK_002 */ | 72 | { ZD_CR118, 0xf8 }, /* MARK_002 */ |
73 | { CR119, 0x12 }, { CR122, 0xe0 }, | 73 | { ZD_CR119, 0x12 }, { ZD_CR122, 0xe0 }, |
74 | { CR128, 0x10 }, /* MARK_001 from 0xe->0x10 */ | 74 | { ZD_CR128, 0x10 }, /* MARK_001 from 0xe->0x10 */ |
75 | { CR129, 0x0e }, /* MARK_001 from 0xd->0x0e */ | 75 | { ZD_CR129, 0x0e }, /* MARK_001 from 0xd->0x0e */ |
76 | { CR130, 0x10 }, /* MARK_001 from 0xb->0x0d */ | 76 | { ZD_CR130, 0x10 }, /* MARK_001 from 0xb->0x0d */ |
77 | }; | 77 | }; |
78 | 78 | ||
79 | static int zd1211b_al2230_finalize_rf(struct zd_chip *chip) | 79 | static int zd1211b_al2230_finalize_rf(struct zd_chip *chip) |
80 | { | 80 | { |
81 | int r; | 81 | int r; |
82 | static const struct zd_ioreq16 ioreqs[] = { | 82 | static const struct zd_ioreq16 ioreqs[] = { |
83 | { CR80, 0x30 }, { CR81, 0x30 }, { CR79, 0x58 }, | 83 | { ZD_CR80, 0x30 }, { ZD_CR81, 0x30 }, { ZD_CR79, 0x58 }, |
84 | { CR12, 0xf0 }, { CR77, 0x1b }, { CR78, 0x58 }, | 84 | { ZD_CR12, 0xf0 }, { ZD_CR77, 0x1b }, { ZD_CR78, 0x58 }, |
85 | { CR203, 0x06 }, | 85 | { ZD_CR203, 0x06 }, |
86 | { }, | 86 | { }, |
87 | 87 | ||
88 | { CR240, 0x80 }, | 88 | { ZD_CR240, 0x80 }, |
89 | }; | 89 | }; |
90 | 90 | ||
91 | r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); | 91 | r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); |
@@ -94,12 +94,12 @@ static int zd1211b_al2230_finalize_rf(struct zd_chip *chip) | |||
94 | 94 | ||
95 | /* related to antenna selection? */ | 95 | /* related to antenna selection? */ |
96 | if (chip->new_phy_layout) { | 96 | if (chip->new_phy_layout) { |
97 | r = zd_iowrite16_locked(chip, 0xe1, CR9); | 97 | r = zd_iowrite16_locked(chip, 0xe1, ZD_CR9); |
98 | if (r) | 98 | if (r) |
99 | return r; | 99 | return r; |
100 | } | 100 | } |
101 | 101 | ||
102 | return zd_iowrite16_locked(chip, 0x06, CR203); | 102 | return zd_iowrite16_locked(chip, 0x06, ZD_CR203); |
103 | } | 103 | } |
104 | 104 | ||
105 | static int zd1211_al2230_init_hw(struct zd_rf *rf) | 105 | static int zd1211_al2230_init_hw(struct zd_rf *rf) |
@@ -108,40 +108,40 @@ static int zd1211_al2230_init_hw(struct zd_rf *rf) | |||
108 | struct zd_chip *chip = zd_rf_to_chip(rf); | 108 | struct zd_chip *chip = zd_rf_to_chip(rf); |
109 | 109 | ||
110 | static const struct zd_ioreq16 ioreqs_init[] = { | 110 | static const struct zd_ioreq16 ioreqs_init[] = { |
111 | { CR15, 0x20 }, { CR23, 0x40 }, { CR24, 0x20 }, | 111 | { ZD_CR15, 0x20 }, { ZD_CR23, 0x40 }, { ZD_CR24, 0x20 }, |
112 | { CR26, 0x11 }, { CR28, 0x3e }, { CR29, 0x00 }, | 112 | { ZD_CR26, 0x11 }, { ZD_CR28, 0x3e }, { ZD_CR29, 0x00 }, |
113 | { CR44, 0x33 }, { CR106, 0x2a }, { CR107, 0x1a }, | 113 | { ZD_CR44, 0x33 }, { ZD_CR106, 0x2a }, { ZD_CR107, 0x1a }, |
114 | { CR109, 0x09 }, { CR110, 0x27 }, { CR111, 0x2b }, | 114 | { ZD_CR109, 0x09 }, { ZD_CR110, 0x27 }, { ZD_CR111, 0x2b }, |
115 | { CR112, 0x2b }, { CR119, 0x0a }, { CR10, 0x89 }, | 115 | { ZD_CR112, 0x2b }, { ZD_CR119, 0x0a }, { ZD_CR10, 0x89 }, |
116 | /* for newest (3rd cut) AL2300 */ | 116 | /* for newest (3rd cut) AL2300 */ |
117 | { CR17, 0x28 }, | 117 | { ZD_CR17, 0x28 }, |
118 | { CR26, 0x93 }, { CR34, 0x30 }, | 118 | { ZD_CR26, 0x93 }, { ZD_CR34, 0x30 }, |
119 | /* for newest (3rd cut) AL2300 */ | 119 | /* for newest (3rd cut) AL2300 */ |
120 | { CR35, 0x3e }, | 120 | { ZD_CR35, 0x3e }, |
121 | { CR41, 0x24 }, { CR44, 0x32 }, | 121 | { ZD_CR41, 0x24 }, { ZD_CR44, 0x32 }, |
122 | /* for newest (3rd cut) AL2300 */ | 122 | /* for newest (3rd cut) AL2300 */ |
123 | { CR46, 0x96 }, | 123 | { ZD_CR46, 0x96 }, |
124 | { CR47, 0x1e }, { CR79, 0x58 }, { CR80, 0x30 }, | 124 | { ZD_CR47, 0x1e }, { ZD_CR79, 0x58 }, { ZD_CR80, 0x30 }, |
125 | { CR81, 0x30 }, { CR87, 0x0a }, { CR89, 0x04 }, | 125 | { ZD_CR81, 0x30 }, { ZD_CR87, 0x0a }, { ZD_CR89, 0x04 }, |
126 | { CR92, 0x0a }, { CR99, 0x28 }, { CR100, 0x00 }, | 126 | { ZD_CR92, 0x0a }, { ZD_CR99, 0x28 }, { ZD_CR100, 0x00 }, |
127 | { CR101, 0x13 }, { CR102, 0x27 }, { CR106, 0x24 }, | 127 | { ZD_CR101, 0x13 }, { ZD_CR102, 0x27 }, { ZD_CR106, 0x24 }, |
128 | { CR107, 0x2a }, { CR109, 0x09 }, { CR110, 0x13 }, | 128 | { ZD_CR107, 0x2a }, { ZD_CR109, 0x09 }, { ZD_CR110, 0x13 }, |
129 | { CR111, 0x1f }, { CR112, 0x1f }, { CR113, 0x27 }, | 129 | { ZD_CR111, 0x1f }, { ZD_CR112, 0x1f }, { ZD_CR113, 0x27 }, |
130 | { CR114, 0x27 }, | 130 | { ZD_CR114, 0x27 }, |
131 | /* for newest (3rd cut) AL2300 */ | 131 | /* for newest (3rd cut) AL2300 */ |
132 | { CR115, 0x24 }, | 132 | { ZD_CR115, 0x24 }, |
133 | { CR116, 0x24 }, { CR117, 0xf4 }, { CR118, 0xfc }, | 133 | { ZD_CR116, 0x24 }, { ZD_CR117, 0xf4 }, { ZD_CR118, 0xfc }, |
134 | { CR119, 0x10 }, { CR120, 0x4f }, { CR121, 0x77 }, | 134 | { ZD_CR119, 0x10 }, { ZD_CR120, 0x4f }, { ZD_CR121, 0x77 }, |
135 | { CR122, 0xe0 }, { CR137, 0x88 }, { CR252, 0xff }, | 135 | { ZD_CR122, 0xe0 }, { ZD_CR137, 0x88 }, { ZD_CR252, 0xff }, |
136 | { CR253, 0xff }, | 136 | { ZD_CR253, 0xff }, |
137 | }; | 137 | }; |
138 | 138 | ||
139 | static const struct zd_ioreq16 ioreqs_pll[] = { | 139 | static const struct zd_ioreq16 ioreqs_pll[] = { |
140 | /* shdnb(PLL_ON)=0 */ | 140 | /* shdnb(PLL_ON)=0 */ |
141 | { CR251, 0x2f }, | 141 | { ZD_CR251, 0x2f }, |
142 | /* shdnb(PLL_ON)=1 */ | 142 | /* shdnb(PLL_ON)=1 */ |
143 | { CR251, 0x3f }, | 143 | { ZD_CR251, 0x3f }, |
144 | { CR138, 0x28 }, { CR203, 0x06 }, | 144 | { ZD_CR138, 0x28 }, { ZD_CR203, 0x06 }, |
145 | }; | 145 | }; |
146 | 146 | ||
147 | static const u32 rv1[] = { | 147 | static const u32 rv1[] = { |
@@ -161,7 +161,7 @@ static int zd1211_al2230_init_hw(struct zd_rf *rf) | |||
161 | 0x0805b6, | 161 | 0x0805b6, |
162 | 0x011687, | 162 | 0x011687, |
163 | 0x000688, | 163 | 0x000688, |
164 | 0x0403b9, /* external control TX power (CR31) */ | 164 | 0x0403b9, /* external control TX power (ZD_CR31) */ |
165 | 0x00dbba, | 165 | 0x00dbba, |
166 | 0x00099b, | 166 | 0x00099b, |
167 | 0x0bdffc, | 167 | 0x0bdffc, |
@@ -221,52 +221,54 @@ static int zd1211b_al2230_init_hw(struct zd_rf *rf) | |||
221 | struct zd_chip *chip = zd_rf_to_chip(rf); | 221 | struct zd_chip *chip = zd_rf_to_chip(rf); |
222 | 222 | ||
223 | static const struct zd_ioreq16 ioreqs1[] = { | 223 | static const struct zd_ioreq16 ioreqs1[] = { |
224 | { CR10, 0x89 }, { CR15, 0x20 }, | 224 | { ZD_CR10, 0x89 }, { ZD_CR15, 0x20 }, |
225 | { CR17, 0x2B }, /* for newest(3rd cut) AL2230 */ | 225 | { ZD_CR17, 0x2B }, /* for newest(3rd cut) AL2230 */ |
226 | { CR23, 0x40 }, { CR24, 0x20 }, { CR26, 0x93 }, | 226 | { ZD_CR23, 0x40 }, { ZD_CR24, 0x20 }, { ZD_CR26, 0x93 }, |
227 | { CR28, 0x3e }, { CR29, 0x00 }, | 227 | { ZD_CR28, 0x3e }, { ZD_CR29, 0x00 }, |
228 | { CR33, 0x28 }, /* 5621 */ | 228 | { ZD_CR33, 0x28 }, /* 5621 */ |
229 | { CR34, 0x30 }, | 229 | { ZD_CR34, 0x30 }, |
230 | { CR35, 0x3e }, /* for newest(3rd cut) AL2230 */ | 230 | { ZD_CR35, 0x3e }, /* for newest(3rd cut) AL2230 */ |
231 | { CR41, 0x24 }, { CR44, 0x32 }, | 231 | { ZD_CR41, 0x24 }, { ZD_CR44, 0x32 }, |
232 | { CR46, 0x99 }, /* for newest(3rd cut) AL2230 */ | 232 | { ZD_CR46, 0x99 }, /* for newest(3rd cut) AL2230 */ |
233 | { CR47, 0x1e }, | 233 | { ZD_CR47, 0x1e }, |
234 | 234 | ||
235 | /* ZD1211B 05.06.10 */ | 235 | /* ZD1211B 05.06.10 */ |
236 | { CR48, 0x06 }, { CR49, 0xf9 }, { CR51, 0x01 }, | 236 | { ZD_CR48, 0x06 }, { ZD_CR49, 0xf9 }, { ZD_CR51, 0x01 }, |
237 | { CR52, 0x80 }, { CR53, 0x7e }, { CR65, 0x00 }, | 237 | { ZD_CR52, 0x80 }, { ZD_CR53, 0x7e }, { ZD_CR65, 0x00 }, |
238 | { CR66, 0x00 }, { CR67, 0x00 }, { CR68, 0x00 }, | 238 | { ZD_CR66, 0x00 }, { ZD_CR67, 0x00 }, { ZD_CR68, 0x00 }, |
239 | { CR69, 0x28 }, | 239 | { ZD_CR69, 0x28 }, |
240 | 240 | ||
241 | { CR79, 0x58 }, { CR80, 0x30 }, { CR81, 0x30 }, | 241 | { ZD_CR79, 0x58 }, { ZD_CR80, 0x30 }, { ZD_CR81, 0x30 }, |
242 | { CR87, 0x0a }, { CR89, 0x04 }, | 242 | { ZD_CR87, 0x0a }, { ZD_CR89, 0x04 }, |
243 | { CR91, 0x00 }, /* 5621 */ | 243 | { ZD_CR91, 0x00 }, /* 5621 */ |
244 | { CR92, 0x0a }, | 244 | { ZD_CR92, 0x0a }, |
245 | { CR98, 0x8d }, /* 4804, for 1212 new algorithm */ | 245 | { ZD_CR98, 0x8d }, /* 4804, for 1212 new algorithm */ |
246 | { CR99, 0x00 }, /* 5621 */ | 246 | { ZD_CR99, 0x00 }, /* 5621 */ |
247 | { CR101, 0x13 }, { CR102, 0x27 }, | 247 | { ZD_CR101, 0x13 }, { ZD_CR102, 0x27 }, |
248 | { CR106, 0x24 }, /* for newest(3rd cut) AL2230 */ | 248 | { ZD_CR106, 0x24 }, /* for newest(3rd cut) AL2230 */ |
249 | { CR107, 0x2a }, | 249 | { ZD_CR107, 0x2a }, |
250 | { CR109, 0x13 }, /* 4804, for 1212 new algorithm */ | 250 | { ZD_CR109, 0x13 }, /* 4804, for 1212 new algorithm */ |
251 | { CR110, 0x1f }, /* 4804, for 1212 new algorithm */ | 251 | { ZD_CR110, 0x1f }, /* 4804, for 1212 new algorithm */ |
252 | { CR111, 0x1f }, { CR112, 0x1f }, { CR113, 0x27 }, | 252 | { ZD_CR111, 0x1f }, { ZD_CR112, 0x1f }, { ZD_CR113, 0x27 }, |
253 | { CR114, 0x27 }, | 253 | { ZD_CR114, 0x27 }, |
254 | { CR115, 0x26 }, /* 24->26 at 4902 for newest(3rd cut) AL2230 */ | 254 | { ZD_CR115, 0x26 }, /* 24->26 at 4902 for newest(3rd cut) |
255 | { CR116, 0x24 }, | 255 | * AL2230 |
256 | { CR117, 0xfa }, /* for 1211b */ | 256 | */ |
257 | { CR118, 0xfa }, /* for 1211b */ | 257 | { ZD_CR116, 0x24 }, |
258 | { CR119, 0x10 }, | 258 | { ZD_CR117, 0xfa }, /* for 1211b */ |
259 | { CR120, 0x4f }, | 259 | { ZD_CR118, 0xfa }, /* for 1211b */ |
260 | { CR121, 0x6c }, /* for 1211b */ | 260 | { ZD_CR119, 0x10 }, |
261 | { CR122, 0xfc }, /* E0->FC at 4902 */ | 261 | { ZD_CR120, 0x4f }, |
262 | { CR123, 0x57 }, /* 5623 */ | 262 | { ZD_CR121, 0x6c }, /* for 1211b */ |
263 | { CR125, 0xad }, /* 4804, for 1212 new algorithm */ | 263 | { ZD_CR122, 0xfc }, /* E0->FC at 4902 */ |
264 | { CR126, 0x6c }, /* 5614 */ | 264 | { ZD_CR123, 0x57 }, /* 5623 */ |
265 | { CR127, 0x03 }, /* 4804, for 1212 new algorithm */ | 265 | { ZD_CR125, 0xad }, /* 4804, for 1212 new algorithm */ |
266 | { CR137, 0x50 }, /* 5614 */ | 266 | { ZD_CR126, 0x6c }, /* 5614 */ |
267 | { CR138, 0xa8 }, | 267 | { ZD_CR127, 0x03 }, /* 4804, for 1212 new algorithm */ |
268 | { CR144, 0xac }, /* 5621 */ | 268 | { ZD_CR137, 0x50 }, /* 5614 */ |
269 | { CR150, 0x0d }, { CR252, 0x34 }, { CR253, 0x34 }, | 269 | { ZD_CR138, 0xa8 }, |
270 | { ZD_CR144, 0xac }, /* 5621 */ | ||
271 | { ZD_CR150, 0x0d }, { ZD_CR252, 0x34 }, { ZD_CR253, 0x34 }, | ||
270 | }; | 272 | }; |
271 | 273 | ||
272 | static const u32 rv1[] = { | 274 | static const u32 rv1[] = { |
@@ -284,7 +286,7 @@ static int zd1211b_al2230_init_hw(struct zd_rf *rf) | |||
284 | 0x6da010, /* Reg6 update for MP versio */ | 286 | 0x6da010, /* Reg6 update for MP versio */ |
285 | 0xe36280, /* Modified by jxiao for Bor-Chin on 2004/08/02 */ | 287 | 0xe36280, /* Modified by jxiao for Bor-Chin on 2004/08/02 */ |
286 | 0x116000, | 288 | 0x116000, |
287 | 0x9dc020, /* External control TX power (CR31) */ | 289 | 0x9dc020, /* External control TX power (ZD_CR31) */ |
288 | 0x5ddb00, /* RegA update for MP version */ | 290 | 0x5ddb00, /* RegA update for MP version */ |
289 | 0xd99000, /* RegB update for MP version */ | 291 | 0xd99000, /* RegB update for MP version */ |
290 | 0x3ffbd0, /* RegC update for MP version */ | 292 | 0x3ffbd0, /* RegC update for MP version */ |
@@ -295,8 +297,8 @@ static int zd1211b_al2230_init_hw(struct zd_rf *rf) | |||
295 | }; | 297 | }; |
296 | 298 | ||
297 | static const struct zd_ioreq16 ioreqs2[] = { | 299 | static const struct zd_ioreq16 ioreqs2[] = { |
298 | { CR251, 0x2f }, /* shdnb(PLL_ON)=0 */ | 300 | { ZD_CR251, 0x2f }, /* shdnb(PLL_ON)=0 */ |
299 | { CR251, 0x7f }, /* shdnb(PLL_ON)=1 */ | 301 | { ZD_CR251, 0x7f }, /* shdnb(PLL_ON)=1 */ |
300 | }; | 302 | }; |
301 | 303 | ||
302 | static const u32 rv3[] = { | 304 | static const u32 rv3[] = { |
@@ -308,7 +310,7 @@ static int zd1211b_al2230_init_hw(struct zd_rf *rf) | |||
308 | 310 | ||
309 | static const struct zd_ioreq16 ioreqs3[] = { | 311 | static const struct zd_ioreq16 ioreqs3[] = { |
310 | /* related to 6M band edge patching, happens unconditionally */ | 312 | /* related to 6M band edge patching, happens unconditionally */ |
311 | { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 }, | 313 | { ZD_CR128, 0x14 }, { ZD_CR129, 0x12 }, { ZD_CR130, 0x10 }, |
312 | }; | 314 | }; |
313 | 315 | ||
314 | r = zd_iowrite16a_locked(chip, zd1211b_ioreqs_shared_1, | 316 | r = zd_iowrite16a_locked(chip, zd1211b_ioreqs_shared_1, |
@@ -361,8 +363,8 @@ static int zd1211_al2230_set_channel(struct zd_rf *rf, u8 channel) | |||
361 | const u32 *rv = zd1211_al2230_table[channel-1]; | 363 | const u32 *rv = zd1211_al2230_table[channel-1]; |
362 | struct zd_chip *chip = zd_rf_to_chip(rf); | 364 | struct zd_chip *chip = zd_rf_to_chip(rf); |
363 | static const struct zd_ioreq16 ioreqs[] = { | 365 | static const struct zd_ioreq16 ioreqs[] = { |
364 | { CR138, 0x28 }, | 366 | { ZD_CR138, 0x28 }, |
365 | { CR203, 0x06 }, | 367 | { ZD_CR203, 0x06 }, |
366 | }; | 368 | }; |
367 | 369 | ||
368 | r = zd_rfwritev_locked(chip, rv, 3, RF_RV_BITS); | 370 | r = zd_rfwritev_locked(chip, rv, 3, RF_RV_BITS); |
@@ -393,8 +395,8 @@ static int zd1211_al2230_switch_radio_on(struct zd_rf *rf) | |||
393 | { | 395 | { |
394 | struct zd_chip *chip = zd_rf_to_chip(rf); | 396 | struct zd_chip *chip = zd_rf_to_chip(rf); |
395 | static const struct zd_ioreq16 ioreqs[] = { | 397 | static const struct zd_ioreq16 ioreqs[] = { |
396 | { CR11, 0x00 }, | 398 | { ZD_CR11, 0x00 }, |
397 | { CR251, 0x3f }, | 399 | { ZD_CR251, 0x3f }, |
398 | }; | 400 | }; |
399 | 401 | ||
400 | return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); | 402 | return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); |
@@ -404,8 +406,8 @@ static int zd1211b_al2230_switch_radio_on(struct zd_rf *rf) | |||
404 | { | 406 | { |
405 | struct zd_chip *chip = zd_rf_to_chip(rf); | 407 | struct zd_chip *chip = zd_rf_to_chip(rf); |
406 | static const struct zd_ioreq16 ioreqs[] = { | 408 | static const struct zd_ioreq16 ioreqs[] = { |
407 | { CR11, 0x00 }, | 409 | { ZD_CR11, 0x00 }, |
408 | { CR251, 0x7f }, | 410 | { ZD_CR251, 0x7f }, |
409 | }; | 411 | }; |
410 | 412 | ||
411 | return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); | 413 | return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); |
@@ -415,8 +417,8 @@ static int al2230_switch_radio_off(struct zd_rf *rf) | |||
415 | { | 417 | { |
416 | struct zd_chip *chip = zd_rf_to_chip(rf); | 418 | struct zd_chip *chip = zd_rf_to_chip(rf); |
417 | static const struct zd_ioreq16 ioreqs[] = { | 419 | static const struct zd_ioreq16 ioreqs[] = { |
418 | { CR11, 0x04 }, | 420 | { ZD_CR11, 0x04 }, |
419 | { CR251, 0x2f }, | 421 | { ZD_CR251, 0x2f }, |
420 | }; | 422 | }; |
421 | 423 | ||
422 | return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); | 424 | return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); |
diff --git a/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c b/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c index 65095d661e6b..385c670d1293 100644 --- a/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c +++ b/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c | |||
@@ -68,19 +68,19 @@ static const u32 rv_init2[] = { | |||
68 | }; | 68 | }; |
69 | 69 | ||
70 | static const struct zd_ioreq16 ioreqs_sw[] = { | 70 | static const struct zd_ioreq16 ioreqs_sw[] = { |
71 | { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 }, | 71 | { ZD_CR128, 0x14 }, { ZD_CR129, 0x12 }, { ZD_CR130, 0x10 }, |
72 | { CR38, 0x38 }, { CR136, 0xdf }, | 72 | { ZD_CR38, 0x38 }, { ZD_CR136, 0xdf }, |
73 | }; | 73 | }; |
74 | 74 | ||
75 | static int zd1211b_al7230b_finalize(struct zd_chip *chip) | 75 | static int zd1211b_al7230b_finalize(struct zd_chip *chip) |
76 | { | 76 | { |
77 | int r; | 77 | int r; |
78 | static const struct zd_ioreq16 ioreqs[] = { | 78 | static const struct zd_ioreq16 ioreqs[] = { |
79 | { CR80, 0x30 }, { CR81, 0x30 }, { CR79, 0x58 }, | 79 | { ZD_CR80, 0x30 }, { ZD_CR81, 0x30 }, { ZD_CR79, 0x58 }, |
80 | { CR12, 0xf0 }, { CR77, 0x1b }, { CR78, 0x58 }, | 80 | { ZD_CR12, 0xf0 }, { ZD_CR77, 0x1b }, { ZD_CR78, 0x58 }, |
81 | { CR203, 0x04 }, | 81 | { ZD_CR203, 0x04 }, |
82 | { }, | 82 | { }, |
83 | { CR240, 0x80 }, | 83 | { ZD_CR240, 0x80 }, |
84 | }; | 84 | }; |
85 | 85 | ||
86 | r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); | 86 | r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); |
@@ -89,12 +89,12 @@ static int zd1211b_al7230b_finalize(struct zd_chip *chip) | |||
89 | 89 | ||
90 | if (chip->new_phy_layout) { | 90 | if (chip->new_phy_layout) { |
91 | /* antenna selection? */ | 91 | /* antenna selection? */ |
92 | r = zd_iowrite16_locked(chip, 0xe5, CR9); | 92 | r = zd_iowrite16_locked(chip, 0xe5, ZD_CR9); |
93 | if (r) | 93 | if (r) |
94 | return r; | 94 | return r; |
95 | } | 95 | } |
96 | 96 | ||
97 | return zd_iowrite16_locked(chip, 0x04, CR203); | 97 | return zd_iowrite16_locked(chip, 0x04, ZD_CR203); |
98 | } | 98 | } |
99 | 99 | ||
100 | static int zd1211_al7230b_init_hw(struct zd_rf *rf) | 100 | static int zd1211_al7230b_init_hw(struct zd_rf *rf) |
@@ -106,66 +106,66 @@ static int zd1211_al7230b_init_hw(struct zd_rf *rf) | |||
106 | * specified */ | 106 | * specified */ |
107 | static const struct zd_ioreq16 ioreqs_1[] = { | 107 | static const struct zd_ioreq16 ioreqs_1[] = { |
108 | /* This one is 7230-specific, and happens before the rest */ | 108 | /* This one is 7230-specific, and happens before the rest */ |
109 | { CR240, 0x57 }, | 109 | { ZD_CR240, 0x57 }, |
110 | { }, | 110 | { }, |
111 | 111 | ||
112 | { CR15, 0x20 }, { CR23, 0x40 }, { CR24, 0x20 }, | 112 | { ZD_CR15, 0x20 }, { ZD_CR23, 0x40 }, { ZD_CR24, 0x20 }, |
113 | { CR26, 0x11 }, { CR28, 0x3e }, { CR29, 0x00 }, | 113 | { ZD_CR26, 0x11 }, { ZD_CR28, 0x3e }, { ZD_CR29, 0x00 }, |
114 | { CR44, 0x33 }, | 114 | { ZD_CR44, 0x33 }, |
115 | /* This value is different for 7230 (was: 0x2a) */ | 115 | /* This value is different for 7230 (was: 0x2a) */ |
116 | { CR106, 0x22 }, | 116 | { ZD_CR106, 0x22 }, |
117 | { CR107, 0x1a }, { CR109, 0x09 }, { CR110, 0x27 }, | 117 | { ZD_CR107, 0x1a }, { ZD_CR109, 0x09 }, { ZD_CR110, 0x27 }, |
118 | { CR111, 0x2b }, { CR112, 0x2b }, { CR119, 0x0a }, | 118 | { ZD_CR111, 0x2b }, { ZD_CR112, 0x2b }, { ZD_CR119, 0x0a }, |
119 | /* This happened further down in AL2230, | 119 | /* This happened further down in AL2230, |
120 | * and the value changed (was: 0xe0) */ | 120 | * and the value changed (was: 0xe0) */ |
121 | { CR122, 0xfc }, | 121 | { ZD_CR122, 0xfc }, |
122 | { CR10, 0x89 }, | 122 | { ZD_CR10, 0x89 }, |
123 | /* for newest (3rd cut) AL2300 */ | 123 | /* for newest (3rd cut) AL2300 */ |
124 | { CR17, 0x28 }, | 124 | { ZD_CR17, 0x28 }, |
125 | { CR26, 0x93 }, { CR34, 0x30 }, | 125 | { ZD_CR26, 0x93 }, { ZD_CR34, 0x30 }, |
126 | /* for newest (3rd cut) AL2300 */ | 126 | /* for newest (3rd cut) AL2300 */ |
127 | { CR35, 0x3e }, | 127 | { ZD_CR35, 0x3e }, |
128 | { CR41, 0x24 }, { CR44, 0x32 }, | 128 | { ZD_CR41, 0x24 }, { ZD_CR44, 0x32 }, |
129 | /* for newest (3rd cut) AL2300 */ | 129 | /* for newest (3rd cut) AL2300 */ |
130 | { CR46, 0x96 }, | 130 | { ZD_CR46, 0x96 }, |
131 | { CR47, 0x1e }, { CR79, 0x58 }, { CR80, 0x30 }, | 131 | { ZD_CR47, 0x1e }, { ZD_CR79, 0x58 }, { ZD_CR80, 0x30 }, |
132 | { CR81, 0x30 }, { CR87, 0x0a }, { CR89, 0x04 }, | 132 | { ZD_CR81, 0x30 }, { ZD_CR87, 0x0a }, { ZD_CR89, 0x04 }, |
133 | { CR92, 0x0a }, { CR99, 0x28 }, | 133 | { ZD_CR92, 0x0a }, { ZD_CR99, 0x28 }, |
134 | /* This value is different for 7230 (was: 0x00) */ | 134 | /* This value is different for 7230 (was: 0x00) */ |
135 | { CR100, 0x02 }, | 135 | { ZD_CR100, 0x02 }, |
136 | { CR101, 0x13 }, { CR102, 0x27 }, | 136 | { ZD_CR101, 0x13 }, { ZD_CR102, 0x27 }, |
137 | /* This value is different for 7230 (was: 0x24) */ | 137 | /* This value is different for 7230 (was: 0x24) */ |
138 | { CR106, 0x22 }, | 138 | { ZD_CR106, 0x22 }, |
139 | /* This value is different for 7230 (was: 0x2a) */ | 139 | /* This value is different for 7230 (was: 0x2a) */ |
140 | { CR107, 0x3f }, | 140 | { ZD_CR107, 0x3f }, |
141 | { CR109, 0x09 }, | 141 | { ZD_CR109, 0x09 }, |
142 | /* This value is different for 7230 (was: 0x13) */ | 142 | /* This value is different for 7230 (was: 0x13) */ |
143 | { CR110, 0x1f }, | 143 | { ZD_CR110, 0x1f }, |
144 | { CR111, 0x1f }, { CR112, 0x1f }, { CR113, 0x27 }, | 144 | { ZD_CR111, 0x1f }, { ZD_CR112, 0x1f }, { ZD_CR113, 0x27 }, |
145 | { CR114, 0x27 }, | 145 | { ZD_CR114, 0x27 }, |
146 | /* for newest (3rd cut) AL2300 */ | 146 | /* for newest (3rd cut) AL2300 */ |
147 | { CR115, 0x24 }, | 147 | { ZD_CR115, 0x24 }, |
148 | /* This value is different for 7230 (was: 0x24) */ | 148 | /* This value is different for 7230 (was: 0x24) */ |
149 | { CR116, 0x3f }, | 149 | { ZD_CR116, 0x3f }, |
150 | /* This value is different for 7230 (was: 0xf4) */ | 150 | /* This value is different for 7230 (was: 0xf4) */ |
151 | { CR117, 0xfa }, | 151 | { ZD_CR117, 0xfa }, |
152 | { CR118, 0xfc }, { CR119, 0x10 }, { CR120, 0x4f }, | 152 | { ZD_CR118, 0xfc }, { ZD_CR119, 0x10 }, { ZD_CR120, 0x4f }, |
153 | { CR121, 0x77 }, { CR137, 0x88 }, | 153 | { ZD_CR121, 0x77 }, { ZD_CR137, 0x88 }, |
154 | /* This one is 7230-specific */ | 154 | /* This one is 7230-specific */ |
155 | { CR138, 0xa8 }, | 155 | { ZD_CR138, 0xa8 }, |
156 | /* This value is different for 7230 (was: 0xff) */ | 156 | /* This value is different for 7230 (was: 0xff) */ |
157 | { CR252, 0x34 }, | 157 | { ZD_CR252, 0x34 }, |
158 | /* This value is different for 7230 (was: 0xff) */ | 158 | /* This value is different for 7230 (was: 0xff) */ |
159 | { CR253, 0x34 }, | 159 | { ZD_CR253, 0x34 }, |
160 | 160 | ||
161 | /* PLL_OFF */ | 161 | /* PLL_OFF */ |
162 | { CR251, 0x2f }, | 162 | { ZD_CR251, 0x2f }, |
163 | }; | 163 | }; |
164 | 164 | ||
165 | static const struct zd_ioreq16 ioreqs_2[] = { | 165 | static const struct zd_ioreq16 ioreqs_2[] = { |
166 | { CR251, 0x3f }, /* PLL_ON */ | 166 | { ZD_CR251, 0x3f }, /* PLL_ON */ |
167 | { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 }, | 167 | { ZD_CR128, 0x14 }, { ZD_CR129, 0x12 }, { ZD_CR130, 0x10 }, |
168 | { CR38, 0x38 }, { CR136, 0xdf }, | 168 | { ZD_CR38, 0x38 }, { ZD_CR136, 0xdf }, |
169 | }; | 169 | }; |
170 | 170 | ||
171 | r = zd_iowrite16a_locked(chip, ioreqs_1, ARRAY_SIZE(ioreqs_1)); | 171 | r = zd_iowrite16a_locked(chip, ioreqs_1, ARRAY_SIZE(ioreqs_1)); |
@@ -192,10 +192,10 @@ static int zd1211_al7230b_init_hw(struct zd_rf *rf) | |||
192 | if (r) | 192 | if (r) |
193 | return r; | 193 | return r; |
194 | 194 | ||
195 | r = zd_iowrite16_locked(chip, 0x06, CR203); | 195 | r = zd_iowrite16_locked(chip, 0x06, ZD_CR203); |
196 | if (r) | 196 | if (r) |
197 | return r; | 197 | return r; |
198 | r = zd_iowrite16_locked(chip, 0x80, CR240); | 198 | r = zd_iowrite16_locked(chip, 0x80, ZD_CR240); |
199 | if (r) | 199 | if (r) |
200 | return r; | 200 | return r; |
201 | 201 | ||
@@ -208,79 +208,79 @@ static int zd1211b_al7230b_init_hw(struct zd_rf *rf) | |||
208 | struct zd_chip *chip = zd_rf_to_chip(rf); | 208 | struct zd_chip *chip = zd_rf_to_chip(rf); |
209 | 209 | ||
210 | static const struct zd_ioreq16 ioreqs_1[] = { | 210 | static const struct zd_ioreq16 ioreqs_1[] = { |
211 | { CR240, 0x57 }, { CR9, 0x9 }, | 211 | { ZD_CR240, 0x57 }, { ZD_CR9, 0x9 }, |
212 | { }, | 212 | { }, |
213 | { CR10, 0x8b }, { CR15, 0x20 }, | 213 | { ZD_CR10, 0x8b }, { ZD_CR15, 0x20 }, |
214 | { CR17, 0x2B }, /* for newest (3rd cut) AL2230 */ | 214 | { ZD_CR17, 0x2B }, /* for newest (3rd cut) AL2230 */ |
215 | { CR20, 0x10 }, /* 4N25->Stone Request */ | 215 | { ZD_CR20, 0x10 }, /* 4N25->Stone Request */ |
216 | { CR23, 0x40 }, { CR24, 0x20 }, { CR26, 0x93 }, | 216 | { ZD_CR23, 0x40 }, { ZD_CR24, 0x20 }, { ZD_CR26, 0x93 }, |
217 | { CR28, 0x3e }, { CR29, 0x00 }, | 217 | { ZD_CR28, 0x3e }, { ZD_CR29, 0x00 }, |
218 | { CR33, 0x28 }, /* 5613 */ | 218 | { ZD_CR33, 0x28 }, /* 5613 */ |
219 | { CR34, 0x30 }, | 219 | { ZD_CR34, 0x30 }, |
220 | { CR35, 0x3e }, /* for newest (3rd cut) AL2230 */ | 220 | { ZD_CR35, 0x3e }, /* for newest (3rd cut) AL2230 */ |
221 | { CR41, 0x24 }, { CR44, 0x32 }, | 221 | { ZD_CR41, 0x24 }, { ZD_CR44, 0x32 }, |
222 | { CR46, 0x99 }, /* for newest (3rd cut) AL2230 */ | 222 | { ZD_CR46, 0x99 }, /* for newest (3rd cut) AL2230 */ |
223 | { CR47, 0x1e }, | 223 | { ZD_CR47, 0x1e }, |
224 | 224 | ||
225 | /* ZD1215 5610 */ | 225 | /* ZD1215 5610 */ |
226 | { CR48, 0x00 }, { CR49, 0x00 }, { CR51, 0x01 }, | 226 | { ZD_CR48, 0x00 }, { ZD_CR49, 0x00 }, { ZD_CR51, 0x01 }, |
227 | { CR52, 0x80 }, { CR53, 0x7e }, { CR65, 0x00 }, | 227 | { ZD_CR52, 0x80 }, { ZD_CR53, 0x7e }, { ZD_CR65, 0x00 }, |
228 | { CR66, 0x00 }, { CR67, 0x00 }, { CR68, 0x00 }, | 228 | { ZD_CR66, 0x00 }, { ZD_CR67, 0x00 }, { ZD_CR68, 0x00 }, |
229 | { CR69, 0x28 }, | 229 | { ZD_CR69, 0x28 }, |
230 | 230 | ||
231 | { CR79, 0x58 }, { CR80, 0x30 }, { CR81, 0x30 }, | 231 | { ZD_CR79, 0x58 }, { ZD_CR80, 0x30 }, { ZD_CR81, 0x30 }, |
232 | { CR87, 0x0A }, { CR89, 0x04 }, | 232 | { ZD_CR87, 0x0A }, { ZD_CR89, 0x04 }, |
233 | { CR90, 0x58 }, /* 5112 */ | 233 | { ZD_CR90, 0x58 }, /* 5112 */ |
234 | { CR91, 0x00 }, /* 5613 */ | 234 | { ZD_CR91, 0x00 }, /* 5613 */ |
235 | { CR92, 0x0a }, | 235 | { ZD_CR92, 0x0a }, |
236 | { CR98, 0x8d }, /* 4804, for 1212 new algorithm */ | 236 | { ZD_CR98, 0x8d }, /* 4804, for 1212 new algorithm */ |
237 | { CR99, 0x00 }, { CR100, 0x02 }, { CR101, 0x13 }, | 237 | { ZD_CR99, 0x00 }, { ZD_CR100, 0x02 }, { ZD_CR101, 0x13 }, |
238 | { CR102, 0x27 }, | 238 | { ZD_CR102, 0x27 }, |
239 | { CR106, 0x20 }, /* change to 0x24 for AL7230B */ | 239 | { ZD_CR106, 0x20 }, /* change to 0x24 for AL7230B */ |
240 | { CR109, 0x13 }, /* 4804, for 1212 new algorithm */ | 240 | { ZD_CR109, 0x13 }, /* 4804, for 1212 new algorithm */ |
241 | { CR112, 0x1f }, | 241 | { ZD_CR112, 0x1f }, |
242 | }; | 242 | }; |
243 | 243 | ||
244 | static const struct zd_ioreq16 ioreqs_new_phy[] = { | 244 | static const struct zd_ioreq16 ioreqs_new_phy[] = { |
245 | { CR107, 0x28 }, | 245 | { ZD_CR107, 0x28 }, |
246 | { CR110, 0x1f }, /* 5127, 0x13->0x1f */ | 246 | { ZD_CR110, 0x1f }, /* 5127, 0x13->0x1f */ |
247 | { CR111, 0x1f }, /* 0x13 to 0x1f for AL7230B */ | 247 | { ZD_CR111, 0x1f }, /* 0x13 to 0x1f for AL7230B */ |
248 | { CR116, 0x2a }, { CR118, 0xfa }, { CR119, 0x12 }, | 248 | { ZD_CR116, 0x2a }, { ZD_CR118, 0xfa }, { ZD_CR119, 0x12 }, |
249 | { CR121, 0x6c }, /* 5613 */ | 249 | { ZD_CR121, 0x6c }, /* 5613 */ |
250 | }; | 250 | }; |
251 | 251 | ||
252 | static const struct zd_ioreq16 ioreqs_old_phy[] = { | 252 | static const struct zd_ioreq16 ioreqs_old_phy[] = { |
253 | { CR107, 0x24 }, | 253 | { ZD_CR107, 0x24 }, |
254 | { CR110, 0x13 }, /* 5127, 0x13->0x1f */ | 254 | { ZD_CR110, 0x13 }, /* 5127, 0x13->0x1f */ |
255 | { CR111, 0x13 }, /* 0x13 to 0x1f for AL7230B */ | 255 | { ZD_CR111, 0x13 }, /* 0x13 to 0x1f for AL7230B */ |
256 | { CR116, 0x24 }, { CR118, 0xfc }, { CR119, 0x11 }, | 256 | { ZD_CR116, 0x24 }, { ZD_CR118, 0xfc }, { ZD_CR119, 0x11 }, |
257 | { CR121, 0x6a }, /* 5613 */ | 257 | { ZD_CR121, 0x6a }, /* 5613 */ |
258 | }; | 258 | }; |
259 | 259 | ||
260 | static const struct zd_ioreq16 ioreqs_2[] = { | 260 | static const struct zd_ioreq16 ioreqs_2[] = { |
261 | { CR113, 0x27 }, { CR114, 0x27 }, { CR115, 0x24 }, | 261 | { ZD_CR113, 0x27 }, { ZD_CR114, 0x27 }, { ZD_CR115, 0x24 }, |
262 | { CR117, 0xfa }, { CR120, 0x4f }, | 262 | { ZD_CR117, 0xfa }, { ZD_CR120, 0x4f }, |
263 | { CR122, 0xfc }, /* E0->FCh at 4901 */ | 263 | { ZD_CR122, 0xfc }, /* E0->FCh at 4901 */ |
264 | { CR123, 0x57 }, /* 5613 */ | 264 | { ZD_CR123, 0x57 }, /* 5613 */ |
265 | { CR125, 0xad }, /* 4804, for 1212 new algorithm */ | 265 | { ZD_CR125, 0xad }, /* 4804, for 1212 new algorithm */ |
266 | { CR126, 0x6c }, /* 5613 */ | 266 | { ZD_CR126, 0x6c }, /* 5613 */ |
267 | { CR127, 0x03 }, /* 4804, for 1212 new algorithm */ | 267 | { ZD_CR127, 0x03 }, /* 4804, for 1212 new algorithm */ |
268 | { CR130, 0x10 }, | 268 | { ZD_CR130, 0x10 }, |
269 | { CR131, 0x00 }, /* 5112 */ | 269 | { ZD_CR131, 0x00 }, /* 5112 */ |
270 | { CR137, 0x50 }, /* 5613 */ | 270 | { ZD_CR137, 0x50 }, /* 5613 */ |
271 | { CR138, 0xa8 }, /* 5112 */ | 271 | { ZD_CR138, 0xa8 }, /* 5112 */ |
272 | { CR144, 0xac }, /* 5613 */ | 272 | { ZD_CR144, 0xac }, /* 5613 */ |
273 | { CR148, 0x40 }, /* 5112 */ | 273 | { ZD_CR148, 0x40 }, /* 5112 */ |
274 | { CR149, 0x40 }, /* 4O07, 50->40 */ | 274 | { ZD_CR149, 0x40 }, /* 4O07, 50->40 */ |
275 | { CR150, 0x1a }, /* 5112, 0C->1A */ | 275 | { ZD_CR150, 0x1a }, /* 5112, 0C->1A */ |
276 | { CR252, 0x34 }, { CR253, 0x34 }, | 276 | { ZD_CR252, 0x34 }, { ZD_CR253, 0x34 }, |
277 | { CR251, 0x2f }, /* PLL_OFF */ | 277 | { ZD_CR251, 0x2f }, /* PLL_OFF */ |
278 | }; | 278 | }; |
279 | 279 | ||
280 | static const struct zd_ioreq16 ioreqs_3[] = { | 280 | static const struct zd_ioreq16 ioreqs_3[] = { |
281 | { CR251, 0x7f }, /* PLL_ON */ | 281 | { ZD_CR251, 0x7f }, /* PLL_ON */ |
282 | { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 }, | 282 | { ZD_CR128, 0x14 }, { ZD_CR129, 0x12 }, { ZD_CR130, 0x10 }, |
283 | { CR38, 0x38 }, { CR136, 0xdf }, | 283 | { ZD_CR38, 0x38 }, { ZD_CR136, 0xdf }, |
284 | }; | 284 | }; |
285 | 285 | ||
286 | r = zd_iowrite16a_locked(chip, ioreqs_1, ARRAY_SIZE(ioreqs_1)); | 286 | r = zd_iowrite16a_locked(chip, ioreqs_1, ARRAY_SIZE(ioreqs_1)); |
@@ -331,16 +331,16 @@ static int zd1211_al7230b_set_channel(struct zd_rf *rf, u8 channel) | |||
331 | 331 | ||
332 | static const struct zd_ioreq16 ioreqs[] = { | 332 | static const struct zd_ioreq16 ioreqs[] = { |
333 | /* PLL_ON */ | 333 | /* PLL_ON */ |
334 | { CR251, 0x3f }, | 334 | { ZD_CR251, 0x3f }, |
335 | { CR203, 0x06 }, { CR240, 0x08 }, | 335 | { ZD_CR203, 0x06 }, { ZD_CR240, 0x08 }, |
336 | }; | 336 | }; |
337 | 337 | ||
338 | r = zd_iowrite16_locked(chip, 0x57, CR240); | 338 | r = zd_iowrite16_locked(chip, 0x57, ZD_CR240); |
339 | if (r) | 339 | if (r) |
340 | return r; | 340 | return r; |
341 | 341 | ||
342 | /* PLL_OFF */ | 342 | /* PLL_OFF */ |
343 | r = zd_iowrite16_locked(chip, 0x2f, CR251); | 343 | r = zd_iowrite16_locked(chip, 0x2f, ZD_CR251); |
344 | if (r) | 344 | if (r) |
345 | return r; | 345 | return r; |
346 | 346 | ||
@@ -376,15 +376,15 @@ static int zd1211b_al7230b_set_channel(struct zd_rf *rf, u8 channel) | |||
376 | const u32 *rv = chan_rv[channel-1]; | 376 | const u32 *rv = chan_rv[channel-1]; |
377 | struct zd_chip *chip = zd_rf_to_chip(rf); | 377 | struct zd_chip *chip = zd_rf_to_chip(rf); |
378 | 378 | ||
379 | r = zd_iowrite16_locked(chip, 0x57, CR240); | 379 | r = zd_iowrite16_locked(chip, 0x57, ZD_CR240); |
380 | if (r) | 380 | if (r) |
381 | return r; | 381 | return r; |
382 | r = zd_iowrite16_locked(chip, 0xe4, CR9); | 382 | r = zd_iowrite16_locked(chip, 0xe4, ZD_CR9); |
383 | if (r) | 383 | if (r) |
384 | return r; | 384 | return r; |
385 | 385 | ||
386 | /* PLL_OFF */ | 386 | /* PLL_OFF */ |
387 | r = zd_iowrite16_locked(chip, 0x2f, CR251); | 387 | r = zd_iowrite16_locked(chip, 0x2f, ZD_CR251); |
388 | if (r) | 388 | if (r) |
389 | return r; | 389 | return r; |
390 | r = zd_rfwritev_cr_locked(chip, std_rv, ARRAY_SIZE(std_rv)); | 390 | r = zd_rfwritev_cr_locked(chip, std_rv, ARRAY_SIZE(std_rv)); |
@@ -410,7 +410,7 @@ static int zd1211b_al7230b_set_channel(struct zd_rf *rf, u8 channel) | |||
410 | if (r) | 410 | if (r) |
411 | return r; | 411 | return r; |
412 | 412 | ||
413 | r = zd_iowrite16_locked(chip, 0x7f, CR251); | 413 | r = zd_iowrite16_locked(chip, 0x7f, ZD_CR251); |
414 | if (r) | 414 | if (r) |
415 | return r; | 415 | return r; |
416 | 416 | ||
@@ -421,8 +421,8 @@ static int zd1211_al7230b_switch_radio_on(struct zd_rf *rf) | |||
421 | { | 421 | { |
422 | struct zd_chip *chip = zd_rf_to_chip(rf); | 422 | struct zd_chip *chip = zd_rf_to_chip(rf); |
423 | static const struct zd_ioreq16 ioreqs[] = { | 423 | static const struct zd_ioreq16 ioreqs[] = { |
424 | { CR11, 0x00 }, | 424 | { ZD_CR11, 0x00 }, |
425 | { CR251, 0x3f }, | 425 | { ZD_CR251, 0x3f }, |
426 | }; | 426 | }; |
427 | 427 | ||
428 | return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); | 428 | return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); |
@@ -432,8 +432,8 @@ static int zd1211b_al7230b_switch_radio_on(struct zd_rf *rf) | |||
432 | { | 432 | { |
433 | struct zd_chip *chip = zd_rf_to_chip(rf); | 433 | struct zd_chip *chip = zd_rf_to_chip(rf); |
434 | static const struct zd_ioreq16 ioreqs[] = { | 434 | static const struct zd_ioreq16 ioreqs[] = { |
435 | { CR11, 0x00 }, | 435 | { ZD_CR11, 0x00 }, |
436 | { CR251, 0x7f }, | 436 | { ZD_CR251, 0x7f }, |
437 | }; | 437 | }; |
438 | 438 | ||
439 | return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); | 439 | return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); |
@@ -443,8 +443,8 @@ static int al7230b_switch_radio_off(struct zd_rf *rf) | |||
443 | { | 443 | { |
444 | struct zd_chip *chip = zd_rf_to_chip(rf); | 444 | struct zd_chip *chip = zd_rf_to_chip(rf); |
445 | static const struct zd_ioreq16 ioreqs[] = { | 445 | static const struct zd_ioreq16 ioreqs[] = { |
446 | { CR11, 0x04 }, | 446 | { ZD_CR11, 0x04 }, |
447 | { CR251, 0x2f }, | 447 | { ZD_CR251, 0x2f }, |
448 | }; | 448 | }; |
449 | 449 | ||
450 | return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); | 450 | return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); |
@@ -456,7 +456,7 @@ static int zd1211b_al7230b_patch_6m(struct zd_rf *rf, u8 channel) | |||
456 | { | 456 | { |
457 | struct zd_chip *chip = zd_rf_to_chip(rf); | 457 | struct zd_chip *chip = zd_rf_to_chip(rf); |
458 | struct zd_ioreq16 ioreqs[] = { | 458 | struct zd_ioreq16 ioreqs[] = { |
459 | { CR128, 0x14 }, { CR129, 0x12 }, | 459 | { ZD_CR128, 0x14 }, { ZD_CR129, 0x12 }, |
460 | }; | 460 | }; |
461 | 461 | ||
462 | /* FIXME: Channel 11 is not the edge for all regulatory domains. */ | 462 | /* FIXME: Channel 11 is not the edge for all regulatory domains. */ |
diff --git a/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c b/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c index e36117486c91..784d9ccb8fef 100644 --- a/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c +++ b/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c | |||
@@ -152,44 +152,44 @@ static int rf2959_init_hw(struct zd_rf *rf) | |||
152 | struct zd_chip *chip = zd_rf_to_chip(rf); | 152 | struct zd_chip *chip = zd_rf_to_chip(rf); |
153 | 153 | ||
154 | static const struct zd_ioreq16 ioreqs[] = { | 154 | static const struct zd_ioreq16 ioreqs[] = { |
155 | { CR2, 0x1E }, { CR9, 0x20 }, { CR10, 0x89 }, | 155 | { ZD_CR2, 0x1E }, { ZD_CR9, 0x20 }, { ZD_CR10, 0x89 }, |
156 | { CR11, 0x00 }, { CR15, 0xD0 }, { CR17, 0x68 }, | 156 | { ZD_CR11, 0x00 }, { ZD_CR15, 0xD0 }, { ZD_CR17, 0x68 }, |
157 | { CR19, 0x4a }, { CR20, 0x0c }, { CR21, 0x0E }, | 157 | { ZD_CR19, 0x4a }, { ZD_CR20, 0x0c }, { ZD_CR21, 0x0E }, |
158 | { CR23, 0x48 }, | 158 | { ZD_CR23, 0x48 }, |
159 | /* normal size for cca threshold */ | 159 | /* normal size for cca threshold */ |
160 | { CR24, 0x14 }, | 160 | { ZD_CR24, 0x14 }, |
161 | /* { CR24, 0x20 }, */ | 161 | /* { ZD_CR24, 0x20 }, */ |
162 | { CR26, 0x90 }, { CR27, 0x30 }, { CR29, 0x20 }, | 162 | { ZD_CR26, 0x90 }, { ZD_CR27, 0x30 }, { ZD_CR29, 0x20 }, |
163 | { CR31, 0xb2 }, { CR32, 0x43 }, { CR33, 0x28 }, | 163 | { ZD_CR31, 0xb2 }, { ZD_CR32, 0x43 }, { ZD_CR33, 0x28 }, |
164 | { CR38, 0x30 }, { CR34, 0x0f }, { CR35, 0xF0 }, | 164 | { ZD_CR38, 0x30 }, { ZD_CR34, 0x0f }, { ZD_CR35, 0xF0 }, |
165 | { CR41, 0x2a }, { CR46, 0x7F }, { CR47, 0x1E }, | 165 | { ZD_CR41, 0x2a }, { ZD_CR46, 0x7F }, { ZD_CR47, 0x1E }, |
166 | { CR51, 0xc5 }, { CR52, 0xc5 }, { CR53, 0xc5 }, | 166 | { ZD_CR51, 0xc5 }, { ZD_CR52, 0xc5 }, { ZD_CR53, 0xc5 }, |
167 | { CR79, 0x58 }, { CR80, 0x30 }, { CR81, 0x30 }, | 167 | { ZD_CR79, 0x58 }, { ZD_CR80, 0x30 }, { ZD_CR81, 0x30 }, |
168 | { CR82, 0x00 }, { CR83, 0x24 }, { CR84, 0x04 }, | 168 | { ZD_CR82, 0x00 }, { ZD_CR83, 0x24 }, { ZD_CR84, 0x04 }, |
169 | { CR85, 0x00 }, { CR86, 0x10 }, { CR87, 0x2A }, | 169 | { ZD_CR85, 0x00 }, { ZD_CR86, 0x10 }, { ZD_CR87, 0x2A }, |
170 | { CR88, 0x10 }, { CR89, 0x24 }, { CR90, 0x18 }, | 170 | { ZD_CR88, 0x10 }, { ZD_CR89, 0x24 }, { ZD_CR90, 0x18 }, |
171 | /* { CR91, 0x18 }, */ | 171 | /* { ZD_CR91, 0x18 }, */ |
172 | /* should solve continuous CTS frame problems */ | 172 | /* should solve continuous CTS frame problems */ |
173 | { CR91, 0x00 }, | 173 | { ZD_CR91, 0x00 }, |
174 | { CR92, 0x0a }, { CR93, 0x00 }, { CR94, 0x01 }, | 174 | { ZD_CR92, 0x0a }, { ZD_CR93, 0x00 }, { ZD_CR94, 0x01 }, |
175 | { CR95, 0x00 }, { CR96, 0x40 }, { CR97, 0x37 }, | 175 | { ZD_CR95, 0x00 }, { ZD_CR96, 0x40 }, { ZD_CR97, 0x37 }, |
176 | { CR98, 0x05 }, { CR99, 0x28 }, { CR100, 0x00 }, | 176 | { ZD_CR98, 0x05 }, { ZD_CR99, 0x28 }, { ZD_CR100, 0x00 }, |
177 | { CR101, 0x13 }, { CR102, 0x27 }, { CR103, 0x27 }, | 177 | { ZD_CR101, 0x13 }, { ZD_CR102, 0x27 }, { ZD_CR103, 0x27 }, |
178 | { CR104, 0x18 }, { CR105, 0x12 }, | 178 | { ZD_CR104, 0x18 }, { ZD_CR105, 0x12 }, |
179 | /* normal size */ | 179 | /* normal size */ |
180 | { CR106, 0x1a }, | 180 | { ZD_CR106, 0x1a }, |
181 | /* { CR106, 0x22 }, */ | 181 | /* { ZD_CR106, 0x22 }, */ |
182 | { CR107, 0x24 }, { CR108, 0x0a }, { CR109, 0x13 }, | 182 | { ZD_CR107, 0x24 }, { ZD_CR108, 0x0a }, { ZD_CR109, 0x13 }, |
183 | { CR110, 0x2F }, { CR111, 0x27 }, { CR112, 0x27 }, | 183 | { ZD_CR110, 0x2F }, { ZD_CR111, 0x27 }, { ZD_CR112, 0x27 }, |
184 | { CR113, 0x27 }, { CR114, 0x27 }, { CR115, 0x40 }, | 184 | { ZD_CR113, 0x27 }, { ZD_CR114, 0x27 }, { ZD_CR115, 0x40 }, |
185 | { CR116, 0x40 }, { CR117, 0xF0 }, { CR118, 0xF0 }, | 185 | { ZD_CR116, 0x40 }, { ZD_CR117, 0xF0 }, { ZD_CR118, 0xF0 }, |
186 | { CR119, 0x16 }, | 186 | { ZD_CR119, 0x16 }, |
187 | /* no TX continuation */ | 187 | /* no TX continuation */ |
188 | { CR122, 0x00 }, | 188 | { ZD_CR122, 0x00 }, |
189 | /* { CR122, 0xff }, */ | 189 | /* { ZD_CR122, 0xff }, */ |
190 | { CR127, 0x03 }, { CR131, 0x08 }, { CR138, 0x28 }, | 190 | { ZD_CR127, 0x03 }, { ZD_CR131, 0x08 }, { ZD_CR138, 0x28 }, |
191 | { CR148, 0x44 }, { CR150, 0x10 }, { CR169, 0xBB }, | 191 | { ZD_CR148, 0x44 }, { ZD_CR150, 0x10 }, { ZD_CR169, 0xBB }, |
192 | { CR170, 0xBB }, | 192 | { ZD_CR170, 0xBB }, |
193 | }; | 193 | }; |
194 | 194 | ||
195 | static const u32 rv[] = { | 195 | static const u32 rv[] = { |
@@ -210,7 +210,7 @@ static int rf2959_init_hw(struct zd_rf *rf) | |||
210 | */ | 210 | */ |
211 | 0x294128, /* internal power */ | 211 | 0x294128, /* internal power */ |
212 | /* 0x28252c, */ /* External control TX power */ | 212 | /* 0x28252c, */ /* External control TX power */ |
213 | /* CR31_CCK, CR51_6-36M, CR52_48M, CR53_54M */ | 213 | /* ZD_CR31_CCK, ZD_CR51_6-36M, ZD_CR52_48M, ZD_CR53_54M */ |
214 | 0x2c0000, | 214 | 0x2c0000, |
215 | 0x300000, | 215 | 0x300000, |
216 | 0x340000, /* REG13(0xD) */ | 216 | 0x340000, /* REG13(0xD) */ |
@@ -245,8 +245,8 @@ static int rf2959_set_channel(struct zd_rf *rf, u8 channel) | |||
245 | static int rf2959_switch_radio_on(struct zd_rf *rf) | 245 | static int rf2959_switch_radio_on(struct zd_rf *rf) |
246 | { | 246 | { |
247 | static const struct zd_ioreq16 ioreqs[] = { | 247 | static const struct zd_ioreq16 ioreqs[] = { |
248 | { CR10, 0x89 }, | 248 | { ZD_CR10, 0x89 }, |
249 | { CR11, 0x00 }, | 249 | { ZD_CR11, 0x00 }, |
250 | }; | 250 | }; |
251 | struct zd_chip *chip = zd_rf_to_chip(rf); | 251 | struct zd_chip *chip = zd_rf_to_chip(rf); |
252 | 252 | ||
@@ -256,8 +256,8 @@ static int rf2959_switch_radio_on(struct zd_rf *rf) | |||
256 | static int rf2959_switch_radio_off(struct zd_rf *rf) | 256 | static int rf2959_switch_radio_off(struct zd_rf *rf) |
257 | { | 257 | { |
258 | static const struct zd_ioreq16 ioreqs[] = { | 258 | static const struct zd_ioreq16 ioreqs[] = { |
259 | { CR10, 0x15 }, | 259 | { ZD_CR10, 0x15 }, |
260 | { CR11, 0x81 }, | 260 | { ZD_CR11, 0x81 }, |
261 | }; | 261 | }; |
262 | struct zd_chip *chip = zd_rf_to_chip(rf); | 262 | struct zd_chip *chip = zd_rf_to_chip(rf); |
263 | 263 | ||
diff --git a/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c b/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c index ba0a0ccb1fa0..c4d324e19c24 100644 --- a/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c +++ b/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c | |||
@@ -314,42 +314,44 @@ static int uw2453_init_hw(struct zd_rf *rf) | |||
314 | struct zd_chip *chip = zd_rf_to_chip(rf); | 314 | struct zd_chip *chip = zd_rf_to_chip(rf); |
315 | 315 | ||
316 | static const struct zd_ioreq16 ioreqs[] = { | 316 | static const struct zd_ioreq16 ioreqs[] = { |
317 | { CR10, 0x89 }, { CR15, 0x20 }, | 317 | { ZD_CR10, 0x89 }, { ZD_CR15, 0x20 }, |
318 | { CR17, 0x28 }, /* 6112 no change */ | 318 | { ZD_CR17, 0x28 }, /* 6112 no change */ |
319 | { CR23, 0x38 }, { CR24, 0x20 }, { CR26, 0x93 }, | 319 | { ZD_CR23, 0x38 }, { ZD_CR24, 0x20 }, { ZD_CR26, 0x93 }, |
320 | { CR27, 0x15 }, { CR28, 0x3e }, { CR29, 0x00 }, | 320 | { ZD_CR27, 0x15 }, { ZD_CR28, 0x3e }, { ZD_CR29, 0x00 }, |
321 | { CR33, 0x28 }, { CR34, 0x30 }, | 321 | { ZD_CR33, 0x28 }, { ZD_CR34, 0x30 }, |
322 | { CR35, 0x43 }, /* 6112 3e->43 */ | 322 | { ZD_CR35, 0x43 }, /* 6112 3e->43 */ |
323 | { CR41, 0x24 }, { CR44, 0x32 }, | 323 | { ZD_CR41, 0x24 }, { ZD_CR44, 0x32 }, |
324 | { CR46, 0x92 }, /* 6112 96->92 */ | 324 | { ZD_CR46, 0x92 }, /* 6112 96->92 */ |
325 | { CR47, 0x1e }, | 325 | { ZD_CR47, 0x1e }, |
326 | { CR48, 0x04 }, /* 5602 Roger */ | 326 | { ZD_CR48, 0x04 }, /* 5602 Roger */ |
327 | { CR49, 0xfa }, { CR79, 0x58 }, { CR80, 0x30 }, | 327 | { ZD_CR49, 0xfa }, { ZD_CR79, 0x58 }, { ZD_CR80, 0x30 }, |
328 | { CR81, 0x30 }, { CR87, 0x0a }, { CR89, 0x04 }, | 328 | { ZD_CR81, 0x30 }, { ZD_CR87, 0x0a }, { ZD_CR89, 0x04 }, |
329 | { CR91, 0x00 }, { CR92, 0x0a }, { CR98, 0x8d }, | 329 | { ZD_CR91, 0x00 }, { ZD_CR92, 0x0a }, { ZD_CR98, 0x8d }, |
330 | { CR99, 0x28 }, { CR100, 0x02 }, | 330 | { ZD_CR99, 0x28 }, { ZD_CR100, 0x02 }, |
331 | { CR101, 0x09 }, /* 6112 13->1f 6220 1f->13 6407 13->9 */ | 331 | { ZD_CR101, 0x09 }, /* 6112 13->1f 6220 1f->13 6407 13->9 */ |
332 | { CR102, 0x27 }, | 332 | { ZD_CR102, 0x27 }, |
333 | { CR106, 0x1c }, /* 5d07 5112 1f->1c 6220 1c->1f 6221 1f->1c */ | 333 | { ZD_CR106, 0x1c }, /* 5d07 5112 1f->1c 6220 1c->1f |
334 | { CR107, 0x1c }, /* 6220 1c->1a 5221 1a->1c */ | 334 | * 6221 1f->1c |
335 | { CR109, 0x13 }, | 335 | */ |
336 | { CR110, 0x1f }, /* 6112 13->1f 6221 1f->13 6407 13->0x09 */ | 336 | { ZD_CR107, 0x1c }, /* 6220 1c->1a 5221 1a->1c */ |
337 | { CR111, 0x13 }, { CR112, 0x1f }, { CR113, 0x27 }, | 337 | { ZD_CR109, 0x13 }, |
338 | { CR114, 0x23 }, /* 6221 27->23 */ | 338 | { ZD_CR110, 0x1f }, /* 6112 13->1f 6221 1f->13 6407 13->0x09 */ |
339 | { CR115, 0x24 }, /* 6112 24->1c 6220 1c->24 */ | 339 | { ZD_CR111, 0x13 }, { ZD_CR112, 0x1f }, { ZD_CR113, 0x27 }, |
340 | { CR116, 0x24 }, /* 6220 1c->24 */ | 340 | { ZD_CR114, 0x23 }, /* 6221 27->23 */ |
341 | { CR117, 0xfa }, /* 6112 fa->f8 6220 f8->f4 6220 f4->fa */ | 341 | { ZD_CR115, 0x24 }, /* 6112 24->1c 6220 1c->24 */ |
342 | { CR118, 0xf0 }, /* 5d07 6112 f0->f2 6220 f2->f0 */ | 342 | { ZD_CR116, 0x24 }, /* 6220 1c->24 */ |
343 | { CR119, 0x1a }, /* 6112 1a->10 6220 10->14 6220 14->1a */ | 343 | { ZD_CR117, 0xfa }, /* 6112 fa->f8 6220 f8->f4 6220 f4->fa */ |
344 | { CR120, 0x4f }, | 344 | { ZD_CR118, 0xf0 }, /* 5d07 6112 f0->f2 6220 f2->f0 */ |
345 | { CR121, 0x1f }, /* 6220 4f->1f */ | 345 | { ZD_CR119, 0x1a }, /* 6112 1a->10 6220 10->14 6220 14->1a */ |
346 | { CR122, 0xf0 }, { CR123, 0x57 }, { CR125, 0xad }, | 346 | { ZD_CR120, 0x4f }, |
347 | { CR126, 0x6c }, { CR127, 0x03 }, | 347 | { ZD_CR121, 0x1f }, /* 6220 4f->1f */ |
348 | { CR128, 0x14 }, /* 6302 12->11 */ | 348 | { ZD_CR122, 0xf0 }, { ZD_CR123, 0x57 }, { ZD_CR125, 0xad }, |
349 | { CR129, 0x12 }, /* 6301 10->0f */ | 349 | { ZD_CR126, 0x6c }, { ZD_CR127, 0x03 }, |
350 | { CR130, 0x10 }, { CR137, 0x50 }, { CR138, 0xa8 }, | 350 | { ZD_CR128, 0x14 }, /* 6302 12->11 */ |
351 | { CR144, 0xac }, { CR146, 0x20 }, { CR252, 0xff }, | 351 | { ZD_CR129, 0x12 }, /* 6301 10->0f */ |
352 | { CR253, 0xff }, | 352 | { ZD_CR130, 0x10 }, { ZD_CR137, 0x50 }, { ZD_CR138, 0xa8 }, |
353 | { ZD_CR144, 0xac }, { ZD_CR146, 0x20 }, { ZD_CR252, 0xff }, | ||
354 | { ZD_CR253, 0xff }, | ||
353 | }; | 355 | }; |
354 | 356 | ||
355 | static const u32 rv[] = { | 357 | static const u32 rv[] = { |
@@ -433,7 +435,7 @@ static int uw2453_init_hw(struct zd_rf *rf) | |||
433 | * the one that produced a lock. */ | 435 | * the one that produced a lock. */ |
434 | UW2453_PRIV(rf)->config = found_config + 1; | 436 | UW2453_PRIV(rf)->config = found_config + 1; |
435 | 437 | ||
436 | return zd_iowrite16_locked(chip, 0x06, CR203); | 438 | return zd_iowrite16_locked(chip, 0x06, ZD_CR203); |
437 | } | 439 | } |
438 | 440 | ||
439 | static int uw2453_set_channel(struct zd_rf *rf, u8 channel) | 441 | static int uw2453_set_channel(struct zd_rf *rf, u8 channel) |
@@ -445,8 +447,8 @@ static int uw2453_set_channel(struct zd_rf *rf, u8 channel) | |||
445 | struct zd_chip *chip = zd_rf_to_chip(rf); | 447 | struct zd_chip *chip = zd_rf_to_chip(rf); |
446 | 448 | ||
447 | static const struct zd_ioreq16 ioreqs[] = { | 449 | static const struct zd_ioreq16 ioreqs[] = { |
448 | { CR80, 0x30 }, { CR81, 0x30 }, { CR79, 0x58 }, | 450 | { ZD_CR80, 0x30 }, { ZD_CR81, 0x30 }, { ZD_CR79, 0x58 }, |
449 | { CR12, 0xf0 }, { CR77, 0x1b }, { CR78, 0x58 }, | 451 | { ZD_CR12, 0xf0 }, { ZD_CR77, 0x1b }, { ZD_CR78, 0x58 }, |
450 | }; | 452 | }; |
451 | 453 | ||
452 | r = uw2453_synth_set_channel(chip, channel, autocal); | 454 | r = uw2453_synth_set_channel(chip, channel, autocal); |
@@ -474,7 +476,7 @@ static int uw2453_set_channel(struct zd_rf *rf, u8 channel) | |||
474 | if (r) | 476 | if (r) |
475 | return r; | 477 | return r; |
476 | 478 | ||
477 | return zd_iowrite16_locked(chip, 0x06, CR203); | 479 | return zd_iowrite16_locked(chip, 0x06, ZD_CR203); |
478 | } | 480 | } |
479 | 481 | ||
480 | static int uw2453_switch_radio_on(struct zd_rf *rf) | 482 | static int uw2453_switch_radio_on(struct zd_rf *rf) |
@@ -482,7 +484,7 @@ static int uw2453_switch_radio_on(struct zd_rf *rf) | |||
482 | int r; | 484 | int r; |
483 | struct zd_chip *chip = zd_rf_to_chip(rf); | 485 | struct zd_chip *chip = zd_rf_to_chip(rf); |
484 | struct zd_ioreq16 ioreqs[] = { | 486 | struct zd_ioreq16 ioreqs[] = { |
485 | { CR11, 0x00 }, { CR251, 0x3f }, | 487 | { ZD_CR11, 0x00 }, { ZD_CR251, 0x3f }, |
486 | }; | 488 | }; |
487 | 489 | ||
488 | /* enter RXTX mode */ | 490 | /* enter RXTX mode */ |
@@ -501,7 +503,7 @@ static int uw2453_switch_radio_off(struct zd_rf *rf) | |||
501 | int r; | 503 | int r; |
502 | struct zd_chip *chip = zd_rf_to_chip(rf); | 504 | struct zd_chip *chip = zd_rf_to_chip(rf); |
503 | static const struct zd_ioreq16 ioreqs[] = { | 505 | static const struct zd_ioreq16 ioreqs[] = { |
504 | { CR11, 0x04 }, { CR251, 0x2f }, | 506 | { ZD_CR11, 0x04 }, { ZD_CR251, 0x2f }, |
505 | }; | 507 | }; |
506 | 508 | ||
507 | /* enter IDLE mode */ | 509 | /* enter IDLE mode */ |
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index ab607bbd6291..0e819943b9e4 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c | |||
@@ -1893,10 +1893,10 @@ int zd_usb_rfwrite(struct zd_usb *usb, u32 value, u8 bits) | |||
1893 | 1893 | ||
1894 | dev_dbg_f(zd_usb_dev(usb), "value %#09x bits %d\n", value, bits); | 1894 | dev_dbg_f(zd_usb_dev(usb), "value %#09x bits %d\n", value, bits); |
1895 | 1895 | ||
1896 | r = zd_usb_ioread16(usb, &bit_value_template, CR203); | 1896 | r = zd_usb_ioread16(usb, &bit_value_template, ZD_CR203); |
1897 | if (r) { | 1897 | if (r) { |
1898 | dev_dbg_f(zd_usb_dev(usb), | 1898 | dev_dbg_f(zd_usb_dev(usb), |
1899 | "error %d: Couldn't read CR203\n", r); | 1899 | "error %d: Couldn't read ZD_CR203\n", r); |
1900 | return r; | 1900 | return r; |
1901 | } | 1901 | } |
1902 | bit_value_template &= ~(RF_IF_LE|RF_CLK|RF_DATA); | 1902 | bit_value_template &= ~(RF_IF_LE|RF_CLK|RF_DATA); |
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.h b/drivers/net/wireless/zd1211rw/zd_usb.h index 325d0f989257..bf942843b733 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.h +++ b/drivers/net/wireless/zd1211rw/zd_usb.h | |||
@@ -109,7 +109,7 @@ struct usb_req_rfwrite { | |||
109 | __le16 bits; | 109 | __le16 bits; |
110 | /* RF2595: 24 */ | 110 | /* RF2595: 24 */ |
111 | __le16 bit_values[0]; | 111 | __le16 bit_values[0]; |
112 | /* (CR203 & ~(RF_IF_LE | RF_CLK | RF_DATA)) | (bit ? RF_DATA : 0) */ | 112 | /* (ZD_CR203 & ~(RF_IF_LE | RF_CLK | RF_DATA)) | (bit ? RF_DATA : 0) */ |
113 | } __packed; | 113 | } __packed; |
114 | 114 | ||
115 | /* USB interrupt */ | 115 | /* USB interrupt */ |