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} |
|