diff options
Diffstat (limited to 'drivers/net/wireless/ath/wil6210/main.c')
-rw-r--r-- | drivers/net/wireless/ath/wil6210/main.c | 95 |
1 files changed, 80 insertions, 15 deletions
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 6500caf8d609..6212983fede2 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c | |||
@@ -38,6 +38,35 @@ static unsigned int itr_trsh = WIL6210_ITR_TRSH_DEFAULT; | |||
38 | module_param(itr_trsh, uint, S_IRUGO); | 38 | module_param(itr_trsh, uint, S_IRUGO); |
39 | MODULE_PARM_DESC(itr_trsh, " Interrupt moderation threshold, usecs."); | 39 | MODULE_PARM_DESC(itr_trsh, " Interrupt moderation threshold, usecs."); |
40 | 40 | ||
41 | /* We allow allocation of more than 1 page buffers to support large packets. | ||
42 | * It is suboptimal behavior performance wise in case MTU above page size. | ||
43 | */ | ||
44 | unsigned int mtu_max = TXRX_BUF_LEN_DEFAULT - ETH_HLEN; | ||
45 | static int mtu_max_set(const char *val, const struct kernel_param *kp) | ||
46 | { | ||
47 | int ret; | ||
48 | |||
49 | /* sets mtu_max directly. no need to restore it in case of | ||
50 | * illegal value since we assume this will fail insmod | ||
51 | */ | ||
52 | ret = param_set_uint(val, kp); | ||
53 | if (ret) | ||
54 | return ret; | ||
55 | |||
56 | if (mtu_max < 68 || mtu_max > IEEE80211_MAX_DATA_LEN_DMG) | ||
57 | ret = -EINVAL; | ||
58 | |||
59 | return ret; | ||
60 | } | ||
61 | |||
62 | static struct kernel_param_ops mtu_max_ops = { | ||
63 | .set = mtu_max_set, | ||
64 | .get = param_get_uint, | ||
65 | }; | ||
66 | |||
67 | module_param_cb(mtu_max, &mtu_max_ops, &mtu_max, S_IRUGO); | ||
68 | MODULE_PARM_DESC(mtu_max, " Max MTU value."); | ||
69 | |||
41 | #define RST_DELAY (20) /* msec, for loop in @wil_target_reset */ | 70 | #define RST_DELAY (20) /* msec, for loop in @wil_target_reset */ |
42 | #define RST_COUNT (1 + 1000/RST_DELAY) /* round up to be above 1 sec total */ | 71 | #define RST_COUNT (1 + 1000/RST_DELAY) /* round up to be above 1 sec total */ |
43 | 72 | ||
@@ -74,7 +103,8 @@ void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src, | |||
74 | __raw_writel(*s++, d++); | 103 | __raw_writel(*s++, d++); |
75 | } | 104 | } |
76 | 105 | ||
77 | static void wil_disconnect_cid(struct wil6210_priv *wil, int cid) | 106 | static void wil_disconnect_cid(struct wil6210_priv *wil, int cid, |
107 | bool from_event) | ||
78 | { | 108 | { |
79 | uint i; | 109 | uint i; |
80 | struct net_device *ndev = wil_to_ndev(wil); | 110 | struct net_device *ndev = wil_to_ndev(wil); |
@@ -86,7 +116,10 @@ static void wil_disconnect_cid(struct wil6210_priv *wil, int cid) | |||
86 | 116 | ||
87 | sta->data_port_open = false; | 117 | sta->data_port_open = false; |
88 | if (sta->status != wil_sta_unused) { | 118 | if (sta->status != wil_sta_unused) { |
89 | wmi_disconnect_sta(wil, sta->addr, WLAN_REASON_DEAUTH_LEAVING); | 119 | if (!from_event) |
120 | wmi_disconnect_sta(wil, sta->addr, | ||
121 | WLAN_REASON_DEAUTH_LEAVING); | ||
122 | |||
90 | switch (wdev->iftype) { | 123 | switch (wdev->iftype) { |
91 | case NL80211_IFTYPE_AP: | 124 | case NL80211_IFTYPE_AP: |
92 | case NL80211_IFTYPE_P2P_GO: | 125 | case NL80211_IFTYPE_P2P_GO: |
@@ -118,7 +151,8 @@ static void wil_disconnect_cid(struct wil6210_priv *wil, int cid) | |||
118 | memset(&sta->stats, 0, sizeof(sta->stats)); | 151 | memset(&sta->stats, 0, sizeof(sta->stats)); |
119 | } | 152 | } |
120 | 153 | ||
121 | static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid) | 154 | static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid, |
155 | bool from_event) | ||
122 | { | 156 | { |
123 | int cid = -ENOENT; | 157 | int cid = -ENOENT; |
124 | struct net_device *ndev = wil_to_ndev(wil); | 158 | struct net_device *ndev = wil_to_ndev(wil); |
@@ -133,10 +167,10 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid) | |||
133 | } | 167 | } |
134 | 168 | ||
135 | if (cid >= 0) /* disconnect 1 peer */ | 169 | if (cid >= 0) /* disconnect 1 peer */ |
136 | wil_disconnect_cid(wil, cid); | 170 | wil_disconnect_cid(wil, cid, from_event); |
137 | else /* disconnect all */ | 171 | else /* disconnect all */ |
138 | for (cid = 0; cid < WIL6210_MAX_CID; cid++) | 172 | for (cid = 0; cid < WIL6210_MAX_CID; cid++) |
139 | wil_disconnect_cid(wil, cid); | 173 | wil_disconnect_cid(wil, cid, from_event); |
140 | 174 | ||
141 | /* link state */ | 175 | /* link state */ |
142 | switch (wdev->iftype) { | 176 | switch (wdev->iftype) { |
@@ -166,7 +200,7 @@ static void wil_disconnect_worker(struct work_struct *work) | |||
166 | struct wil6210_priv, disconnect_worker); | 200 | struct wil6210_priv, disconnect_worker); |
167 | 201 | ||
168 | mutex_lock(&wil->mutex); | 202 | mutex_lock(&wil->mutex); |
169 | _wil6210_disconnect(wil, NULL); | 203 | _wil6210_disconnect(wil, NULL, false); |
170 | mutex_unlock(&wil->mutex); | 204 | mutex_unlock(&wil->mutex); |
171 | } | 205 | } |
172 | 206 | ||
@@ -223,6 +257,11 @@ static void wil_fw_error_worker(struct work_struct *work) | |||
223 | 257 | ||
224 | wil_dbg_misc(wil, "fw error worker\n"); | 258 | wil_dbg_misc(wil, "fw error worker\n"); |
225 | 259 | ||
260 | if (!netif_running(wil_to_ndev(wil))) { | ||
261 | wil_info(wil, "No recovery - interface is down\n"); | ||
262 | return; | ||
263 | } | ||
264 | |||
226 | /* increment @recovery_count if less then WIL6210_FW_RECOVERY_TO | 265 | /* increment @recovery_count if less then WIL6210_FW_RECOVERY_TO |
227 | * passed since last recovery attempt | 266 | * passed since last recovery attempt |
228 | */ | 267 | */ |
@@ -257,9 +296,12 @@ static void wil_fw_error_worker(struct work_struct *work) | |||
257 | break; | 296 | break; |
258 | case NL80211_IFTYPE_AP: | 297 | case NL80211_IFTYPE_AP: |
259 | case NL80211_IFTYPE_P2P_GO: | 298 | case NL80211_IFTYPE_P2P_GO: |
299 | wil_info(wil, "No recovery for AP-like interface\n"); | ||
260 | /* recovery in these modes is done by upper layers */ | 300 | /* recovery in these modes is done by upper layers */ |
261 | break; | 301 | break; |
262 | default: | 302 | default: |
303 | wil_err(wil, "No recovery - unknown interface type %d\n", | ||
304 | wdev->iftype); | ||
263 | break; | 305 | break; |
264 | } | 306 | } |
265 | mutex_unlock(&wil->mutex); | 307 | mutex_unlock(&wil->mutex); |
@@ -346,12 +388,22 @@ int wil_priv_init(struct wil6210_priv *wil) | |||
346 | return 0; | 388 | return 0; |
347 | } | 389 | } |
348 | 390 | ||
349 | void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid) | 391 | /** |
392 | * wil6210_disconnect - disconnect one connection | ||
393 | * @wil: driver context | ||
394 | * @bssid: peer to disconnect, NULL to disconnect all | ||
395 | * @from_event: whether is invoked from FW event handler | ||
396 | * | ||
397 | * Disconnect and release associated resources. If invoked not from the | ||
398 | * FW event handler, issue WMI command(s) to trigger MAC disconnect. | ||
399 | */ | ||
400 | void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid, | ||
401 | bool from_event) | ||
350 | { | 402 | { |
351 | wil_dbg_misc(wil, "%s()\n", __func__); | 403 | wil_dbg_misc(wil, "%s()\n", __func__); |
352 | 404 | ||
353 | del_timer_sync(&wil->connect_timer); | 405 | del_timer_sync(&wil->connect_timer); |
354 | _wil6210_disconnect(wil, bssid); | 406 | _wil6210_disconnect(wil, bssid, from_event); |
355 | } | 407 | } |
356 | 408 | ||
357 | void wil_priv_deinit(struct wil6210_priv *wil) | 409 | void wil_priv_deinit(struct wil6210_priv *wil) |
@@ -363,7 +415,7 @@ void wil_priv_deinit(struct wil6210_priv *wil) | |||
363 | cancel_work_sync(&wil->disconnect_worker); | 415 | cancel_work_sync(&wil->disconnect_worker); |
364 | cancel_work_sync(&wil->fw_error_worker); | 416 | cancel_work_sync(&wil->fw_error_worker); |
365 | mutex_lock(&wil->mutex); | 417 | mutex_lock(&wil->mutex); |
366 | wil6210_disconnect(wil, NULL); | 418 | wil6210_disconnect(wil, NULL, false); |
367 | mutex_unlock(&wil->mutex); | 419 | mutex_unlock(&wil->mutex); |
368 | wmi_event_flush(wil); | 420 | wmi_event_flush(wil); |
369 | destroy_workqueue(wil->wmi_wq_conn); | 421 | destroy_workqueue(wil->wmi_wq_conn); |
@@ -395,7 +447,7 @@ static inline void wil_release_cpu(struct wil6210_priv *wil) | |||
395 | static int wil_target_reset(struct wil6210_priv *wil) | 447 | static int wil_target_reset(struct wil6210_priv *wil) |
396 | { | 448 | { |
397 | int delay = 0; | 449 | int delay = 0; |
398 | u32 hw_state; | 450 | u32 x; |
399 | u32 rev_id; | 451 | u32 rev_id; |
400 | bool is_sparrow = (wil->board->board == WIL_BOARD_SPARROW); | 452 | bool is_sparrow = (wil->board->board == WIL_BOARD_SPARROW); |
401 | 453 | ||
@@ -410,9 +462,22 @@ static int wil_target_reset(struct wil6210_priv *wil) | |||
410 | S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT_CAR_PERST_RST); | 462 | S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT_CAR_PERST_RST); |
411 | 463 | ||
412 | wil_halt_cpu(wil); | 464 | wil_halt_cpu(wil); |
413 | C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_CAR_AHB_SW_SEL); /* 40 MHz */ | ||
414 | 465 | ||
415 | if (is_sparrow) { | 466 | if (is_sparrow) { |
467 | S(RGF_CAF_OSC_CONTROL, BIT_CAF_OSC_XTAL_EN); | ||
468 | /* XTAL stabilization should take about 3ms */ | ||
469 | usleep_range(5000, 7000); | ||
470 | x = R(RGF_CAF_PLL_LOCK_STATUS); | ||
471 | if (!(x & BIT_CAF_OSC_DIG_XTAL_STABLE)) { | ||
472 | wil_err(wil, "Xtal stabilization timeout\n" | ||
473 | "RGF_CAF_PLL_LOCK_STATUS = 0x%08x\n", x); | ||
474 | return -ETIME; | ||
475 | } | ||
476 | /* switch 10k to XTAL*/ | ||
477 | C(RGF_USER_SPARROW_M_4, BIT_SPARROW_M_4_SEL_SLEEP_OR_REF); | ||
478 | /* 40 MHz */ | ||
479 | C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_CAR_AHB_SW_SEL); | ||
480 | |||
416 | W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x3ff81f); | 481 | W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x3ff81f); |
417 | W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1, 0xf); | 482 | W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1, 0xf); |
418 | } | 483 | } |
@@ -453,13 +518,13 @@ static int wil_target_reset(struct wil6210_priv *wil) | |||
453 | /* wait until device ready. typical time is 200..250 msec */ | 518 | /* wait until device ready. typical time is 200..250 msec */ |
454 | do { | 519 | do { |
455 | msleep(RST_DELAY); | 520 | msleep(RST_DELAY); |
456 | hw_state = R(RGF_USER_HW_MACHINE_STATE); | 521 | x = R(RGF_USER_HW_MACHINE_STATE); |
457 | if (delay++ > RST_COUNT) { | 522 | if (delay++ > RST_COUNT) { |
458 | wil_err(wil, "Reset not completed, hw_state 0x%08x\n", | 523 | wil_err(wil, "Reset not completed, hw_state 0x%08x\n", |
459 | hw_state); | 524 | x); |
460 | return -ETIME; | 525 | return -ETIME; |
461 | } | 526 | } |
462 | } while (hw_state != HW_MACHINE_BOOT_DONE); | 527 | } while (x != HW_MACHINE_BOOT_DONE); |
463 | 528 | ||
464 | /* TODO: Erez check rev_id != 1 */ | 529 | /* TODO: Erez check rev_id != 1 */ |
465 | if (!is_sparrow && (rev_id != 1)) | 530 | if (!is_sparrow && (rev_id != 1)) |
@@ -535,7 +600,7 @@ int wil_reset(struct wil6210_priv *wil) | |||
535 | WARN_ON(test_bit(wil_status_napi_en, &wil->status)); | 600 | WARN_ON(test_bit(wil_status_napi_en, &wil->status)); |
536 | 601 | ||
537 | cancel_work_sync(&wil->disconnect_worker); | 602 | cancel_work_sync(&wil->disconnect_worker); |
538 | wil6210_disconnect(wil, NULL); | 603 | wil6210_disconnect(wil, NULL, false); |
539 | 604 | ||
540 | wil->status = 0; /* prevent NAPI from being scheduled */ | 605 | wil->status = 0; /* prevent NAPI from being scheduled */ |
541 | 606 | ||