wmi.c (b8fa3bfb14e78dbfcfbd2fac1d81a0e666eb8f42) wmi.c (a5dc688392737bbab3699d63f26e853a40c52d2d)
1/*
2 * Copyright (c) 2012-2017 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

--- 24 unchanged lines hidden (view full) ---

33 " 0 - use default; < 0 - don't auto-establish");
34
35u8 led_id = WIL_LED_INVALID_ID;
36module_param(led_id, byte, 0444);
37MODULE_PARM_DESC(led_id,
38 " 60G device led enablement. Set the led ID (0-2) to enable");
39
40#define WIL_WAIT_FOR_SUSPEND_RESUME_COMP 200
1/*
2 * Copyright (c) 2012-2017 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

--- 24 unchanged lines hidden (view full) ---

33 " 0 - use default; < 0 - don't auto-establish");
34
35u8 led_id = WIL_LED_INVALID_ID;
36module_param(led_id, byte, 0444);
37MODULE_PARM_DESC(led_id,
38 " 60G device led enablement. Set the led ID (0-2) to enable");
39
40#define WIL_WAIT_FOR_SUSPEND_RESUME_COMP 200
41#define WIL_WMI_CALL_GENERAL_TO_MS 100
41
42/**
43 * WMI event receiving - theory of operations
44 *
45 * When firmware about to report WMI event, it fills memory area
46 * in the mailbox and raises misc. IRQ. Thread interrupt handler invoked for
47 * the misc IRQ, function @wmi_recv_cmd called by thread IRQ handler.
48 *

--- 260 unchanged lines hidden (view full) ---

309 case WMI_SET_THERMAL_THROTTLING_CFG_CMDID:
310 return "WMI_SET_THERMAL_THROTTLING_CFG_CMD";
311 case WMI_GET_THERMAL_THROTTLING_CFG_CMDID:
312 return "WMI_GET_THERMAL_THROTTLING_CFG_CMD";
313 case WMI_LINK_MAINTAIN_CFG_WRITE_CMDID:
314 return "WMI_LINK_MAINTAIN_CFG_WRITE_CMD";
315 case WMI_LO_POWER_CALIB_FROM_OTP_CMDID:
316 return "WMI_LO_POWER_CALIB_FROM_OTP_CMD";
42
43/**
44 * WMI event receiving - theory of operations
45 *
46 * When firmware about to report WMI event, it fills memory area
47 * in the mailbox and raises misc. IRQ. Thread interrupt handler invoked for
48 * the misc IRQ, function @wmi_recv_cmd called by thread IRQ handler.
49 *

--- 260 unchanged lines hidden (view full) ---

310 case WMI_SET_THERMAL_THROTTLING_CFG_CMDID:
311 return "WMI_SET_THERMAL_THROTTLING_CFG_CMD";
312 case WMI_GET_THERMAL_THROTTLING_CFG_CMDID:
313 return "WMI_GET_THERMAL_THROTTLING_CFG_CMD";
314 case WMI_LINK_MAINTAIN_CFG_WRITE_CMDID:
315 return "WMI_LINK_MAINTAIN_CFG_WRITE_CMD";
316 case WMI_LO_POWER_CALIB_FROM_OTP_CMDID:
317 return "WMI_LO_POWER_CALIB_FROM_OTP_CMD";
318 case WMI_START_SCHED_SCAN_CMDID:
319 return "WMI_START_SCHED_SCAN_CMD";
320 case WMI_STOP_SCHED_SCAN_CMDID:
321 return "WMI_STOP_SCHED_SCAN_CMD";
317 default:
318 return "Untracked CMD";
319 }
320}
321
322static const char *eventid2name(u16 eventid)
323{
324 switch (eventid) {

--- 98 unchanged lines hidden (view full) ---

423 case WMI_SET_THERMAL_THROTTLING_CFG_EVENTID:
424 return "WMI_SET_THERMAL_THROTTLING_CFG_EVENT";
425 case WMI_GET_THERMAL_THROTTLING_CFG_EVENTID:
426 return "WMI_GET_THERMAL_THROTTLING_CFG_EVENT";
427 case WMI_LINK_MAINTAIN_CFG_WRITE_DONE_EVENTID:
428 return "WMI_LINK_MAINTAIN_CFG_WRITE_DONE_EVENT";
429 case WMI_LO_POWER_CALIB_FROM_OTP_EVENTID:
430 return "WMI_LO_POWER_CALIB_FROM_OTP_EVENT";
322 default:
323 return "Untracked CMD";
324 }
325}
326
327static const char *eventid2name(u16 eventid)
328{
329 switch (eventid) {

--- 98 unchanged lines hidden (view full) ---

428 case WMI_SET_THERMAL_THROTTLING_CFG_EVENTID:
429 return "WMI_SET_THERMAL_THROTTLING_CFG_EVENT";
430 case WMI_GET_THERMAL_THROTTLING_CFG_EVENTID:
431 return "WMI_GET_THERMAL_THROTTLING_CFG_EVENT";
432 case WMI_LINK_MAINTAIN_CFG_WRITE_DONE_EVENTID:
433 return "WMI_LINK_MAINTAIN_CFG_WRITE_DONE_EVENT";
434 case WMI_LO_POWER_CALIB_FROM_OTP_EVENTID:
435 return "WMI_LO_POWER_CALIB_FROM_OTP_EVENT";
436 case WMI_START_SCHED_SCAN_EVENTID:
437 return "WMI_START_SCHED_SCAN_EVENT";
438 case WMI_STOP_SCHED_SCAN_EVENTID:
439 return "WMI_STOP_SCHED_SCAN_EVENT";
440 case WMI_SCHED_SCAN_RESULT_EVENTID:
441 return "WMI_SCHED_SCAN_RESULT_EVENT";
431 default:
432 return "Untracked EVENT";
433 }
434}
435
436static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len)
437{
438 struct {

--- 622 unchanged lines hidden (view full) ---

1061
1062 r = sta->tid_rx[tid];
1063 sta->tid_rx[tid] = NULL;
1064 wil_tid_ampdu_rx_free(wil, r);
1065
1066 spin_unlock_bh(&sta->tid_rx_lock);
1067}
1068
442 default:
443 return "Untracked EVENT";
444 }
445}
446
447static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len)
448{
449 struct {

--- 622 unchanged lines hidden (view full) ---

1072
1073 r = sta->tid_rx[tid];
1074 sta->tid_rx[tid] = NULL;
1075 wil_tid_ampdu_rx_free(wil, r);
1076
1077 spin_unlock_bh(&sta->tid_rx_lock);
1078}
1079
1080static void
1081wmi_evt_sched_scan_result(struct wil6210_priv *wil, int id, void *d, int len)
1082{
1083 struct wmi_sched_scan_result_event *data = d;
1084 struct wiphy *wiphy = wil_to_wiphy(wil);
1085 struct ieee80211_mgmt *rx_mgmt_frame =
1086 (struct ieee80211_mgmt *)data->payload;
1087 int flen = len - offsetof(struct wmi_sched_scan_result_event, payload);
1088 int ch_no;
1089 u32 freq;
1090 struct ieee80211_channel *channel;
1091 s32 signal;
1092 __le16 fc;
1093 u32 d_len;
1094 struct cfg80211_bss *bss;
1095
1096 if (flen < 0) {
1097 wil_err(wil, "sched scan result event too short, len %d\n",
1098 len);
1099 return;
1100 }
1101
1102 d_len = le32_to_cpu(data->info.len);
1103 if (d_len != flen) {
1104 wil_err(wil,
1105 "sched scan result length mismatch, d_len %d should be %d\n",
1106 d_len, flen);
1107 return;
1108 }
1109
1110 fc = rx_mgmt_frame->frame_control;
1111 if (!ieee80211_is_probe_resp(fc)) {
1112 wil_err(wil, "sched scan result invalid frame, fc 0x%04x\n",
1113 fc);
1114 return;
1115 }
1116
1117 ch_no = data->info.channel + 1;
1118 freq = ieee80211_channel_to_frequency(ch_no, NL80211_BAND_60GHZ);
1119 channel = ieee80211_get_channel(wiphy, freq);
1120 if (test_bit(WMI_FW_CAPABILITY_RSSI_REPORTING, wil->fw_capabilities))
1121 signal = 100 * data->info.rssi;
1122 else
1123 signal = data->info.sqi;
1124
1125 wil_dbg_wmi(wil, "sched scan result: channel %d MCS %d RSSI %d\n",
1126 data->info.channel, data->info.mcs, data->info.rssi);
1127 wil_dbg_wmi(wil, "len %d qid %d mid %d cid %d\n",
1128 d_len, data->info.qid, data->info.mid, data->info.cid);
1129 wil_hex_dump_wmi("PROBE ", DUMP_PREFIX_OFFSET, 16, 1, rx_mgmt_frame,
1130 d_len, true);
1131
1132 if (!channel) {
1133 wil_err(wil, "Frame on unsupported channel\n");
1134 return;
1135 }
1136
1137 bss = cfg80211_inform_bss_frame(wiphy, channel, rx_mgmt_frame,
1138 d_len, signal, GFP_KERNEL);
1139 if (bss) {
1140 wil_dbg_wmi(wil, "Added BSS %pM\n", rx_mgmt_frame->bssid);
1141 cfg80211_put_bss(wiphy, bss);
1142 } else {
1143 wil_err(wil, "cfg80211_inform_bss_frame() failed\n");
1144 }
1145
1146 cfg80211_sched_scan_results(wiphy, 0);
1147}
1148
1069/**
1070 * Some events are ignored for purpose; and need not be interpreted as
1071 * "unhandled events"
1072 */
1073static void wmi_evt_ignore(struct wil6210_priv *wil, int id, void *d, int len)
1074{
1075 wil_dbg_wmi(wil, "Ignore event 0x%04x len %d\n", id, len);
1076}

--- 11 unchanged lines hidden (view full) ---

1088 {WMI_CONNECT_EVENTID, wmi_evt_connect},
1089 {WMI_DISCONNECT_EVENTID, wmi_evt_disconnect},
1090 {WMI_EAPOL_RX_EVENTID, wmi_evt_eapol_rx},
1091 {WMI_BA_STATUS_EVENTID, wmi_evt_ba_status},
1092 {WMI_RCP_ADDBA_REQ_EVENTID, wmi_evt_addba_rx_req},
1093 {WMI_DELBA_EVENTID, wmi_evt_delba},
1094 {WMI_VRING_EN_EVENTID, wmi_evt_vring_en},
1095 {WMI_DATA_PORT_OPEN_EVENTID, wmi_evt_ignore},
1149/**
1150 * Some events are ignored for purpose; and need not be interpreted as
1151 * "unhandled events"
1152 */
1153static void wmi_evt_ignore(struct wil6210_priv *wil, int id, void *d, int len)
1154{
1155 wil_dbg_wmi(wil, "Ignore event 0x%04x len %d\n", id, len);
1156}

--- 11 unchanged lines hidden (view full) ---

1168 {WMI_CONNECT_EVENTID, wmi_evt_connect},
1169 {WMI_DISCONNECT_EVENTID, wmi_evt_disconnect},
1170 {WMI_EAPOL_RX_EVENTID, wmi_evt_eapol_rx},
1171 {WMI_BA_STATUS_EVENTID, wmi_evt_ba_status},
1172 {WMI_RCP_ADDBA_REQ_EVENTID, wmi_evt_addba_rx_req},
1173 {WMI_DELBA_EVENTID, wmi_evt_delba},
1174 {WMI_VRING_EN_EVENTID, wmi_evt_vring_en},
1175 {WMI_DATA_PORT_OPEN_EVENTID, wmi_evt_ignore},
1176 {WMI_SCHED_SCAN_RESULT_EVENTID, wmi_evt_sched_scan_result},
1096};
1097
1098/*
1099 * Run in IRQ context
1100 * Extract WMI command from mailbox. Queue it to the @wil->pending_wmi_ev
1101 * that will be eventually handled by the @wmi_event_worker in the thread
1102 * context of thread "wil6210_wmi"
1103 */

--- 1175 unchanged lines hidden (view full) ---

2279 wil_dbg_pm(wil, "Pending WMI mbox events\n");
2280 else
2281 rc = true;
2282
2283out:
2284 spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
2285 return rc;
2286}
1177};
1178
1179/*
1180 * Run in IRQ context
1181 * Extract WMI command from mailbox. Queue it to the @wil->pending_wmi_ev
1182 * that will be eventually handled by the @wmi_event_worker in the thread
1183 * context of thread "wil6210_wmi"
1184 */

--- 1175 unchanged lines hidden (view full) ---

2360 wil_dbg_pm(wil, "Pending WMI mbox events\n");
2361 else
2362 rc = true;
2363
2364out:
2365 spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
2366 return rc;
2367}
2368
2369static void
2370wmi_sched_scan_set_ssids(struct wil6210_priv *wil,
2371 struct wmi_start_sched_scan_cmd *cmd,
2372 struct cfg80211_ssid *ssids, int n_ssids,
2373 struct cfg80211_match_set *match_sets,
2374 int n_match_sets)
2375{
2376 int i;
2377
2378 if (n_match_sets > WMI_MAX_PNO_SSID_NUM) {
2379 wil_dbg_wmi(wil, "too many match sets (%d), use first %d\n",
2380 n_match_sets, WMI_MAX_PNO_SSID_NUM);
2381 n_match_sets = WMI_MAX_PNO_SSID_NUM;
2382 }
2383 cmd->num_of_ssids = n_match_sets;
2384
2385 for (i = 0; i < n_match_sets; i++) {
2386 struct wmi_sched_scan_ssid_match *wmi_match =
2387 &cmd->ssid_for_match[i];
2388 struct cfg80211_match_set *cfg_match = &match_sets[i];
2389 int j;
2390
2391 wmi_match->ssid_len = cfg_match->ssid.ssid_len;
2392 memcpy(wmi_match->ssid, cfg_match->ssid.ssid,
2393 min_t(u8, wmi_match->ssid_len, WMI_MAX_SSID_LEN));
2394 wmi_match->rssi_threshold = S8_MIN;
2395 if (cfg_match->rssi_thold >= S8_MIN &&
2396 cfg_match->rssi_thold <= S8_MAX)
2397 wmi_match->rssi_threshold = cfg_match->rssi_thold;
2398
2399 for (j = 0; j < n_ssids; j++)
2400 if (wmi_match->ssid_len == ssids[j].ssid_len &&
2401 memcmp(wmi_match->ssid, ssids[j].ssid,
2402 wmi_match->ssid_len) == 0)
2403 wmi_match->add_ssid_to_probe = true;
2404 }
2405}
2406
2407static void
2408wmi_sched_scan_set_channels(struct wil6210_priv *wil,
2409 struct wmi_start_sched_scan_cmd *cmd,
2410 u32 n_channels,
2411 struct ieee80211_channel **channels)
2412{
2413 int i;
2414
2415 if (n_channels > WMI_MAX_CHANNEL_NUM) {
2416 wil_dbg_wmi(wil, "too many channels (%d), use first %d\n",
2417 n_channels, WMI_MAX_CHANNEL_NUM);
2418 n_channels = WMI_MAX_CHANNEL_NUM;
2419 }
2420 cmd->num_of_channels = n_channels;
2421
2422 for (i = 0; i < n_channels; i++) {
2423 struct ieee80211_channel *cfg_chan = channels[i];
2424
2425 cmd->channel_list[i] = cfg_chan->hw_value - 1;
2426 }
2427}
2428
2429static void
2430wmi_sched_scan_set_plans(struct wil6210_priv *wil,
2431 struct wmi_start_sched_scan_cmd *cmd,
2432 struct cfg80211_sched_scan_plan *scan_plans,
2433 int n_scan_plans)
2434{
2435 int i;
2436
2437 if (n_scan_plans > WMI_MAX_PLANS_NUM) {
2438 wil_dbg_wmi(wil, "too many plans (%d), use first %d\n",
2439 n_scan_plans, WMI_MAX_PLANS_NUM);
2440 n_scan_plans = WMI_MAX_PLANS_NUM;
2441 }
2442
2443 for (i = 0; i < n_scan_plans; i++) {
2444 struct cfg80211_sched_scan_plan *cfg_plan = &scan_plans[i];
2445
2446 cmd->scan_plans[i].interval_sec =
2447 cpu_to_le16(cfg_plan->interval);
2448 cmd->scan_plans[i].num_of_iterations =
2449 cpu_to_le16(cfg_plan->iterations);
2450 }
2451}
2452
2453int wmi_start_sched_scan(struct wil6210_priv *wil,
2454 struct cfg80211_sched_scan_request *request)
2455{
2456 int rc;
2457 struct wmi_start_sched_scan_cmd cmd = {
2458 .min_rssi_threshold = S8_MIN,
2459 .initial_delay_sec = cpu_to_le16(request->delay),
2460 };
2461 struct {
2462 struct wmi_cmd_hdr wmi;
2463 struct wmi_start_sched_scan_event evt;
2464 } __packed reply;
2465
2466 if (!test_bit(WMI_FW_CAPABILITY_PNO, wil->fw_capabilities))
2467 return -ENOTSUPP;
2468
2469 if (request->min_rssi_thold >= S8_MIN &&
2470 request->min_rssi_thold <= S8_MAX)
2471 cmd.min_rssi_threshold = request->min_rssi_thold;
2472
2473 wmi_sched_scan_set_ssids(wil, &cmd, request->ssids, request->n_ssids,
2474 request->match_sets, request->n_match_sets);
2475 wmi_sched_scan_set_channels(wil, &cmd,
2476 request->n_channels, request->channels);
2477 wmi_sched_scan_set_plans(wil, &cmd,
2478 request->scan_plans, request->n_scan_plans);
2479
2480 reply.evt.result = WMI_PNO_REJECT;
2481
2482 rc = wmi_call(wil, WMI_START_SCHED_SCAN_CMDID, &cmd, sizeof(cmd),
2483 WMI_START_SCHED_SCAN_EVENTID, &reply, sizeof(reply),
2484 WIL_WMI_CALL_GENERAL_TO_MS);
2485 if (rc)
2486 return rc;
2487
2488 if (reply.evt.result != WMI_PNO_SUCCESS) {
2489 wil_err(wil, "start sched scan failed, result %d\n",
2490 reply.evt.result);
2491 return -EINVAL;
2492 }
2493
2494 return 0;
2495}
2496
2497int wmi_stop_sched_scan(struct wil6210_priv *wil)
2498{
2499 int rc;
2500 struct {
2501 struct wmi_cmd_hdr wmi;
2502 struct wmi_stop_sched_scan_event evt;
2503 } __packed reply;
2504
2505 if (!test_bit(WMI_FW_CAPABILITY_PNO, wil->fw_capabilities))
2506 return -ENOTSUPP;
2507
2508 reply.evt.result = WMI_PNO_REJECT;
2509
2510 rc = wmi_call(wil, WMI_STOP_SCHED_SCAN_CMDID, NULL, 0,
2511 WMI_STOP_SCHED_SCAN_EVENTID, &reply, sizeof(reply),
2512 WIL_WMI_CALL_GENERAL_TO_MS);
2513 if (rc)
2514 return rc;
2515
2516 if (reply.evt.result != WMI_PNO_SUCCESS) {
2517 wil_err(wil, "stop sched scan failed, result %d\n",
2518 reply.evt.result);
2519 return -EINVAL;
2520 }
2521
2522 return 0;
2523}