aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--MAINTAINERS8
-rw-r--r--drivers/net/wireless/ath/Kconfig1
-rw-r--r--drivers/net/wireless/ath/Makefile1
-rw-r--r--drivers/net/wireless/ath/wil6210/Kconfig29
-rw-r--r--drivers/net/wireless/ath/wil6210/Makefile13
-rw-r--r--drivers/net/wireless/ath/wil6210/cfg80211.c573
-rw-r--r--drivers/net/wireless/ath/wil6210/dbg_hexdump.h30
-rw-r--r--drivers/net/wireless/ath/wil6210/debugfs.c603
-rw-r--r--drivers/net/wireless/ath/wil6210/interrupt.c471
-rw-r--r--drivers/net/wireless/ath/wil6210/main.c407
-rw-r--r--drivers/net/wireless/ath/wil6210/netdev.c157
-rw-r--r--drivers/net/wireless/ath/wil6210/pcie_bus.c223
-rw-r--r--drivers/net/wireless/ath/wil6210/txrx.c871
-rw-r--r--drivers/net/wireless/ath/wil6210/txrx.h362
-rw-r--r--drivers/net/wireless/ath/wil6210/wil6210.h363
-rw-r--r--drivers/net/wireless/ath/wil6210/wmi.c975
-rw-r--r--drivers/net/wireless/ath/wil6210/wmi.h1116
17 files changed, 6203 insertions, 0 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 4e2a1f67a1fc..16c3506da16c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1353,6 +1353,14 @@ W: http://wireless.kernel.org/en/users/Drivers/ath9k
1353S: Supported 1353S: Supported
1354F: drivers/net/wireless/ath/ath9k/ 1354F: drivers/net/wireless/ath/ath9k/
1355 1355
1356WILOCITY WIL6210 WIRELESS DRIVER
1357M: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
1358L: linux-wireless@vger.kernel.org
1359L: wil6210@qca.qualcomm.com
1360S: Supported
1361W: http://wireless.kernel.org/en/users/Drivers/wil6210
1362F: drivers/net/wireless/ath/wil6210/
1363
1356CARL9170 LINUX COMMUNITY WIRELESS DRIVER 1364CARL9170 LINUX COMMUNITY WIRELESS DRIVER
1357M: Christian Lamparter <chunkeey@googlemail.com> 1365M: Christian Lamparter <chunkeey@googlemail.com>
1358L: linux-wireless@vger.kernel.org 1366L: linux-wireless@vger.kernel.org
diff --git a/drivers/net/wireless/ath/Kconfig b/drivers/net/wireless/ath/Kconfig
index 1a67a4f829fe..2c02b4e84094 100644
--- a/drivers/net/wireless/ath/Kconfig
+++ b/drivers/net/wireless/ath/Kconfig
@@ -30,5 +30,6 @@ source "drivers/net/wireless/ath/ath9k/Kconfig"
30source "drivers/net/wireless/ath/carl9170/Kconfig" 30source "drivers/net/wireless/ath/carl9170/Kconfig"
31source "drivers/net/wireless/ath/ath6kl/Kconfig" 31source "drivers/net/wireless/ath/ath6kl/Kconfig"
32source "drivers/net/wireless/ath/ar5523/Kconfig" 32source "drivers/net/wireless/ath/ar5523/Kconfig"
33source "drivers/net/wireless/ath/wil6210/Kconfig"
33 34
34endif 35endif
diff --git a/drivers/net/wireless/ath/Makefile b/drivers/net/wireless/ath/Makefile
index 1e18621326dc..97b964ded2be 100644
--- a/drivers/net/wireless/ath/Makefile
+++ b/drivers/net/wireless/ath/Makefile
@@ -3,6 +3,7 @@ obj-$(CONFIG_ATH9K_HW) += ath9k/
3obj-$(CONFIG_CARL9170) += carl9170/ 3obj-$(CONFIG_CARL9170) += carl9170/
4obj-$(CONFIG_ATH6KL) += ath6kl/ 4obj-$(CONFIG_ATH6KL) += ath6kl/
5obj-$(CONFIG_AR5523) += ar5523/ 5obj-$(CONFIG_AR5523) += ar5523/
6obj-$(CONFIG_WIL6210) += wil6210/
6 7
7obj-$(CONFIG_ATH_COMMON) += ath.o 8obj-$(CONFIG_ATH_COMMON) += ath.o
8 9
diff --git a/drivers/net/wireless/ath/wil6210/Kconfig b/drivers/net/wireless/ath/wil6210/Kconfig
new file mode 100644
index 000000000000..bac3d98a0cfb
--- /dev/null
+++ b/drivers/net/wireless/ath/wil6210/Kconfig
@@ -0,0 +1,29 @@
1config WIL6210
2 tristate "Wilocity 60g WiFi card wil6210 support"
3 depends on CFG80211
4 depends on PCI
5 default n
6 ---help---
7 This module adds support for wireless adapter based on
8 wil6210 chip by Wilocity. It supports operation on the
9 60 GHz band, covered by the IEEE802.11ad standard.
10
11 http://wireless.kernel.org/en/users/Drivers/wil6210
12
13 If you choose to build it as a module, it will be called
14 wil6210
15
16config WIL6210_ISR_COR
17 bool "Use Clear-On-Read mode for ISR registers for wil6210"
18 depends on WIL6210
19 default y
20 ---help---
21 ISR registers on wil6210 chip may operate in either
22 COR (Clear-On-Read) or W1C (Write-1-to-Clear) mode.
23 For production code, use COR (say y); is default since
24 it saves extra target transaction;
25 For ISR debug, use W1C (say n); is allows to monitor ISR
26 registers with debugfs. If COR were used, ISR would
27 self-clear when accessed for debug purposes, it makes
28 such monitoring impossible.
29 Say y unless you debug interrupts
diff --git a/drivers/net/wireless/ath/wil6210/Makefile b/drivers/net/wireless/ath/wil6210/Makefile
new file mode 100644
index 000000000000..9396dc9fe3c5
--- /dev/null
+++ b/drivers/net/wireless/ath/wil6210/Makefile
@@ -0,0 +1,13 @@
1obj-$(CONFIG_WIL6210) += wil6210.o
2
3wil6210-objs := main.o
4wil6210-objs += netdev.o
5wil6210-objs += cfg80211.o
6wil6210-objs += pcie_bus.o
7wil6210-objs += debugfs.o
8wil6210-objs += wmi.o
9wil6210-objs += interrupt.o
10wil6210-objs += txrx.o
11
12subdir-ccflags-y += -Werror
13subdir-ccflags-y += -D__CHECK_ENDIAN__
diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c
new file mode 100644
index 000000000000..116f4e807ae1
--- /dev/null
+++ b/drivers/net/wireless/ath/wil6210/cfg80211.c
@@ -0,0 +1,573 @@
1/*
2 * Copyright (c) 2012 Qualcomm Atheros, Inc.
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include <linux/kernel.h>
18#include <linux/netdevice.h>
19#include <linux/sched.h>
20#include <linux/etherdevice.h>
21#include <linux/wireless.h>
22#include <linux/ieee80211.h>
23#include <linux/slab.h>
24#include <linux/version.h>
25#include <net/cfg80211.h>
26
27#include "wil6210.h"
28#include "wmi.h"
29
30#define CHAN60G(_channel, _flags) { \
31 .band = IEEE80211_BAND_60GHZ, \
32 .center_freq = 56160 + (2160 * (_channel)), \
33 .hw_value = (_channel), \
34 .flags = (_flags), \
35 .max_antenna_gain = 0, \
36 .max_power = 40, \
37}
38
39static struct ieee80211_channel wil_60ghz_channels[] = {
40 CHAN60G(1, 0),
41 CHAN60G(2, 0),
42 CHAN60G(3, 0),
43/* channel 4 not supported yet */
44};
45
46static struct ieee80211_supported_band wil_band_60ghz = {
47 .channels = wil_60ghz_channels,
48 .n_channels = ARRAY_SIZE(wil_60ghz_channels),
49 .ht_cap = {
50 .ht_supported = true,
51 .cap = 0, /* TODO */
52 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K, /* TODO */
53 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, /* TODO */
54 .mcs = {
55 /* MCS 1..12 - SC PHY */
56 .rx_mask = {0xfe, 0x1f}, /* 1..12 */
57 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, /* TODO */
58 },
59 },
60};
61
62static const struct ieee80211_txrx_stypes
63wil_mgmt_stypes[NUM_NL80211_IFTYPES] = {
64 [NL80211_IFTYPE_STATION] = {
65 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
66 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
67 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
68 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
69 },
70 [NL80211_IFTYPE_AP] = {
71 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
72 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
73 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
74 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
75 },
76 [NL80211_IFTYPE_P2P_CLIENT] = {
77 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
78 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
79 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
80 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
81 },
82 [NL80211_IFTYPE_P2P_GO] = {
83 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
84 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
85 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
86 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
87 },
88};
89
90static const u32 wil_cipher_suites[] = {
91 WLAN_CIPHER_SUITE_GCMP,
92};
93
94int wil_iftype_nl2wmi(enum nl80211_iftype type)
95{
96 static const struct {
97 enum nl80211_iftype nl;
98 enum wmi_network_type wmi;
99 } __nl2wmi[] = {
100 {NL80211_IFTYPE_ADHOC, WMI_NETTYPE_ADHOC},
101 {NL80211_IFTYPE_STATION, WMI_NETTYPE_INFRA},
102 {NL80211_IFTYPE_AP, WMI_NETTYPE_AP},
103 {NL80211_IFTYPE_P2P_CLIENT, WMI_NETTYPE_P2P},
104 {NL80211_IFTYPE_P2P_GO, WMI_NETTYPE_P2P},
105 {NL80211_IFTYPE_MONITOR, WMI_NETTYPE_ADHOC}, /* FIXME */
106 };
107 uint i;
108
109 for (i = 0; i < ARRAY_SIZE(__nl2wmi); i++) {
110 if (__nl2wmi[i].nl == type)
111 return __nl2wmi[i].wmi;
112 }
113
114 return -EOPNOTSUPP;
115}
116
117static int wil_cfg80211_get_station(struct wiphy *wiphy,
118 struct net_device *ndev,
119 u8 *mac, struct station_info *sinfo)
120{
121 struct wil6210_priv *wil = wiphy_to_wil(wiphy);
122 int rc;
123 struct wmi_notify_req_cmd cmd = {
124 .cid = 0,
125 .interval_usec = 0,
126 };
127
128 if (memcmp(mac, wil->dst_addr[0], ETH_ALEN))
129 return -ENOENT;
130
131 /* WMI_NOTIFY_REQ_DONE_EVENTID handler fills wil->stats.bf_mcs */
132 rc = wmi_call(wil, WMI_NOTIFY_REQ_CMDID, &cmd, sizeof(cmd),
133 WMI_NOTIFY_REQ_DONE_EVENTID, NULL, 0, 20);
134 if (rc)
135 return rc;
136
137 sinfo->generation = wil->sinfo_gen;
138
139 sinfo->filled |= STATION_INFO_TX_BITRATE;
140 sinfo->txrate.flags = RATE_INFO_FLAGS_MCS | RATE_INFO_FLAGS_60G;
141 sinfo->txrate.mcs = wil->stats.bf_mcs;
142 sinfo->filled |= STATION_INFO_RX_BITRATE;
143 sinfo->rxrate.flags = RATE_INFO_FLAGS_MCS | RATE_INFO_FLAGS_60G;
144 sinfo->rxrate.mcs = wil->stats.last_mcs_rx;
145
146 if (test_bit(wil_status_fwconnected, &wil->status)) {
147 sinfo->filled |= STATION_INFO_SIGNAL;
148 sinfo->signal = 12; /* TODO: provide real value */
149 }
150
151 return 0;
152}
153
154static int wil_cfg80211_change_iface(struct wiphy *wiphy,
155 struct net_device *ndev,
156 enum nl80211_iftype type, u32 *flags,
157 struct vif_params *params)
158{
159 struct wil6210_priv *wil = wiphy_to_wil(wiphy);
160 struct wireless_dev *wdev = wil->wdev;
161
162 switch (type) {
163 case NL80211_IFTYPE_STATION:
164 case NL80211_IFTYPE_AP:
165 case NL80211_IFTYPE_P2P_CLIENT:
166 case NL80211_IFTYPE_P2P_GO:
167 break;
168 case NL80211_IFTYPE_MONITOR:
169 if (flags)
170 wil->monitor_flags = *flags;
171 else
172 wil->monitor_flags = 0;
173
174 break;
175 default:
176 return -EOPNOTSUPP;
177 }
178
179 wdev->iftype = type;
180
181 return 0;
182}
183
184static int wil_cfg80211_scan(struct wiphy *wiphy,
185 struct cfg80211_scan_request *request)
186{
187 struct wil6210_priv *wil = wiphy_to_wil(wiphy);
188 struct wireless_dev *wdev = wil->wdev;
189 struct {
190 struct wmi_start_scan_cmd cmd;
191 u16 chnl[4];
192 } __packed cmd;
193 uint i, n;
194
195 if (wil->scan_request) {
196 wil_err(wil, "Already scanning\n");
197 return -EAGAIN;
198 }
199
200 /* check we are client side */
201 switch (wdev->iftype) {
202 case NL80211_IFTYPE_STATION:
203 case NL80211_IFTYPE_P2P_CLIENT:
204 break;
205 default:
206 return -EOPNOTSUPP;
207
208 }
209
210 /* FW don't support scan after connection attempt */
211 if (test_bit(wil_status_dontscan, &wil->status)) {
212 wil_err(wil, "Scan after connect attempt not supported\n");
213 return -EBUSY;
214 }
215
216 wil->scan_request = request;
217
218 memset(&cmd, 0, sizeof(cmd));
219 cmd.cmd.num_channels = 0;
220 n = min(request->n_channels, 4U);
221 for (i = 0; i < n; i++) {
222 int ch = request->channels[i]->hw_value;
223 if (ch == 0) {
224 wil_err(wil,
225 "Scan requested for unknown frequency %dMhz\n",
226 request->channels[i]->center_freq);
227 continue;
228 }
229 /* 0-based channel indexes */
230 cmd.cmd.channel_list[cmd.cmd.num_channels++].channel = ch - 1;
231 wil_dbg(wil, "Scan for ch %d : %d MHz\n", ch,
232 request->channels[i]->center_freq);
233 }
234
235 return wmi_send(wil, WMI_START_SCAN_CMDID, &cmd, sizeof(cmd.cmd) +
236 cmd.cmd.num_channels * sizeof(cmd.cmd.channel_list[0]));
237}
238
239static int wil_cfg80211_connect(struct wiphy *wiphy,
240 struct net_device *ndev,
241 struct cfg80211_connect_params *sme)
242{
243 struct wil6210_priv *wil = wiphy_to_wil(wiphy);
244 struct cfg80211_bss *bss;
245 struct wmi_connect_cmd conn;
246 const u8 *ssid_eid;
247 const u8 *rsn_eid;
248 int ch;
249 int rc = 0;
250
251 bss = cfg80211_get_bss(wiphy, sme->channel, sme->bssid,
252 sme->ssid, sme->ssid_len,
253 WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
254 if (!bss) {
255 wil_err(wil, "Unable to find BSS\n");
256 return -ENOENT;
257 }
258
259 ssid_eid = ieee80211_bss_get_ie(bss, WLAN_EID_SSID);
260 if (!ssid_eid) {
261 wil_err(wil, "No SSID\n");
262 rc = -ENOENT;
263 goto out;
264 }
265
266 rsn_eid = sme->ie ?
267 cfg80211_find_ie(WLAN_EID_RSN, sme->ie, sme->ie_len) :
268 NULL;
269 if (rsn_eid) {
270 if (sme->ie_len > WMI_MAX_IE_LEN) {
271 rc = -ERANGE;
272 wil_err(wil, "IE too large (%td bytes)\n",
273 sme->ie_len);
274 goto out;
275 }
276 /*
277 * For secure assoc, send:
278 * (1) WMI_DELETE_CIPHER_KEY_CMD
279 * (2) WMI_SET_APPIE_CMD
280 */
281 rc = wmi_del_cipher_key(wil, 0, bss->bssid);
282 if (rc) {
283 wil_err(wil, "WMI_DELETE_CIPHER_KEY_CMD failed\n");
284 goto out;
285 }
286 /* WMI_SET_APPIE_CMD */
287 rc = wmi_set_ie(wil, WMI_FRAME_ASSOC_REQ, sme->ie_len, sme->ie);
288 if (rc) {
289 wil_err(wil, "WMI_SET_APPIE_CMD failed\n");
290 goto out;
291 }
292 }
293
294 /* WMI_CONNECT_CMD */
295 memset(&conn, 0, sizeof(conn));
296 switch (bss->capability & 0x03) {
297 case WLAN_CAPABILITY_DMG_TYPE_AP:
298 conn.network_type = WMI_NETTYPE_INFRA;
299 break;
300 case WLAN_CAPABILITY_DMG_TYPE_PBSS:
301 conn.network_type = WMI_NETTYPE_P2P;
302 break;
303 default:
304 wil_err(wil, "Unsupported BSS type, capability= 0x%04x\n",
305 bss->capability);
306 goto out;
307 }
308 if (rsn_eid) {
309 conn.dot11_auth_mode = WMI_AUTH11_SHARED;
310 conn.auth_mode = WMI_AUTH_WPA2_PSK;
311 conn.pairwise_crypto_type = WMI_CRYPT_AES_GCMP;
312 conn.pairwise_crypto_len = 16;
313 } else {
314 conn.dot11_auth_mode = WMI_AUTH11_OPEN;
315 conn.auth_mode = WMI_AUTH_NONE;
316 }
317
318 conn.ssid_len = min_t(u8, ssid_eid[1], 32);
319 memcpy(conn.ssid, ssid_eid+2, conn.ssid_len);
320
321 ch = bss->channel->hw_value;
322 if (ch == 0) {
323 wil_err(wil, "BSS at unknown frequency %dMhz\n",
324 bss->channel->center_freq);
325 rc = -EOPNOTSUPP;
326 goto out;
327 }
328 conn.channel = ch - 1;
329
330 memcpy(conn.bssid, bss->bssid, 6);
331 memcpy(conn.dst_mac, bss->bssid, 6);
332 /*
333 * FW don't support scan after connection attempt
334 */
335 set_bit(wil_status_dontscan, &wil->status);
336
337 rc = wmi_send(wil, WMI_CONNECT_CMDID, &conn, sizeof(conn));
338 if (rc == 0) {
339 /* Connect can take lots of time */
340 mod_timer(&wil->connect_timer,
341 jiffies + msecs_to_jiffies(2000));
342 }
343
344 out:
345 cfg80211_put_bss(bss);
346
347 return rc;
348}
349
350static int wil_cfg80211_disconnect(struct wiphy *wiphy,
351 struct net_device *ndev,
352 u16 reason_code)
353{
354 int rc;
355 struct wil6210_priv *wil = wiphy_to_wil(wiphy);
356
357 rc = wmi_send(wil, WMI_DISCONNECT_CMDID, NULL, 0);
358
359 return rc;
360}
361
362static int wil_cfg80211_set_channel(struct wiphy *wiphy,
363 struct cfg80211_chan_def *chandef)
364{
365 struct wil6210_priv *wil = wiphy_to_wil(wiphy);
366 struct wireless_dev *wdev = wil->wdev;
367
368 wdev->preset_chandef = *chandef;
369
370 return 0;
371}
372
373static int wil_cfg80211_add_key(struct wiphy *wiphy,
374 struct net_device *ndev,
375 u8 key_index, bool pairwise,
376 const u8 *mac_addr,
377 struct key_params *params)
378{
379 struct wil6210_priv *wil = wiphy_to_wil(wiphy);
380
381 /* group key is not used */
382 if (!pairwise)
383 return 0;
384
385 return wmi_add_cipher_key(wil, key_index, mac_addr,
386 params->key_len, params->key);
387}
388
389static int wil_cfg80211_del_key(struct wiphy *wiphy,
390 struct net_device *ndev,
391 u8 key_index, bool pairwise,
392 const u8 *mac_addr)
393{
394 struct wil6210_priv *wil = wiphy_to_wil(wiphy);
395
396 /* group key is not used */
397 if (!pairwise)
398 return 0;
399
400 return wmi_del_cipher_key(wil, key_index, mac_addr);
401}
402
403/* Need to be present or wiphy_new() will WARN */
404static int wil_cfg80211_set_default_key(struct wiphy *wiphy,
405 struct net_device *ndev,
406 u8 key_index, bool unicast,
407 bool multicast)
408{
409 return 0;
410}
411
412static int wil_cfg80211_start_ap(struct wiphy *wiphy,
413 struct net_device *ndev,
414 struct cfg80211_ap_settings *info)
415{
416 int rc = 0;
417 struct wil6210_priv *wil = wiphy_to_wil(wiphy);
418 struct wireless_dev *wdev = ndev->ieee80211_ptr;
419 struct ieee80211_channel *channel = info->chandef.chan;
420 struct cfg80211_beacon_data *bcon = &info->beacon;
421 u8 wmi_nettype = wil_iftype_nl2wmi(wdev->iftype);
422
423 if (!channel) {
424 wil_err(wil, "AP: No channel???\n");
425 return -EINVAL;
426 }
427
428 wil_dbg(wil, "AP on Channel %d %d MHz, %s\n", channel->hw_value,
429 channel->center_freq, info->privacy ? "secure" : "open");
430 print_hex_dump_bytes("SSID ", DUMP_PREFIX_OFFSET,
431 info->ssid, info->ssid_len);
432
433 rc = wil_reset(wil);
434 if (rc)
435 return rc;
436
437 rc = wmi_set_ssid(wil, info->ssid_len, info->ssid);
438 if (rc)
439 return rc;
440
441 rc = wmi_set_channel(wil, channel->hw_value);
442 if (rc)
443 return rc;
444
445 /* MAC address - pre-requisite for other commands */
446 wmi_set_mac_address(wil, ndev->dev_addr);
447
448 /* IE's */
449 /* bcon 'head IE's are not relevant for 60g band */
450 wmi_set_ie(wil, WMI_FRAME_BEACON, bcon->beacon_ies_len,
451 bcon->beacon_ies);
452 wmi_set_ie(wil, WMI_FRAME_PROBE_RESP, bcon->proberesp_ies_len,
453 bcon->proberesp_ies);
454 wmi_set_ie(wil, WMI_FRAME_ASSOC_RESP, bcon->assocresp_ies_len,
455 bcon->assocresp_ies);
456
457 wil->secure_pcp = info->privacy;
458
459 rc = wmi_set_bcon(wil, info->beacon_interval, wmi_nettype);
460 if (rc)
461 return rc;
462
463 /* Rx VRING. After MAC and beacon */
464 rc = wil_rx_init(wil);
465
466 netif_carrier_on(ndev);
467
468 return rc;
469}
470
471static int wil_cfg80211_stop_ap(struct wiphy *wiphy,
472 struct net_device *ndev)
473{
474 int rc = 0;
475 struct wil6210_priv *wil = wiphy_to_wil(wiphy);
476 struct wireless_dev *wdev = ndev->ieee80211_ptr;
477 u8 wmi_nettype = wil_iftype_nl2wmi(wdev->iftype);
478
479 /* To stop beaconing, set BI to 0 */
480 rc = wmi_set_bcon(wil, 0, wmi_nettype);
481
482 return rc;
483}
484
485static struct cfg80211_ops wil_cfg80211_ops = {
486 .scan = wil_cfg80211_scan,
487 .connect = wil_cfg80211_connect,
488 .disconnect = wil_cfg80211_disconnect,
489 .change_virtual_intf = wil_cfg80211_change_iface,
490 .get_station = wil_cfg80211_get_station,
491 .set_monitor_channel = wil_cfg80211_set_channel,
492 .add_key = wil_cfg80211_add_key,
493 .del_key = wil_cfg80211_del_key,
494 .set_default_key = wil_cfg80211_set_default_key,
495 /* AP mode */
496 .start_ap = wil_cfg80211_start_ap,
497 .stop_ap = wil_cfg80211_stop_ap,
498};
499
500static void wil_wiphy_init(struct wiphy *wiphy)
501{
502 /* TODO: set real value */
503 wiphy->max_scan_ssids = 10;
504 wiphy->max_num_pmkids = 0 /* TODO: */;
505 wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
506 BIT(NL80211_IFTYPE_AP) |
507 BIT(NL80211_IFTYPE_MONITOR);
508 /* TODO: enable P2P when integrated with supplicant:
509 * BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO)
510 */
511 wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME |
512 WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
513 dev_warn(wiphy_dev(wiphy), "%s : flags = 0x%08x\n",
514 __func__, wiphy->flags);
515 wiphy->probe_resp_offload =
516 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
517 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
518 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P;
519
520 wiphy->bands[IEEE80211_BAND_60GHZ] = &wil_band_60ghz;
521
522 /* TODO: figure this out */
523 wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
524
525 wiphy->cipher_suites = wil_cipher_suites;
526 wiphy->n_cipher_suites = ARRAY_SIZE(wil_cipher_suites);
527 wiphy->mgmt_stypes = wil_mgmt_stypes;
528}
529
530struct wireless_dev *wil_cfg80211_init(struct device *dev)
531{
532 int rc = 0;
533 struct wireless_dev *wdev;
534
535 wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
536 if (!wdev)
537 return ERR_PTR(-ENOMEM);
538
539 wdev->wiphy = wiphy_new(&wil_cfg80211_ops,
540 sizeof(struct wil6210_priv));
541 if (!wdev->wiphy) {
542 rc = -ENOMEM;
543 goto out;
544 }
545
546 set_wiphy_dev(wdev->wiphy, dev);
547 wil_wiphy_init(wdev->wiphy);
548
549 rc = wiphy_register(wdev->wiphy);
550 if (rc < 0)
551 goto out_failed_reg;
552
553 return wdev;
554
555out_failed_reg:
556 wiphy_free(wdev->wiphy);
557out:
558 kfree(wdev);
559
560 return ERR_PTR(rc);
561}
562
563void wil_wdev_free(struct wil6210_priv *wil)
564{
565 struct wireless_dev *wdev = wil_to_wdev(wil);
566
567 if (!wdev)
568 return;
569
570 wiphy_unregister(wdev->wiphy);
571 wiphy_free(wdev->wiphy);
572 kfree(wdev);
573}
diff --git a/drivers/net/wireless/ath/wil6210/dbg_hexdump.h b/drivers/net/wireless/ath/wil6210/dbg_hexdump.h
new file mode 100644
index 000000000000..6a315ba5aa7d
--- /dev/null
+++ b/drivers/net/wireless/ath/wil6210/dbg_hexdump.h
@@ -0,0 +1,30 @@
1#ifndef WIL_DBG_HEXDUMP_H_
2#define WIL_DBG_HEXDUMP_H_
3
4#if defined(CONFIG_DYNAMIC_DEBUG)
5#define wil_dynamic_hex_dump(prefix_str, prefix_type, rowsize, \
6 groupsize, buf, len, ascii) \
7do { \
8 DEFINE_DYNAMIC_DEBUG_METADATA(descriptor, \
9 __builtin_constant_p(prefix_str) ? prefix_str : "hexdump");\
10 if (unlikely(descriptor.flags & _DPRINTK_FLAGS_PRINT)) \
11 print_hex_dump(KERN_DEBUG, prefix_str, \
12 prefix_type, rowsize, groupsize, \
13 buf, len, ascii); \
14} while (0)
15
16#define wil_print_hex_dump_debug(prefix_str, prefix_type, rowsize, \
17 groupsize, buf, len, ascii) \
18 wil_dynamic_hex_dump(prefix_str, prefix_type, rowsize, \
19 groupsize, buf, len, ascii)
20
21#define print_hex_dump_bytes(prefix_str, prefix_type, buf, len) \
22 wil_dynamic_hex_dump(prefix_str, prefix_type, 16, 1, buf, len, true)
23#else /* defined(CONFIG_DYNAMIC_DEBUG) */
24#define wil_print_hex_dump_debug(prefix_str, prefix_type, rowsize, \
25 groupsize, buf, len, ascii) \
26 print_hex_dump(KERN_DEBUG, prefix_str, prefix_type, rowsize, \
27 groupsize, buf, len, ascii)
28#endif /* defined(CONFIG_DYNAMIC_DEBUG) */
29
30#endif /* WIL_DBG_HEXDUMP_H_ */
diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c
new file mode 100644
index 000000000000..65fc9683bfd8
--- /dev/null
+++ b/drivers/net/wireless/ath/wil6210/debugfs.c
@@ -0,0 +1,603 @@
1/*
2 * Copyright (c) 2012 Qualcomm Atheros, Inc.
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include <linux/module.h>
18#include <linux/debugfs.h>
19#include <linux/seq_file.h>
20#include <linux/pci.h>
21#include <linux/rtnetlink.h>
22
23#include "wil6210.h"
24#include "txrx.h"
25
26/* Nasty hack. Better have per device instances */
27static u32 mem_addr;
28static u32 dbg_txdesc_index;
29
30static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil,
31 const char *name, struct vring *vring)
32{
33 void __iomem *x = wmi_addr(wil, vring->hwtail);
34
35 seq_printf(s, "VRING %s = {\n", name);
36 seq_printf(s, " pa = 0x%016llx\n", (unsigned long long)vring->pa);
37 seq_printf(s, " va = 0x%p\n", vring->va);
38 seq_printf(s, " size = %d\n", vring->size);
39 seq_printf(s, " swtail = %d\n", vring->swtail);
40 seq_printf(s, " swhead = %d\n", vring->swhead);
41 seq_printf(s, " hwtail = [0x%08x] -> ", vring->hwtail);
42 if (x)
43 seq_printf(s, "0x%08x\n", ioread32(x));
44 else
45 seq_printf(s, "???\n");
46
47 if (vring->va && (vring->size < 1025)) {
48 uint i;
49 for (i = 0; i < vring->size; i++) {
50 volatile struct vring_tx_desc *d = &vring->va[i].tx;
51 if ((i % 64) == 0 && (i != 0))
52 seq_printf(s, "\n");
53 seq_printf(s, "%s", (d->dma.status & BIT(0)) ?
54 "S" : (vring->ctx[i] ? "H" : "h"));
55 }
56 seq_printf(s, "\n");
57 }
58 seq_printf(s, "}\n");
59}
60
61static int wil_vring_debugfs_show(struct seq_file *s, void *data)
62{
63 uint i;
64 struct wil6210_priv *wil = s->private;
65
66 wil_print_vring(s, wil, "rx", &wil->vring_rx);
67
68 for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) {
69 struct vring *vring = &(wil->vring_tx[i]);
70 if (vring->va) {
71 char name[10];
72 snprintf(name, sizeof(name), "tx_%2d", i);
73 wil_print_vring(s, wil, name, vring);
74 }
75 }
76
77 return 0;
78}
79
80static int wil_vring_seq_open(struct inode *inode, struct file *file)
81{
82 return single_open(file, wil_vring_debugfs_show, inode->i_private);
83}
84
85static const struct file_operations fops_vring = {
86 .open = wil_vring_seq_open,
87 .release = single_release,
88 .read = seq_read,
89 .llseek = seq_lseek,
90};
91
92static void wil_print_ring(struct seq_file *s, const char *prefix,
93 void __iomem *off)
94{
95 struct wil6210_priv *wil = s->private;
96 struct wil6210_mbox_ring r;
97 int rsize;
98 uint i;
99
100 wil_memcpy_fromio_32(&r, off, sizeof(r));
101 wil_mbox_ring_le2cpus(&r);
102 /*
103 * we just read memory block from NIC. This memory may be
104 * garbage. Check validity before using it.
105 */
106 rsize = r.size / sizeof(struct wil6210_mbox_ring_desc);
107
108 seq_printf(s, "ring %s = {\n", prefix);
109 seq_printf(s, " base = 0x%08x\n", r.base);
110 seq_printf(s, " size = 0x%04x bytes -> %d entries\n", r.size, rsize);
111 seq_printf(s, " tail = 0x%08x\n", r.tail);
112 seq_printf(s, " head = 0x%08x\n", r.head);
113 seq_printf(s, " entry size = %d\n", r.entry_size);
114
115 if (r.size % sizeof(struct wil6210_mbox_ring_desc)) {
116 seq_printf(s, " ??? size is not multiple of %zd, garbage?\n",
117 sizeof(struct wil6210_mbox_ring_desc));
118 goto out;
119 }
120
121 if (!wmi_addr(wil, r.base) ||
122 !wmi_addr(wil, r.tail) ||
123 !wmi_addr(wil, r.head)) {
124 seq_printf(s, " ??? pointers are garbage?\n");
125 goto out;
126 }
127
128 for (i = 0; i < rsize; i++) {
129 struct wil6210_mbox_ring_desc d;
130 struct wil6210_mbox_hdr hdr;
131 size_t delta = i * sizeof(d);
132 void __iomem *x = wil->csr + HOSTADDR(r.base) + delta;
133
134 wil_memcpy_fromio_32(&d, x, sizeof(d));
135
136 seq_printf(s, " [%2x] %s %s%s 0x%08x", i,
137 d.sync ? "F" : "E",
138 (r.tail - r.base == delta) ? "t" : " ",
139 (r.head - r.base == delta) ? "h" : " ",
140 le32_to_cpu(d.addr));
141 if (0 == wmi_read_hdr(wil, d.addr, &hdr)) {
142 u16 len = le16_to_cpu(hdr.len);
143 seq_printf(s, " -> %04x %04x %04x %02x\n",
144 le16_to_cpu(hdr.seq), len,
145 le16_to_cpu(hdr.type), hdr.flags);
146 if (len <= MAX_MBOXITEM_SIZE) {
147 int n = 0;
148 unsigned char printbuf[16 * 3 + 2];
149 unsigned char databuf[MAX_MBOXITEM_SIZE];
150 void __iomem *src = wmi_buffer(wil, d.addr) +
151 sizeof(struct wil6210_mbox_hdr);
152 /*
153 * No need to check @src for validity -
154 * we already validated @d.addr while
155 * reading header
156 */
157 wil_memcpy_fromio_32(databuf, src, len);
158 while (n < len) {
159 int l = min(len - n, 16);
160 hex_dump_to_buffer(databuf + n, l,
161 16, 1, printbuf,
162 sizeof(printbuf),
163 false);
164 seq_printf(s, " : %s\n", printbuf);
165 n += l;
166 }
167 }
168 } else {
169 seq_printf(s, "\n");
170 }
171 }
172 out:
173 seq_printf(s, "}\n");
174}
175
176static int wil_mbox_debugfs_show(struct seq_file *s, void *data)
177{
178 struct wil6210_priv *wil = s->private;
179
180 wil_print_ring(s, "tx", wil->csr + HOST_MBOX +
181 offsetof(struct wil6210_mbox_ctl, tx));
182 wil_print_ring(s, "rx", wil->csr + HOST_MBOX +
183 offsetof(struct wil6210_mbox_ctl, rx));
184
185 return 0;
186}
187
188static int wil_mbox_seq_open(struct inode *inode, struct file *file)
189{
190 return single_open(file, wil_mbox_debugfs_show, inode->i_private);
191}
192
193static const struct file_operations fops_mbox = {
194 .open = wil_mbox_seq_open,
195 .release = single_release,
196 .read = seq_read,
197 .llseek = seq_lseek,
198};
199
200static int wil_debugfs_iomem_x32_set(void *data, u64 val)
201{
202 iowrite32(val, (void __iomem *)data);
203 wmb(); /* make sure write propagated to HW */
204
205 return 0;
206}
207
208static int wil_debugfs_iomem_x32_get(void *data, u64 *val)
209{
210 *val = ioread32((void __iomem *)data);
211
212 return 0;
213}
214
215DEFINE_SIMPLE_ATTRIBUTE(fops_iomem_x32, wil_debugfs_iomem_x32_get,
216 wil_debugfs_iomem_x32_set, "0x%08llx\n");
217
218static struct dentry *wil_debugfs_create_iomem_x32(const char *name,
219 mode_t mode,
220 struct dentry *parent,
221 void __iomem *value)
222{
223 return debugfs_create_file(name, mode, parent, (void * __force)value,
224 &fops_iomem_x32);
225}
226
227static int wil6210_debugfs_create_ISR(struct wil6210_priv *wil,
228 const char *name,
229 struct dentry *parent, u32 off)
230{
231 struct dentry *d = debugfs_create_dir(name, parent);
232
233 if (IS_ERR_OR_NULL(d))
234 return -ENODEV;
235
236 wil_debugfs_create_iomem_x32("ICC", S_IRUGO | S_IWUSR, d,
237 wil->csr + off);
238 wil_debugfs_create_iomem_x32("ICR", S_IRUGO | S_IWUSR, d,
239 wil->csr + off + 4);
240 wil_debugfs_create_iomem_x32("ICM", S_IRUGO | S_IWUSR, d,
241 wil->csr + off + 8);
242 wil_debugfs_create_iomem_x32("ICS", S_IWUSR, d,
243 wil->csr + off + 12);
244 wil_debugfs_create_iomem_x32("IMV", S_IRUGO | S_IWUSR, d,
245 wil->csr + off + 16);
246 wil_debugfs_create_iomem_x32("IMS", S_IWUSR, d,
247 wil->csr + off + 20);
248 wil_debugfs_create_iomem_x32("IMC", S_IWUSR, d,
249 wil->csr + off + 24);
250
251 return 0;
252}
253
254static int wil6210_debugfs_create_pseudo_ISR(struct wil6210_priv *wil,
255 struct dentry *parent)
256{
257 struct dentry *d = debugfs_create_dir("PSEUDO_ISR", parent);
258
259 if (IS_ERR_OR_NULL(d))
260 return -ENODEV;
261
262 wil_debugfs_create_iomem_x32("CAUSE", S_IRUGO, d, wil->csr +
263 HOSTADDR(RGF_DMA_PSEUDO_CAUSE));
264 wil_debugfs_create_iomem_x32("MASK_SW", S_IRUGO, d, wil->csr +
265 HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW));
266 wil_debugfs_create_iomem_x32("MASK_FW", S_IRUGO, d, wil->csr +
267 HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_FW));
268
269 return 0;
270}
271
272static int wil6210_debugfs_create_ITR_CNT(struct wil6210_priv *wil,
273 struct dentry *parent)
274{
275 struct dentry *d = debugfs_create_dir("ITR_CNT", parent);
276
277 if (IS_ERR_OR_NULL(d))
278 return -ENODEV;
279
280 wil_debugfs_create_iomem_x32("TRSH", S_IRUGO, d, wil->csr +
281 HOSTADDR(RGF_DMA_ITR_CNT_TRSH));
282 wil_debugfs_create_iomem_x32("DATA", S_IRUGO, d, wil->csr +
283 HOSTADDR(RGF_DMA_ITR_CNT_DATA));
284 wil_debugfs_create_iomem_x32("CTL", S_IRUGO, d, wil->csr +
285 HOSTADDR(RGF_DMA_ITR_CNT_CRL));
286
287 return 0;
288}
289
290static int wil_memread_debugfs_show(struct seq_file *s, void *data)
291{
292 struct wil6210_priv *wil = s->private;
293 void __iomem *a = wmi_buffer(wil, cpu_to_le32(mem_addr));
294
295 if (a)
296 seq_printf(s, "[0x%08x] = 0x%08x\n", mem_addr, ioread32(a));
297 else
298 seq_printf(s, "[0x%08x] = INVALID\n", mem_addr);
299
300 return 0;
301}
302
303static int wil_memread_seq_open(struct inode *inode, struct file *file)
304{
305 return single_open(file, wil_memread_debugfs_show, inode->i_private);
306}
307
308static const struct file_operations fops_memread = {
309 .open = wil_memread_seq_open,
310 .release = single_release,
311 .read = seq_read,
312 .llseek = seq_lseek,
313};
314
315static int wil_default_open(struct inode *inode, struct file *file)
316{
317 if (inode->i_private)
318 file->private_data = inode->i_private;
319
320 return 0;
321}
322
323static ssize_t wil_read_file_ioblob(struct file *file, char __user *user_buf,
324 size_t count, loff_t *ppos)
325{
326 enum { max_count = 4096 };
327 struct debugfs_blob_wrapper *blob = file->private_data;
328 loff_t pos = *ppos;
329 size_t available = blob->size;
330 void *buf;
331 size_t ret;
332
333 if (pos < 0)
334 return -EINVAL;
335
336 if (pos >= available || !count)
337 return 0;
338
339 if (count > available - pos)
340 count = available - pos;
341 if (count > max_count)
342 count = max_count;
343
344 buf = kmalloc(count, GFP_KERNEL);
345 if (!buf)
346 return -ENOMEM;
347
348 wil_memcpy_fromio_32(buf, (const volatile void __iomem *)blob->data +
349 pos, count);
350
351 ret = copy_to_user(user_buf, buf, count);
352 kfree(buf);
353 if (ret == count)
354 return -EFAULT;
355
356 count -= ret;
357 *ppos = pos + count;
358
359 return count;
360}
361
362static const struct file_operations fops_ioblob = {
363 .read = wil_read_file_ioblob,
364 .open = wil_default_open,
365 .llseek = default_llseek,
366};
367
368static
369struct dentry *wil_debugfs_create_ioblob(const char *name,
370 mode_t mode,
371 struct dentry *parent,
372 struct debugfs_blob_wrapper *blob)
373{
374 return debugfs_create_file(name, mode, parent, blob, &fops_ioblob);
375}
376/*---reset---*/
377static ssize_t wil_write_file_reset(struct file *file, const char __user *buf,
378 size_t len, loff_t *ppos)
379{
380 struct wil6210_priv *wil = file->private_data;
381 struct net_device *ndev = wil_to_ndev(wil);
382
383 /**
384 * BUG:
385 * this code does NOT sync device state with the rest of system
386 * use with care, debug only!!!
387 */
388 rtnl_lock();
389 dev_close(ndev);
390 ndev->flags &= ~IFF_UP;
391 rtnl_unlock();
392 wil_reset(wil);
393
394 return len;
395}
396
397static const struct file_operations fops_reset = {
398 .write = wil_write_file_reset,
399 .open = wil_default_open,
400};
401/*---------Tx descriptor------------*/
402
403static int wil_txdesc_debugfs_show(struct seq_file *s, void *data)
404{
405 struct wil6210_priv *wil = s->private;
406 struct vring *vring = &(wil->vring_tx[0]);
407
408 if (!vring->va) {
409 seq_printf(s, "No Tx VRING\n");
410 return 0;
411 }
412
413 if (dbg_txdesc_index < vring->size) {
414 volatile struct vring_tx_desc *d =
415 &(vring->va[dbg_txdesc_index].tx);
416 volatile u32 *u = (volatile u32 *)d;
417 struct sk_buff *skb = vring->ctx[dbg_txdesc_index];
418
419 seq_printf(s, "Tx[%3d] = {\n", dbg_txdesc_index);
420 seq_printf(s, " MAC = 0x%08x 0x%08x 0x%08x 0x%08x\n",
421 u[0], u[1], u[2], u[3]);
422 seq_printf(s, " DMA = 0x%08x 0x%08x 0x%08x 0x%08x\n",
423 u[4], u[5], u[6], u[7]);
424 seq_printf(s, " SKB = %p\n", skb);
425
426 if (skb) {
427 unsigned char printbuf[16 * 3 + 2];
428 int i = 0;
429 int len = skb_headlen(skb);
430 void *p = skb->data;
431
432 seq_printf(s, " len = %d\n", len);
433
434 while (i < len) {
435 int l = min(len - i, 16);
436 hex_dump_to_buffer(p + i, l, 16, 1, printbuf,
437 sizeof(printbuf), false);
438 seq_printf(s, " : %s\n", printbuf);
439 i += l;
440 }
441 }
442 seq_printf(s, "}\n");
443 } else {
444 seq_printf(s, "TxDesc index (%d) >= size (%d)\n",
445 dbg_txdesc_index, vring->size);
446 }
447
448 return 0;
449}
450
451static int wil_txdesc_seq_open(struct inode *inode, struct file *file)
452{
453 return single_open(file, wil_txdesc_debugfs_show, inode->i_private);
454}
455
456static const struct file_operations fops_txdesc = {
457 .open = wil_txdesc_seq_open,
458 .release = single_release,
459 .read = seq_read,
460 .llseek = seq_lseek,
461};
462
463/*---------beamforming------------*/
464static int wil_bf_debugfs_show(struct seq_file *s, void *data)
465{
466 struct wil6210_priv *wil = s->private;
467 seq_printf(s,
468 "TSF : 0x%016llx\n"
469 "TxMCS : %d\n"
470 "Sectors(rx:tx) my %2d:%2d peer %2d:%2d\n",
471 wil->stats.tsf, wil->stats.bf_mcs,
472 wil->stats.my_rx_sector, wil->stats.my_tx_sector,
473 wil->stats.peer_rx_sector, wil->stats.peer_tx_sector);
474 return 0;
475}
476
477static int wil_bf_seq_open(struct inode *inode, struct file *file)
478{
479 return single_open(file, wil_bf_debugfs_show, inode->i_private);
480}
481
482static const struct file_operations fops_bf = {
483 .open = wil_bf_seq_open,
484 .release = single_release,
485 .read = seq_read,
486 .llseek = seq_lseek,
487};
488/*---------SSID------------*/
489static ssize_t wil_read_file_ssid(struct file *file, char __user *user_buf,
490 size_t count, loff_t *ppos)
491{
492 struct wil6210_priv *wil = file->private_data;
493 struct wireless_dev *wdev = wil_to_wdev(wil);
494
495 return simple_read_from_buffer(user_buf, count, ppos,
496 wdev->ssid, wdev->ssid_len);
497}
498
499static ssize_t wil_write_file_ssid(struct file *file, const char __user *buf,
500 size_t count, loff_t *ppos)
501{
502 struct wil6210_priv *wil = file->private_data;
503 struct wireless_dev *wdev = wil_to_wdev(wil);
504 struct net_device *ndev = wil_to_ndev(wil);
505
506 if (*ppos != 0) {
507 wil_err(wil, "Unable to set SSID substring from [%d]\n",
508 (int)*ppos);
509 return -EINVAL;
510 }
511
512 if (count > sizeof(wdev->ssid)) {
513 wil_err(wil, "SSID too long, len = %d\n", (int)count);
514 return -EINVAL;
515 }
516 if (netif_running(ndev)) {
517 wil_err(wil, "Unable to change SSID on running interface\n");
518 return -EINVAL;
519 }
520
521 wdev->ssid_len = count;
522 return simple_write_to_buffer(wdev->ssid, wdev->ssid_len, ppos,
523 buf, count);
524}
525
526static const struct file_operations fops_ssid = {
527 .read = wil_read_file_ssid,
528 .write = wil_write_file_ssid,
529 .open = wil_default_open,
530};
531
532/*----------------*/
533int wil6210_debugfs_init(struct wil6210_priv *wil)
534{
535 struct dentry *dbg = wil->debug = debugfs_create_dir(WIL_NAME,
536 wil_to_wiphy(wil)->debugfsdir);
537
538 if (IS_ERR_OR_NULL(dbg))
539 return -ENODEV;
540
541 debugfs_create_file("mbox", S_IRUGO, dbg, wil, &fops_mbox);
542 debugfs_create_file("vrings", S_IRUGO, dbg, wil, &fops_vring);
543 debugfs_create_file("txdesc", S_IRUGO, dbg, wil, &fops_txdesc);
544 debugfs_create_u32("txdesc_index", S_IRUGO | S_IWUSR, dbg,
545 &dbg_txdesc_index);
546 debugfs_create_file("bf", S_IRUGO, dbg, wil, &fops_bf);
547 debugfs_create_file("ssid", S_IRUGO | S_IWUSR, dbg, wil, &fops_ssid);
548 debugfs_create_u32("secure_pcp", S_IRUGO | S_IWUSR, dbg,
549 &wil->secure_pcp);
550
551 wil6210_debugfs_create_ISR(wil, "USER_ICR", dbg,
552 HOSTADDR(RGF_USER_USER_ICR));
553 wil6210_debugfs_create_ISR(wil, "DMA_EP_TX_ICR", dbg,
554 HOSTADDR(RGF_DMA_EP_TX_ICR));
555 wil6210_debugfs_create_ISR(wil, "DMA_EP_RX_ICR", dbg,
556 HOSTADDR(RGF_DMA_EP_RX_ICR));
557 wil6210_debugfs_create_ISR(wil, "DMA_EP_MISC_ICR", dbg,
558 HOSTADDR(RGF_DMA_EP_MISC_ICR));
559 wil6210_debugfs_create_pseudo_ISR(wil, dbg);
560 wil6210_debugfs_create_ITR_CNT(wil, dbg);
561
562 debugfs_create_u32("mem_addr", S_IRUGO | S_IWUSR, dbg, &mem_addr);
563 debugfs_create_file("mem_val", S_IRUGO, dbg, wil, &fops_memread);
564
565 debugfs_create_file("reset", S_IWUSR, dbg, wil, &fops_reset);
566
567 wil->rgf_blob.data = (void * __force)wil->csr + 0;
568 wil->rgf_blob.size = 0xa000;
569 wil_debugfs_create_ioblob("blob_rgf", S_IRUGO, dbg, &wil->rgf_blob);
570
571 wil->fw_code_blob.data = (void * __force)wil->csr + 0x40000;
572 wil->fw_code_blob.size = 0x40000;
573 wil_debugfs_create_ioblob("blob_fw_code", S_IRUGO, dbg,
574 &wil->fw_code_blob);
575
576 wil->fw_data_blob.data = (void * __force)wil->csr + 0x80000;
577 wil->fw_data_blob.size = 0x8000;
578 wil_debugfs_create_ioblob("blob_fw_data", S_IRUGO, dbg,
579 &wil->fw_data_blob);
580
581 wil->fw_peri_blob.data = (void * __force)wil->csr + 0x88000;
582 wil->fw_peri_blob.size = 0x18000;
583 wil_debugfs_create_ioblob("blob_fw_peri", S_IRUGO, dbg,
584 &wil->fw_peri_blob);
585
586 wil->uc_code_blob.data = (void * __force)wil->csr + 0xa0000;
587 wil->uc_code_blob.size = 0x10000;
588 wil_debugfs_create_ioblob("blob_uc_code", S_IRUGO, dbg,
589 &wil->uc_code_blob);
590
591 wil->uc_data_blob.data = (void * __force)wil->csr + 0xb0000;
592 wil->uc_data_blob.size = 0x4000;
593 wil_debugfs_create_ioblob("blob_uc_data", S_IRUGO, dbg,
594 &wil->uc_data_blob);
595
596 return 0;
597}
598
599void wil6210_debugfs_remove(struct wil6210_priv *wil)
600{
601 debugfs_remove_recursive(wil->debug);
602 wil->debug = NULL;
603}
diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c
new file mode 100644
index 000000000000..38049da71049
--- /dev/null
+++ b/drivers/net/wireless/ath/wil6210/interrupt.c
@@ -0,0 +1,471 @@
1/*
2 * Copyright (c) 2012 Qualcomm Atheros, Inc.
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include <linux/interrupt.h>
18
19#include "wil6210.h"
20
21/**
22 * Theory of operation:
23 *
24 * There is ISR pseudo-cause register,
25 * dma_rgf->DMA_RGF.PSEUDO_CAUSE.PSEUDO_CAUSE
26 * Its bits represents OR'ed bits from 3 real ISR registers:
27 * TX, RX, and MISC.
28 *
29 * Registers may be configured to either "write 1 to clear" or
30 * "clear on read" mode
31 *
32 * When handling interrupt, one have to mask/unmask interrupts for the
33 * real ISR registers, or hardware may malfunction.
34 *
35 */
36
37#define WIL6210_IRQ_DISABLE (0xFFFFFFFFUL)
38#define WIL6210_IMC_RX BIT_DMA_EP_RX_ICR_RX_DONE
39#define WIL6210_IMC_TX (BIT_DMA_EP_TX_ICR_TX_DONE | \
40 BIT_DMA_EP_TX_ICR_TX_DONE_N(0))
41#define WIL6210_IMC_MISC (ISR_MISC_FW_READY | ISR_MISC_MBOX_EVT)
42
43#define WIL6210_IRQ_PSEUDO_MASK (u32)(~(BIT_DMA_PSEUDO_CAUSE_RX | \
44 BIT_DMA_PSEUDO_CAUSE_TX | \
45 BIT_DMA_PSEUDO_CAUSE_MISC))
46
47#if defined(CONFIG_WIL6210_ISR_COR)
48/* configure to Clear-On-Read mode */
49#define WIL_ICR_ICC_VALUE (0xFFFFFFFFUL)
50
51static inline void wil_icr_clear(u32 x, void __iomem *addr)
52{
53
54}
55#else /* defined(CONFIG_WIL6210_ISR_COR) */
56/* configure to Write-1-to-Clear mode */
57#define WIL_ICR_ICC_VALUE (0UL)
58
59static inline void wil_icr_clear(u32 x, void __iomem *addr)
60{
61 iowrite32(x, addr);
62}
63#endif /* defined(CONFIG_WIL6210_ISR_COR) */
64
65static inline u32 wil_ioread32_and_clear(void __iomem *addr)
66{
67 u32 x = ioread32(addr);
68
69 wil_icr_clear(x, addr);
70
71 return x;
72}
73
74static void wil6210_mask_irq_tx(struct wil6210_priv *wil)
75{
76 iowrite32(WIL6210_IRQ_DISABLE, wil->csr +
77 HOSTADDR(RGF_DMA_EP_TX_ICR) +
78 offsetof(struct RGF_ICR, IMS));
79}
80
81static void wil6210_mask_irq_rx(struct wil6210_priv *wil)
82{
83 iowrite32(WIL6210_IRQ_DISABLE, wil->csr +
84 HOSTADDR(RGF_DMA_EP_RX_ICR) +
85 offsetof(struct RGF_ICR, IMS));
86}
87
88static void wil6210_mask_irq_misc(struct wil6210_priv *wil)
89{
90 iowrite32(WIL6210_IRQ_DISABLE, wil->csr +
91 HOSTADDR(RGF_DMA_EP_MISC_ICR) +
92 offsetof(struct RGF_ICR, IMS));
93}
94
95static void wil6210_mask_irq_pseudo(struct wil6210_priv *wil)
96{
97 wil_dbg_IRQ(wil, "%s()\n", __func__);
98
99 iowrite32(WIL6210_IRQ_DISABLE, wil->csr +
100 HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW));
101
102 clear_bit(wil_status_irqen, &wil->status);
103}
104
105static void wil6210_unmask_irq_tx(struct wil6210_priv *wil)
106{
107 iowrite32(WIL6210_IMC_TX, wil->csr +
108 HOSTADDR(RGF_DMA_EP_TX_ICR) +
109 offsetof(struct RGF_ICR, IMC));
110}
111
112static void wil6210_unmask_irq_rx(struct wil6210_priv *wil)
113{
114 iowrite32(WIL6210_IMC_RX, wil->csr +
115 HOSTADDR(RGF_DMA_EP_RX_ICR) +
116 offsetof(struct RGF_ICR, IMC));
117}
118
119static void wil6210_unmask_irq_misc(struct wil6210_priv *wil)
120{
121 iowrite32(WIL6210_IMC_MISC, wil->csr +
122 HOSTADDR(RGF_DMA_EP_MISC_ICR) +
123 offsetof(struct RGF_ICR, IMC));
124}
125
126static void wil6210_unmask_irq_pseudo(struct wil6210_priv *wil)
127{
128 wil_dbg_IRQ(wil, "%s()\n", __func__);
129
130 set_bit(wil_status_irqen, &wil->status);
131
132 iowrite32(WIL6210_IRQ_PSEUDO_MASK, wil->csr +
133 HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW));
134}
135
136void wil6210_disable_irq(struct wil6210_priv *wil)
137{
138 wil_dbg_IRQ(wil, "%s()\n", __func__);
139
140 wil6210_mask_irq_tx(wil);
141 wil6210_mask_irq_rx(wil);
142 wil6210_mask_irq_misc(wil);
143 wil6210_mask_irq_pseudo(wil);
144}
145
146void wil6210_enable_irq(struct wil6210_priv *wil)
147{
148 wil_dbg_IRQ(wil, "%s()\n", __func__);
149
150 iowrite32(WIL_ICR_ICC_VALUE, wil->csr + HOSTADDR(RGF_DMA_EP_RX_ICR) +
151 offsetof(struct RGF_ICR, ICC));
152 iowrite32(WIL_ICR_ICC_VALUE, wil->csr + HOSTADDR(RGF_DMA_EP_TX_ICR) +
153 offsetof(struct RGF_ICR, ICC));
154 iowrite32(WIL_ICR_ICC_VALUE, wil->csr + HOSTADDR(RGF_DMA_EP_MISC_ICR) +
155 offsetof(struct RGF_ICR, ICC));
156
157 wil6210_unmask_irq_pseudo(wil);
158 wil6210_unmask_irq_tx(wil);
159 wil6210_unmask_irq_rx(wil);
160 wil6210_unmask_irq_misc(wil);
161}
162
163static irqreturn_t wil6210_irq_rx(int irq, void *cookie)
164{
165 struct wil6210_priv *wil = cookie;
166 u32 isr = wil_ioread32_and_clear(wil->csr +
167 HOSTADDR(RGF_DMA_EP_RX_ICR) +
168 offsetof(struct RGF_ICR, ICR));
169
170 wil_dbg_IRQ(wil, "ISR RX 0x%08x\n", isr);
171
172 if (!isr) {
173 wil_err(wil, "spurious IRQ: RX\n");
174 return IRQ_NONE;
175 }
176
177 wil6210_mask_irq_rx(wil);
178
179 if (isr & BIT_DMA_EP_RX_ICR_RX_DONE) {
180 wil_dbg_IRQ(wil, "RX done\n");
181 isr &= ~BIT_DMA_EP_RX_ICR_RX_DONE;
182 wil_rx_handle(wil);
183 }
184
185 if (isr)
186 wil_err(wil, "un-handled RX ISR bits 0x%08x\n", isr);
187
188 wil6210_unmask_irq_rx(wil);
189
190 return IRQ_HANDLED;
191}
192
193static irqreturn_t wil6210_irq_tx(int irq, void *cookie)
194{
195 struct wil6210_priv *wil = cookie;
196 u32 isr = wil_ioread32_and_clear(wil->csr +
197 HOSTADDR(RGF_DMA_EP_TX_ICR) +
198 offsetof(struct RGF_ICR, ICR));
199
200 wil_dbg_IRQ(wil, "ISR TX 0x%08x\n", isr);
201
202 if (!isr) {
203 wil_err(wil, "spurious IRQ: TX\n");
204 return IRQ_NONE;
205 }
206
207 wil6210_mask_irq_tx(wil);
208
209 if (isr & BIT_DMA_EP_TX_ICR_TX_DONE) {
210 uint i;
211 wil_dbg_IRQ(wil, "TX done\n");
212 isr &= ~BIT_DMA_EP_TX_ICR_TX_DONE;
213 for (i = 0; i < 24; i++) {
214 u32 mask = BIT_DMA_EP_TX_ICR_TX_DONE_N(i);
215 if (isr & mask) {
216 isr &= ~mask;
217 wil_dbg_IRQ(wil, "TX done(%i)\n", i);
218 wil_tx_complete(wil, i);
219 }
220 }
221 }
222
223 if (isr)
224 wil_err(wil, "un-handled TX ISR bits 0x%08x\n", isr);
225
226 wil6210_unmask_irq_tx(wil);
227
228 return IRQ_HANDLED;
229}
230
231static irqreturn_t wil6210_irq_misc(int irq, void *cookie)
232{
233 struct wil6210_priv *wil = cookie;
234 u32 isr = wil_ioread32_and_clear(wil->csr +
235 HOSTADDR(RGF_DMA_EP_MISC_ICR) +
236 offsetof(struct RGF_ICR, ICR));
237
238 wil_dbg_IRQ(wil, "ISR MISC 0x%08x\n", isr);
239
240 if (!isr) {
241 wil_err(wil, "spurious IRQ: MISC\n");
242 return IRQ_NONE;
243 }
244
245 wil6210_mask_irq_misc(wil);
246
247 if (isr & ISR_MISC_FW_READY) {
248 wil_dbg_IRQ(wil, "IRQ: FW ready\n");
249 /**
250 * Actual FW ready indicated by the
251 * WMI_FW_READY_EVENTID
252 */
253 isr &= ~ISR_MISC_FW_READY;
254 }
255
256 wil->isr_misc = isr;
257
258 if (isr) {
259 return IRQ_WAKE_THREAD;
260 } else {
261 wil6210_unmask_irq_misc(wil);
262 return IRQ_HANDLED;
263 }
264}
265
266static irqreturn_t wil6210_irq_misc_thread(int irq, void *cookie)
267{
268 struct wil6210_priv *wil = cookie;
269 u32 isr = wil->isr_misc;
270
271 wil_dbg_IRQ(wil, "Thread ISR MISC 0x%08x\n", isr);
272
273 if (isr & ISR_MISC_MBOX_EVT) {
274 wil_dbg_IRQ(wil, "MBOX event\n");
275 wmi_recv_cmd(wil);
276 isr &= ~ISR_MISC_MBOX_EVT;
277 }
278
279 if (isr)
280 wil_err(wil, "un-handled MISC ISR bits 0x%08x\n", isr);
281
282 wil->isr_misc = 0;
283
284 wil6210_unmask_irq_misc(wil);
285
286 return IRQ_HANDLED;
287}
288
289/**
290 * thread IRQ handler
291 */
292static irqreturn_t wil6210_thread_irq(int irq, void *cookie)
293{
294 struct wil6210_priv *wil = cookie;
295
296 wil_dbg_IRQ(wil, "Thread IRQ\n");
297 /* Discover real IRQ cause */
298 if (wil->isr_misc)
299 wil6210_irq_misc_thread(irq, cookie);
300
301 wil6210_unmask_irq_pseudo(wil);
302
303 return IRQ_HANDLED;
304}
305
306/* DEBUG
307 * There is subtle bug in hardware that causes IRQ to raise when it should be
308 * masked. It is quite rare and hard to debug.
309 *
310 * Catch irq issue if it happens and print all I can.
311 */
312static int wil6210_debug_irq_mask(struct wil6210_priv *wil, u32 pseudo_cause)
313{
314 if (!test_bit(wil_status_irqen, &wil->status)) {
315 u32 icm_rx = wil_ioread32_and_clear(wil->csr +
316 HOSTADDR(RGF_DMA_EP_RX_ICR) +
317 offsetof(struct RGF_ICR, ICM));
318 u32 icr_rx = wil_ioread32_and_clear(wil->csr +
319 HOSTADDR(RGF_DMA_EP_RX_ICR) +
320 offsetof(struct RGF_ICR, ICR));
321 u32 imv_rx = ioread32(wil->csr +
322 HOSTADDR(RGF_DMA_EP_RX_ICR) +
323 offsetof(struct RGF_ICR, IMV));
324 u32 icm_tx = wil_ioread32_and_clear(wil->csr +
325 HOSTADDR(RGF_DMA_EP_TX_ICR) +
326 offsetof(struct RGF_ICR, ICM));
327 u32 icr_tx = wil_ioread32_and_clear(wil->csr +
328 HOSTADDR(RGF_DMA_EP_TX_ICR) +
329 offsetof(struct RGF_ICR, ICR));
330 u32 imv_tx = ioread32(wil->csr +
331 HOSTADDR(RGF_DMA_EP_TX_ICR) +
332 offsetof(struct RGF_ICR, IMV));
333 u32 icm_misc = wil_ioread32_and_clear(wil->csr +
334 HOSTADDR(RGF_DMA_EP_MISC_ICR) +
335 offsetof(struct RGF_ICR, ICM));
336 u32 icr_misc = wil_ioread32_and_clear(wil->csr +
337 HOSTADDR(RGF_DMA_EP_MISC_ICR) +
338 offsetof(struct RGF_ICR, ICR));
339 u32 imv_misc = ioread32(wil->csr +
340 HOSTADDR(RGF_DMA_EP_MISC_ICR) +
341 offsetof(struct RGF_ICR, IMV));
342 wil_err(wil, "IRQ when it should be masked: pseudo 0x%08x\n"
343 "Rx icm:icr:imv 0x%08x 0x%08x 0x%08x\n"
344 "Tx icm:icr:imv 0x%08x 0x%08x 0x%08x\n"
345 "Misc icm:icr:imv 0x%08x 0x%08x 0x%08x\n",
346 pseudo_cause,
347 icm_rx, icr_rx, imv_rx,
348 icm_tx, icr_tx, imv_tx,
349 icm_misc, icr_misc, imv_misc);
350
351 return -EINVAL;
352 }
353
354 return 0;
355}
356
357static irqreturn_t wil6210_hardirq(int irq, void *cookie)
358{
359 irqreturn_t rc = IRQ_HANDLED;
360 struct wil6210_priv *wil = cookie;
361 u32 pseudo_cause = ioread32(wil->csr + HOSTADDR(RGF_DMA_PSEUDO_CAUSE));
362
363 /**
364 * pseudo_cause is Clear-On-Read, no need to ACK
365 */
366 if ((pseudo_cause == 0) || ((pseudo_cause & 0xff) == 0xff))
367 return IRQ_NONE;
368
369 /* FIXME: IRQ mask debug */
370 if (wil6210_debug_irq_mask(wil, pseudo_cause))
371 return IRQ_NONE;
372
373 wil6210_mask_irq_pseudo(wil);
374
375 /* Discover real IRQ cause
376 * There are 2 possible phases for every IRQ:
377 * - hard IRQ handler called right here
378 * - threaded handler called later
379 *
380 * Hard IRQ handler reads and clears ISR.
381 *
382 * If threaded handler requested, hard IRQ handler
383 * returns IRQ_WAKE_THREAD and saves ISR register value
384 * for the threaded handler use.
385 *
386 * voting for wake thread - need at least 1 vote
387 */
388 if ((pseudo_cause & BIT_DMA_PSEUDO_CAUSE_RX) &&
389 (wil6210_irq_rx(irq, cookie) == IRQ_WAKE_THREAD))
390 rc = IRQ_WAKE_THREAD;
391
392 if ((pseudo_cause & BIT_DMA_PSEUDO_CAUSE_TX) &&
393 (wil6210_irq_tx(irq, cookie) == IRQ_WAKE_THREAD))
394 rc = IRQ_WAKE_THREAD;
395
396 if ((pseudo_cause & BIT_DMA_PSEUDO_CAUSE_MISC) &&
397 (wil6210_irq_misc(irq, cookie) == IRQ_WAKE_THREAD))
398 rc = IRQ_WAKE_THREAD;
399
400 /* if thread is requested, it will unmask IRQ */
401 if (rc != IRQ_WAKE_THREAD)
402 wil6210_unmask_irq_pseudo(wil);
403
404 wil_dbg_IRQ(wil, "Hard IRQ 0x%08x\n", pseudo_cause);
405
406 return rc;
407}
408
409static int wil6210_request_3msi(struct wil6210_priv *wil, int irq)
410{
411 int rc;
412 /*
413 * IRQ's are in the following order:
414 * - Tx
415 * - Rx
416 * - Misc
417 */
418
419 rc = request_irq(irq, wil6210_irq_tx, IRQF_SHARED,
420 WIL_NAME"_tx", wil);
421 if (rc)
422 return rc;
423
424 rc = request_irq(irq + 1, wil6210_irq_rx, IRQF_SHARED,
425 WIL_NAME"_rx", wil);
426 if (rc)
427 goto free0;
428
429 rc = request_threaded_irq(irq + 2, wil6210_irq_misc,
430 wil6210_irq_misc_thread,
431 IRQF_SHARED, WIL_NAME"_misc", wil);
432 if (rc)
433 goto free1;
434
435 return 0;
436 /* error branch */
437free1:
438 free_irq(irq + 1, wil);
439free0:
440 free_irq(irq, wil);
441
442 return rc;
443}
444
445int wil6210_init_irq(struct wil6210_priv *wil, int irq)
446{
447 int rc;
448 if (wil->n_msi == 3)
449 rc = wil6210_request_3msi(wil, irq);
450 else
451 rc = request_threaded_irq(irq, wil6210_hardirq,
452 wil6210_thread_irq,
453 wil->n_msi ? 0 : IRQF_SHARED,
454 WIL_NAME, wil);
455 if (rc)
456 return rc;
457
458 wil6210_enable_irq(wil);
459
460 return 0;
461}
462
463void wil6210_fini_irq(struct wil6210_priv *wil, int irq)
464{
465 wil6210_disable_irq(wil);
466 free_irq(irq, wil);
467 if (wil->n_msi == 3) {
468 free_irq(irq + 1, wil);
469 free_irq(irq + 2, wil);
470 }
471}
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
new file mode 100644
index 000000000000..95fcd361322b
--- /dev/null
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -0,0 +1,407 @@
1/*
2 * Copyright (c) 2012 Qualcomm Atheros, Inc.
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include <linux/kernel.h>
18#include <linux/netdevice.h>
19#include <linux/sched.h>
20#include <linux/ieee80211.h>
21#include <linux/wireless.h>
22#include <linux/slab.h>
23#include <linux/moduleparam.h>
24#include <linux/if_arp.h>
25
26#include "wil6210.h"
27
28/*
29 * Due to a hardware issue,
30 * one has to read/write to/from NIC in 32-bit chunks;
31 * regular memcpy_fromio and siblings will
32 * not work on 64-bit platform - it uses 64-bit transactions
33 *
34 * Force 32-bit transactions to enable NIC on 64-bit platforms
35 *
36 * To avoid byte swap on big endian host, __raw_{read|write}l
37 * should be used - {read|write}l would swap bytes to provide
38 * little endian on PCI value in host endianness.
39 */
40void wil_memcpy_fromio_32(void *dst, const volatile void __iomem *src,
41 size_t count)
42{
43 u32 *d = dst;
44 const volatile u32 __iomem *s = src;
45
46 /* size_t is unsigned, if (count%4 != 0) it will wrap */
47 for (count += 4; count > 4; count -= 4)
48 *d++ = __raw_readl(s++);
49}
50
51void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src,
52 size_t count)
53{
54 volatile u32 __iomem *d = dst;
55 const u32 *s = src;
56
57 for (count += 4; count > 4; count -= 4)
58 __raw_writel(*s++, d++);
59}
60
61static void _wil6210_disconnect(struct wil6210_priv *wil, void *bssid)
62{
63 uint i;
64 struct net_device *ndev = wil_to_ndev(wil);
65 struct wireless_dev *wdev = wil->wdev;
66
67 wil_dbg(wil, "%s()\n", __func__);
68
69 wil_link_off(wil);
70 clear_bit(wil_status_fwconnected, &wil->status);
71
72 switch (wdev->sme_state) {
73 case CFG80211_SME_CONNECTED:
74 cfg80211_disconnected(ndev, WLAN_STATUS_UNSPECIFIED_FAILURE,
75 NULL, 0, GFP_KERNEL);
76 break;
77 case CFG80211_SME_CONNECTING:
78 cfg80211_connect_result(ndev, bssid, NULL, 0, NULL, 0,
79 WLAN_STATUS_UNSPECIFIED_FAILURE,
80 GFP_KERNEL);
81 break;
82 default:
83 ;
84 }
85
86 for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++)
87 wil_vring_fini_tx(wil, i);
88}
89
90static void wil_disconnect_worker(struct work_struct *work)
91{
92 struct wil6210_priv *wil = container_of(work,
93 struct wil6210_priv, disconnect_worker);
94
95 _wil6210_disconnect(wil, NULL);
96}
97
98static void wil_connect_timer_fn(ulong x)
99{
100 struct wil6210_priv *wil = (void *)x;
101
102 wil_dbg(wil, "Connect timeout\n");
103
104 /* reschedule to thread context - disconnect won't
105 * run from atomic context
106 */
107 schedule_work(&wil->disconnect_worker);
108}
109
110int wil_priv_init(struct wil6210_priv *wil)
111{
112 wil_dbg(wil, "%s()\n", __func__);
113
114 mutex_init(&wil->mutex);
115 mutex_init(&wil->wmi_mutex);
116
117 init_completion(&wil->wmi_ready);
118
119 wil->pending_connect_cid = -1;
120 setup_timer(&wil->connect_timer, wil_connect_timer_fn, (ulong)wil);
121
122 INIT_WORK(&wil->wmi_connect_worker, wmi_connect_worker);
123 INIT_WORK(&wil->disconnect_worker, wil_disconnect_worker);
124 INIT_WORK(&wil->wmi_event_worker, wmi_event_worker);
125
126 INIT_LIST_HEAD(&wil->pending_wmi_ev);
127 spin_lock_init(&wil->wmi_ev_lock);
128
129 wil->wmi_wq = create_singlethread_workqueue(WIL_NAME"_wmi");
130 if (!wil->wmi_wq)
131 return -EAGAIN;
132
133 wil->wmi_wq_conn = create_singlethread_workqueue(WIL_NAME"_connect");
134 if (!wil->wmi_wq_conn) {
135 destroy_workqueue(wil->wmi_wq);
136 return -EAGAIN;
137 }
138
139 /* make shadow copy of registers that should not change on run time */
140 wil_memcpy_fromio_32(&wil->mbox_ctl, wil->csr + HOST_MBOX,
141 sizeof(struct wil6210_mbox_ctl));
142 wil_mbox_ring_le2cpus(&wil->mbox_ctl.rx);
143 wil_mbox_ring_le2cpus(&wil->mbox_ctl.tx);
144
145 return 0;
146}
147
148void wil6210_disconnect(struct wil6210_priv *wil, void *bssid)
149{
150 del_timer_sync(&wil->connect_timer);
151 _wil6210_disconnect(wil, bssid);
152}
153
154void wil_priv_deinit(struct wil6210_priv *wil)
155{
156 cancel_work_sync(&wil->disconnect_worker);
157 wil6210_disconnect(wil, NULL);
158 wmi_event_flush(wil);
159 destroy_workqueue(wil->wmi_wq_conn);
160 destroy_workqueue(wil->wmi_wq);
161}
162
163static void wil_target_reset(struct wil6210_priv *wil)
164{
165 wil_dbg(wil, "Resetting...\n");
166
167 /* register write */
168#define W(a, v) iowrite32(v, wil->csr + HOSTADDR(a))
169 /* register set = read, OR, write */
170#define S(a, v) iowrite32(ioread32(wil->csr + HOSTADDR(a)) | v, \
171 wil->csr + HOSTADDR(a))
172
173 /* hpal_perst_from_pad_src_n_mask */
174 S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT(6));
175 /* car_perst_rst_src_n_mask */
176 S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT(7));
177
178 W(RGF_USER_MAC_CPU_0, BIT(1)); /* mac_cpu_man_rst */
179 W(RGF_USER_USER_CPU_0, BIT(1)); /* user_cpu_man_rst */
180
181 msleep(100);
182
183 W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0xFE000000);
184 W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0x0000003F);
185 W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000170);
186 W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0xFFE7FC00);
187
188 msleep(100);
189
190 W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0);
191 W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0);
192 W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0);
193 W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0);
194
195 W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000001);
196 W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00000080);
197 W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0);
198
199 msleep(2000);
200
201 W(RGF_USER_USER_CPU_0, BIT(0)); /* user_cpu_man_de_rst */
202
203 msleep(2000);
204
205 wil_dbg(wil, "Reset completed\n");
206
207#undef W
208#undef S
209}
210
211void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r)
212{
213 le32_to_cpus(&r->base);
214 le16_to_cpus(&r->entry_size);
215 le16_to_cpus(&r->size);
216 le32_to_cpus(&r->tail);
217 le32_to_cpus(&r->head);
218}
219
220static int wil_wait_for_fw_ready(struct wil6210_priv *wil)
221{
222 ulong to = msecs_to_jiffies(1000);
223 ulong left = wait_for_completion_timeout(&wil->wmi_ready, to);
224 if (0 == left) {
225 wil_err(wil, "Firmware not ready\n");
226 return -ETIME;
227 } else {
228 wil_dbg(wil, "FW ready after %d ms\n",
229 jiffies_to_msecs(to-left));
230 }
231 return 0;
232}
233
234/*
235 * We reset all the structures, and we reset the UMAC.
236 * After calling this routine, you're expected to reload
237 * the firmware.
238 */
239int wil_reset(struct wil6210_priv *wil)
240{
241 int rc;
242
243 cancel_work_sync(&wil->disconnect_worker);
244 wil6210_disconnect(wil, NULL);
245
246 wmi_event_flush(wil);
247
248 flush_workqueue(wil->wmi_wq);
249 flush_workqueue(wil->wmi_wq_conn);
250
251 wil6210_disable_irq(wil);
252 wil->status = 0;
253
254 /* TODO: put MAC in reset */
255 wil_target_reset(wil);
256
257 /* init after reset */
258 wil->pending_connect_cid = -1;
259 INIT_COMPLETION(wil->wmi_ready);
260
261 /* make shadow copy of registers that should not change on run time */
262 wil_memcpy_fromio_32(&wil->mbox_ctl, wil->csr + HOST_MBOX,
263 sizeof(struct wil6210_mbox_ctl));
264 wil_mbox_ring_le2cpus(&wil->mbox_ctl.rx);
265 wil_mbox_ring_le2cpus(&wil->mbox_ctl.tx);
266
267 /* TODO: release MAC reset */
268 wil6210_enable_irq(wil);
269
270 /* we just started MAC, wait for FW ready */
271 rc = wil_wait_for_fw_ready(wil);
272
273 return rc;
274}
275
276
277void wil_link_on(struct wil6210_priv *wil)
278{
279 struct net_device *ndev = wil_to_ndev(wil);
280
281 wil_dbg(wil, "%s()\n", __func__);
282
283 netif_carrier_on(ndev);
284 netif_tx_wake_all_queues(ndev);
285}
286
287void wil_link_off(struct wil6210_priv *wil)
288{
289 struct net_device *ndev = wil_to_ndev(wil);
290
291 wil_dbg(wil, "%s()\n", __func__);
292
293 netif_tx_stop_all_queues(ndev);
294 netif_carrier_off(ndev);
295}
296
297static int __wil_up(struct wil6210_priv *wil)
298{
299 struct net_device *ndev = wil_to_ndev(wil);
300 struct wireless_dev *wdev = wil->wdev;
301 struct ieee80211_channel *channel = wdev->preset_chandef.chan;
302 int rc;
303 int bi;
304 u16 wmi_nettype = wil_iftype_nl2wmi(wdev->iftype);
305
306 rc = wil_reset(wil);
307 if (rc)
308 return rc;
309
310 /* FIXME Firmware works now in PBSS mode(ToDS=0, FromDS=0) */
311 wmi_nettype = wil_iftype_nl2wmi(NL80211_IFTYPE_ADHOC);
312 switch (wdev->iftype) {
313 case NL80211_IFTYPE_STATION:
314 wil_dbg(wil, "type: STATION\n");
315 bi = 0;
316 ndev->type = ARPHRD_ETHER;
317 break;
318 case NL80211_IFTYPE_AP:
319 wil_dbg(wil, "type: AP\n");
320 bi = 100;
321 ndev->type = ARPHRD_ETHER;
322 break;
323 case NL80211_IFTYPE_P2P_CLIENT:
324 wil_dbg(wil, "type: P2P_CLIENT\n");
325 bi = 0;
326 ndev->type = ARPHRD_ETHER;
327 break;
328 case NL80211_IFTYPE_P2P_GO:
329 wil_dbg(wil, "type: P2P_GO\n");
330 bi = 100;
331 ndev->type = ARPHRD_ETHER;
332 break;
333 case NL80211_IFTYPE_MONITOR:
334 wil_dbg(wil, "type: Monitor\n");
335 bi = 0;
336 ndev->type = ARPHRD_IEEE80211_RADIOTAP;
337 /* ARPHRD_IEEE80211 or ARPHRD_IEEE80211_RADIOTAP ? */
338 break;
339 default:
340 return -EOPNOTSUPP;
341 }
342
343 /* Apply profile in the following order: */
344 /* SSID and channel for the AP */
345 switch (wdev->iftype) {
346 case NL80211_IFTYPE_AP:
347 case NL80211_IFTYPE_P2P_GO:
348 if (wdev->ssid_len == 0) {
349 wil_err(wil, "SSID not set\n");
350 return -EINVAL;
351 }
352 wmi_set_ssid(wil, wdev->ssid_len, wdev->ssid);
353 if (channel)
354 wmi_set_channel(wil, channel->hw_value);
355 break;
356 default:
357 ;
358 }
359
360 /* MAC address - pre-requisite for other commands */
361 wmi_set_mac_address(wil, ndev->dev_addr);
362
363 /* Set up beaconing if required. */
364 rc = wmi_set_bcon(wil, bi, wmi_nettype);
365 if (rc)
366 return rc;
367
368 /* Rx VRING. After MAC and beacon */
369 wil_rx_init(wil);
370
371 return 0;
372}
373
374int wil_up(struct wil6210_priv *wil)
375{
376 int rc;
377
378 mutex_lock(&wil->mutex);
379 rc = __wil_up(wil);
380 mutex_unlock(&wil->mutex);
381
382 return rc;
383}
384
385static int __wil_down(struct wil6210_priv *wil)
386{
387 if (wil->scan_request) {
388 cfg80211_scan_done(wil->scan_request, true);
389 wil->scan_request = NULL;
390 }
391
392 wil6210_disconnect(wil, NULL);
393 wil_rx_fini(wil);
394
395 return 0;
396}
397
398int wil_down(struct wil6210_priv *wil)
399{
400 int rc;
401
402 mutex_lock(&wil->mutex);
403 rc = __wil_down(wil);
404 mutex_unlock(&wil->mutex);
405
406 return rc;
407}
diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c
new file mode 100644
index 000000000000..3068b5cb53a7
--- /dev/null
+++ b/drivers/net/wireless/ath/wil6210/netdev.c
@@ -0,0 +1,157 @@
1/*
2 * Copyright (c) 2012 Qualcomm Atheros, Inc.
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include <linux/module.h>
18#include <linux/netdevice.h>
19#include <linux/etherdevice.h>
20#include <linux/slab.h>
21
22#include "wil6210.h"
23
24static int wil_open(struct net_device *ndev)
25{
26 struct wil6210_priv *wil = ndev_to_wil(ndev);
27
28 return wil_up(wil);
29}
30
31static int wil_stop(struct net_device *ndev)
32{
33 struct wil6210_priv *wil = ndev_to_wil(ndev);
34
35 return wil_down(wil);
36}
37
38/*
39 * AC to queue mapping
40 *
41 * AC_VO -> queue 3
42 * AC_VI -> queue 2
43 * AC_BE -> queue 1
44 * AC_BK -> queue 0
45 */
46static u16 wil_select_queue(struct net_device *ndev, struct sk_buff *skb)
47{
48 static const u16 wil_1d_to_queue[8] = { 1, 0, 0, 1, 2, 2, 3, 3 };
49 struct wil6210_priv *wil = ndev_to_wil(ndev);
50 u16 rc;
51
52 skb->priority = cfg80211_classify8021d(skb);
53
54 rc = wil_1d_to_queue[skb->priority];
55
56 wil_dbg_TXRX(wil, "%s() %d -> %d\n", __func__, (int)skb->priority,
57 (int)rc);
58
59 return rc;
60}
61
62static const struct net_device_ops wil_netdev_ops = {
63 .ndo_open = wil_open,
64 .ndo_stop = wil_stop,
65 .ndo_start_xmit = wil_start_xmit,
66 .ndo_select_queue = wil_select_queue,
67 .ndo_set_mac_address = eth_mac_addr,
68 .ndo_validate_addr = eth_validate_addr,
69};
70
71void *wil_if_alloc(struct device *dev, void __iomem *csr)
72{
73 struct net_device *ndev;
74 struct wireless_dev *wdev;
75 struct wil6210_priv *wil;
76 struct ieee80211_channel *ch;
77 int rc = 0;
78
79 wdev = wil_cfg80211_init(dev);
80 if (IS_ERR(wdev)) {
81 dev_err(dev, "wil_cfg80211_init failed\n");
82 return wdev;
83 }
84
85 wil = wdev_to_wil(wdev);
86 wil->csr = csr;
87 wil->wdev = wdev;
88
89 rc = wil_priv_init(wil);
90 if (rc) {
91 dev_err(dev, "wil_priv_init failed\n");
92 goto out_wdev;
93 }
94
95 wdev->iftype = NL80211_IFTYPE_STATION; /* TODO */
96 /* default monitor channel */
97 ch = wdev->wiphy->bands[IEEE80211_BAND_60GHZ]->channels;
98 cfg80211_chandef_create(&wdev->preset_chandef, ch, NL80211_CHAN_NO_HT);
99
100 ndev = alloc_netdev_mqs(0, "wlan%d", ether_setup, WIL6210_TX_QUEUES, 1);
101 if (!ndev) {
102 dev_err(dev, "alloc_netdev_mqs failed\n");
103 rc = -ENOMEM;
104 goto out_priv;
105 }
106
107 ndev->netdev_ops = &wil_netdev_ops;
108 ndev->ieee80211_ptr = wdev;
109 SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
110 wdev->netdev = ndev;
111
112 wil_link_off(wil);
113
114 return wil;
115
116 out_priv:
117 wil_priv_deinit(wil);
118
119 out_wdev:
120 wil_wdev_free(wil);
121
122 return ERR_PTR(rc);
123}
124
125void wil_if_free(struct wil6210_priv *wil)
126{
127 struct net_device *ndev = wil_to_ndev(wil);
128 if (!ndev)
129 return;
130
131 free_netdev(ndev);
132 wil_priv_deinit(wil);
133 wil_wdev_free(wil);
134}
135
136int wil_if_add(struct wil6210_priv *wil)
137{
138 struct net_device *ndev = wil_to_ndev(wil);
139 int rc;
140
141 rc = register_netdev(ndev);
142 if (rc < 0) {
143 dev_err(&ndev->dev, "Failed to register netdev: %d\n", rc);
144 return rc;
145 }
146
147 wil_link_off(wil);
148
149 return 0;
150}
151
152void wil_if_remove(struct wil6210_priv *wil)
153{
154 struct net_device *ndev = wil_to_ndev(wil);
155
156 unregister_netdev(ndev);
157}
diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c
new file mode 100644
index 000000000000..0fc83edd6bad
--- /dev/null
+++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c
@@ -0,0 +1,223 @@
1/*
2 * Copyright (c) 2012 Qualcomm Atheros, Inc.
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include <linux/kernel.h>
18#include <linux/module.h>
19#include <linux/slab.h>
20#include <linux/netdevice.h>
21#include <linux/debugfs.h>
22#include <linux/pci.h>
23#include <linux/moduleparam.h>
24
25#include "wil6210.h"
26
27static int use_msi = 1;
28module_param(use_msi, int, S_IRUGO);
29MODULE_PARM_DESC(use_msi,
30 " Use MSI interrupt: "
31 "0 - don't, 1 - (default) - single, or 3");
32
33/* Bus ops */
34static int wil_if_pcie_enable(struct wil6210_priv *wil)
35{
36 struct pci_dev *pdev = wil->pdev;
37 int rc;
38
39 pci_set_master(pdev);
40
41 /*
42 * how many MSI interrupts to request?
43 */
44 switch (use_msi) {
45 case 3:
46 case 1:
47 case 0:
48 break;
49 default:
50 wil_err(wil, "Invalid use_msi=%d, default to 1\n",
51 use_msi);
52 use_msi = 1;
53 }
54 wil->n_msi = use_msi;
55 if (wil->n_msi) {
56 wil_dbg(wil, "Setup %d MSI interrupts\n", use_msi);
57 rc = pci_enable_msi_block(pdev, wil->n_msi);
58 if (rc && (wil->n_msi == 3)) {
59 wil_err(wil, "3 MSI mode failed, try 1 MSI\n");
60 wil->n_msi = 1;
61 rc = pci_enable_msi_block(pdev, wil->n_msi);
62 }
63 if (rc) {
64 wil_err(wil, "pci_enable_msi failed, use INTx\n");
65 wil->n_msi = 0;
66 }
67 } else {
68 wil_dbg(wil, "MSI interrupts disabled, use INTx\n");
69 }
70
71 rc = wil6210_init_irq(wil, pdev->irq);
72 if (rc)
73 goto stop_master;
74
75 /* need reset here to obtain MAC */
76 rc = wil_reset(wil);
77 if (rc)
78 goto release_irq;
79
80 return 0;
81
82 release_irq:
83 wil6210_fini_irq(wil, pdev->irq);
84 /* safe to call if no MSI */
85 pci_disable_msi(pdev);
86 stop_master:
87 pci_clear_master(pdev);
88 return rc;
89}
90
91static int wil_if_pcie_disable(struct wil6210_priv *wil)
92{
93 struct pci_dev *pdev = wil->pdev;
94
95 pci_clear_master(pdev);
96 /* disable and release IRQ */
97 wil6210_fini_irq(wil, pdev->irq);
98 /* safe to call if no MSI */
99 pci_disable_msi(pdev);
100 /* TODO: disable HW */
101
102 return 0;
103}
104
105static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
106{
107 struct wil6210_priv *wil;
108 struct device *dev = &pdev->dev;
109 void __iomem *csr;
110 int rc;
111
112 /* check HW */
113 dev_info(&pdev->dev, WIL_NAME " device found [%04x:%04x] (rev %x)\n",
114 (int)pdev->vendor, (int)pdev->device, (int)pdev->revision);
115
116 if (pci_resource_len(pdev, 0) != WIL6210_MEM_SIZE) {
117 dev_err(&pdev->dev, "Not " WIL_NAME "? "
118 "BAR0 size is %lu while expecting %lu\n",
119 (ulong)pci_resource_len(pdev, 0), WIL6210_MEM_SIZE);
120 return -ENODEV;
121 }
122
123 rc = pci_enable_device(pdev);
124 if (rc) {
125 dev_err(&pdev->dev, "pci_enable_device failed\n");
126 return -ENODEV;
127 }
128 /* rollback to err_disable_pdev */
129
130 rc = pci_request_region(pdev, 0, WIL_NAME);
131 if (rc) {
132 dev_err(&pdev->dev, "pci_request_region failed\n");
133 goto err_disable_pdev;
134 }
135 /* rollback to err_release_reg */
136
137 csr = pci_ioremap_bar(pdev, 0);
138 if (!csr) {
139 dev_err(&pdev->dev, "pci_ioremap_bar failed\n");
140 rc = -ENODEV;
141 goto err_release_reg;
142 }
143 /* rollback to err_iounmap */
144 dev_info(&pdev->dev, "CSR at %pR -> %p\n", &pdev->resource[0], csr);
145
146 wil = wil_if_alloc(dev, csr);
147 if (IS_ERR(wil)) {
148 rc = (int)PTR_ERR(wil);
149 dev_err(dev, "wil_if_alloc failed: %d\n", rc);
150 goto err_iounmap;
151 }
152 /* rollback to if_free */
153
154 pci_set_drvdata(pdev, wil);
155 wil->pdev = pdev;
156
157 /* FW should raise IRQ when ready */
158 rc = wil_if_pcie_enable(wil);
159 if (rc) {
160 wil_err(wil, "Enable device failed\n");
161 goto if_free;
162 }
163 /* rollback to bus_disable */
164
165 rc = wil_if_add(wil);
166 if (rc) {
167 wil_err(wil, "wil_if_add failed: %d\n", rc);
168 goto bus_disable;
169 }
170
171 wil6210_debugfs_init(wil);
172
173 /* check FW is alive */
174 wmi_echo(wil);
175
176 return 0;
177
178 bus_disable:
179 wil_if_pcie_disable(wil);
180 if_free:
181 wil_if_free(wil);
182 err_iounmap:
183 pci_iounmap(pdev, csr);
184 err_release_reg:
185 pci_release_region(pdev, 0);
186 err_disable_pdev:
187 pci_disable_device(pdev);
188
189 return rc;
190}
191
192static void wil_pcie_remove(struct pci_dev *pdev)
193{
194 struct wil6210_priv *wil = pci_get_drvdata(pdev);
195
196 wil6210_debugfs_remove(wil);
197 wil_if_pcie_disable(wil);
198 wil_if_remove(wil);
199 wil_if_free(wil);
200 pci_iounmap(pdev, wil->csr);
201 pci_release_region(pdev, 0);
202 pci_disable_device(pdev);
203 pci_set_drvdata(pdev, NULL);
204}
205
206static DEFINE_PCI_DEVICE_TABLE(wil6210_pcie_ids) = {
207 { PCI_DEVICE(0x1ae9, 0x0301) },
208 { /* end: all zeroes */ },
209};
210MODULE_DEVICE_TABLE(pci, wil6210_pcie_ids);
211
212static struct pci_driver wil6210_driver = {
213 .probe = wil_pcie_probe,
214 .remove = wil_pcie_remove,
215 .id_table = wil6210_pcie_ids,
216 .name = WIL_NAME,
217};
218
219module_pci_driver(wil6210_driver);
220
221MODULE_LICENSE("Dual BSD/GPL");
222MODULE_AUTHOR("Qualcomm Atheros <wil6210@qca.qualcomm.com>");
223MODULE_DESCRIPTION("Driver for 60g WiFi WIL6210 card");
diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c
new file mode 100644
index 000000000000..f29c294413cf
--- /dev/null
+++ b/drivers/net/wireless/ath/wil6210/txrx.c
@@ -0,0 +1,871 @@
1/*
2 * Copyright (c) 2012 Qualcomm Atheros, Inc.
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include <linux/kernel.h>
18#include <linux/netdevice.h>
19#include <linux/etherdevice.h>
20#include <linux/hardirq.h>
21#include <net/ieee80211_radiotap.h>
22#include <linux/if_arp.h>
23#include <linux/moduleparam.h>
24
25#include "wil6210.h"
26#include "wmi.h"
27#include "txrx.h"
28
29static bool rtap_include_phy_info;
30module_param(rtap_include_phy_info, bool, S_IRUGO);
31MODULE_PARM_DESC(rtap_include_phy_info,
32 " Include PHY info in the radiotap header, default - no");
33
34static inline int wil_vring_is_empty(struct vring *vring)
35{
36 return vring->swhead == vring->swtail;
37}
38
39static inline u32 wil_vring_next_tail(struct vring *vring)
40{
41 return (vring->swtail + 1) % vring->size;
42}
43
44static inline void wil_vring_advance_head(struct vring *vring, int n)
45{
46 vring->swhead = (vring->swhead + n) % vring->size;
47}
48
49static inline int wil_vring_is_full(struct vring *vring)
50{
51 return wil_vring_next_tail(vring) == vring->swhead;
52}
53/*
54 * Available space in Tx Vring
55 */
56static inline int wil_vring_avail_tx(struct vring *vring)
57{
58 u32 swhead = vring->swhead;
59 u32 swtail = vring->swtail;
60 int used = (vring->size + swhead - swtail) % vring->size;
61
62 return vring->size - used - 1;
63}
64
65static int wil_vring_alloc(struct wil6210_priv *wil, struct vring *vring)
66{
67 struct device *dev = wil_to_dev(wil);
68 size_t sz = vring->size * sizeof(vring->va[0]);
69 uint i;
70
71 BUILD_BUG_ON(sizeof(vring->va[0]) != 32);
72
73 vring->swhead = 0;
74 vring->swtail = 0;
75 vring->ctx = kzalloc(vring->size * sizeof(vring->ctx[0]), GFP_KERNEL);
76 if (!vring->ctx) {
77 wil_err(wil, "vring_alloc [%d] failed to alloc ctx mem\n",
78 vring->size);
79 vring->va = NULL;
80 return -ENOMEM;
81 }
82 /*
83 * vring->va should be aligned on its size rounded up to power of 2
84 * This is granted by the dma_alloc_coherent
85 */
86 vring->va = dma_alloc_coherent(dev, sz, &vring->pa, GFP_KERNEL);
87 if (!vring->va) {
88 wil_err(wil, "vring_alloc [%d] failed to alloc DMA mem\n",
89 vring->size);
90 kfree(vring->ctx);
91 vring->ctx = NULL;
92 return -ENOMEM;
93 }
94 /* initially, all descriptors are SW owned
95 * For Tx and Rx, ownership bit is at the same location, thus
96 * we can use any
97 */
98 for (i = 0; i < vring->size; i++) {
99 volatile struct vring_tx_desc *d = &(vring->va[i].tx);
100 d->dma.status = TX_DMA_STATUS_DU;
101 }
102
103 wil_dbg(wil, "vring[%d] 0x%p:0x%016llx 0x%p\n", vring->size,
104 vring->va, (unsigned long long)vring->pa, vring->ctx);
105
106 return 0;
107}
108
109static void wil_vring_free(struct wil6210_priv *wil, struct vring *vring,
110 int tx)
111{
112 struct device *dev = wil_to_dev(wil);
113 size_t sz = vring->size * sizeof(vring->va[0]);
114
115 while (!wil_vring_is_empty(vring)) {
116 if (tx) {
117 volatile struct vring_tx_desc *d =
118 &vring->va[vring->swtail].tx;
119 dma_addr_t pa = d->dma.addr_low |
120 ((u64)d->dma.addr_high << 32);
121 struct sk_buff *skb = vring->ctx[vring->swtail];
122 if (skb) {
123 dma_unmap_single(dev, pa, d->dma.length,
124 DMA_TO_DEVICE);
125 dev_kfree_skb_any(skb);
126 vring->ctx[vring->swtail] = NULL;
127 } else {
128 dma_unmap_page(dev, pa, d->dma.length,
129 DMA_TO_DEVICE);
130 }
131 vring->swtail = wil_vring_next_tail(vring);
132 } else { /* rx */
133 volatile struct vring_rx_desc *d =
134 &vring->va[vring->swtail].rx;
135 dma_addr_t pa = d->dma.addr_low |
136 ((u64)d->dma.addr_high << 32);
137 struct sk_buff *skb = vring->ctx[vring->swhead];
138 dma_unmap_single(dev, pa, d->dma.length,
139 DMA_FROM_DEVICE);
140 kfree_skb(skb);
141 wil_vring_advance_head(vring, 1);
142 }
143 }
144 dma_free_coherent(dev, sz, (void *)vring->va, vring->pa);
145 kfree(vring->ctx);
146 vring->pa = 0;
147 vring->va = NULL;
148 vring->ctx = NULL;
149}
150
151/**
152 * Allocate one skb for Rx VRING
153 *
154 * Safe to call from IRQ
155 */
156static int wil_vring_alloc_skb(struct wil6210_priv *wil, struct vring *vring,
157 u32 i, int headroom)
158{
159 struct device *dev = wil_to_dev(wil);
160 unsigned int sz = RX_BUF_LEN;
161 volatile struct vring_rx_desc *d = &(vring->va[i].rx);
162 dma_addr_t pa;
163
164 /* TODO align */
165 struct sk_buff *skb = dev_alloc_skb(sz + headroom);
166 if (unlikely(!skb))
167 return -ENOMEM;
168
169 skb_reserve(skb, headroom);
170 skb_put(skb, sz);
171
172 pa = dma_map_single(dev, skb->data, skb->len, DMA_FROM_DEVICE);
173 if (unlikely(dma_mapping_error(dev, pa))) {
174 kfree_skb(skb);
175 return -ENOMEM;
176 }
177
178 d->dma.d0 = BIT(9) | RX_DMA_D0_CMD_DMA_IT;
179 d->dma.addr_low = lower_32_bits(pa);
180 d->dma.addr_high = (u16)upper_32_bits(pa);
181 /* ip_length don't care */
182 /* b11 don't care */
183 /* error don't care */
184 d->dma.status = 0; /* BIT(0) should be 0 for HW_OWNED */
185 d->dma.length = sz;
186 vring->ctx[i] = skb;
187
188 return 0;
189}
190
191/**
192 * Adds radiotap header
193 *
194 * Any error indicated as "Bad FCS"
195 *
196 * Vendor data for 04:ce:14-1 (Wilocity-1) consists of:
197 * - Rx descriptor: 32 bytes
198 * - Phy info
199 */
200static void wil_rx_add_radiotap_header(struct wil6210_priv *wil,
201 struct sk_buff *skb,
202 volatile struct vring_rx_desc *d)
203{
204 struct wireless_dev *wdev = wil->wdev;
205 struct wil6210_rtap {
206 struct ieee80211_radiotap_header rthdr;
207 /* fields should be in the order of bits in rthdr.it_present */
208 /* flags */
209 u8 flags;
210 /* channel */
211 __le16 chnl_freq __aligned(2);
212 __le16 chnl_flags;
213 /* MCS */
214 u8 mcs_present;
215 u8 mcs_flags;
216 u8 mcs_index;
217 } __packed;
218 struct wil6210_rtap_vendor {
219 struct wil6210_rtap rtap;
220 /* vendor */
221 u8 vendor_oui[3] __aligned(2);
222 u8 vendor_ns;
223 __le16 vendor_skip;
224 u8 vendor_data[0];
225 } __packed;
226 struct wil6210_rtap_vendor *rtap_vendor;
227 int rtap_len = sizeof(struct wil6210_rtap);
228 int phy_length = 0; /* phy info header size, bytes */
229 static char phy_data[128];
230 struct ieee80211_channel *ch = wdev->preset_chandef.chan;
231
232 if (rtap_include_phy_info) {
233 rtap_len = sizeof(*rtap_vendor) + sizeof(*d);
234 /* calculate additional length */
235 if (d->dma.status & RX_DMA_STATUS_PHY_INFO) {
236 /**
237 * PHY info starts from 8-byte boundary
238 * there are 8-byte lines, last line may be partially
239 * written (HW bug), thus FW configures for last line
240 * to be excessive. Driver skips this last line.
241 */
242 int len = min_t(int, 8 + sizeof(phy_data),
243 wil_rxdesc_phy_length(d));
244 if (len > 8) {
245 void *p = skb_tail_pointer(skb);
246 void *pa = PTR_ALIGN(p, 8);
247 if (skb_tailroom(skb) >= len + (pa - p)) {
248 phy_length = len - 8;
249 memcpy(phy_data, pa, phy_length);
250 }
251 }
252 }
253 rtap_len += phy_length;
254 }
255
256 if (skb_headroom(skb) < rtap_len &&
257 pskb_expand_head(skb, rtap_len, 0, GFP_ATOMIC)) {
258 wil_err(wil, "Unable to expand headrom to %d\n", rtap_len);
259 return;
260 }
261
262 rtap_vendor = (void *)skb_push(skb, rtap_len);
263 memset(rtap_vendor, 0, rtap_len);
264
265 rtap_vendor->rtap.rthdr.it_version = PKTHDR_RADIOTAP_VERSION;
266 rtap_vendor->rtap.rthdr.it_len = cpu_to_le16(rtap_len);
267 rtap_vendor->rtap.rthdr.it_present = cpu_to_le32(
268 (1 << IEEE80211_RADIOTAP_FLAGS) |
269 (1 << IEEE80211_RADIOTAP_CHANNEL) |
270 (1 << IEEE80211_RADIOTAP_MCS));
271 if (d->dma.status & RX_DMA_STATUS_ERROR)
272 rtap_vendor->rtap.flags |= IEEE80211_RADIOTAP_F_BADFCS;
273
274 rtap_vendor->rtap.chnl_freq = cpu_to_le16(ch ? ch->center_freq : 58320);
275 rtap_vendor->rtap.chnl_flags = cpu_to_le16(0);
276
277 rtap_vendor->rtap.mcs_present = IEEE80211_RADIOTAP_MCS_HAVE_MCS;
278 rtap_vendor->rtap.mcs_flags = 0;
279 rtap_vendor->rtap.mcs_index = wil_rxdesc_mcs(d);
280
281 if (rtap_include_phy_info) {
282 rtap_vendor->rtap.rthdr.it_present |= cpu_to_le32(1 <<
283 IEEE80211_RADIOTAP_VENDOR_NAMESPACE);
284 /* OUI for Wilocity 04:ce:14 */
285 rtap_vendor->vendor_oui[0] = 0x04;
286 rtap_vendor->vendor_oui[1] = 0xce;
287 rtap_vendor->vendor_oui[2] = 0x14;
288 rtap_vendor->vendor_ns = 1;
289 /* Rx descriptor + PHY data */
290 rtap_vendor->vendor_skip = cpu_to_le16(sizeof(*d) +
291 phy_length);
292 memcpy(rtap_vendor->vendor_data, (void *)d, sizeof(*d));
293 memcpy(rtap_vendor->vendor_data + sizeof(*d), phy_data,
294 phy_length);
295 }
296}
297
298/*
299 * Fast swap in place between 2 registers
300 */
301static void wil_swap_u16(u16 *a, u16 *b)
302{
303 *a ^= *b;
304 *b ^= *a;
305 *a ^= *b;
306}
307
308static void wil_swap_ethaddr(void *data)
309{
310 struct ethhdr *eth = data;
311 u16 *s = (u16 *)eth->h_source;
312 u16 *d = (u16 *)eth->h_dest;
313
314 wil_swap_u16(s++, d++);
315 wil_swap_u16(s++, d++);
316 wil_swap_u16(s, d);
317}
318
319/**
320 * reap 1 frame from @swhead
321 *
322 * Safe to call from IRQ
323 */
324static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
325 struct vring *vring)
326{
327 struct device *dev = wil_to_dev(wil);
328 struct net_device *ndev = wil_to_ndev(wil);
329 volatile struct vring_rx_desc *d;
330 struct sk_buff *skb;
331 dma_addr_t pa;
332 unsigned int sz = RX_BUF_LEN;
333 u8 ftype;
334 u8 ds_bits;
335
336 if (wil_vring_is_empty(vring))
337 return NULL;
338
339 d = &(vring->va[vring->swhead].rx);
340 if (!(d->dma.status & RX_DMA_STATUS_DU)) {
341 /* it is not error, we just reached end of Rx done area */
342 return NULL;
343 }
344
345 pa = d->dma.addr_low | ((u64)d->dma.addr_high << 32);
346 skb = vring->ctx[vring->swhead];
347 dma_unmap_single(dev, pa, sz, DMA_FROM_DEVICE);
348 skb_trim(skb, d->dma.length);
349
350 wil->stats.last_mcs_rx = wil_rxdesc_mcs(d);
351
352 /* use radiotap header only if required */
353 if (ndev->type == ARPHRD_IEEE80211_RADIOTAP)
354 wil_rx_add_radiotap_header(wil, skb, d);
355
356 wil_dbg_TXRX(wil, "Rx[%3d] : %d bytes\n", vring->swhead, d->dma.length);
357 wil_hex_dump_TXRX("Rx ", DUMP_PREFIX_NONE, 32, 4,
358 (const void *)d, sizeof(*d), false);
359
360 wil_vring_advance_head(vring, 1);
361
362 /* no extra checks if in sniffer mode */
363 if (ndev->type != ARPHRD_ETHER)
364 return skb;
365 /*
366 * Non-data frames may be delivered through Rx DMA channel (ex: BAR)
367 * Driver should recognize it by frame type, that is found
368 * in Rx descriptor. If type is not data, it is 802.11 frame as is
369 */
370 ftype = wil_rxdesc_ftype(d) << 2;
371 if (ftype != IEEE80211_FTYPE_DATA) {
372 wil_dbg_TXRX(wil, "Non-data frame ftype 0x%08x\n", ftype);
373 /* TODO: process it */
374 kfree_skb(skb);
375 return NULL;
376 }
377
378 if (skb->len < ETH_HLEN) {
379 wil_err(wil, "Short frame, len = %d\n", skb->len);
380 /* TODO: process it (i.e. BAR) */
381 kfree_skb(skb);
382 return NULL;
383 }
384
385 ds_bits = wil_rxdesc_ds_bits(d);
386 if (ds_bits == 1) {
387 /*
388 * HW bug - in ToDS mode, i.e. Rx on AP side,
389 * addresses get swapped
390 */
391 wil_swap_ethaddr(skb->data);
392 }
393
394 return skb;
395}
396
397/**
398 * allocate and fill up to @count buffers in rx ring
399 * buffers posted at @swtail
400 */
401static int wil_rx_refill(struct wil6210_priv *wil, int count)
402{
403 struct net_device *ndev = wil_to_ndev(wil);
404 struct vring *v = &wil->vring_rx;
405 u32 next_tail;
406 int rc = 0;
407 int headroom = ndev->type == ARPHRD_IEEE80211_RADIOTAP ?
408 WIL6210_RTAP_SIZE : 0;
409
410 for (; next_tail = wil_vring_next_tail(v),
411 (next_tail != v->swhead) && (count-- > 0);
412 v->swtail = next_tail) {
413 rc = wil_vring_alloc_skb(wil, v, v->swtail, headroom);
414 if (rc) {
415 wil_err(wil, "Error %d in wil_rx_refill[%d]\n",
416 rc, v->swtail);
417 break;
418 }
419 }
420 iowrite32(v->swtail, wil->csr + HOSTADDR(v->hwtail));
421
422 return rc;
423}
424
425/*
426 * Pass Rx packet to the netif. Update statistics.
427 */
428static void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev)
429{
430 int rc;
431 unsigned int len = skb->len;
432
433 if (in_interrupt())
434 rc = netif_rx(skb);
435 else
436 rc = netif_rx_ni(skb);
437
438 if (likely(rc == NET_RX_SUCCESS)) {
439 ndev->stats.rx_packets++;
440 ndev->stats.rx_bytes += len;
441
442 } else {
443 ndev->stats.rx_dropped++;
444 }
445}
446
447/**
448 * Proceed all completed skb's from Rx VRING
449 *
450 * Safe to call from IRQ
451 */
452void wil_rx_handle(struct wil6210_priv *wil)
453{
454 struct net_device *ndev = wil_to_ndev(wil);
455 struct vring *v = &wil->vring_rx;
456 struct sk_buff *skb;
457
458 if (!v->va) {
459 wil_err(wil, "Rx IRQ while Rx not yet initialized\n");
460 return;
461 }
462 wil_dbg_TXRX(wil, "%s()\n", __func__);
463 while (NULL != (skb = wil_vring_reap_rx(wil, v))) {
464 wil_hex_dump_TXRX("Rx ", DUMP_PREFIX_OFFSET, 16, 1,
465 skb->data, skb_headlen(skb), false);
466
467 skb_orphan(skb);
468
469 if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR) {
470 skb->dev = ndev;
471 skb_reset_mac_header(skb);
472 skb->ip_summed = CHECKSUM_UNNECESSARY;
473 skb->pkt_type = PACKET_OTHERHOST;
474 skb->protocol = htons(ETH_P_802_2);
475
476 } else {
477 skb->protocol = eth_type_trans(skb, ndev);
478 }
479
480 wil_netif_rx_any(skb, ndev);
481 }
482 wil_rx_refill(wil, v->size);
483}
484
485int wil_rx_init(struct wil6210_priv *wil)
486{
487 struct net_device *ndev = wil_to_ndev(wil);
488 struct wireless_dev *wdev = wil->wdev;
489 struct vring *vring = &wil->vring_rx;
490 int rc;
491 struct wmi_cfg_rx_chain_cmd cmd = {
492 .action = WMI_RX_CHAIN_ADD,
493 .rx_sw_ring = {
494 .max_mpdu_size = cpu_to_le16(RX_BUF_LEN),
495 },
496 .mid = 0, /* TODO - what is it? */
497 .decap_trans_type = WMI_DECAP_TYPE_802_3,
498 };
499 struct {
500 struct wil6210_mbox_hdr_wmi wmi;
501 struct wmi_cfg_rx_chain_done_event evt;
502 } __packed evt;
503
504 vring->size = WIL6210_RX_RING_SIZE;
505 rc = wil_vring_alloc(wil, vring);
506 if (rc)
507 return rc;
508
509 cmd.rx_sw_ring.ring_mem_base = cpu_to_le64(vring->pa);
510 cmd.rx_sw_ring.ring_size = cpu_to_le16(vring->size);
511 if (wdev->iftype == NL80211_IFTYPE_MONITOR) {
512 struct ieee80211_channel *ch = wdev->preset_chandef.chan;
513
514 cmd.sniffer_cfg.mode = cpu_to_le32(WMI_SNIFFER_ON);
515 if (ch)
516 cmd.sniffer_cfg.channel = ch->hw_value - 1;
517 cmd.sniffer_cfg.phy_info_mode =
518 cpu_to_le32(ndev->type == ARPHRD_IEEE80211_RADIOTAP);
519 cmd.sniffer_cfg.phy_support =
520 cpu_to_le32((wil->monitor_flags & MONITOR_FLAG_CONTROL)
521 ? WMI_SNIFFER_CP : WMI_SNIFFER_DP);
522 }
523 /* typical time for secure PCP is 840ms */
524 rc = wmi_call(wil, WMI_CFG_RX_CHAIN_CMDID, &cmd, sizeof(cmd),
525 WMI_CFG_RX_CHAIN_DONE_EVENTID, &evt, sizeof(evt), 2000);
526 if (rc)
527 goto err_free;
528
529 vring->hwtail = le32_to_cpu(evt.evt.rx_ring_tail_ptr);
530
531 wil_dbg(wil, "Rx init: status %d tail 0x%08x\n",
532 le32_to_cpu(evt.evt.status), vring->hwtail);
533
534 rc = wil_rx_refill(wil, vring->size);
535 if (rc)
536 goto err_free;
537
538 return 0;
539 err_free:
540 wil_vring_free(wil, vring, 0);
541
542 return rc;
543}
544
545void wil_rx_fini(struct wil6210_priv *wil)
546{
547 struct vring *vring = &wil->vring_rx;
548
549 if (vring->va) {
550 int rc;
551 struct wmi_cfg_rx_chain_cmd cmd = {
552 .action = cpu_to_le32(WMI_RX_CHAIN_DEL),
553 .rx_sw_ring = {
554 .max_mpdu_size = cpu_to_le16(RX_BUF_LEN),
555 },
556 };
557 struct {
558 struct wil6210_mbox_hdr_wmi wmi;
559 struct wmi_cfg_rx_chain_done_event cfg;
560 } __packed wmi_rx_cfg_reply;
561
562 rc = wmi_call(wil, WMI_CFG_RX_CHAIN_CMDID, &cmd, sizeof(cmd),
563 WMI_CFG_RX_CHAIN_DONE_EVENTID,
564 &wmi_rx_cfg_reply, sizeof(wmi_rx_cfg_reply),
565 100);
566 wil_vring_free(wil, vring, 0);
567 }
568}
569
570int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
571 int cid, int tid)
572{
573 int rc;
574 struct wmi_vring_cfg_cmd cmd = {
575 .action = cpu_to_le32(WMI_VRING_CMD_ADD),
576 .vring_cfg = {
577 .tx_sw_ring = {
578 .max_mpdu_size = cpu_to_le16(TX_BUF_LEN),
579 },
580 .ringid = id,
581 .cidxtid = (cid & 0xf) | ((tid & 0xf) << 4),
582 .encap_trans_type = WMI_VRING_ENC_TYPE_802_3,
583 .mac_ctrl = 0,
584 .to_resolution = 0,
585 .agg_max_wsize = 16,
586 .schd_params = {
587 .priority = cpu_to_le16(0),
588 .timeslot_us = cpu_to_le16(0xfff),
589 },
590 },
591 };
592 struct {
593 struct wil6210_mbox_hdr_wmi wmi;
594 struct wmi_vring_cfg_done_event cmd;
595 } __packed reply;
596 struct vring *vring = &wil->vring_tx[id];
597
598 if (vring->va) {
599 wil_err(wil, "Tx ring [%d] already allocated\n", id);
600 rc = -EINVAL;
601 goto out;
602 }
603
604 vring->size = size;
605 rc = wil_vring_alloc(wil, vring);
606 if (rc)
607 goto out;
608
609 cmd.vring_cfg.tx_sw_ring.ring_mem_base = cpu_to_le64(vring->pa);
610 cmd.vring_cfg.tx_sw_ring.ring_size = cpu_to_le16(vring->size);
611
612 rc = wmi_call(wil, WMI_VRING_CFG_CMDID, &cmd, sizeof(cmd),
613 WMI_VRING_CFG_DONE_EVENTID, &reply, sizeof(reply), 100);
614 if (rc)
615 goto out_free;
616
617 if (reply.cmd.status != WMI_VRING_CFG_SUCCESS) {
618 wil_err(wil, "Tx config failed, status 0x%02x\n",
619 reply.cmd.status);
620 goto out_free;
621 }
622 vring->hwtail = le32_to_cpu(reply.cmd.tx_vring_tail_ptr);
623
624 return 0;
625 out_free:
626 wil_vring_free(wil, vring, 1);
627 out:
628
629 return rc;
630}
631
632void wil_vring_fini_tx(struct wil6210_priv *wil, int id)
633{
634 struct vring *vring = &wil->vring_tx[id];
635
636 if (!vring->va)
637 return;
638
639 wil_vring_free(wil, vring, 1);
640}
641
642static struct vring *wil_find_tx_vring(struct wil6210_priv *wil,
643 struct sk_buff *skb)
644{
645 struct vring *v = &wil->vring_tx[0];
646
647 if (v->va)
648 return v;
649
650 return NULL;
651}
652
653static int wil_tx_desc_map(volatile struct vring_tx_desc *d,
654 dma_addr_t pa, u32 len)
655{
656 d->dma.addr_low = lower_32_bits(pa);
657 d->dma.addr_high = (u16)upper_32_bits(pa);
658 d->dma.ip_length = 0;
659 /* 0..6: mac_length; 7:ip_version 0-IP6 1-IP4*/
660 d->dma.b11 = 0/*14 | BIT(7)*/;
661 d->dma.error = 0;
662 d->dma.status = 0; /* BIT(0) should be 0 for HW_OWNED */
663 d->dma.length = len;
664 d->dma.d0 = 0;
665 d->mac.d[0] = 0;
666 d->mac.d[1] = 0;
667 d->mac.d[2] = 0;
668 d->mac.ucode_cmd = 0;
669 /* use dst index 0 */
670 d->mac.d[1] |= BIT(MAC_CFG_DESC_TX_1_DST_INDEX_EN_POS) |
671 (0 << MAC_CFG_DESC_TX_1_DST_INDEX_POS);
672 /* translation type: 0 - bypass; 1 - 802.3; 2 - native wifi */
673 d->mac.d[2] = BIT(MAC_CFG_DESC_TX_2_SNAP_HDR_INSERTION_EN_POS) |
674 (1 << MAC_CFG_DESC_TX_2_L2_TRANSLATION_TYPE_POS);
675
676 return 0;
677}
678
679static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
680 struct sk_buff *skb)
681{
682 struct device *dev = wil_to_dev(wil);
683 volatile struct vring_tx_desc *d;
684 u32 swhead = vring->swhead;
685 int avail = wil_vring_avail_tx(vring);
686 int nr_frags = skb_shinfo(skb)->nr_frags;
687 uint f;
688 int vring_index = vring - wil->vring_tx;
689 uint i = swhead;
690 dma_addr_t pa;
691
692 wil_dbg_TXRX(wil, "%s()\n", __func__);
693
694 if (avail < vring->size/8)
695 netif_tx_stop_all_queues(wil_to_ndev(wil));
696 if (avail < 1 + nr_frags) {
697 wil_err(wil, "Tx ring full. No space for %d fragments\n",
698 1 + nr_frags);
699 return -ENOMEM;
700 }
701 d = &(vring->va[i].tx);
702
703 /* FIXME FW can accept only unicast frames for the peer */
704 memcpy(skb->data, wil->dst_addr[vring_index], ETH_ALEN);
705
706 pa = dma_map_single(dev, skb->data,
707 skb_headlen(skb), DMA_TO_DEVICE);
708
709 wil_dbg_TXRX(wil, "Tx skb %d bytes %p -> %#08llx\n", skb_headlen(skb),
710 skb->data, (unsigned long long)pa);
711 wil_hex_dump_TXRX("Tx ", DUMP_PREFIX_OFFSET, 16, 1,
712 skb->data, skb_headlen(skb), false);
713
714 if (unlikely(dma_mapping_error(dev, pa)))
715 return -EINVAL;
716 /* 1-st segment */
717 wil_tx_desc_map(d, pa, skb_headlen(skb));
718 d->mac.d[2] |= ((nr_frags + 1) <<
719 MAC_CFG_DESC_TX_2_NUM_OF_DESCRIPTORS_POS);
720 /* middle segments */
721 for (f = 0; f < nr_frags; f++) {
722 const struct skb_frag_struct *frag =
723 &skb_shinfo(skb)->frags[f];
724 int len = skb_frag_size(frag);
725 i = (swhead + f + 1) % vring->size;
726 d = &(vring->va[i].tx);
727 pa = skb_frag_dma_map(dev, frag, 0, skb_frag_size(frag),
728 DMA_TO_DEVICE);
729 if (unlikely(dma_mapping_error(dev, pa)))
730 goto dma_error;
731 wil_tx_desc_map(d, pa, len);
732 vring->ctx[i] = NULL;
733 }
734 /* for the last seg only */
735 d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_CMD_EOP_POS);
736 d->dma.d0 |= BIT(9); /* BUG: undocumented bit */
737 d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_CMD_DMA_IT_POS);
738 d->dma.d0 |= (vring_index << DMA_CFG_DESC_TX_0_QID_POS);
739
740 wil_hex_dump_TXRX("Tx ", DUMP_PREFIX_NONE, 32, 4,
741 (const void *)d, sizeof(*d), false);
742
743 /* advance swhead */
744 wil_vring_advance_head(vring, nr_frags + 1);
745 wil_dbg_TXRX(wil, "Tx swhead %d -> %d\n", swhead, vring->swhead);
746 iowrite32(vring->swhead, wil->csr + HOSTADDR(vring->hwtail));
747 /* hold reference to skb
748 * to prevent skb release before accounting
749 * in case of immediate "tx done"
750 */
751 vring->ctx[i] = skb_get(skb);
752
753 return 0;
754 dma_error:
755 /* unmap what we have mapped */
756 /* Note: increment @f to operate with positive index */
757 for (f++; f > 0; f--) {
758 i = (swhead + f) % vring->size;
759 d = &(vring->va[i].tx);
760 d->dma.status = TX_DMA_STATUS_DU;
761 pa = d->dma.addr_low | ((u64)d->dma.addr_high << 32);
762 if (vring->ctx[i])
763 dma_unmap_single(dev, pa, d->dma.length, DMA_TO_DEVICE);
764 else
765 dma_unmap_page(dev, pa, d->dma.length, DMA_TO_DEVICE);
766 }
767
768 return -EINVAL;
769}
770
771
772netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
773{
774 struct wil6210_priv *wil = ndev_to_wil(ndev);
775 struct vring *vring;
776 int rc;
777
778 wil_dbg_TXRX(wil, "%s()\n", __func__);
779 if (!test_bit(wil_status_fwready, &wil->status)) {
780 wil_err(wil, "FW not ready\n");
781 goto drop;
782 }
783 if (!test_bit(wil_status_fwconnected, &wil->status)) {
784 wil_err(wil, "FW not connected\n");
785 goto drop;
786 }
787 if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR) {
788 wil_err(wil, "Xmit in monitor mode not supported\n");
789 goto drop;
790 }
791 if (skb->protocol == cpu_to_be16(ETH_P_PAE)) {
792 rc = wmi_tx_eapol(wil, skb);
793 } else {
794 /* find vring */
795 vring = wil_find_tx_vring(wil, skb);
796 if (!vring) {
797 wil_err(wil, "No Tx VRING available\n");
798 goto drop;
799 }
800 /* set up vring entry */
801 rc = wil_tx_vring(wil, vring, skb);
802 }
803 switch (rc) {
804 case 0:
805 ndev->stats.tx_packets++;
806 ndev->stats.tx_bytes += skb->len;
807 dev_kfree_skb_any(skb);
808 return NETDEV_TX_OK;
809 case -ENOMEM:
810 return NETDEV_TX_BUSY;
811 default:
812 ; /* goto drop; */
813 break;
814 }
815 drop:
816 netif_tx_stop_all_queues(ndev);
817 ndev->stats.tx_dropped++;
818 dev_kfree_skb_any(skb);
819
820 return NET_XMIT_DROP;
821}
822
823/**
824 * Clean up transmitted skb's from the Tx VRING
825 *
826 * Safe to call from IRQ
827 */
828void wil_tx_complete(struct wil6210_priv *wil, int ringid)
829{
830 struct device *dev = wil_to_dev(wil);
831 struct vring *vring = &wil->vring_tx[ringid];
832
833 if (!vring->va) {
834 wil_err(wil, "Tx irq[%d]: vring not initialized\n", ringid);
835 return;
836 }
837
838 wil_dbg_TXRX(wil, "%s(%d)\n", __func__, ringid);
839
840 while (!wil_vring_is_empty(vring)) {
841 volatile struct vring_tx_desc *d = &vring->va[vring->swtail].tx;
842 dma_addr_t pa;
843 struct sk_buff *skb;
844 if (!(d->dma.status & TX_DMA_STATUS_DU))
845 break;
846
847 wil_dbg_TXRX(wil,
848 "Tx[%3d] : %d bytes, status 0x%02x err 0x%02x\n",
849 vring->swtail, d->dma.length, d->dma.status,
850 d->dma.error);
851 wil_hex_dump_TXRX("TxC ", DUMP_PREFIX_NONE, 32, 4,
852 (const void *)d, sizeof(*d), false);
853
854 pa = d->dma.addr_low | ((u64)d->dma.addr_high << 32);
855 skb = vring->ctx[vring->swtail];
856 if (skb) {
857 dma_unmap_single(dev, pa, d->dma.length, DMA_TO_DEVICE);
858 dev_kfree_skb_any(skb);
859 vring->ctx[vring->swtail] = NULL;
860 } else {
861 dma_unmap_page(dev, pa, d->dma.length, DMA_TO_DEVICE);
862 }
863 d->dma.addr_low = 0;
864 d->dma.addr_high = 0;
865 d->dma.length = 0;
866 d->dma.status = TX_DMA_STATUS_DU;
867 vring->swtail = wil_vring_next_tail(vring);
868 }
869 if (wil_vring_avail_tx(vring) > vring->size/4)
870 netif_tx_wake_all_queues(wil_to_ndev(wil));
871}
diff --git a/drivers/net/wireless/ath/wil6210/txrx.h b/drivers/net/wireless/ath/wil6210/txrx.h
new file mode 100644
index 000000000000..45a61f597c5c
--- /dev/null
+++ b/drivers/net/wireless/ath/wil6210/txrx.h
@@ -0,0 +1,362 @@
1/*
2 * Copyright (c) 2012 Qualcomm Atheros, Inc.
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#ifndef WIL6210_TXRX_H
18#define WIL6210_TXRX_H
19
20#define BUF_SW_OWNED (1)
21#define BUF_HW_OWNED (0)
22
23/* size of max. Rx packet */
24#define RX_BUF_LEN (2048)
25#define TX_BUF_LEN (2048)
26/* how many bytes to reserve for rtap header? */
27#define WIL6210_RTAP_SIZE (128)
28
29/* Tx/Rx path */
30/*
31 * Tx descriptor - MAC part
32 * [dword 0]
33 * bit 0.. 9 : lifetime_expiry_value:10
34 * bit 10 : interrup_en:1
35 * bit 11 : status_en:1
36 * bit 12..13 : txss_override:2
37 * bit 14 : timestamp_insertion:1
38 * bit 15 : duration_preserve:1
39 * bit 16..21 : reserved0:6
40 * bit 22..26 : mcs_index:5
41 * bit 27 : mcs_en:1
42 * bit 28..29 : reserved1:2
43 * bit 30 : reserved2:1
44 * bit 31 : sn_preserved:1
45 * [dword 1]
46 * bit 0.. 3 : pkt_mode:4
47 * bit 4 : pkt_mode_en:1
48 * bit 5.. 7 : reserved0:3
49 * bit 8..13 : reserved1:6
50 * bit 14 : reserved2:1
51 * bit 15 : ack_policy_en:1
52 * bit 16..19 : dst_index:4
53 * bit 20 : dst_index_en:1
54 * bit 21..22 : ack_policy:2
55 * bit 23 : lifetime_en:1
56 * bit 24..30 : max_retry:7
57 * bit 31 : max_retry_en:1
58 * [dword 2]
59 * bit 0.. 7 : num_of_descriptors:8
60 * bit 8..17 : reserved:10
61 * bit 18..19 : l2_translation_type:2
62 * bit 20 : snap_hdr_insertion_en:1
63 * bit 21 : vlan_removal_en:1
64 * bit 22..31 : reserved0:10
65 * [dword 3]
66 * bit 0.. 31: ucode_cmd:32
67 */
68struct vring_tx_mac {
69 u32 d[3];
70 u32 ucode_cmd;
71} __packed;
72
73/* TX MAC Dword 0 */
74#define MAC_CFG_DESC_TX_0_LIFETIME_EXPIRY_VALUE_POS 0
75#define MAC_CFG_DESC_TX_0_LIFETIME_EXPIRY_VALUE_LEN 10
76#define MAC_CFG_DESC_TX_0_LIFETIME_EXPIRY_VALUE_MSK 0x3FF
77
78#define MAC_CFG_DESC_TX_0_INTERRUP_EN_POS 10
79#define MAC_CFG_DESC_TX_0_INTERRUP_EN_LEN 1
80#define MAC_CFG_DESC_TX_0_INTERRUP_EN_MSK 0x400
81
82#define MAC_CFG_DESC_TX_0_STATUS_EN_POS 11
83#define MAC_CFG_DESC_TX_0_STATUS_EN_LEN 1
84#define MAC_CFG_DESC_TX_0_STATUS_EN_MSK 0x800
85
86#define MAC_CFG_DESC_TX_0_TXSS_OVERRIDE_POS 12
87#define MAC_CFG_DESC_TX_0_TXSS_OVERRIDE_LEN 2
88#define MAC_CFG_DESC_TX_0_TXSS_OVERRIDE_MSK 0x3000
89
90#define MAC_CFG_DESC_TX_0_TIMESTAMP_INSERTION_POS 14
91#define MAC_CFG_DESC_TX_0_TIMESTAMP_INSERTION_LEN 1
92#define MAC_CFG_DESC_TX_0_TIMESTAMP_INSERTION_MSK 0x4000
93
94#define MAC_CFG_DESC_TX_0_DURATION_PRESERVE_POS 15
95#define MAC_CFG_DESC_TX_0_DURATION_PRESERVE_LEN 1
96#define MAC_CFG_DESC_TX_0_DURATION_PRESERVE_MSK 0x8000
97
98#define MAC_CFG_DESC_TX_0_MCS_INDEX_POS 22
99#define MAC_CFG_DESC_TX_0_MCS_INDEX_LEN 5
100#define MAC_CFG_DESC_TX_0_MCS_INDEX_MSK 0x7C00000
101
102#define MAC_CFG_DESC_TX_0_MCS_EN_POS 27
103#define MAC_CFG_DESC_TX_0_MCS_EN_LEN 1
104#define MAC_CFG_DESC_TX_0_MCS_EN_MSK 0x8000000
105
106#define MAC_CFG_DESC_TX_0_SN_PRESERVED_POS 31
107#define MAC_CFG_DESC_TX_0_SN_PRESERVED_LEN 1
108#define MAC_CFG_DESC_TX_0_SN_PRESERVED_MSK 0x80000000
109
110/* TX MAC Dword 1 */
111#define MAC_CFG_DESC_TX_1_PKT_MODE_POS 0
112#define MAC_CFG_DESC_TX_1_PKT_MODE_LEN 4
113#define MAC_CFG_DESC_TX_1_PKT_MODE_MSK 0xF
114
115#define MAC_CFG_DESC_TX_1_PKT_MODE_EN_POS 4
116#define MAC_CFG_DESC_TX_1_PKT_MODE_EN_LEN 1
117#define MAC_CFG_DESC_TX_1_PKT_MODE_EN_MSK 0x10
118
119#define MAC_CFG_DESC_TX_1_ACK_POLICY_EN_POS 15
120#define MAC_CFG_DESC_TX_1_ACK_POLICY_EN_LEN 1
121#define MAC_CFG_DESC_TX_1_ACK_POLICY_EN_MSK 0x8000
122
123#define MAC_CFG_DESC_TX_1_DST_INDEX_POS 16
124#define MAC_CFG_DESC_TX_1_DST_INDEX_LEN 4
125#define MAC_CFG_DESC_TX_1_DST_INDEX_MSK 0xF0000
126
127#define MAC_CFG_DESC_TX_1_DST_INDEX_EN_POS 20
128#define MAC_CFG_DESC_TX_1_DST_INDEX_EN_LEN 1
129#define MAC_CFG_DESC_TX_1_DST_INDEX_EN_MSK 0x100000
130
131#define MAC_CFG_DESC_TX_1_ACK_POLICY_POS 21
132#define MAC_CFG_DESC_TX_1_ACK_POLICY_LEN 2
133#define MAC_CFG_DESC_TX_1_ACK_POLICY_MSK 0x600000
134
135#define MAC_CFG_DESC_TX_1_LIFETIME_EN_POS 23
136#define MAC_CFG_DESC_TX_1_LIFETIME_EN_LEN 1
137#define MAC_CFG_DESC_TX_1_LIFETIME_EN_MSK 0x800000
138
139#define MAC_CFG_DESC_TX_1_MAX_RETRY_POS 24
140#define MAC_CFG_DESC_TX_1_MAX_RETRY_LEN 7
141#define MAC_CFG_DESC_TX_1_MAX_RETRY_MSK 0x7F000000
142
143#define MAC_CFG_DESC_TX_1_MAX_RETRY_EN_POS 31
144#define MAC_CFG_DESC_TX_1_MAX_RETRY_EN_LEN 1
145#define MAC_CFG_DESC_TX_1_MAX_RETRY_EN_MSK 0x80000000
146
147/* TX MAC Dword 2 */
148#define MAC_CFG_DESC_TX_2_NUM_OF_DESCRIPTORS_POS 0
149#define MAC_CFG_DESC_TX_2_NUM_OF_DESCRIPTORS_LEN 8
150#define MAC_CFG_DESC_TX_2_NUM_OF_DESCRIPTORS_MSK 0xFF
151
152#define MAC_CFG_DESC_TX_2_RESERVED_POS 8
153#define MAC_CFG_DESC_TX_2_RESERVED_LEN 10
154#define MAC_CFG_DESC_TX_2_RESERVED_MSK 0x3FF00
155
156#define MAC_CFG_DESC_TX_2_L2_TRANSLATION_TYPE_POS 18
157#define MAC_CFG_DESC_TX_2_L2_TRANSLATION_TYPE_LEN 2
158#define MAC_CFG_DESC_TX_2_L2_TRANSLATION_TYPE_MSK 0xC0000
159
160#define MAC_CFG_DESC_TX_2_SNAP_HDR_INSERTION_EN_POS 20
161#define MAC_CFG_DESC_TX_2_SNAP_HDR_INSERTION_EN_LEN 1
162#define MAC_CFG_DESC_TX_2_SNAP_HDR_INSERTION_EN_MSK 0x100000
163
164#define MAC_CFG_DESC_TX_2_VLAN_REMOVAL_EN_POS 21
165#define MAC_CFG_DESC_TX_2_VLAN_REMOVAL_EN_LEN 1
166#define MAC_CFG_DESC_TX_2_VLAN_REMOVAL_EN_MSK 0x200000
167
168/* TX MAC Dword 3 */
169#define MAC_CFG_DESC_TX_3_UCODE_CMD_POS 0
170#define MAC_CFG_DESC_TX_3_UCODE_CMD_LEN 32
171#define MAC_CFG_DESC_TX_3_UCODE_CMD_MSK 0xFFFFFFFF
172
173/* TX DMA Dword 0 */
174#define DMA_CFG_DESC_TX_0_L4_LENGTH_POS 0
175#define DMA_CFG_DESC_TX_0_L4_LENGTH_LEN 8
176#define DMA_CFG_DESC_TX_0_L4_LENGTH_MSK 0xFF
177
178#define DMA_CFG_DESC_TX_0_CMD_EOP_POS 8
179#define DMA_CFG_DESC_TX_0_CMD_EOP_LEN 1
180#define DMA_CFG_DESC_TX_0_CMD_EOP_MSK 0x100
181
182#define DMA_CFG_DESC_TX_0_CMD_DMA_IT_POS 10
183#define DMA_CFG_DESC_TX_0_CMD_DMA_IT_LEN 1
184#define DMA_CFG_DESC_TX_0_CMD_DMA_IT_MSK 0x400
185
186#define DMA_CFG_DESC_TX_0_SEGMENT_BUF_DETAILS_POS 11
187#define DMA_CFG_DESC_TX_0_SEGMENT_BUF_DETAILS_LEN 2
188#define DMA_CFG_DESC_TX_0_SEGMENT_BUF_DETAILS_MSK 0x1800
189
190#define DMA_CFG_DESC_TX_0_TCP_SEG_EN_POS 13
191#define DMA_CFG_DESC_TX_0_TCP_SEG_EN_LEN 1
192#define DMA_CFG_DESC_TX_0_TCP_SEG_EN_MSK 0x2000
193
194#define DMA_CFG_DESC_TX_0_IPV4_CHECKSUM_EN_POS 14
195#define DMA_CFG_DESC_TX_0_IPV4_CHECKSUM_EN_LEN 1
196#define DMA_CFG_DESC_TX_0_IPV4_CHECKSUM_EN_MSK 0x4000
197
198#define DMA_CFG_DESC_TX_0_TCP_UDP_CHECKSUM_EN_POS 15
199#define DMA_CFG_DESC_TX_0_TCP_UDP_CHECKSUM_EN_LEN 1
200#define DMA_CFG_DESC_TX_0_TCP_UDP_CHECKSUM_EN_MSK 0x8000
201
202#define DMA_CFG_DESC_TX_0_QID_POS 16
203#define DMA_CFG_DESC_TX_0_QID_LEN 5
204#define DMA_CFG_DESC_TX_0_QID_MSK 0x1F0000
205
206#define DMA_CFG_DESC_TX_0_PSEUDO_HEADER_CALC_EN_POS 21
207#define DMA_CFG_DESC_TX_0_PSEUDO_HEADER_CALC_EN_LEN 1
208#define DMA_CFG_DESC_TX_0_PSEUDO_HEADER_CALC_EN_MSK 0x200000
209
210#define DMA_CFG_DESC_TX_0_L4_TYPE_POS 30
211#define DMA_CFG_DESC_TX_0_L4_TYPE_LEN 2
212#define DMA_CFG_DESC_TX_0_L4_TYPE_MSK 0xC0000000
213
214
215#define TX_DMA_STATUS_DU BIT(0)
216
217struct vring_tx_dma {
218 u32 d0;
219 u32 addr_low;
220 u16 addr_high;
221 u8 ip_length;
222 u8 b11; /* 0..6: mac_length; 7:ip_version */
223 u8 error; /* 0..2: err; 3..7: reserved; */
224 u8 status; /* 0: used; 1..7; reserved */
225 u16 length;
226} __packed;
227
228/*
229 * Rx descriptor - MAC part
230 * [dword 0]
231 * bit 0.. 3 : tid:4 The QoS (b3-0) TID Field
232 * bit 4.. 6 : connection_id:3 :The Source index that was found during
233 * Parsing the TA. This field is used to define the source of the packet
234 * bit 7 : reserved:1
235 * bit 8.. 9 : mac_id:2 : The MAC virtual Ring number (always zero)
236 * bit 10..11 : frame_type:2 : The FC Control (b3-2) - MPDU Type
237 * (management, data, control and extension)
238 * bit 12..15 : frame_subtype:4 : The FC Control (b7-4) - Frame Subtype
239 * bit 16..27 : seq_number:12 The received Sequence number field
240 * bit 28..31 : extended:4 extended subtype
241 * [dword 1]
242 * bit 0.. 3 : reserved
243 * bit 4.. 5 : key_id:2
244 * bit 6 : decrypt_bypass:1
245 * bit 7 : security:1
246 * bit 8.. 9 : ds_bits:2
247 * bit 10 : a_msdu_present:1 from qos header
248 * bit 11 : a_msdu_type:1 from qos header
249 * bit 12 : a_mpdu:1 part of AMPDU aggregation
250 * bit 13 : broadcast:1
251 * bit 14 : mutlicast:1
252 * bit 15 : reserved:1
253 * bit 16..20 : rx_mac_qid:5 The Queue Identifier that the packet
254 * is received from
255 * bit 21..24 : mcs:4
256 * bit 25..28 : mic_icr:4
257 * bit 29..31 : reserved:3
258 * [dword 2]
259 * bit 0.. 2 : time_slot:3 The timeslot that the MPDU is received
260 * bit 3 : fc_protocol_ver:1 The FC Control (b0) - Protocol Version
261 * bit 4 : fc_order:1 The FC Control (b15) -Order
262 * bit 5.. 7 : qos_ack_policy:3 The QoS (b6-5) ack policy Field
263 * bit 8 : esop:1 The QoS (b4) ESOP field
264 * bit 9 : qos_rdg_more_ppdu:1 The QoS (b9) RDG field
265 * bit 10..14 : qos_reserved:5 The QoS (b14-10) Reserved field
266 * bit 15 : qos_ac_constraint:1
267 * bit 16..31 : pn_15_0:16 low 2 bytes of PN
268 * [dword 3]
269 * bit 0..31 : pn_47_16:32 high 4 bytes of PN
270 */
271struct vring_rx_mac {
272 u32 d0;
273 u32 d1;
274 u16 w4;
275 u16 pn_15_0;
276 u32 pn_47_16;
277} __packed;
278
279/*
280 * Rx descriptor - DMA part
281 * [dword 0]
282 * bit 0.. 7 : l4_length:8 layer 4 length
283 * bit 8.. 9 : reserved:2
284 * bit 10 : cmd_dma_it:1
285 * bit 11..15 : reserved:5
286 * bit 16..29 : phy_info_length:14
287 * bit 30..31 : l4_type:2 valid if the L4I bit is set in the status field
288 * [dword 1]
289 * bit 0..31 : addr_low:32 The payload buffer low address
290 * [dword 2]
291 * bit 0..15 : addr_high:16 The payload buffer high address
292 * bit 16..23 : ip_length:8
293 * bit 24..30 : mac_length:7
294 * bit 31 : ip_version:1
295 * [dword 3]
296 * [byte 12] error
297 * [byte 13] status
298 * bit 0 : du:1
299 * bit 1 : eop:1
300 * bit 2 : error:1
301 * bit 3 : mi:1
302 * bit 4 : l3_identified:1
303 * bit 5 : l4_identified:1
304 * bit 6 : phy_info_included:1
305 * bit 7 : reserved:1
306 * [word 7] length
307 *
308 */
309
310#define RX_DMA_D0_CMD_DMA_IT BIT(10)
311
312#define RX_DMA_STATUS_DU BIT(0)
313#define RX_DMA_STATUS_ERROR BIT(2)
314#define RX_DMA_STATUS_PHY_INFO BIT(6)
315
316struct vring_rx_dma {
317 u32 d0;
318 u32 addr_low;
319 u16 addr_high;
320 u8 ip_length;
321 u8 b11;
322 u8 error;
323 u8 status;
324 u16 length;
325} __packed;
326
327struct vring_tx_desc {
328 struct vring_tx_mac mac;
329 struct vring_tx_dma dma;
330} __packed;
331
332struct vring_rx_desc {
333 struct vring_rx_mac mac;
334 struct vring_rx_dma dma;
335} __packed;
336
337union vring_desc {
338 struct vring_tx_desc tx;
339 struct vring_rx_desc rx;
340} __packed;
341
342static inline int wil_rxdesc_phy_length(volatile struct vring_rx_desc *d)
343{
344 return WIL_GET_BITS(d->dma.d0, 16, 29);
345}
346
347static inline int wil_rxdesc_mcs(volatile struct vring_rx_desc *d)
348{
349 return WIL_GET_BITS(d->mac.d1, 21, 24);
350}
351
352static inline int wil_rxdesc_ds_bits(volatile struct vring_rx_desc *d)
353{
354 return WIL_GET_BITS(d->mac.d1, 8, 9);
355}
356
357static inline int wil_rxdesc_ftype(volatile struct vring_rx_desc *d)
358{
359 return WIL_GET_BITS(d->mac.d0, 10, 11);
360}
361
362#endif /* WIL6210_TXRX_H */
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
new file mode 100644
index 000000000000..9bcfffa4006c
--- /dev/null
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -0,0 +1,363 @@
1/*
2 * Copyright (c) 2012 Qualcomm Atheros, Inc.
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#ifndef __WIL6210_H__
18#define __WIL6210_H__
19
20#include <linux/netdevice.h>
21#include <linux/wireless.h>
22#include <net/cfg80211.h>
23
24#include "dbg_hexdump.h"
25
26#define WIL_NAME "wil6210"
27
28/**
29 * extract bits [@b0:@b1] (inclusive) from the value @x
30 * it should be @b0 <= @b1, or result is incorrect
31 */
32static inline u32 WIL_GET_BITS(u32 x, int b0, int b1)
33{
34 return (x >> b0) & ((1 << (b1 - b0 + 1)) - 1);
35}
36
37#define WIL6210_MEM_SIZE (2*1024*1024UL)
38
39#define WIL6210_TX_QUEUES (4)
40
41#define WIL6210_RX_RING_SIZE (128)
42#define WIL6210_TX_RING_SIZE (128)
43#define WIL6210_MAX_TX_RINGS (24)
44
45/* Hardware definitions begin */
46
47/*
48 * Mapping
49 * RGF File | Host addr | FW addr
50 * | |
51 * user_rgf | 0x000000 | 0x880000
52 * dma_rgf | 0x001000 | 0x881000
53 * pcie_rgf | 0x002000 | 0x882000
54 * | |
55 */
56
57/* Where various structures placed in host address space */
58#define WIL6210_FW_HOST_OFF (0x880000UL)
59
60#define HOSTADDR(fwaddr) (fwaddr - WIL6210_FW_HOST_OFF)
61
62/*
63 * Interrupt control registers block
64 *
65 * each interrupt controlled by the same bit in all registers
66 */
67struct RGF_ICR {
68 u32 ICC; /* Cause Control, RW: 0 - W1C, 1 - COR */
69 u32 ICR; /* Cause, W1C/COR depending on ICC */
70 u32 ICM; /* Cause masked (ICR & ~IMV), W1C/COR depending on ICC */
71 u32 ICS; /* Cause Set, WO */
72 u32 IMV; /* Mask, RW+S/C */
73 u32 IMS; /* Mask Set, write 1 to set */
74 u32 IMC; /* Mask Clear, write 1 to clear */
75} __packed;
76
77/* registers - FW addresses */
78#define RGF_USER_USER_SCRATCH_PAD (0x8802bc)
79#define RGF_USER_USER_ICR (0x880b4c) /* struct RGF_ICR */
80 #define BIT_USER_USER_ICR_SW_INT_2 BIT(18)
81#define RGF_USER_CLKS_CTL_SW_RST_MASK_0 (0x880b14)
82#define RGF_USER_MAC_CPU_0 (0x8801fc)
83#define RGF_USER_USER_CPU_0 (0x8801e0)
84#define RGF_USER_CLKS_CTL_SW_RST_VEC_0 (0x880b04)
85#define RGF_USER_CLKS_CTL_SW_RST_VEC_1 (0x880b08)
86#define RGF_USER_CLKS_CTL_SW_RST_VEC_2 (0x880b0c)
87#define RGF_USER_CLKS_CTL_SW_RST_VEC_3 (0x880b10)
88
89#define RGF_DMA_PSEUDO_CAUSE (0x881c68)
90#define RGF_DMA_PSEUDO_CAUSE_MASK_SW (0x881c6c)
91#define RGF_DMA_PSEUDO_CAUSE_MASK_FW (0x881c70)
92 #define BIT_DMA_PSEUDO_CAUSE_RX BIT(0)
93 #define BIT_DMA_PSEUDO_CAUSE_TX BIT(1)
94 #define BIT_DMA_PSEUDO_CAUSE_MISC BIT(2)
95
96#define RGF_DMA_EP_TX_ICR (0x881bb4) /* struct RGF_ICR */
97 #define BIT_DMA_EP_TX_ICR_TX_DONE BIT(0)
98 #define BIT_DMA_EP_TX_ICR_TX_DONE_N(n) BIT(n+1) /* n = [0..23] */
99#define RGF_DMA_EP_RX_ICR (0x881bd0) /* struct RGF_ICR */
100 #define BIT_DMA_EP_RX_ICR_RX_DONE BIT(0)
101#define RGF_DMA_EP_MISC_ICR (0x881bec) /* struct RGF_ICR */
102 #define BIT_DMA_EP_MISC_ICR_RX_HTRSH BIT(0)
103 #define BIT_DMA_EP_MISC_ICR_TX_NO_ACT BIT(1)
104 #define BIT_DMA_EP_MISC_ICR_FW_INT0 BIT(28)
105 #define BIT_DMA_EP_MISC_ICR_FW_INT1 BIT(29)
106
107/* Interrupt moderation control */
108#define RGF_DMA_ITR_CNT_TRSH (0x881c5c)
109#define RGF_DMA_ITR_CNT_DATA (0x881c60)
110#define RGF_DMA_ITR_CNT_CRL (0x881C64)
111 #define BIT_DMA_ITR_CNT_CRL_EN BIT(0)
112 #define BIT_DMA_ITR_CNT_CRL_EXT_TICK BIT(1)
113 #define BIT_DMA_ITR_CNT_CRL_FOREVER BIT(2)
114 #define BIT_DMA_ITR_CNT_CRL_CLR BIT(3)
115 #define BIT_DMA_ITR_CNT_CRL_REACH_TRSH BIT(4)
116
117/* popular locations */
118#define HOST_MBOX HOSTADDR(RGF_USER_USER_SCRATCH_PAD)
119#define HOST_SW_INT (HOSTADDR(RGF_USER_USER_ICR) + \
120 offsetof(struct RGF_ICR, ICS))
121#define SW_INT_MBOX BIT_USER_USER_ICR_SW_INT_2
122
123/* ISR register bits */
124#define ISR_MISC_FW_READY BIT_DMA_EP_MISC_ICR_FW_INT0
125#define ISR_MISC_MBOX_EVT BIT_DMA_EP_MISC_ICR_FW_INT1
126
127/* Hardware definitions end */
128
129struct wil6210_mbox_ring {
130 u32 base;
131 u16 entry_size; /* max. size of mbox entry, incl. all headers */
132 u16 size;
133 u32 tail;
134 u32 head;
135} __packed;
136
137struct wil6210_mbox_ring_desc {
138 __le32 sync;
139 __le32 addr;
140} __packed;
141
142/* at HOST_OFF_WIL6210_MBOX_CTL */
143struct wil6210_mbox_ctl {
144 struct wil6210_mbox_ring tx;
145 struct wil6210_mbox_ring rx;
146} __packed;
147
148struct wil6210_mbox_hdr {
149 __le16 seq;
150 __le16 len; /* payload, bytes after this header */
151 __le16 type;
152 u8 flags;
153 u8 reserved;
154} __packed;
155
156#define WIL_MBOX_HDR_TYPE_WMI (0)
157
158/* max. value for wil6210_mbox_hdr.len */
159#define MAX_MBOXITEM_SIZE (240)
160
161struct wil6210_mbox_hdr_wmi {
162 u8 reserved0[2];
163 __le16 id;
164 __le16 info1; /* bits [0..3] - device_id, rest - unused */
165 u8 reserved1[2];
166} __packed;
167
168struct pending_wmi_event {
169 struct list_head list;
170 struct {
171 struct wil6210_mbox_hdr hdr;
172 struct wil6210_mbox_hdr_wmi wmi;
173 u8 data[0];
174 } __packed event;
175};
176
177union vring_desc;
178
179struct vring {
180 dma_addr_t pa;
181 volatile union vring_desc *va; /* vring_desc[size], WriteBack by DMA */
182 u16 size; /* number of vring_desc elements */
183 u32 swtail;
184 u32 swhead;
185 u32 hwtail; /* write here to inform hw */
186 void **ctx; /* void *ctx[size] - software context */
187};
188
189enum { /* for wil6210_priv.status */
190 wil_status_fwready = 0,
191 wil_status_fwconnected,
192 wil_status_dontscan,
193 wil_status_irqen, /* FIXME: interrupts enabled - for debug */
194};
195
196struct pci_dev;
197
198struct wil6210_stats {
199 u64 tsf;
200 u32 snr;
201 u16 last_mcs_rx;
202 u16 bf_mcs; /* last BF, used for Tx */
203 u16 my_rx_sector;
204 u16 my_tx_sector;
205 u16 peer_rx_sector;
206 u16 peer_tx_sector;
207};
208
209struct wil6210_priv {
210 struct pci_dev *pdev;
211 int n_msi;
212 struct wireless_dev *wdev;
213 void __iomem *csr;
214 ulong status;
215 /* profile */
216 u32 monitor_flags;
217 u32 secure_pcp; /* create secure PCP? */
218 int sinfo_gen;
219 /* cached ISR registers */
220 u32 isr_misc;
221 /* mailbox related */
222 struct mutex wmi_mutex;
223 struct wil6210_mbox_ctl mbox_ctl;
224 struct completion wmi_ready;
225 u16 wmi_seq;
226 u16 reply_id; /**< wait for this WMI event */
227 void *reply_buf;
228 u16 reply_size;
229 struct workqueue_struct *wmi_wq; /* for deferred calls */
230 struct work_struct wmi_event_worker;
231 struct workqueue_struct *wmi_wq_conn; /* for connect worker */
232 struct work_struct wmi_connect_worker;
233 struct work_struct disconnect_worker;
234 struct timer_list connect_timer;
235 int pending_connect_cid;
236 struct list_head pending_wmi_ev;
237 /*
238 * protect pending_wmi_ev
239 * - fill in IRQ from wil6210_irq_misc,
240 * - consumed in thread by wmi_event_worker
241 */
242 spinlock_t wmi_ev_lock;
243 /* DMA related */
244 struct vring vring_rx;
245 struct vring vring_tx[WIL6210_MAX_TX_RINGS];
246 u8 dst_addr[WIL6210_MAX_TX_RINGS][ETH_ALEN];
247 /* scan */
248 struct cfg80211_scan_request *scan_request;
249
250 struct mutex mutex; /* for wil6210_priv access in wil_{up|down} */
251 /* statistics */
252 struct wil6210_stats stats;
253 /* debugfs */
254 struct dentry *debug;
255 struct debugfs_blob_wrapper fw_code_blob;
256 struct debugfs_blob_wrapper fw_data_blob;
257 struct debugfs_blob_wrapper fw_peri_blob;
258 struct debugfs_blob_wrapper uc_code_blob;
259 struct debugfs_blob_wrapper uc_data_blob;
260 struct debugfs_blob_wrapper rgf_blob;
261};
262
263#define wil_to_wiphy(i) (i->wdev->wiphy)
264#define wil_to_dev(i) (wiphy_dev(wil_to_wiphy(i)))
265#define wiphy_to_wil(w) (struct wil6210_priv *)(wiphy_priv(w))
266#define wil_to_wdev(i) (i->wdev)
267#define wdev_to_wil(w) (struct wil6210_priv *)(wdev_priv(w))
268#define wil_to_ndev(i) (wil_to_wdev(i)->netdev)
269#define ndev_to_wil(n) (wdev_to_wil(n->ieee80211_ptr))
270
271#define wil_dbg(wil, fmt, arg...) netdev_dbg(wil_to_ndev(wil), fmt, ##arg)
272#define wil_info(wil, fmt, arg...) netdev_info(wil_to_ndev(wil), fmt, ##arg)
273#define wil_err(wil, fmt, arg...) netdev_err(wil_to_ndev(wil), fmt, ##arg)
274
275#define wil_dbg_IRQ(wil, fmt, arg...) wil_dbg(wil, "DBG[ IRQ]" fmt, ##arg)
276#define wil_dbg_TXRX(wil, fmt, arg...) wil_dbg(wil, "DBG[TXRX]" fmt, ##arg)
277#define wil_dbg_WMI(wil, fmt, arg...) wil_dbg(wil, "DBG[ WMI]" fmt, ##arg)
278
279#define wil_hex_dump_TXRX(prefix_str, prefix_type, rowsize, \
280 groupsize, buf, len, ascii) \
281 wil_print_hex_dump_debug("DBG[TXRX]" prefix_str,\
282 prefix_type, rowsize, \
283 groupsize, buf, len, ascii)
284
285#define wil_hex_dump_WMI(prefix_str, prefix_type, rowsize, \
286 groupsize, buf, len, ascii) \
287 wil_print_hex_dump_debug("DBG[ WMI]" prefix_str,\
288 prefix_type, rowsize, \
289 groupsize, buf, len, ascii)
290
291void wil_memcpy_fromio_32(void *dst, const volatile void __iomem *src,
292 size_t count);
293void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src,
294 size_t count);
295
296void *wil_if_alloc(struct device *dev, void __iomem *csr);
297void wil_if_free(struct wil6210_priv *wil);
298int wil_if_add(struct wil6210_priv *wil);
299void wil_if_remove(struct wil6210_priv *wil);
300int wil_priv_init(struct wil6210_priv *wil);
301void wil_priv_deinit(struct wil6210_priv *wil);
302int wil_reset(struct wil6210_priv *wil);
303void wil_link_on(struct wil6210_priv *wil);
304void wil_link_off(struct wil6210_priv *wil);
305int wil_up(struct wil6210_priv *wil);
306int wil_down(struct wil6210_priv *wil);
307void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r);
308
309void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr);
310void __iomem *wmi_addr(struct wil6210_priv *wil, u32 ptr);
311int wmi_read_hdr(struct wil6210_priv *wil, __le32 ptr,
312 struct wil6210_mbox_hdr *hdr);
313int wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len);
314void wmi_recv_cmd(struct wil6210_priv *wil);
315int wmi_call(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len,
316 u16 reply_id, void *reply, u8 reply_size, int to_msec);
317void wmi_connect_worker(struct work_struct *work);
318void wmi_event_worker(struct work_struct *work);
319void wmi_event_flush(struct wil6210_priv *wil);
320int wmi_set_ssid(struct wil6210_priv *wil, u8 ssid_len, const void *ssid);
321int wmi_get_ssid(struct wil6210_priv *wil, u8 *ssid_len, void *ssid);
322int wmi_set_channel(struct wil6210_priv *wil, int channel);
323int wmi_get_channel(struct wil6210_priv *wil, int *channel);
324int wmi_tx_eapol(struct wil6210_priv *wil, struct sk_buff *skb);
325int wmi_del_cipher_key(struct wil6210_priv *wil, u8 key_index,
326 const void *mac_addr);
327int wmi_add_cipher_key(struct wil6210_priv *wil, u8 key_index,
328 const void *mac_addr, int key_len, const void *key);
329int wmi_echo(struct wil6210_priv *wil);
330int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie);
331
332int wil6210_init_irq(struct wil6210_priv *wil, int irq);
333void wil6210_fini_irq(struct wil6210_priv *wil, int irq);
334void wil6210_disable_irq(struct wil6210_priv *wil);
335void wil6210_enable_irq(struct wil6210_priv *wil);
336
337int wil6210_debugfs_init(struct wil6210_priv *wil);
338void wil6210_debugfs_remove(struct wil6210_priv *wil);
339
340struct wireless_dev *wil_cfg80211_init(struct device *dev);
341void wil_wdev_free(struct wil6210_priv *wil);
342
343int wmi_set_mac_address(struct wil6210_priv *wil, void *addr);
344int wmi_set_bcon(struct wil6210_priv *wil, int bi, u8 wmi_nettype);
345void wil6210_disconnect(struct wil6210_priv *wil, void *bssid);
346
347int wil_rx_init(struct wil6210_priv *wil);
348void wil_rx_fini(struct wil6210_priv *wil);
349
350/* TX API */
351int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
352 int cid, int tid);
353void wil_vring_fini_tx(struct wil6210_priv *wil, int id);
354
355netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev);
356void wil_tx_complete(struct wil6210_priv *wil, int ringid);
357
358/* RX API */
359void wil_rx_handle(struct wil6210_priv *wil);
360
361int wil_iftype_nl2wmi(enum nl80211_iftype type);
362
363#endif /* __WIL6210_H__ */
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
new file mode 100644
index 000000000000..12915f6e7617
--- /dev/null
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -0,0 +1,975 @@
1/*
2 * Copyright (c) 2012 Qualcomm Atheros, Inc.
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include <linux/pci.h>
18#include <linux/io.h>
19#include <linux/list.h>
20#include <linux/etherdevice.h>
21
22#include "wil6210.h"
23#include "wmi.h"
24
25/**
26 * WMI event receiving - theory of operations
27 *
28 * When firmware about to report WMI event, it fills memory area
29 * in the mailbox and raises misc. IRQ. Thread interrupt handler invoked for
30 * the misc IRQ, function @wmi_recv_cmd called by thread IRQ handler.
31 *
32 * @wmi_recv_cmd reads event, allocates memory chunk and attaches it to the
33 * event list @wil->pending_wmi_ev. Then, work queue @wil->wmi_wq wakes up
34 * and handles events within the @wmi_event_worker. Every event get detached
35 * from list, processed and deleted.
36 *
37 * Purpose for this mechanism is to release IRQ thread; otherwise,
38 * if WMI event handling involves another WMI command flow, this 2-nd flow
39 * won't be completed because of blocked IRQ thread.
40 */
41
42/**
43 * Addressing - theory of operations
44 *
45 * There are several buses present on the WIL6210 card.
46 * Same memory areas are visible at different address on
47 * the different busses. There are 3 main bus masters:
48 * - MAC CPU (ucode)
49 * - User CPU (firmware)
50 * - AHB (host)
51 *
52 * On the PCI bus, there is one BAR (BAR0) of 2Mb size, exposing
53 * AHB addresses starting from 0x880000
54 *
55 * Internally, firmware uses addresses that allows faster access but
56 * are invisible from the host. To read from these addresses, alternative
57 * AHB address must be used.
58 *
59 * Memory mapping
60 * Linker address PCI/Host address
61 * 0x880000 .. 0xa80000 2Mb BAR0
62 * 0x800000 .. 0x807000 0x900000 .. 0x907000 28k DCCM
63 * 0x840000 .. 0x857000 0x908000 .. 0x91f000 92k PERIPH
64 */
65
66/**
67 * @fw_mapping provides memory remapping table
68 */
69static const struct {
70 u32 from; /* linker address - from, inclusive */
71 u32 to; /* linker address - to, exclusive */
72 u32 host; /* PCI/Host address - BAR0 + 0x880000 */
73} fw_mapping[] = {
74 {0x000000, 0x040000, 0x8c0000}, /* FW code RAM 256k */
75 {0x800000, 0x808000, 0x900000}, /* FW data RAM 32k */
76 {0x840000, 0x860000, 0x908000}, /* peripheral data RAM 128k/96k used */
77 {0x880000, 0x88a000, 0x880000}, /* various RGF */
78 {0x8c0000, 0x932000, 0x8c0000}, /* trivial mapping for upper area */
79 /*
80 * 920000..930000 ucode code RAM
81 * 930000..932000 ucode data RAM
82 */
83};
84
85/**
86 * return AHB address for given firmware/ucode internal (linker) address
87 * @x - internal address
88 * If address have no valid AHB mapping, return 0
89 */
90static u32 wmi_addr_remap(u32 x)
91{
92 uint i;
93
94 for (i = 0; i < ARRAY_SIZE(fw_mapping); i++) {
95 if ((x >= fw_mapping[i].from) && (x < fw_mapping[i].to))
96 return x + fw_mapping[i].host - fw_mapping[i].from;
97 }
98
99 return 0;
100}
101
102/**
103 * Check address validity for WMI buffer; remap if needed
104 * @ptr - internal (linker) fw/ucode address
105 *
106 * Valid buffer should be DWORD aligned
107 *
108 * return address for accessing buffer from the host;
109 * if buffer is not valid, return NULL.
110 */
111void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr_)
112{
113 u32 off;
114 u32 ptr = le32_to_cpu(ptr_);
115
116 if (ptr % 4)
117 return NULL;
118
119 ptr = wmi_addr_remap(ptr);
120 if (ptr < WIL6210_FW_HOST_OFF)
121 return NULL;
122
123 off = HOSTADDR(ptr);
124 if (off > WIL6210_MEM_SIZE - 4)
125 return NULL;
126
127 return wil->csr + off;
128}
129
130/**
131 * Check address validity
132 */
133void __iomem *wmi_addr(struct wil6210_priv *wil, u32 ptr)
134{
135 u32 off;
136
137 if (ptr % 4)
138 return NULL;
139
140 if (ptr < WIL6210_FW_HOST_OFF)
141 return NULL;
142
143 off = HOSTADDR(ptr);
144 if (off > WIL6210_MEM_SIZE - 4)
145 return NULL;
146
147 return wil->csr + off;
148}
149
150int wmi_read_hdr(struct wil6210_priv *wil, __le32 ptr,
151 struct wil6210_mbox_hdr *hdr)
152{
153 void __iomem *src = wmi_buffer(wil, ptr);
154 if (!src)
155 return -EINVAL;
156
157 wil_memcpy_fromio_32(hdr, src, sizeof(*hdr));
158
159 return 0;
160}
161
162static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len)
163{
164 struct {
165 struct wil6210_mbox_hdr hdr;
166 struct wil6210_mbox_hdr_wmi wmi;
167 } __packed cmd = {
168 .hdr = {
169 .type = WIL_MBOX_HDR_TYPE_WMI,
170 .flags = 0,
171 .len = cpu_to_le16(sizeof(cmd.wmi) + len),
172 },
173 .wmi = {
174 .id = cpu_to_le16(cmdid),
175 .info1 = 0,
176 },
177 };
178 struct wil6210_mbox_ring *r = &wil->mbox_ctl.tx;
179 struct wil6210_mbox_ring_desc d_head;
180 u32 next_head;
181 void __iomem *dst;
182 void __iomem *head = wmi_addr(wil, r->head);
183 uint retry;
184
185 if (sizeof(cmd) + len > r->entry_size) {
186 wil_err(wil, "WMI size too large: %d bytes, max is %d\n",
187 (int)(sizeof(cmd) + len), r->entry_size);
188 return -ERANGE;
189
190 }
191
192 might_sleep();
193
194 if (!test_bit(wil_status_fwready, &wil->status)) {
195 wil_err(wil, "FW not ready\n");
196 return -EAGAIN;
197 }
198
199 if (!head) {
200 wil_err(wil, "WMI head is garbage: 0x%08x\n", r->head);
201 return -EINVAL;
202 }
203 /* read Tx head till it is not busy */
204 for (retry = 5; retry > 0; retry--) {
205 wil_memcpy_fromio_32(&d_head, head, sizeof(d_head));
206 if (d_head.sync == 0)
207 break;
208 msleep(20);
209 }
210 if (d_head.sync != 0) {
211 wil_err(wil, "WMI head busy\n");
212 return -EBUSY;
213 }
214 /* next head */
215 next_head = r->base + ((r->head - r->base + sizeof(d_head)) % r->size);
216 wil_dbg_WMI(wil, "Head 0x%08x -> 0x%08x\n", r->head, next_head);
217 /* wait till FW finish with previous command */
218 for (retry = 5; retry > 0; retry--) {
219 r->tail = ioread32(wil->csr + HOST_MBOX +
220 offsetof(struct wil6210_mbox_ctl, tx.tail));
221 if (next_head != r->tail)
222 break;
223 msleep(20);
224 }
225 if (next_head == r->tail) {
226 wil_err(wil, "WMI ring full\n");
227 return -EBUSY;
228 }
229 dst = wmi_buffer(wil, d_head.addr);
230 if (!dst) {
231 wil_err(wil, "invalid WMI buffer: 0x%08x\n",
232 le32_to_cpu(d_head.addr));
233 return -EINVAL;
234 }
235 cmd.hdr.seq = cpu_to_le16(++wil->wmi_seq);
236 /* set command */
237 wil_dbg_WMI(wil, "WMI command 0x%04x [%d]\n", cmdid, len);
238 wil_hex_dump_WMI("Cmd ", DUMP_PREFIX_OFFSET, 16, 1, &cmd,
239 sizeof(cmd), true);
240 wil_hex_dump_WMI("cmd ", DUMP_PREFIX_OFFSET, 16, 1, buf,
241 len, true);
242 wil_memcpy_toio_32(dst, &cmd, sizeof(cmd));
243 wil_memcpy_toio_32(dst + sizeof(cmd), buf, len);
244 /* mark entry as full */
245 iowrite32(1, wil->csr + HOSTADDR(r->head) +
246 offsetof(struct wil6210_mbox_ring_desc, sync));
247 /* advance next ptr */
248 iowrite32(r->head = next_head, wil->csr + HOST_MBOX +
249 offsetof(struct wil6210_mbox_ctl, tx.head));
250
251 /* interrupt to FW */
252 iowrite32(SW_INT_MBOX, wil->csr + HOST_SW_INT);
253
254 return 0;
255}
256
257int wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len)
258{
259 int rc;
260
261 mutex_lock(&wil->wmi_mutex);
262 rc = __wmi_send(wil, cmdid, buf, len);
263 mutex_unlock(&wil->wmi_mutex);
264
265 return rc;
266}
267
268/*=== Event handlers ===*/
269static void wmi_evt_ready(struct wil6210_priv *wil, int id, void *d, int len)
270{
271 struct net_device *ndev = wil_to_ndev(wil);
272 struct wireless_dev *wdev = wil->wdev;
273 struct wmi_ready_event *evt = d;
274 u32 ver = le32_to_cpu(evt->sw_version);
275
276 wil_dbg_WMI(wil, "FW ver. %d; MAC %pM\n", ver, evt->mac);
277
278 if (!is_valid_ether_addr(ndev->dev_addr)) {
279 memcpy(ndev->dev_addr, evt->mac, ETH_ALEN);
280 memcpy(ndev->perm_addr, evt->mac, ETH_ALEN);
281 }
282 snprintf(wdev->wiphy->fw_version, sizeof(wdev->wiphy->fw_version),
283 "%d", ver);
284}
285
286static void wmi_evt_fw_ready(struct wil6210_priv *wil, int id, void *d,
287 int len)
288{
289 wil_dbg_WMI(wil, "WMI: FW ready\n");
290
291 set_bit(wil_status_fwready, &wil->status);
292 /* reuse wmi_ready for the firmware ready indication */
293 complete(&wil->wmi_ready);
294}
295
296static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len)
297{
298 struct wmi_rx_mgmt_packet_event *data = d;
299 struct wiphy *wiphy = wil_to_wiphy(wil);
300 struct ieee80211_mgmt *rx_mgmt_frame =
301 (struct ieee80211_mgmt *)data->payload;
302 int ch_no = data->info.channel+1;
303 u32 freq = ieee80211_channel_to_frequency(ch_no,
304 IEEE80211_BAND_60GHZ);
305 struct ieee80211_channel *channel = ieee80211_get_channel(wiphy, freq);
306 /* TODO convert LE to CPU */
307 s32 signal = 0; /* TODO */
308 __le16 fc = rx_mgmt_frame->frame_control;
309 u32 d_len = le32_to_cpu(data->info.len);
310 u16 d_status = le16_to_cpu(data->info.status);
311
312 wil_dbg_WMI(wil, "MGMT: channel %d MCS %d SNR %d\n",
313 data->info.channel, data->info.mcs, data->info.snr);
314 wil_dbg_WMI(wil, "status 0x%04x len %d stype %04x\n", d_status, d_len,
315 le16_to_cpu(data->info.stype));
316 wil_dbg_WMI(wil, "qid %d mid %d cid %d\n",
317 data->info.qid, data->info.mid, data->info.cid);
318
319 if (!channel) {
320 wil_err(wil, "Frame on unsupported channel\n");
321 return;
322 }
323
324 if (ieee80211_is_beacon(fc) || ieee80211_is_probe_resp(fc)) {
325 struct cfg80211_bss *bss;
326 u64 tsf = le64_to_cpu(rx_mgmt_frame->u.beacon.timestamp);
327 u16 cap = le16_to_cpu(rx_mgmt_frame->u.beacon.capab_info);
328 u16 bi = le16_to_cpu(rx_mgmt_frame->u.beacon.beacon_int);
329 const u8 *ie_buf = rx_mgmt_frame->u.beacon.variable;
330 size_t ie_len = d_len - offsetof(struct ieee80211_mgmt,
331 u.beacon.variable);
332 wil_dbg_WMI(wil, "Capability info : 0x%04x\n", cap);
333
334 bss = cfg80211_inform_bss(wiphy, channel, rx_mgmt_frame->bssid,
335 tsf, cap, bi, ie_buf, ie_len,
336 signal, GFP_KERNEL);
337 if (bss) {
338 wil_dbg_WMI(wil, "Added BSS %pM\n",
339 rx_mgmt_frame->bssid);
340 cfg80211_put_bss(bss);
341 } else {
342 wil_err(wil, "cfg80211_inform_bss() failed\n");
343 }
344 }
345}
346
347static void wmi_evt_scan_complete(struct wil6210_priv *wil, int id,
348 void *d, int len)
349{
350 if (wil->scan_request) {
351 struct wmi_scan_complete_event *data = d;
352 bool aborted = (data->status != 0);
353
354 wil_dbg_WMI(wil, "SCAN_COMPLETE(0x%08x)\n", data->status);
355 cfg80211_scan_done(wil->scan_request, aborted);
356 wil->scan_request = NULL;
357 } else {
358 wil_err(wil, "SCAN_COMPLETE while not scanning\n");
359 }
360}
361
362static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len)
363{
364 struct net_device *ndev = wil_to_ndev(wil);
365 struct wireless_dev *wdev = wil->wdev;
366 struct wmi_connect_event *evt = d;
367 int ch; /* channel number */
368 struct station_info sinfo;
369 u8 *assoc_req_ie, *assoc_resp_ie;
370 size_t assoc_req_ielen, assoc_resp_ielen;
371 /* capinfo(u16) + listen_interval(u16) + IEs */
372 const size_t assoc_req_ie_offset = sizeof(u16) * 2;
373 /* capinfo(u16) + status_code(u16) + associd(u16) + IEs */
374 const size_t assoc_resp_ie_offset = sizeof(u16) * 3;
375
376 if (len < sizeof(*evt)) {
377 wil_err(wil, "Connect event too short : %d bytes\n", len);
378 return;
379 }
380 if (len != sizeof(*evt) + evt->beacon_ie_len + evt->assoc_req_len +
381 evt->assoc_resp_len) {
382 wil_err(wil,
383 "Connect event corrupted : %d != %d + %d + %d + %d\n",
384 len, (int)sizeof(*evt), evt->beacon_ie_len,
385 evt->assoc_req_len, evt->assoc_resp_len);
386 return;
387 }
388 ch = evt->channel + 1;
389 wil_dbg_WMI(wil, "Connect %pM channel [%d] cid %d\n",
390 evt->bssid, ch, evt->cid);
391 wil_hex_dump_WMI("connect AI : ", DUMP_PREFIX_OFFSET, 16, 1,
392 evt->assoc_info, len - sizeof(*evt), true);
393
394 /* figure out IE's */
395 assoc_req_ie = &evt->assoc_info[evt->beacon_ie_len +
396 assoc_req_ie_offset];
397 assoc_req_ielen = evt->assoc_req_len - assoc_req_ie_offset;
398 if (evt->assoc_req_len <= assoc_req_ie_offset) {
399 assoc_req_ie = NULL;
400 assoc_req_ielen = 0;
401 }
402
403 assoc_resp_ie = &evt->assoc_info[evt->beacon_ie_len +
404 evt->assoc_req_len +
405 assoc_resp_ie_offset];
406 assoc_resp_ielen = evt->assoc_resp_len - assoc_resp_ie_offset;
407 if (evt->assoc_resp_len <= assoc_resp_ie_offset) {
408 assoc_resp_ie = NULL;
409 assoc_resp_ielen = 0;
410 }
411
412 if ((wdev->iftype == NL80211_IFTYPE_STATION) ||
413 (wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) {
414 if (wdev->sme_state != CFG80211_SME_CONNECTING) {
415 wil_err(wil, "Not in connecting state\n");
416 return;
417 }
418 del_timer_sync(&wil->connect_timer);
419 cfg80211_connect_result(ndev, evt->bssid,
420 assoc_req_ie, assoc_req_ielen,
421 assoc_resp_ie, assoc_resp_ielen,
422 WLAN_STATUS_SUCCESS, GFP_KERNEL);
423
424 } else if ((wdev->iftype == NL80211_IFTYPE_AP) ||
425 (wdev->iftype == NL80211_IFTYPE_P2P_GO)) {
426 memset(&sinfo, 0, sizeof(sinfo));
427
428 sinfo.generation = wil->sinfo_gen++;
429
430 if (assoc_req_ie) {
431 sinfo.assoc_req_ies = assoc_req_ie;
432 sinfo.assoc_req_ies_len = assoc_req_ielen;
433 sinfo.filled |= STATION_INFO_ASSOC_REQ_IES;
434 }
435
436 cfg80211_new_sta(ndev, evt->bssid, &sinfo, GFP_KERNEL);
437 }
438 set_bit(wil_status_fwconnected, &wil->status);
439
440 /* FIXME FW can transmit only ucast frames to peer */
441 /* FIXME real ring_id instead of hard coded 0 */
442 memcpy(wil->dst_addr[0], evt->bssid, ETH_ALEN);
443
444 wil->pending_connect_cid = evt->cid;
445 queue_work(wil->wmi_wq_conn, &wil->wmi_connect_worker);
446}
447
448static void wmi_evt_disconnect(struct wil6210_priv *wil, int id,
449 void *d, int len)
450{
451 struct wmi_disconnect_event *evt = d;
452
453 wil_dbg_WMI(wil, "Disconnect %pM reason %d proto %d wmi\n",
454 evt->bssid,
455 evt->protocol_reason_status, evt->disconnect_reason);
456
457 wil->sinfo_gen++;
458
459 wil6210_disconnect(wil, evt->bssid);
460 clear_bit(wil_status_dontscan, &wil->status);
461}
462
463static void wmi_evt_notify(struct wil6210_priv *wil, int id, void *d, int len)
464{
465 struct wmi_notify_req_done_event *evt = d;
466
467 if (len < sizeof(*evt)) {
468 wil_err(wil, "Short NOTIFY event\n");
469 return;
470 }
471
472 wil->stats.tsf = le64_to_cpu(evt->tsf);
473 wil->stats.snr = le32_to_cpu(evt->snr_val);
474 wil->stats.bf_mcs = le16_to_cpu(evt->bf_mcs);
475 wil->stats.my_rx_sector = le16_to_cpu(evt->my_rx_sector);
476 wil->stats.my_tx_sector = le16_to_cpu(evt->my_tx_sector);
477 wil->stats.peer_rx_sector = le16_to_cpu(evt->other_rx_sector);
478 wil->stats.peer_tx_sector = le16_to_cpu(evt->other_tx_sector);
479 wil_dbg_WMI(wil, "Link status, MCS %d TSF 0x%016llx\n"
480 "BF status 0x%08x SNR 0x%08x\n"
481 "Tx Tpt %d goodput %d Rx goodput %d\n"
482 "Sectors(rx:tx) my %d:%d peer %d:%d\n",
483 wil->stats.bf_mcs, wil->stats.tsf, evt->status,
484 wil->stats.snr, le32_to_cpu(evt->tx_tpt),
485 le32_to_cpu(evt->tx_goodput), le32_to_cpu(evt->rx_goodput),
486 wil->stats.my_rx_sector, wil->stats.my_tx_sector,
487 wil->stats.peer_rx_sector, wil->stats.peer_tx_sector);
488}
489
490/*
491 * Firmware reports EAPOL frame using WME event.
492 * Reconstruct Ethernet frame and deliver it via normal Rx
493 */
494static void wmi_evt_eapol_rx(struct wil6210_priv *wil, int id,
495 void *d, int len)
496{
497 struct net_device *ndev = wil_to_ndev(wil);
498 struct wmi_eapol_rx_event *evt = d;
499 u16 eapol_len = le16_to_cpu(evt->eapol_len);
500 int sz = eapol_len + ETH_HLEN;
501 struct sk_buff *skb;
502 struct ethhdr *eth;
503
504 wil_dbg_WMI(wil, "EAPOL len %d from %pM\n", eapol_len,
505 evt->src_mac);
506
507 if (eapol_len > 196) { /* TODO: revisit size limit */
508 wil_err(wil, "EAPOL too large\n");
509 return;
510 }
511
512 skb = alloc_skb(sz, GFP_KERNEL);
513 if (!skb) {
514 wil_err(wil, "Failed to allocate skb\n");
515 return;
516 }
517 eth = (struct ethhdr *)skb_put(skb, ETH_HLEN);
518 memcpy(eth->h_dest, ndev->dev_addr, ETH_ALEN);
519 memcpy(eth->h_source, evt->src_mac, ETH_ALEN);
520 eth->h_proto = cpu_to_be16(ETH_P_PAE);
521 memcpy(skb_put(skb, eapol_len), evt->eapol, eapol_len);
522 skb->protocol = eth_type_trans(skb, ndev);
523 if (likely(netif_rx_ni(skb) == NET_RX_SUCCESS)) {
524 ndev->stats.rx_packets++;
525 ndev->stats.rx_bytes += skb->len;
526 } else {
527 ndev->stats.rx_dropped++;
528 }
529}
530
531static const struct {
532 int eventid;
533 void (*handler)(struct wil6210_priv *wil, int eventid,
534 void *data, int data_len);
535} wmi_evt_handlers[] = {
536 {WMI_READY_EVENTID, wmi_evt_ready},
537 {WMI_FW_READY_EVENTID, wmi_evt_fw_ready},
538 {WMI_RX_MGMT_PACKET_EVENTID, wmi_evt_rx_mgmt},
539 {WMI_SCAN_COMPLETE_EVENTID, wmi_evt_scan_complete},
540 {WMI_CONNECT_EVENTID, wmi_evt_connect},
541 {WMI_DISCONNECT_EVENTID, wmi_evt_disconnect},
542 {WMI_NOTIFY_REQ_DONE_EVENTID, wmi_evt_notify},
543 {WMI_EAPOL_RX_EVENTID, wmi_evt_eapol_rx},
544};
545
546/*
547 * Run in IRQ context
548 * Extract WMI command from mailbox. Queue it to the @wil->pending_wmi_ev
549 * that will be eventually handled by the @wmi_event_worker in the thread
550 * context of thread "wil6210_wmi"
551 */
552void wmi_recv_cmd(struct wil6210_priv *wil)
553{
554 struct wil6210_mbox_ring_desc d_tail;
555 struct wil6210_mbox_hdr hdr;
556 struct wil6210_mbox_ring *r = &wil->mbox_ctl.rx;
557 struct pending_wmi_event *evt;
558 u8 *cmd;
559 void __iomem *src;
560 ulong flags;
561
562 for (;;) {
563 u16 len;
564
565 r->head = ioread32(wil->csr + HOST_MBOX +
566 offsetof(struct wil6210_mbox_ctl, rx.head));
567 if (r->tail == r->head)
568 return;
569
570 /* read cmd from tail */
571 wil_memcpy_fromio_32(&d_tail, wil->csr + HOSTADDR(r->tail),
572 sizeof(struct wil6210_mbox_ring_desc));
573 if (d_tail.sync == 0) {
574 wil_err(wil, "Mbox evt not owned by FW?\n");
575 return;
576 }
577
578 if (0 != wmi_read_hdr(wil, d_tail.addr, &hdr)) {
579 wil_err(wil, "Mbox evt at 0x%08x?\n",
580 le32_to_cpu(d_tail.addr));
581 return;
582 }
583
584 len = le16_to_cpu(hdr.len);
585 src = wmi_buffer(wil, d_tail.addr) +
586 sizeof(struct wil6210_mbox_hdr);
587 evt = kmalloc(ALIGN(offsetof(struct pending_wmi_event,
588 event.wmi) + len, 4),
589 GFP_KERNEL);
590 if (!evt) {
591 wil_err(wil, "kmalloc for WMI event (%d) failed\n",
592 len);
593 return;
594 }
595 evt->event.hdr = hdr;
596 cmd = (void *)&evt->event.wmi;
597 wil_memcpy_fromio_32(cmd, src, len);
598 /* mark entry as empty */
599 iowrite32(0, wil->csr + HOSTADDR(r->tail) +
600 offsetof(struct wil6210_mbox_ring_desc, sync));
601 /* indicate */
602 wil_dbg_WMI(wil, "Mbox evt %04x %04x %04x %02x\n",
603 le16_to_cpu(hdr.seq), len, le16_to_cpu(hdr.type),
604 hdr.flags);
605 if ((hdr.type == WIL_MBOX_HDR_TYPE_WMI) &&
606 (len >= sizeof(struct wil6210_mbox_hdr_wmi))) {
607 wil_dbg_WMI(wil, "WMI event 0x%04x\n",
608 evt->event.wmi.id);
609 }
610 wil_hex_dump_WMI("evt ", DUMP_PREFIX_OFFSET, 16, 1,
611 &evt->event.hdr, sizeof(hdr) + len, true);
612
613 /* advance tail */
614 r->tail = r->base + ((r->tail - r->base +
615 sizeof(struct wil6210_mbox_ring_desc)) % r->size);
616 iowrite32(r->tail, wil->csr + HOST_MBOX +
617 offsetof(struct wil6210_mbox_ctl, rx.tail));
618
619 /* add to the pending list */
620 spin_lock_irqsave(&wil->wmi_ev_lock, flags);
621 list_add_tail(&evt->list, &wil->pending_wmi_ev);
622 spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
623 {
624 int q = queue_work(wil->wmi_wq,
625 &wil->wmi_event_worker);
626 wil_dbg_WMI(wil, "queue_work -> %d\n", q);
627 }
628 }
629}
630
631int wmi_call(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len,
632 u16 reply_id, void *reply, u8 reply_size, int to_msec)
633{
634 int rc;
635 int remain;
636
637 mutex_lock(&wil->wmi_mutex);
638
639 rc = __wmi_send(wil, cmdid, buf, len);
640 if (rc)
641 goto out;
642
643 wil->reply_id = reply_id;
644 wil->reply_buf = reply;
645 wil->reply_size = reply_size;
646 remain = wait_for_completion_timeout(&wil->wmi_ready,
647 msecs_to_jiffies(to_msec));
648 if (0 == remain) {
649 wil_err(wil, "wmi_call(0x%04x->0x%04x) timeout %d msec\n",
650 cmdid, reply_id, to_msec);
651 rc = -ETIME;
652 } else {
653 wil_dbg_WMI(wil,
654 "wmi_call(0x%04x->0x%04x) completed in %d msec\n",
655 cmdid, reply_id,
656 to_msec - jiffies_to_msecs(remain));
657 }
658 wil->reply_id = 0;
659 wil->reply_buf = NULL;
660 wil->reply_size = 0;
661 out:
662 mutex_unlock(&wil->wmi_mutex);
663
664 return rc;
665}
666
667int wmi_echo(struct wil6210_priv *wil)
668{
669 struct wmi_echo_cmd cmd = {
670 .value = cpu_to_le32(0x12345678),
671 };
672
673 return wmi_call(wil, WMI_ECHO_CMDID, &cmd, sizeof(cmd),
674 WMI_ECHO_RSP_EVENTID, NULL, 0, 20);
675}
676
677int wmi_set_mac_address(struct wil6210_priv *wil, void *addr)
678{
679 struct wmi_set_mac_address_cmd cmd;
680
681 memcpy(cmd.mac, addr, ETH_ALEN);
682
683 wil_dbg_WMI(wil, "Set MAC %pM\n", addr);
684
685 return wmi_send(wil, WMI_SET_MAC_ADDRESS_CMDID, &cmd, sizeof(cmd));
686}
687
688int wmi_set_bcon(struct wil6210_priv *wil, int bi, u8 wmi_nettype)
689{
690 struct wmi_bcon_ctrl_cmd cmd = {
691 .bcon_interval = cpu_to_le16(bi),
692 .network_type = wmi_nettype,
693 .disable_sec_offload = 1,
694 };
695
696 if (!wil->secure_pcp)
697 cmd.disable_sec = 1;
698
699 return wmi_send(wil, WMI_BCON_CTRL_CMDID, &cmd, sizeof(cmd));
700}
701
702int wmi_set_ssid(struct wil6210_priv *wil, u8 ssid_len, const void *ssid)
703{
704 struct wmi_set_ssid_cmd cmd = {
705 .ssid_len = cpu_to_le32(ssid_len),
706 };
707
708 if (ssid_len > sizeof(cmd.ssid))
709 return -EINVAL;
710
711 memcpy(cmd.ssid, ssid, ssid_len);
712
713 return wmi_send(wil, WMI_SET_SSID_CMDID, &cmd, sizeof(cmd));
714}
715
716int wmi_get_ssid(struct wil6210_priv *wil, u8 *ssid_len, void *ssid)
717{
718 int rc;
719 struct {
720 struct wil6210_mbox_hdr_wmi wmi;
721 struct wmi_set_ssid_cmd cmd;
722 } __packed reply;
723 int len; /* reply.cmd.ssid_len in CPU order */
724
725 rc = wmi_call(wil, WMI_GET_SSID_CMDID, NULL, 0, WMI_GET_SSID_EVENTID,
726 &reply, sizeof(reply), 20);
727 if (rc)
728 return rc;
729
730 len = le32_to_cpu(reply.cmd.ssid_len);
731 if (len > sizeof(reply.cmd.ssid))
732 return -EINVAL;
733
734 *ssid_len = len;
735 memcpy(ssid, reply.cmd.ssid, len);
736
737 return 0;
738}
739
740int wmi_set_channel(struct wil6210_priv *wil, int channel)
741{
742 struct wmi_set_pcp_channel_cmd cmd = {
743 .channel = channel - 1,
744 };
745
746 return wmi_send(wil, WMI_SET_PCP_CHANNEL_CMDID, &cmd, sizeof(cmd));
747}
748
749int wmi_get_channel(struct wil6210_priv *wil, int *channel)
750{
751 int rc;
752 struct {
753 struct wil6210_mbox_hdr_wmi wmi;
754 struct wmi_set_pcp_channel_cmd cmd;
755 } __packed reply;
756
757 rc = wmi_call(wil, WMI_GET_PCP_CHANNEL_CMDID, NULL, 0,
758 WMI_GET_PCP_CHANNEL_EVENTID, &reply, sizeof(reply), 20);
759 if (rc)
760 return rc;
761
762 if (reply.cmd.channel > 3)
763 return -EINVAL;
764
765 *channel = reply.cmd.channel + 1;
766
767 return 0;
768}
769
770int wmi_tx_eapol(struct wil6210_priv *wil, struct sk_buff *skb)
771{
772 struct wmi_eapol_tx_cmd *cmd;
773 struct ethhdr *eth;
774 u16 eapol_len = skb->len - ETH_HLEN;
775 void *eapol = skb->data + ETH_HLEN;
776 uint i;
777 int rc;
778
779 skb_set_mac_header(skb, 0);
780 eth = eth_hdr(skb);
781 wil_dbg_WMI(wil, "EAPOL %d bytes to %pM\n", eapol_len, eth->h_dest);
782 for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) {
783 if (memcmp(wil->dst_addr[i], eth->h_dest, ETH_ALEN) == 0)
784 goto found_dest;
785 }
786
787 return -EINVAL;
788
789 found_dest:
790 /* find out eapol data & len */
791 cmd = kzalloc(sizeof(*cmd) + eapol_len, GFP_KERNEL);
792 if (!cmd)
793 return -EINVAL;
794
795 memcpy(cmd->dst_mac, eth->h_dest, ETH_ALEN);
796 cmd->eapol_len = cpu_to_le16(eapol_len);
797 memcpy(cmd->eapol, eapol, eapol_len);
798 rc = wmi_send(wil, WMI_EAPOL_TX_CMDID, cmd, sizeof(*cmd) + eapol_len);
799 kfree(cmd);
800
801 return rc;
802}
803
804int wmi_del_cipher_key(struct wil6210_priv *wil, u8 key_index,
805 const void *mac_addr)
806{
807 struct wmi_delete_cipher_key_cmd cmd = {
808 .key_index = key_index,
809 };
810
811 if (mac_addr)
812 memcpy(cmd.mac, mac_addr, WMI_MAC_LEN);
813
814 return wmi_send(wil, WMI_DELETE_CIPHER_KEY_CMDID, &cmd, sizeof(cmd));
815}
816
817int wmi_add_cipher_key(struct wil6210_priv *wil, u8 key_index,
818 const void *mac_addr, int key_len, const void *key)
819{
820 struct wmi_add_cipher_key_cmd cmd = {
821 .key_index = key_index,
822 .key_usage = WMI_KEY_USE_PAIRWISE,
823 .key_len = key_len,
824 };
825
826 if (!key || (key_len > sizeof(cmd.key)))
827 return -EINVAL;
828
829 memcpy(cmd.key, key, key_len);
830 if (mac_addr)
831 memcpy(cmd.mac, mac_addr, WMI_MAC_LEN);
832
833 return wmi_send(wil, WMI_ADD_CIPHER_KEY_CMDID, &cmd, sizeof(cmd));
834}
835
836int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie)
837{
838 int rc;
839 u16 len = sizeof(struct wmi_set_appie_cmd) + ie_len;
840 struct wmi_set_appie_cmd *cmd = kzalloc(len, GFP_KERNEL);
841 if (!cmd) {
842 wil_err(wil, "kmalloc(%d) failed\n", len);
843 return -ENOMEM;
844 }
845
846 cmd->mgmt_frm_type = type;
847 /* BUG: FW API define ieLen as u8. Will fix FW */
848 cmd->ie_len = cpu_to_le16(ie_len);
849 memcpy(cmd->ie_info, ie, ie_len);
850 rc = wmi_send(wil, WMI_SET_APPIE_CMDID, &cmd, len);
851 kfree(cmd);
852
853 return rc;
854}
855
856void wmi_event_flush(struct wil6210_priv *wil)
857{
858 struct pending_wmi_event *evt, *t;
859
860 wil_dbg_WMI(wil, "%s()\n", __func__);
861
862 list_for_each_entry_safe(evt, t, &wil->pending_wmi_ev, list) {
863 list_del(&evt->list);
864 kfree(evt);
865 }
866}
867
868static bool wmi_evt_call_handler(struct wil6210_priv *wil, int id,
869 void *d, int len)
870{
871 uint i;
872
873 for (i = 0; i < ARRAY_SIZE(wmi_evt_handlers); i++) {
874 if (wmi_evt_handlers[i].eventid == id) {
875 wmi_evt_handlers[i].handler(wil, id, d, len);
876 return true;
877 }
878 }
879
880 return false;
881}
882
883static void wmi_event_handle(struct wil6210_priv *wil,
884 struct wil6210_mbox_hdr *hdr)
885{
886 u16 len = le16_to_cpu(hdr->len);
887
888 if ((hdr->type == WIL_MBOX_HDR_TYPE_WMI) &&
889 (len >= sizeof(struct wil6210_mbox_hdr_wmi))) {
890 struct wil6210_mbox_hdr_wmi *wmi = (void *)(&hdr[1]);
891 void *evt_data = (void *)(&wmi[1]);
892 u16 id = le16_to_cpu(wmi->id);
893 /* check if someone waits for this event */
894 if (wil->reply_id && wil->reply_id == id) {
895 if (wil->reply_buf) {
896 memcpy(wil->reply_buf, wmi,
897 min(len, wil->reply_size));
898 } else {
899 wmi_evt_call_handler(wil, id, evt_data,
900 len - sizeof(*wmi));
901 }
902 wil_dbg_WMI(wil, "Complete WMI 0x%04x\n", id);
903 complete(&wil->wmi_ready);
904 return;
905 }
906 /* unsolicited event */
907 /* search for handler */
908 if (!wmi_evt_call_handler(wil, id, evt_data,
909 len - sizeof(*wmi))) {
910 wil_err(wil, "Unhandled event 0x%04x\n", id);
911 }
912 } else {
913 wil_err(wil, "Unknown event type\n");
914 print_hex_dump(KERN_ERR, "evt?? ", DUMP_PREFIX_OFFSET, 16, 1,
915 hdr, sizeof(*hdr) + len, true);
916 }
917}
918
919/*
920 * Retrieve next WMI event from the pending list
921 */
922static struct list_head *next_wmi_ev(struct wil6210_priv *wil)
923{
924 ulong flags;
925 struct list_head *ret = NULL;
926
927 spin_lock_irqsave(&wil->wmi_ev_lock, flags);
928
929 if (!list_empty(&wil->pending_wmi_ev)) {
930 ret = wil->pending_wmi_ev.next;
931 list_del(ret);
932 }
933
934 spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
935
936 return ret;
937}
938
939/*
940 * Handler for the WMI events
941 */
942void wmi_event_worker(struct work_struct *work)
943{
944 struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
945 wmi_event_worker);
946 struct pending_wmi_event *evt;
947 struct list_head *lh;
948
949 while ((lh = next_wmi_ev(wil)) != NULL) {
950 evt = list_entry(lh, struct pending_wmi_event, list);
951 wmi_event_handle(wil, &evt->event.hdr);
952 kfree(evt);
953 }
954}
955
956void wmi_connect_worker(struct work_struct *work)
957{
958 int rc;
959 struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
960 wmi_connect_worker);
961
962 if (wil->pending_connect_cid < 0) {
963 wil_err(wil, "No connection pending\n");
964 return;
965 }
966
967 wil_dbg_WMI(wil, "Configure for connection CID %d\n",
968 wil->pending_connect_cid);
969
970 rc = wil_vring_init_tx(wil, 0, WIL6210_TX_RING_SIZE,
971 wil->pending_connect_cid, 0);
972 wil->pending_connect_cid = -1;
973 if (rc == 0)
974 wil_link_on(wil);
975}
diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h
new file mode 100644
index 000000000000..3bbf87572b07
--- /dev/null
+++ b/drivers/net/wireless/ath/wil6210/wmi.h
@@ -0,0 +1,1116 @@
1/*
2 * Copyright (c) 2012 Qualcomm Atheros, Inc.
3 * Copyright (c) 2006-2012 Wilocity .
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18/*
19 * This file contains the definitions of the WMI protocol specified in the
20 * Wireless Module Interface (WMI) for the Wilocity
21 * MARLON 60 Gigabit wireless solution.
22 * It includes definitions of all the commands and events.
23 * Commands are messages from the host to the WM.
24 * Events are messages from the WM to the host.
25 */
26
27#ifndef __WILOCITY_WMI_H__
28#define __WILOCITY_WMI_H__
29
30/* General */
31
32#define WMI_MAC_LEN (6)
33#define WMI_PROX_RANGE_NUM (3)
34
35/* List of Commands */
36enum wmi_command_id {
37 WMI_CONNECT_CMDID = 0x0001,
38 WMI_DISCONNECT_CMDID = 0x0003,
39 WMI_START_SCAN_CMDID = 0x0007,
40 WMI_SET_BSS_FILTER_CMDID = 0x0009,
41 WMI_SET_PROBED_SSID_CMDID = 0x000a,
42 WMI_SET_LISTEN_INT_CMDID = 0x000b,
43 WMI_BCON_CTRL_CMDID = 0x000f,
44 WMI_ADD_CIPHER_KEY_CMDID = 0x0016,
45 WMI_DELETE_CIPHER_KEY_CMDID = 0x0017,
46 WMI_SET_APPIE_CMDID = 0x003f,
47 WMI_GET_APPIE_CMDID = 0x0040,
48 WMI_SET_WSC_STATUS_CMDID = 0x0041,
49 WMI_PXMT_RANGE_CFG_CMDID = 0x0042,
50 WMI_PXMT_SNR2_RANGE_CFG_CMDID = 0x0043,
51 WMI_FAST_MEM_ACC_MODE_CMDID = 0x0300,
52 WMI_MEM_READ_CMDID = 0x0800,
53 WMI_MEM_WR_CMDID = 0x0801,
54 WMI_ECHO_CMDID = 0x0803,
55 WMI_DEEP_ECHO_CMDID = 0x0804,
56 WMI_CONFIG_MAC_CMDID = 0x0805,
57 WMI_CONFIG_PHY_DEBUG_CMDID = 0x0806,
58 WMI_ADD_STATION_CMDID = 0x0807,
59 WMI_ADD_DEBUG_TX_PCKT_CMDID = 0x0808,
60 WMI_PHY_GET_STATISTICS_CMDID = 0x0809,
61 WMI_FS_TUNE_CMDID = 0x080a,
62 WMI_CORR_MEASURE_CMDID = 0x080b,
63 WMI_TEMP_SENSE_CMDID = 0x080e,
64 WMI_DC_CALIB_CMDID = 0x080f,
65 WMI_SEND_TONE_CMDID = 0x0810,
66 WMI_IQ_TX_CALIB_CMDID = 0x0811,
67 WMI_IQ_RX_CALIB_CMDID = 0x0812,
68 WMI_SET_UCODE_IDLE_CMDID = 0x0813,
69 WMI_SET_WORK_MODE_CMDID = 0x0815,
70 WMI_LO_LEAKAGE_CALIB_CMDID = 0x0816,
71 WMI_MARLON_R_ACTIVATE_CMDID = 0x0817,
72 WMI_MARLON_R_READ_CMDID = 0x0818,
73 WMI_MARLON_R_WRITE_CMDID = 0x0819,
74 WMI_MARLON_R_TXRX_SEL_CMDID = 0x081a,
75 MAC_IO_STATIC_PARAMS_CMDID = 0x081b,
76 MAC_IO_DYNAMIC_PARAMS_CMDID = 0x081c,
77 WMI_SILENT_RSSI_CALIB_CMDID = 0x081d,
78 WMI_CFG_RX_CHAIN_CMDID = 0x0820,
79 WMI_VRING_CFG_CMDID = 0x0821,
80 WMI_RX_ON_CMDID = 0x0822,
81 WMI_VRING_BA_EN_CMDID = 0x0823,
82 WMI_VRING_BA_DIS_CMDID = 0x0824,
83 WMI_RCP_ADDBA_RESP_CMDID = 0x0825,
84 WMI_RCP_DELBA_CMDID = 0x0826,
85 WMI_SET_SSID_CMDID = 0x0827,
86 WMI_GET_SSID_CMDID = 0x0828,
87 WMI_SET_PCP_CHANNEL_CMDID = 0x0829,
88 WMI_GET_PCP_CHANNEL_CMDID = 0x082a,
89 WMI_SW_TX_REQ_CMDID = 0x082b,
90 WMI_RX_OFF_CMDID = 0x082c,
91 WMI_READ_MAC_RXQ_CMDID = 0x0830,
92 WMI_READ_MAC_TXQ_CMDID = 0x0831,
93 WMI_WRITE_MAC_RXQ_CMDID = 0x0832,
94 WMI_WRITE_MAC_TXQ_CMDID = 0x0833,
95 WMI_WRITE_MAC_XQ_FIELD_CMDID = 0x0834,
96 WMI_MLME_PUSH_CMDID = 0x0835,
97 WMI_BEAMFORMING_MGMT_CMDID = 0x0836,
98 WMI_BF_TXSS_MGMT_CMDID = 0x0837,
99 WMI_BF_SM_MGMT_CMDID = 0x0838,
100 WMI_BF_RXSS_MGMT_CMDID = 0x0839,
101 WMI_SET_SECTORS_CMDID = 0x0849,
102 WMI_MAINTAIN_PAUSE_CMDID = 0x0850,
103 WMI_MAINTAIN_RESUME_CMDID = 0x0851,
104 WMI_RS_MGMT_CMDID = 0x0852,
105 WMI_RF_MGMT_CMDID = 0x0853,
106 /* Performance monitoring commands */
107 WMI_BF_CTRL_CMDID = 0x0862,
108 WMI_NOTIFY_REQ_CMDID = 0x0863,
109 WMI_GET_STATUS_CMDID = 0x0864,
110 WMI_UNIT_TEST_CMDID = 0x0900,
111 WMI_HICCUP_CMDID = 0x0901,
112 WMI_FLASH_READ_CMDID = 0x0902,
113 WMI_FLASH_WRITE_CMDID = 0x0903,
114 WMI_SECURITY_UNIT_TEST_CMDID = 0x0904,
115
116 WMI_SET_MAC_ADDRESS_CMDID = 0xf003,
117 WMI_ABORT_SCAN_CMDID = 0xf007,
118 WMI_SET_PMK_CMDID = 0xf028,
119
120 WMI_SET_PROMISCUOUS_MODE_CMDID = 0xf041,
121 WMI_GET_PMK_CMDID = 0xf048,
122 WMI_SET_PASSPHRASE_CMDID = 0xf049,
123 WMI_SEND_ASSOC_RES_CMDID = 0xf04a,
124 WMI_SET_ASSOC_REQ_RELAY_CMDID = 0xf04b,
125 WMI_EAPOL_TX_CMDID = 0xf04c,
126 WMI_MAC_ADDR_REQ_CMDID = 0xf04d,
127 WMI_FW_VER_CMDID = 0xf04e,
128};
129
130/*
131 * Commands data structures
132 */
133
134/*
135 * Frame Types
136 */
137enum wmi_mgmt_frame_type {
138 WMI_FRAME_BEACON = 0,
139 WMI_FRAME_PROBE_REQ = 1,
140 WMI_FRAME_PROBE_RESP = 2,
141 WMI_FRAME_ASSOC_REQ = 3,
142 WMI_FRAME_ASSOC_RESP = 4,
143 WMI_NUM_MGMT_FRAME,
144};
145
146/*
147 * WMI_CONNECT_CMDID
148 */
149enum wmi_network_type {
150 WMI_NETTYPE_INFRA = 0x01,
151 WMI_NETTYPE_ADHOC = 0x02,
152 WMI_NETTYPE_ADHOC_CREATOR = 0x04,
153 WMI_NETTYPE_AP = 0x10,
154 WMI_NETTYPE_P2P = 0x20,
155 WMI_NETTYPE_WBE = 0x40, /* PCIE over 60g */
156};
157
158enum wmi_dot11_auth_mode {
159 WMI_AUTH11_OPEN = 0x01,
160 WMI_AUTH11_SHARED = 0x02,
161 WMI_AUTH11_LEAP = 0x04,
162 WMI_AUTH11_WSC = 0x08,
163};
164
165enum wmi_auth_mode {
166 WMI_AUTH_NONE = 0x01,
167 WMI_AUTH_WPA = 0x02,
168 WMI_AUTH_WPA2 = 0x04,
169 WMI_AUTH_WPA_PSK = 0x08,
170 WMI_AUTH_WPA2_PSK = 0x10,
171 WMI_AUTH_WPA_CCKM = 0x20,
172 WMI_AUTH_WPA2_CCKM = 0x40,
173};
174
175enum wmi_crypto_type {
176 WMI_CRYPT_NONE = 0x01,
177 WMI_CRYPT_WEP = 0x02,
178 WMI_CRYPT_TKIP = 0x04,
179 WMI_CRYPT_AES = 0x08,
180 WMI_CRYPT_AES_GCMP = 0x20,
181};
182
183
184enum wmi_connect_ctrl_flag_bits {
185 WMI_CONNECT_ASSOC_POLICY_USER = 0x0001,
186 WMI_CONNECT_SEND_REASSOC = 0x0002,
187 WMI_CONNECT_IGNORE_WPAx_GROUP_CIPHER = 0x0004,
188 WMI_CONNECT_PROFILE_MATCH_DONE = 0x0008,
189 WMI_CONNECT_IGNORE_AAC_BEACON = 0x0010,
190 WMI_CONNECT_CSA_FOLLOW_BSS = 0x0020,
191 WMI_CONNECT_DO_WPA_OFFLOAD = 0x0040,
192 WMI_CONNECT_DO_NOT_DEAUTH = 0x0080,
193};
194
195#define WMI_MAX_SSID_LEN (32)
196
197struct wmi_connect_cmd {
198 u8 network_type;
199 u8 dot11_auth_mode;
200 u8 auth_mode;
201 u8 pairwise_crypto_type;
202 u8 pairwise_crypto_len;
203 u8 group_crypto_type;
204 u8 group_crypto_len;
205 u8 ssid_len;
206 u8 ssid[WMI_MAX_SSID_LEN];
207 u8 channel;
208 u8 reserved0;
209 u8 bssid[WMI_MAC_LEN];
210 __le32 ctrl_flags;
211 u8 dst_mac[WMI_MAC_LEN];
212 u8 reserved1[2];
213} __packed;
214
215
216/*
217 * WMI_RECONNECT_CMDID
218 */
219struct wmi_reconnect_cmd {
220 u8 channel; /* hint */
221 u8 reserved;
222 u8 bssid[WMI_MAC_LEN]; /* mandatory if set */
223} __packed;
224
225
226/*
227 * WMI_SET_PMK_CMDID
228 */
229
230#define WMI_MIN_KEY_INDEX (0)
231#define WMI_MAX_KEY_INDEX (3)
232#define WMI_MAX_KEY_LEN (32)
233#define WMI_PASSPHRASE_LEN (64)
234#define WMI_PMK_LEN (32)
235
236struct wmi_set_pmk_cmd {
237 u8 pmk[WMI_PMK_LEN];
238} __packed;
239
240
241/*
242 * WMI_SET_PASSPHRASE_CMDID
243 */
244struct wmi_set_passphrase_cmd {
245 u8 ssid[WMI_MAX_SSID_LEN];
246 u8 passphrase[WMI_PASSPHRASE_LEN];
247 u8 ssid_len;
248 u8 passphrase_len;
249} __packed;
250
251/*
252 * WMI_ADD_CIPHER_KEY_CMDID
253 */
254enum wmi_key_usage {
255 WMI_KEY_USE_PAIRWISE = 0,
256 WMI_KEY_USE_GROUP = 1,
257 WMI_KEY_USE_TX = 2, /* default Tx Key - Static WEP only */
258};
259
260struct wmi_add_cipher_key_cmd {
261 u8 key_index;
262 u8 key_type;
263 u8 key_usage; /* enum wmi_key_usage */
264 u8 key_len;
265 u8 key_rsc[8]; /* key replay sequence counter */
266 u8 key[WMI_MAX_KEY_LEN];
267 u8 key_op_ctrl; /* Additional Key Control information */
268 u8 mac[WMI_MAC_LEN];
269} __packed;
270
271/*
272 * WMI_DELETE_CIPHER_KEY_CMDID
273 */
274struct wmi_delete_cipher_key_cmd {
275 u8 key_index;
276 u8 mac[WMI_MAC_LEN];
277} __packed;
278
279
280/*
281 * WMI_START_SCAN_CMDID
282 *
283 * Start L1 scan operation
284 *
285 * Returned events:
286 * - WMI_RX_MGMT_PACKET_EVENTID - for every probe resp.
287 * - WMI_SCAN_COMPLETE_EVENTID
288 */
289enum wmi_scan_type {
290 WMI_LONG_SCAN = 0,
291 WMI_SHORT_SCAN = 1,
292};
293
294struct wmi_start_scan_cmd {
295 u8 reserved[8];
296 __le32 home_dwell_time; /* Max duration in the home channel(ms) */
297 __le32 force_scan_interval; /* Time interval between scans (ms)*/
298 u8 scan_type; /* wmi_scan_type */
299 u8 num_channels; /* how many channels follow */
300 struct {
301 u8 channel;
302 u8 reserved;
303 } channel_list[0]; /* channels ID's */
304 /* 0 - 58320 MHz */
305 /* 1 - 60480 MHz */
306 /* 2 - 62640 MHz */
307} __packed;
308
309/*
310 * WMI_SET_PROBED_SSID_CMDID
311 */
312#define MAX_PROBED_SSID_INDEX (15)
313
314enum wmi_ssid_flag {
315 WMI_SSID_FLAG_DISABLE = 0, /* disables entry */
316 WMI_SSID_FLAG_SPECIFIC = 1, /* probes specified ssid */
317 WMI_SSID_FLAG_ANY = 2, /* probes for any ssid */
318};
319
320struct wmi_probed_ssid_cmd {
321 u8 entry_index; /* 0 to MAX_PROBED_SSID_INDEX */
322 u8 flag; /* enum wmi_ssid_flag */
323 u8 ssid_len;
324 u8 ssid[WMI_MAX_SSID_LEN];
325} __packed;
326
327/*
328 * WMI_SET_APPIE_CMDID
329 * Add Application specified IE to a management frame
330 */
331struct wmi_set_appie_cmd {
332 u8 mgmt_frm_type; /* enum wmi_mgmt_frame_type */
333 u8 reserved;
334 __le16 ie_len; /* Length of the IE to be added to MGMT frame */
335 u8 ie_info[0];
336} __packed;
337
338#define WMI_MAX_IE_LEN (1024)
339
340struct wmi_pxmt_range_cfg_cmd {
341 u8 dst_mac[WMI_MAC_LEN];
342 __le16 range;
343} __packed;
344
345struct wmi_pxmt_snr2_range_cfg_cmd {
346 s8 snr2range_arr[WMI_PROX_RANGE_NUM-1];
347} __packed;
348
349/*
350 * WMI_RF_MGMT_CMDID
351 */
352enum wmi_rf_mgmt_type {
353 WMI_RF_MGMT_W_DISABLE = 0,
354 WMI_RF_MGMT_W_ENABLE = 1,
355 WMI_RF_MGMT_GET_STATUS = 2,
356};
357
358struct wmi_rf_mgmt_cmd {
359 __le32 rf_mgmt_type;
360} __packed;
361
362/*
363 * WMI_SET_SSID_CMDID
364 */
365struct wmi_set_ssid_cmd {
366 __le32 ssid_len;
367 u8 ssid[WMI_MAX_SSID_LEN];
368} __packed;
369
370/*
371 * WMI_SET_PCP_CHANNEL_CMDID
372 */
373struct wmi_set_pcp_channel_cmd {
374 u8 channel;
375 u8 reserved[3];
376} __packed;
377
378/*
379 * WMI_BCON_CTRL_CMDID
380 */
381struct wmi_bcon_ctrl_cmd {
382 __le16 bcon_interval;
383 __le16 frag_num;
384 __le64 ss_mask;
385 u8 network_type;
386 u8 reserved;
387 u8 disable_sec_offload;
388 u8 disable_sec;
389} __packed;
390
391/*
392 * WMI_SW_TX_REQ_CMDID
393 */
394struct wmi_sw_tx_req_cmd {
395 u8 dst_mac[WMI_MAC_LEN];
396 __le16 len;
397 u8 payload[0];
398} __packed;
399
400/*
401 * WMI_VRING_CFG_CMDID
402 */
403
404struct wmi_sw_ring_cfg {
405 __le64 ring_mem_base;
406 __le16 ring_size;
407 __le16 max_mpdu_size;
408} __packed;
409
410struct wmi_vring_cfg_schd {
411 __le16 priority;
412 __le16 timeslot_us;
413} __packed;
414
415enum wmi_vring_cfg_encap_trans_type {
416 WMI_VRING_ENC_TYPE_802_3 = 0,
417 WMI_VRING_ENC_TYPE_NATIVE_WIFI = 1,
418};
419
420enum wmi_vring_cfg_ds_cfg {
421 WMI_VRING_DS_PBSS = 0,
422 WMI_VRING_DS_STATION = 1,
423 WMI_VRING_DS_AP = 2,
424 WMI_VRING_DS_ADDR4 = 3,
425};
426
427enum wmi_vring_cfg_nwifi_ds_trans_type {
428 WMI_NWIFI_TX_TRANS_MODE_NO = 0,
429 WMI_NWIFI_TX_TRANS_MODE_AP2PBSS = 1,
430 WMI_NWIFI_TX_TRANS_MODE_STA2PBSS = 2,
431};
432
433enum wmi_vring_cfg_schd_params_priority {
434 WMI_SCH_PRIO_REGULAR = 0,
435 WMI_SCH_PRIO_HIGH = 1,
436};
437
438struct wmi_vring_cfg {
439 struct wmi_sw_ring_cfg tx_sw_ring;
440 u8 ringid; /* 0-23 vrings */
441
442 #define CIDXTID_CID_POS (0)
443 #define CIDXTID_CID_LEN (4)
444 #define CIDXTID_CID_MSK (0xF)
445 #define CIDXTID_TID_POS (4)
446 #define CIDXTID_TID_LEN (4)
447 #define CIDXTID_TID_MSK (0xF0)
448 u8 cidxtid;
449
450 u8 encap_trans_type;
451 u8 ds_cfg; /* 802.3 DS cfg */
452 u8 nwifi_ds_trans_type;
453
454 #define VRING_CFG_MAC_CTRL_LIFETIME_EN_POS (0)
455 #define VRING_CFG_MAC_CTRL_LIFETIME_EN_LEN (1)
456 #define VRING_CFG_MAC_CTRL_LIFETIME_EN_MSK (0x1)
457 #define VRING_CFG_MAC_CTRL_AGGR_EN_POS (1)
458 #define VRING_CFG_MAC_CTRL_AGGR_EN_LEN (1)
459 #define VRING_CFG_MAC_CTRL_AGGR_EN_MSK (0x2)
460 u8 mac_ctrl;
461
462 #define VRING_CFG_TO_RESOLUTION_VALUE_POS (0)
463 #define VRING_CFG_TO_RESOLUTION_VALUE_LEN (6)
464 #define VRING_CFG_TO_RESOLUTION_VALUE_MSK (0x3F)
465 u8 to_resolution;
466 u8 agg_max_wsize;
467 struct wmi_vring_cfg_schd schd_params;
468} __packed;
469
470enum wmi_vring_cfg_cmd_action {
471 WMI_VRING_CMD_ADD = 0,
472 WMI_VRING_CMD_MODIFY = 1,
473 WMI_VRING_CMD_DELETE = 2,
474};
475
476struct wmi_vring_cfg_cmd {
477 __le32 action;
478 struct wmi_vring_cfg vring_cfg;
479} __packed;
480
481/*
482 * WMI_VRING_BA_EN_CMDID
483 */
484struct wmi_vring_ba_en_cmd {
485 u8 ringid;
486 u8 agg_max_wsize;
487 __le16 ba_timeout;
488} __packed;
489
490/*
491 * WMI_VRING_BA_DIS_CMDID
492 */
493struct wmi_vring_ba_dis_cmd {
494 u8 ringid;
495 u8 reserved;
496 __le16 reason;
497} __packed;
498
499/*
500 * WMI_NOTIFY_REQ_CMDID
501 */
502struct wmi_notify_req_cmd {
503 u8 cid;
504 u8 reserved[3];
505 __le32 interval_usec;
506} __packed;
507
508/*
509 * WMI_CFG_RX_CHAIN_CMDID
510 */
511enum wmi_sniffer_cfg_mode {
512 WMI_SNIFFER_OFF = 0,
513 WMI_SNIFFER_ON = 1,
514};
515
516enum wmi_sniffer_cfg_phy_info_mode {
517 WMI_SNIFFER_PHY_INFO_DISABLED = 0,
518 WMI_SNIFFER_PHY_INFO_ENABLED = 1,
519};
520
521enum wmi_sniffer_cfg_phy_support {
522 WMI_SNIFFER_CP = 0,
523 WMI_SNIFFER_DP = 1,
524 WMI_SNIFFER_BOTH_PHYS = 2,
525};
526
527struct wmi_sniffer_cfg {
528 __le32 mode; /* enum wmi_sniffer_cfg_mode */
529 __le32 phy_info_mode; /* enum wmi_sniffer_cfg_phy_info_mode */
530 __le32 phy_support; /* enum wmi_sniffer_cfg_phy_support */
531 u8 channel;
532 u8 reserved[3];
533} __packed;
534
535enum wmi_cfg_rx_chain_cmd_action {
536 WMI_RX_CHAIN_ADD = 0,
537 WMI_RX_CHAIN_DEL = 1,
538};
539
540enum wmi_cfg_rx_chain_cmd_decap_trans_type {
541 WMI_DECAP_TYPE_802_3 = 0,
542 WMI_DECAP_TYPE_NATIVE_WIFI = 1,
543};
544
545enum wmi_cfg_rx_chain_cmd_nwifi_ds_trans_type {
546 WMI_NWIFI_RX_TRANS_MODE_NO = 0,
547 WMI_NWIFI_RX_TRANS_MODE_PBSS2AP = 1,
548 WMI_NWIFI_RX_TRANS_MODE_PBSS2STA = 2,
549};
550
551struct wmi_cfg_rx_chain_cmd {
552 __le32 action;
553 struct wmi_sw_ring_cfg rx_sw_ring;
554 u8 mid;
555 u8 decap_trans_type;
556
557 #define L2_802_3_OFFLOAD_CTRL_VLAN_TAG_INSERTION_POS (0)
558 #define L2_802_3_OFFLOAD_CTRL_VLAN_TAG_INSERTION_LEN (1)
559 #define L2_802_3_OFFLOAD_CTRL_VLAN_TAG_INSERTION_MSK (0x1)
560 u8 l2_802_3_offload_ctrl;
561
562 #define L2_NWIFI_OFFLOAD_CTRL_REMOVE_QOS_POS (0)
563 #define L2_NWIFI_OFFLOAD_CTRL_REMOVE_QOS_LEN (1)
564 #define L2_NWIFI_OFFLOAD_CTRL_REMOVE_QOS_MSK (0x1)
565 #define L2_NWIFI_OFFLOAD_CTRL_REMOVE_PN_POS (1)
566 #define L2_NWIFI_OFFLOAD_CTRL_REMOVE_PN_LEN (1)
567 #define L2_NWIFI_OFFLOAD_CTRL_REMOVE_PN_MSK (0x2)
568 u8 l2_nwifi_offload_ctrl;
569
570 u8 vlan_id;
571 u8 nwifi_ds_trans_type;
572
573 #define L3_L4_CTRL_IPV4_CHECKSUM_EN_POS (0)
574 #define L3_L4_CTRL_IPV4_CHECKSUM_EN_LEN (1)
575 #define L3_L4_CTRL_IPV4_CHECKSUM_EN_MSK (0x1)
576 #define L3_L4_CTRL_TCPIP_CHECKSUM_EN_POS (1)
577 #define L3_L4_CTRL_TCPIP_CHECKSUM_EN_LEN (1)
578 #define L3_L4_CTRL_TCPIP_CHECKSUM_EN_MSK (0x2)
579 u8 l3_l4_ctrl;
580
581 #define RING_CTRL_OVERRIDE_PREFETCH_THRSH_POS (0)
582 #define RING_CTRL_OVERRIDE_PREFETCH_THRSH_LEN (1)
583 #define RING_CTRL_OVERRIDE_PREFETCH_THRSH_MSK (0x1)
584 #define RING_CTRL_OVERRIDE_WB_THRSH_POS (1)
585 #define RING_CTRL_OVERRIDE_WB_THRSH_LEN (1)
586 #define RING_CTRL_OVERRIDE_WB_THRSH_MSK (0x2)
587 #define RING_CTRL_OVERRIDE_ITR_THRSH_POS (2)
588 #define RING_CTRL_OVERRIDE_ITR_THRSH_LEN (1)
589 #define RING_CTRL_OVERRIDE_ITR_THRSH_MSK (0x4)
590 #define RING_CTRL_OVERRIDE_HOST_THRSH_POS (3)
591 #define RING_CTRL_OVERRIDE_HOST_THRSH_LEN (1)
592 #define RING_CTRL_OVERRIDE_HOST_THRSH_MSK (0x8)
593 u8 ring_ctrl;
594
595 __le16 prefetch_thrsh;
596 __le16 wb_thrsh;
597 __le32 itr_value;
598 __le16 host_thrsh;
599 u8 reserved[2];
600 struct wmi_sniffer_cfg sniffer_cfg;
601} __packed;
602
603/*
604 * WMI_RCP_ADDBA_RESP_CMDID
605 */
606struct wmi_rcp_addba_resp_cmd {
607
608 #define CIDXTID_CID_POS (0)
609 #define CIDXTID_CID_LEN (4)
610 #define CIDXTID_CID_MSK (0xF)
611 #define CIDXTID_TID_POS (4)
612 #define CIDXTID_TID_LEN (4)
613 #define CIDXTID_TID_MSK (0xF0)
614 u8 cidxtid;
615
616 u8 dialog_token;
617 __le16 status_code;
618 __le16 ba_param_set; /* ieee80211_ba_parameterset field to send */
619 __le16 ba_timeout;
620} __packed;
621
622/*
623 * WMI_RCP_DELBA_CMDID
624 */
625struct wmi_rcp_delba_cmd {
626
627 #define CIDXTID_CID_POS (0)
628 #define CIDXTID_CID_LEN (4)
629 #define CIDXTID_CID_MSK (0xF)
630 #define CIDXTID_TID_POS (4)
631 #define CIDXTID_TID_LEN (4)
632 #define CIDXTID_TID_MSK (0xF0)
633 u8 cidxtid;
634
635 u8 reserved;
636 __le16 reason;
637} __packed;
638
639/*
640 * WMI_RCP_ADDBA_REQ_CMDID
641 */
642struct wmi_rcp_addba_req_cmd {
643
644 #define CIDXTID_CID_POS (0)
645 #define CIDXTID_CID_LEN (4)
646 #define CIDXTID_CID_MSK (0xF)
647 #define CIDXTID_TID_POS (4)
648 #define CIDXTID_TID_LEN (4)
649 #define CIDXTID_TID_MSK (0xF0)
650 u8 cidxtid;
651
652 u8 dialog_token;
653 /* ieee80211_ba_parameterset field as it received */
654 __le16 ba_param_set;
655 __le16 ba_timeout;
656 /* ieee80211_ba_seqstrl field as it received */
657 __le16 ba_seq_ctrl;
658} __packed;
659
660/*
661 * WMI_SET_MAC_ADDRESS_CMDID
662 */
663struct wmi_set_mac_address_cmd {
664 u8 mac[WMI_MAC_LEN];
665 u8 reserved[2];
666} __packed;
667
668
669/*
670* WMI_EAPOL_TX_CMDID
671*/
672struct wmi_eapol_tx_cmd {
673 u8 dst_mac[WMI_MAC_LEN];
674 __le16 eapol_len;
675 u8 eapol[0];
676} __packed;
677
678/*
679 * WMI_ECHO_CMDID
680 *
681 * Check FW is alive
682 *
683 * WMI_DEEP_ECHO_CMDID
684 *
685 * Check FW and ucode are alive
686 *
687 * Returned event: WMI_ECHO_RSP_EVENTID
688 * same event for both commands
689 */
690struct wmi_echo_cmd {
691 __le32 value;
692} __packed;
693
694/*
695 * WMI Events
696 */
697
698/*
699 * List of Events (target to host)
700 */
701enum wmi_event_id {
702 WMI_IMM_RSP_EVENTID = 0x0000,
703 WMI_READY_EVENTID = 0x1001,
704 WMI_CONNECT_EVENTID = 0x1002,
705 WMI_DISCONNECT_EVENTID = 0x1003,
706 WMI_SCAN_COMPLETE_EVENTID = 0x100a,
707 WMI_REPORT_STATISTICS_EVENTID = 0x100b,
708 WMI_RD_MEM_RSP_EVENTID = 0x1800,
709 WMI_FW_READY_EVENTID = 0x1801,
710 WMI_EXIT_FAST_MEM_ACC_MODE_EVENTID = 0x0200,
711 WMI_ECHO_RSP_EVENTID = 0x1803,
712 WMI_CONFIG_MAC_DONE_EVENTID = 0x1805,
713 WMI_CONFIG_PHY_DEBUG_DONE_EVENTID = 0x1806,
714 WMI_ADD_STATION_DONE_EVENTID = 0x1807,
715 WMI_ADD_DEBUG_TX_PCKT_DONE_EVENTID = 0x1808,
716 WMI_PHY_GET_STATISTICS_EVENTID = 0x1809,
717 WMI_FS_TUNE_DONE_EVENTID = 0x180a,
718 WMI_CORR_MEASURE_DONE_EVENTID = 0x180b,
719 WMI_TEMP_SENSE_DONE_EVENTID = 0x180e,
720 WMI_DC_CALIB_DONE_EVENTID = 0x180f,
721 WMI_IQ_TX_CALIB_DONE_EVENTID = 0x1811,
722 WMI_IQ_RX_CALIB_DONE_EVENTID = 0x1812,
723 WMI_SET_WORK_MODE_DONE_EVENTID = 0x1815,
724 WMI_LO_LEAKAGE_CALIB_DONE_EVENTID = 0x1816,
725 WMI_MARLON_R_ACTIVATE_DONE_EVENTID = 0x1817,
726 WMI_MARLON_R_READ_DONE_EVENTID = 0x1818,
727 WMI_MARLON_R_WRITE_DONE_EVENTID = 0x1819,
728 WMI_MARLON_R_TXRX_SEL_DONE_EVENTID = 0x181a,
729 WMI_SILENT_RSSI_CALIB_DONE_EVENTID = 0x181d,
730
731 WMI_CFG_RX_CHAIN_DONE_EVENTID = 0x1820,
732 WMI_VRING_CFG_DONE_EVENTID = 0x1821,
733 WMI_RX_ON_DONE_EVENTID = 0x1822,
734 WMI_BA_STATUS_EVENTID = 0x1823,
735 WMI_RCP_ADDBA_REQ_EVENTID = 0x1824,
736 WMI_ADDBA_RESP_SENT_EVENTID = 0x1825,
737 WMI_DELBA_EVENTID = 0x1826,
738 WMI_GET_SSID_EVENTID = 0x1828,
739 WMI_GET_PCP_CHANNEL_EVENTID = 0x182a,
740 WMI_SW_TX_COMPLETE_EVENTID = 0x182b,
741 WMI_RX_OFF_DONE_EVENTID = 0x182c,
742
743 WMI_READ_MAC_RXQ_EVENTID = 0x1830,
744 WMI_READ_MAC_TXQ_EVENTID = 0x1831,
745 WMI_WRITE_MAC_RXQ_EVENTID = 0x1832,
746 WMI_WRITE_MAC_TXQ_EVENTID = 0x1833,
747 WMI_WRITE_MAC_XQ_FIELD_EVENTID = 0x1834,
748
749 WMI_BEAFORMING_MGMT_DONE_EVENTID = 0x1836,
750 WMI_BF_TXSS_MGMT_DONE_EVENTID = 0x1837,
751 WMI_BF_RXSS_MGMT_DONE_EVENTID = 0x1839,
752 WMI_RS_MGMT_DONE_EVENTID = 0x1852,
753 WMI_RF_MGMT_STATUS_EVENTID = 0x1853,
754 WMI_BF_SM_MGMT_DONE_EVENTID = 0x1838,
755 WMI_RX_MGMT_PACKET_EVENTID = 0x1840,
756
757 /* Performance monitoring events */
758 WMI_DATA_PORT_OPEN_EVENTID = 0x1860,
759 WMI_WBE_LINKDOWN_EVENTID = 0x1861,
760
761 WMI_BF_CTRL_DONE_EVENTID = 0x1862,
762 WMI_NOTIFY_REQ_DONE_EVENTID = 0x1863,
763 WMI_GET_STATUS_DONE_EVENTID = 0x1864,
764
765 WMI_UNIT_TEST_EVENTID = 0x1900,
766 WMI_FLASH_READ_DONE_EVENTID = 0x1902,
767 WMI_FLASH_WRITE_DONE_EVENTID = 0x1903,
768
769 WMI_SET_CHANNEL_EVENTID = 0x9000,
770 WMI_ASSOC_REQ_EVENTID = 0x9001,
771 WMI_EAPOL_RX_EVENTID = 0x9002,
772 WMI_MAC_ADDR_RESP_EVENTID = 0x9003,
773 WMI_FW_VER_EVENTID = 0x9004,
774};
775
776/*
777 * Events data structures
778 */
779
780/*
781 * WMI_RF_MGMT_STATUS_EVENTID
782 */
783enum wmi_rf_status {
784 WMI_RF_ENABLED = 0,
785 WMI_RF_DISABLED_HW = 1,
786 WMI_RF_DISABLED_SW = 2,
787 WMI_RF_DISABLED_HW_SW = 3,
788};
789
790struct wmi_rf_mgmt_status_event {
791 __le32 rf_status;
792} __packed;
793
794/*
795 * WMI_GET_STATUS_DONE_EVENTID
796 */
797struct wmi_get_status_done_event {
798 __le32 is_associated;
799 u8 cid;
800 u8 reserved0[3];
801 u8 bssid[WMI_MAC_LEN];
802 u8 channel;
803 u8 reserved1;
804 u8 network_type;
805 u8 reserved2[3];
806 __le32 ssid_len;
807 u8 ssid[WMI_MAX_SSID_LEN];
808 __le32 rf_status;
809 __le32 is_secured;
810} __packed;
811
812/*
813 * WMI_FW_VER_EVENTID
814 */
815struct wmi_fw_ver_event {
816 u8 major;
817 u8 minor;
818 __le16 subminor;
819 __le16 build;
820} __packed;
821
822/*
823* WMI_MAC_ADDR_RESP_EVENTID
824*/
825struct wmi_mac_addr_resp_event {
826 u8 mac[WMI_MAC_LEN];
827 u8 auth_mode;
828 u8 crypt_mode;
829 __le32 offload_mode;
830} __packed;
831
832/*
833* WMI_EAPOL_RX_EVENTID
834*/
835struct wmi_eapol_rx_event {
836 u8 src_mac[WMI_MAC_LEN];
837 __le16 eapol_len;
838 u8 eapol[0];
839} __packed;
840
841/*
842* WMI_READY_EVENTID
843*/
844enum wmi_phy_capability {
845 WMI_11A_CAPABILITY = 1,
846 WMI_11G_CAPABILITY = 2,
847 WMI_11AG_CAPABILITY = 3,
848 WMI_11NA_CAPABILITY = 4,
849 WMI_11NG_CAPABILITY = 5,
850 WMI_11NAG_CAPABILITY = 6,
851 WMI_11AD_CAPABILITY = 7,
852 WMI_11N_CAPABILITY_OFFSET = WMI_11NA_CAPABILITY - WMI_11A_CAPABILITY,
853};
854
855struct wmi_ready_event {
856 __le32 sw_version;
857 __le32 abi_version;
858 u8 mac[WMI_MAC_LEN];
859 u8 phy_capability; /* enum wmi_phy_capability */
860 u8 reserved;
861} __packed;
862
863/*
864 * WMI_NOTIFY_REQ_DONE_EVENTID
865 */
866struct wmi_notify_req_done_event {
867 __le32 status;
868 __le64 tsf;
869 __le32 snr_val;
870 __le32 tx_tpt;
871 __le32 tx_goodput;
872 __le32 rx_goodput;
873 __le16 bf_mcs;
874 __le16 my_rx_sector;
875 __le16 my_tx_sector;
876 __le16 other_rx_sector;
877 __le16 other_tx_sector;
878 __le16 range;
879} __packed;
880
881/*
882 * WMI_CONNECT_EVENTID
883 */
884struct wmi_connect_event {
885 u8 channel;
886 u8 reserved0;
887 u8 bssid[WMI_MAC_LEN];
888 __le16 listen_interval;
889 __le16 beacon_interval;
890 u8 network_type;
891 u8 reserved1[3];
892 u8 beacon_ie_len;
893 u8 assoc_req_len;
894 u8 assoc_resp_len;
895 u8 cid;
896 u8 reserved2[3];
897 u8 assoc_info[0];
898} __packed;
899
900/*
901 * WMI_DISCONNECT_EVENTID
902 */
903enum wmi_disconnect_reason {
904 WMI_DIS_REASON_NO_NETWORK_AVAIL = 1,
905 WMI_DIS_REASON_LOST_LINK = 2, /* bmiss */
906 WMI_DIS_REASON_DISCONNECT_CMD = 3,
907 WMI_DIS_REASON_BSS_DISCONNECTED = 4,
908 WMI_DIS_REASON_AUTH_FAILED = 5,
909 WMI_DIS_REASON_ASSOC_FAILED = 6,
910 WMI_DIS_REASON_NO_RESOURCES_AVAIL = 7,
911 WMI_DIS_REASON_CSERV_DISCONNECT = 8,
912 WMI_DIS_REASON_INVALID_PROFILE = 10,
913 WMI_DIS_REASON_DOT11H_CHANNEL_SWITCH = 11,
914 WMI_DIS_REASON_PROFILE_MISMATCH = 12,
915 WMI_DIS_REASON_CONNECTION_EVICTED = 13,
916 WMI_DIS_REASON_IBSS_MERGE = 14,
917};
918
919struct wmi_disconnect_event {
920 __le16 protocol_reason_status; /* reason code, see 802.11 spec. */
921 u8 bssid[WMI_MAC_LEN]; /* set if known */
922 u8 disconnect_reason; /* see wmi_disconnect_reason_e */
923 u8 assoc_resp_len;
924 u8 assoc_info[0];
925} __packed;
926
927/*
928 * WMI_SCAN_COMPLETE_EVENTID
929 */
930struct wmi_scan_complete_event {
931 __le32 status;
932} __packed;
933
934/*
935 * WMI_BA_STATUS_EVENTID
936 */
937enum wmi_vring_ba_status {
938 WMI_BA_AGREED = 0,
939 WMI_BA_NON_AGREED = 1,
940};
941
942struct wmi_vring_ba_status_event {
943 __le16 status;
944 u8 reserved[2];
945 u8 ringid;
946 u8 agg_wsize;
947 __le16 ba_timeout;
948} __packed;
949
950/*
951 * WMI_DELBA_EVENTID
952 */
953struct wmi_delba_event {
954
955 #define CIDXTID_CID_POS (0)
956 #define CIDXTID_CID_LEN (4)
957 #define CIDXTID_CID_MSK (0xF)
958 #define CIDXTID_TID_POS (4)
959 #define CIDXTID_TID_LEN (4)
960 #define CIDXTID_TID_MSK (0xF0)
961 u8 cidxtid;
962
963 u8 from_initiator;
964 __le16 reason;
965} __packed;
966
967/*
968 * WMI_VRING_CFG_DONE_EVENTID
969 */
970enum wmi_vring_cfg_done_event_status {
971 WMI_VRING_CFG_SUCCESS = 0,
972 WMI_VRING_CFG_FAILURE = 1,
973};
974
975struct wmi_vring_cfg_done_event {
976 u8 ringid;
977 u8 status;
978 u8 reserved[2];
979 __le32 tx_vring_tail_ptr;
980} __packed;
981
982/*
983 * WMI_ADDBA_RESP_SENT_EVENTID
984 */
985enum wmi_rcp_addba_resp_sent_event_status {
986 WMI_ADDBA_SUCCESS = 0,
987 WMI_ADDBA_FAIL = 1,
988};
989
990struct wmi_rcp_addba_resp_sent_event {
991
992 #define CIDXTID_CID_POS (0)
993 #define CIDXTID_CID_LEN (4)
994 #define CIDXTID_CID_MSK (0xF)
995 #define CIDXTID_TID_POS (4)
996 #define CIDXTID_TID_LEN (4)
997 #define CIDXTID_TID_MSK (0xF0)
998 u8 cidxtid;
999
1000 u8 reserved;
1001 __le16 status;
1002} __packed;
1003
1004/*
1005 * WMI_RCP_ADDBA_REQ_EVENTID
1006 */
1007struct wmi_rcp_addba_req_event {
1008
1009 #define CIDXTID_CID_POS (0)
1010 #define CIDXTID_CID_LEN (4)
1011 #define CIDXTID_CID_MSK (0xF)
1012 #define CIDXTID_TID_POS (4)
1013 #define CIDXTID_TID_LEN (4)
1014 #define CIDXTID_TID_MSK (0xF0)
1015 u8 cidxtid;
1016
1017 u8 dialog_token;
1018 __le16 ba_param_set; /* ieee80211_ba_parameterset as it received */
1019 __le16 ba_timeout;
1020 __le16 ba_seq_ctrl; /* ieee80211_ba_seqstrl field as it received */
1021} __packed;
1022
1023/*
1024 * WMI_CFG_RX_CHAIN_DONE_EVENTID
1025 */
1026enum wmi_cfg_rx_chain_done_event_status {
1027 WMI_CFG_RX_CHAIN_SUCCESS = 1,
1028};
1029
1030struct wmi_cfg_rx_chain_done_event {
1031 __le32 rx_ring_tail_ptr; /* Rx V-Ring Tail pointer */
1032 __le32 status;
1033} __packed;
1034
1035/*
1036 * WMI_WBE_LINKDOWN_EVENTID
1037 */
1038enum wmi_wbe_link_down_event_reason {
1039 WMI_WBE_REASON_USER_REQUEST = 0,
1040 WMI_WBE_REASON_RX_DISASSOC = 1,
1041 WMI_WBE_REASON_BAD_PHY_LINK = 2,
1042};
1043
1044struct wmi_wbe_link_down_event {
1045 u8 cid;
1046 u8 reserved[3];
1047 __le32 reason;
1048} __packed;
1049
1050/*
1051 * WMI_DATA_PORT_OPEN_EVENTID
1052 */
1053struct wmi_data_port_open_event {
1054 u8 cid;
1055 u8 reserved[3];
1056} __packed;
1057
1058/*
1059 * WMI_GET_PCP_CHANNEL_EVENTID
1060 */
1061struct wmi_get_pcp_channel_event {
1062 u8 channel;
1063 u8 reserved[3];
1064} __packed;
1065
1066/*
1067 * WMI_SW_TX_COMPLETE_EVENTID
1068 */
1069enum wmi_sw_tx_status {
1070 WMI_TX_SW_STATUS_SUCCESS = 0,
1071 WMI_TX_SW_STATUS_FAILED_NO_RESOURCES = 1,
1072 WMI_TX_SW_STATUS_FAILED_TX = 2,
1073};
1074
1075struct wmi_sw_tx_complete_event {
1076 u8 status; /* enum wmi_sw_tx_status */
1077 u8 reserved[3];
1078} __packed;
1079
1080/*
1081 * WMI_GET_SSID_EVENTID
1082 */
1083struct wmi_get_ssid_event {
1084 __le32 ssid_len;
1085 u8 ssid[WMI_MAX_SSID_LEN];
1086} __packed;
1087
1088/*
1089 * WMI_RX_MGMT_PACKET_EVENTID
1090 */
1091struct wmi_rx_mgmt_info {
1092 u8 mcs;
1093 s8 snr;
1094 __le16 range;
1095 __le16 stype;
1096 __le16 status;
1097 __le32 len;
1098 u8 qid;
1099 u8 mid;
1100 u8 cid;
1101 u8 channel; /* From Radio MNGR */
1102} __packed;
1103
1104struct wmi_rx_mgmt_packet_event {
1105 struct wmi_rx_mgmt_info info;
1106 u8 payload[0];
1107} __packed;
1108
1109/*
1110 * WMI_ECHO_RSP_EVENTID
1111 */
1112struct wmi_echo_event {
1113 __le32 echoed_value;
1114} __packed;
1115
1116#endif /* __WILOCITY_WMI_H__ */