From 611b3682bbefd8213b9f46e5883c15f132b20f7c Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Fri, 25 Jul 2014 11:56:40 +0300 Subject: [PATCH 001/221] ath10k: improve 'hard' simulate fw crash Different firmware may support different numbers of vdevs. Use value that is always out of range for all firmware. Signed-off-by: Ben Greear Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/debug.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index 3030158c478e..c9e35c87edfb 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -531,7 +531,10 @@ static ssize_t ath10k_write_simulate_fw_crash(struct file *file, ret = ath10k_wmi_force_fw_hang(ar, WMI_FORCE_FW_HANG_ASSERT, 0); } else if (!strcmp(buf, "hard")) { ath10k_info("simulating hard firmware crash\n"); - ret = ath10k_wmi_vdev_set_param(ar, TARGET_NUM_VDEVS + 1, + /* 0x7fff is vdev id, and it is always out of range for all + * firmware variants in order to force a firmware crash. + */ + ret = ath10k_wmi_vdev_set_param(ar, 0x7fff, ar->wmi.vdev_param->rts_threshold, 0); } else { ret = -EINVAL; From 24c88f7807fb7c723690474d0a5d3441468185d9 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Fri, 25 Jul 2014 13:32:17 +0200 Subject: [PATCH 002/221] ath10k: add support for 10.2 firmware The 10.2 firmware is a successor of 10.1 firmware (formerly identified as 10.x). Both share a lot but have some slight ABI differences that need to be taken care of. The 10.2 firmware introduces some new features but those can be added in subsequent patches. This patch makes ath10k boot and work with 10.2 with comparable functionality to 10.1. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 14 + drivers/net/wireless/ath/ath10k/core.h | 5 + drivers/net/wireless/ath/ath10k/hw.h | 3 +- drivers/net/wireless/ath/ath10k/pci.c | 2 +- drivers/net/wireless/ath/ath10k/wmi.c | 451 +++++++++++++++++++++++-- drivers/net/wireless/ath/ath10k/wmi.h | 233 ++++++++++++- 6 files changed, 678 insertions(+), 30 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 93adb8c58969..bef797d5f4d3 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -499,6 +499,13 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name) goto err; } + if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features) && + !test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) { + ath10k_err("feature bits corrupted: 10.2 feature requires 10.x feature to be set as well"); + ret = -EINVAL; + goto err; + } + /* now fetch the board file */ if (ar->hw_params.fw.board == NULL) { ath10k_err("board data file not defined"); @@ -531,6 +538,13 @@ static int ath10k_core_fetch_firmware_files(struct ath10k *ar) { int ret; + ar->fw_api = 3; + ath10k_dbg(ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api); + + ret = ath10k_core_fetch_firmware_api_n(ar, ATH10K_FW_API3_FILE); + if (ret == 0) + goto success; + ar->fw_api = 2; ath10k_dbg(ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api); diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 83a5fa91531d..ded3af2266d0 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -330,6 +330,11 @@ enum ath10k_fw_features { /* Firmware does not support P2P */ ATH10K_FW_FEATURE_NO_P2P = 3, + /* Firmware 10.2 feature bit. The ATH10K_FW_FEATURE_WMI_10X feature bit + * is required to be set as well. + */ + ATH10K_FW_FEATURE_WMI_10_2 = 4, + /* keep last */ ATH10K_FW_FEATURE_COUNT, }; diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 007e855f4ba9..ffd04890407e 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -28,12 +28,13 @@ #define QCA988X_HW_2_0_CHIP_ID_REV 0x2 #define QCA988X_HW_2_0_FW_DIR "ath10k/QCA988X/hw2.0" #define QCA988X_HW_2_0_FW_FILE "firmware.bin" -#define QCA988X_HW_2_0_FW_2_FILE "firmware-2.bin" +#define QCA988X_HW_2_0_FW_3_FILE "firmware-3.bin" #define QCA988X_HW_2_0_OTP_FILE "otp.bin" #define QCA988X_HW_2_0_BOARD_DATA_FILE "board.bin" #define QCA988X_HW_2_0_PATCH_LOAD_ADDR 0x1234 #define ATH10K_FW_API2_FILE "firmware-2.bin" +#define ATH10K_FW_API3_FILE "firmware-3.bin" /* includes also the null byte */ #define ATH10K_FIRMWARE_MAGIC "QCA-ATH10K" diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 0ffff205478d..2d340cc522e3 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -2809,5 +2809,5 @@ module_exit(ath10k_pci_exit); MODULE_AUTHOR("Qualcomm Atheros"); MODULE_DESCRIPTION("Driver support for Atheros QCA988X PCIe devices"); MODULE_LICENSE("Dual BSD/GPL"); -MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_FW_2_FILE); +MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_FW_3_FILE); MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_BOARD_DATA_FILE); diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index c2c87c916b5a..b09661db9447 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -487,6 +487,127 @@ static struct wmi_pdev_param_map wmi_10x_pdev_param_map = { .burst_enable = WMI_10X_PDEV_PARAM_BURST_ENABLE, }; +/* firmware 10.2 specific mappings */ +static struct wmi_cmd_map wmi_10_2_cmd_map = { + .init_cmdid = WMI_10_2_INIT_CMDID, + .start_scan_cmdid = WMI_10_2_START_SCAN_CMDID, + .stop_scan_cmdid = WMI_10_2_STOP_SCAN_CMDID, + .scan_chan_list_cmdid = WMI_10_2_SCAN_CHAN_LIST_CMDID, + .scan_sch_prio_tbl_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_set_regdomain_cmdid = WMI_10_2_PDEV_SET_REGDOMAIN_CMDID, + .pdev_set_channel_cmdid = WMI_10_2_PDEV_SET_CHANNEL_CMDID, + .pdev_set_param_cmdid = WMI_10_2_PDEV_SET_PARAM_CMDID, + .pdev_pktlog_enable_cmdid = WMI_10_2_PDEV_PKTLOG_ENABLE_CMDID, + .pdev_pktlog_disable_cmdid = WMI_10_2_PDEV_PKTLOG_DISABLE_CMDID, + .pdev_set_wmm_params_cmdid = WMI_10_2_PDEV_SET_WMM_PARAMS_CMDID, + .pdev_set_ht_cap_ie_cmdid = WMI_10_2_PDEV_SET_HT_CAP_IE_CMDID, + .pdev_set_vht_cap_ie_cmdid = WMI_10_2_PDEV_SET_VHT_CAP_IE_CMDID, + .pdev_set_quiet_mode_cmdid = WMI_10_2_PDEV_SET_QUIET_MODE_CMDID, + .pdev_green_ap_ps_enable_cmdid = WMI_10_2_PDEV_GREEN_AP_PS_ENABLE_CMDID, + .pdev_get_tpc_config_cmdid = WMI_10_2_PDEV_GET_TPC_CONFIG_CMDID, + .pdev_set_base_macaddr_cmdid = WMI_10_2_PDEV_SET_BASE_MACADDR_CMDID, + .vdev_create_cmdid = WMI_10_2_VDEV_CREATE_CMDID, + .vdev_delete_cmdid = WMI_10_2_VDEV_DELETE_CMDID, + .vdev_start_request_cmdid = WMI_10_2_VDEV_START_REQUEST_CMDID, + .vdev_restart_request_cmdid = WMI_10_2_VDEV_RESTART_REQUEST_CMDID, + .vdev_up_cmdid = WMI_10_2_VDEV_UP_CMDID, + .vdev_stop_cmdid = WMI_10_2_VDEV_STOP_CMDID, + .vdev_down_cmdid = WMI_10_2_VDEV_DOWN_CMDID, + .vdev_set_param_cmdid = WMI_10_2_VDEV_SET_PARAM_CMDID, + .vdev_install_key_cmdid = WMI_10_2_VDEV_INSTALL_KEY_CMDID, + .peer_create_cmdid = WMI_10_2_PEER_CREATE_CMDID, + .peer_delete_cmdid = WMI_10_2_PEER_DELETE_CMDID, + .peer_flush_tids_cmdid = WMI_10_2_PEER_FLUSH_TIDS_CMDID, + .peer_set_param_cmdid = WMI_10_2_PEER_SET_PARAM_CMDID, + .peer_assoc_cmdid = WMI_10_2_PEER_ASSOC_CMDID, + .peer_add_wds_entry_cmdid = WMI_10_2_PEER_ADD_WDS_ENTRY_CMDID, + .peer_remove_wds_entry_cmdid = WMI_10_2_PEER_REMOVE_WDS_ENTRY_CMDID, + .peer_mcast_group_cmdid = WMI_10_2_PEER_MCAST_GROUP_CMDID, + .bcn_tx_cmdid = WMI_10_2_BCN_TX_CMDID, + .pdev_send_bcn_cmdid = WMI_10_2_PDEV_SEND_BCN_CMDID, + .bcn_tmpl_cmdid = WMI_CMD_UNSUPPORTED, + .bcn_filter_rx_cmdid = WMI_10_2_BCN_FILTER_RX_CMDID, + .prb_req_filter_rx_cmdid = WMI_10_2_PRB_REQ_FILTER_RX_CMDID, + .mgmt_tx_cmdid = WMI_10_2_MGMT_TX_CMDID, + .prb_tmpl_cmdid = WMI_CMD_UNSUPPORTED, + .addba_clear_resp_cmdid = WMI_10_2_ADDBA_CLEAR_RESP_CMDID, + .addba_send_cmdid = WMI_10_2_ADDBA_SEND_CMDID, + .addba_status_cmdid = WMI_10_2_ADDBA_STATUS_CMDID, + .delba_send_cmdid = WMI_10_2_DELBA_SEND_CMDID, + .addba_set_resp_cmdid = WMI_10_2_ADDBA_SET_RESP_CMDID, + .send_singleamsdu_cmdid = WMI_10_2_SEND_SINGLEAMSDU_CMDID, + .sta_powersave_mode_cmdid = WMI_10_2_STA_POWERSAVE_MODE_CMDID, + .sta_powersave_param_cmdid = WMI_10_2_STA_POWERSAVE_PARAM_CMDID, + .sta_mimo_ps_mode_cmdid = WMI_10_2_STA_MIMO_PS_MODE_CMDID, + .pdev_dfs_enable_cmdid = WMI_10_2_PDEV_DFS_ENABLE_CMDID, + .pdev_dfs_disable_cmdid = WMI_10_2_PDEV_DFS_DISABLE_CMDID, + .roam_scan_mode = WMI_10_2_ROAM_SCAN_MODE, + .roam_scan_rssi_threshold = WMI_10_2_ROAM_SCAN_RSSI_THRESHOLD, + .roam_scan_period = WMI_10_2_ROAM_SCAN_PERIOD, + .roam_scan_rssi_change_threshold = + WMI_10_2_ROAM_SCAN_RSSI_CHANGE_THRESHOLD, + .roam_ap_profile = WMI_10_2_ROAM_AP_PROFILE, + .ofl_scan_add_ap_profile = WMI_10_2_OFL_SCAN_ADD_AP_PROFILE, + .ofl_scan_remove_ap_profile = WMI_10_2_OFL_SCAN_REMOVE_AP_PROFILE, + .ofl_scan_period = WMI_10_2_OFL_SCAN_PERIOD, + .p2p_dev_set_device_info = WMI_10_2_P2P_DEV_SET_DEVICE_INFO, + .p2p_dev_set_discoverability = WMI_10_2_P2P_DEV_SET_DISCOVERABILITY, + .p2p_go_set_beacon_ie = WMI_10_2_P2P_GO_SET_BEACON_IE, + .p2p_go_set_probe_resp_ie = WMI_10_2_P2P_GO_SET_PROBE_RESP_IE, + .p2p_set_vendor_ie_data_cmdid = WMI_CMD_UNSUPPORTED, + .ap_ps_peer_param_cmdid = WMI_10_2_AP_PS_PEER_PARAM_CMDID, + .ap_ps_peer_uapsd_coex_cmdid = WMI_CMD_UNSUPPORTED, + .peer_rate_retry_sched_cmdid = WMI_10_2_PEER_RATE_RETRY_SCHED_CMDID, + .wlan_profile_trigger_cmdid = WMI_10_2_WLAN_PROFILE_TRIGGER_CMDID, + .wlan_profile_set_hist_intvl_cmdid = + WMI_10_2_WLAN_PROFILE_SET_HIST_INTVL_CMDID, + .wlan_profile_get_profile_data_cmdid = + WMI_10_2_WLAN_PROFILE_GET_PROFILE_DATA_CMDID, + .wlan_profile_enable_profile_id_cmdid = + WMI_10_2_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID, + .wlan_profile_list_profile_id_cmdid = + WMI_10_2_WLAN_PROFILE_LIST_PROFILE_ID_CMDID, + .pdev_suspend_cmdid = WMI_10_2_PDEV_SUSPEND_CMDID, + .pdev_resume_cmdid = WMI_10_2_PDEV_RESUME_CMDID, + .add_bcn_filter_cmdid = WMI_10_2_ADD_BCN_FILTER_CMDID, + .rmv_bcn_filter_cmdid = WMI_10_2_RMV_BCN_FILTER_CMDID, + .wow_add_wake_pattern_cmdid = WMI_10_2_WOW_ADD_WAKE_PATTERN_CMDID, + .wow_del_wake_pattern_cmdid = WMI_10_2_WOW_DEL_WAKE_PATTERN_CMDID, + .wow_enable_disable_wake_event_cmdid = + WMI_10_2_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID, + .wow_enable_cmdid = WMI_10_2_WOW_ENABLE_CMDID, + .wow_hostwakeup_from_sleep_cmdid = + WMI_10_2_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID, + .rtt_measreq_cmdid = WMI_10_2_RTT_MEASREQ_CMDID, + .rtt_tsf_cmdid = WMI_10_2_RTT_TSF_CMDID, + .vdev_spectral_scan_configure_cmdid = + WMI_10_2_VDEV_SPECTRAL_SCAN_CONFIGURE_CMDID, + .vdev_spectral_scan_enable_cmdid = + WMI_10_2_VDEV_SPECTRAL_SCAN_ENABLE_CMDID, + .request_stats_cmdid = WMI_10_2_REQUEST_STATS_CMDID, + .set_arp_ns_offload_cmdid = WMI_CMD_UNSUPPORTED, + .network_list_offload_config_cmdid = WMI_CMD_UNSUPPORTED, + .gtk_offload_cmdid = WMI_CMD_UNSUPPORTED, + .csa_offload_enable_cmdid = WMI_CMD_UNSUPPORTED, + .csa_offload_chanswitch_cmdid = WMI_CMD_UNSUPPORTED, + .chatter_set_mode_cmdid = WMI_CMD_UNSUPPORTED, + .peer_tid_addba_cmdid = WMI_CMD_UNSUPPORTED, + .peer_tid_delba_cmdid = WMI_CMD_UNSUPPORTED, + .sta_dtim_ps_method_cmdid = WMI_CMD_UNSUPPORTED, + .sta_uapsd_auto_trig_cmdid = WMI_CMD_UNSUPPORTED, + .sta_keepalive_cmd = WMI_CMD_UNSUPPORTED, + .echo_cmdid = WMI_10_2_ECHO_CMDID, + .pdev_utf_cmdid = WMI_10_2_PDEV_UTF_CMDID, + .dbglog_cfg_cmdid = WMI_10_2_DBGLOG_CFG_CMDID, + .pdev_qvit_cmdid = WMI_10_2_PDEV_QVIT_CMDID, + .pdev_ftm_intg_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_set_keepalive_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_get_keepalive_cmdid = WMI_CMD_UNSUPPORTED, + .force_fw_hang_cmdid = WMI_CMD_UNSUPPORTED, + .gpio_config_cmdid = WMI_10_2_GPIO_CONFIG_CMDID, + .gpio_output_cmdid = WMI_10_2_GPIO_OUTPUT_CMDID, +}; + int ath10k_wmi_wait_for_service_ready(struct ath10k *ar) { int ret; @@ -2325,20 +2446,144 @@ static void ath10k_wmi_10x_process_rx(struct ath10k *ar, struct sk_buff *skb) dev_kfree_skb(skb); } +static void ath10k_wmi_10_2_process_rx(struct ath10k *ar, struct sk_buff *skb) +{ + struct wmi_cmd_hdr *cmd_hdr; + enum wmi_10_2_event_id id; + + cmd_hdr = (struct wmi_cmd_hdr *)skb->data; + id = MS(__le32_to_cpu(cmd_hdr->cmd_id), WMI_CMD_HDR_CMD_ID); + + if (skb_pull(skb, sizeof(struct wmi_cmd_hdr)) == NULL) + return; + + trace_ath10k_wmi_event(id, skb->data, skb->len); + + switch (id) { + case WMI_10_2_MGMT_RX_EVENTID: + ath10k_wmi_event_mgmt_rx(ar, skb); + /* mgmt_rx() owns the skb now! */ + return; + case WMI_10_2_SCAN_EVENTID: + ath10k_wmi_event_scan(ar, skb); + break; + case WMI_10_2_CHAN_INFO_EVENTID: + ath10k_wmi_event_chan_info(ar, skb); + break; + case WMI_10_2_ECHO_EVENTID: + ath10k_wmi_event_echo(ar, skb); + break; + case WMI_10_2_DEBUG_MESG_EVENTID: + ath10k_wmi_event_debug_mesg(ar, skb); + break; + case WMI_10_2_UPDATE_STATS_EVENTID: + ath10k_wmi_event_update_stats(ar, skb); + break; + case WMI_10_2_VDEV_START_RESP_EVENTID: + ath10k_wmi_event_vdev_start_resp(ar, skb); + break; + case WMI_10_2_VDEV_STOPPED_EVENTID: + ath10k_wmi_event_vdev_stopped(ar, skb); + break; + case WMI_10_2_PEER_STA_KICKOUT_EVENTID: + ath10k_wmi_event_peer_sta_kickout(ar, skb); + break; + case WMI_10_2_HOST_SWBA_EVENTID: + ath10k_wmi_event_host_swba(ar, skb); + break; + case WMI_10_2_TBTTOFFSET_UPDATE_EVENTID: + ath10k_wmi_event_tbttoffset_update(ar, skb); + break; + case WMI_10_2_PHYERR_EVENTID: + ath10k_wmi_event_phyerr(ar, skb); + break; + case WMI_10_2_ROAM_EVENTID: + ath10k_wmi_event_roam(ar, skb); + break; + case WMI_10_2_PROFILE_MATCH: + ath10k_wmi_event_profile_match(ar, skb); + break; + case WMI_10_2_DEBUG_PRINT_EVENTID: + ath10k_wmi_event_debug_print(ar, skb); + break; + case WMI_10_2_PDEV_QVIT_EVENTID: + ath10k_wmi_event_pdev_qvit(ar, skb); + break; + case WMI_10_2_WLAN_PROFILE_DATA_EVENTID: + ath10k_wmi_event_wlan_profile_data(ar, skb); + break; + case WMI_10_2_RTT_MEASUREMENT_REPORT_EVENTID: + ath10k_wmi_event_rtt_measurement_report(ar, skb); + break; + case WMI_10_2_TSF_MEASUREMENT_REPORT_EVENTID: + ath10k_wmi_event_tsf_measurement_report(ar, skb); + break; + case WMI_10_2_RTT_ERROR_REPORT_EVENTID: + ath10k_wmi_event_rtt_error_report(ar, skb); + break; + case WMI_10_2_WOW_WAKEUP_HOST_EVENTID: + ath10k_wmi_event_wow_wakeup_host(ar, skb); + break; + case WMI_10_2_DCS_INTERFERENCE_EVENTID: + ath10k_wmi_event_dcs_interference(ar, skb); + break; + case WMI_10_2_PDEV_TPC_CONFIG_EVENTID: + ath10k_wmi_event_pdev_tpc_config(ar, skb); + break; + case WMI_10_2_INST_RSSI_STATS_EVENTID: + ath10k_wmi_event_inst_rssi_stats(ar, skb); + break; + case WMI_10_2_VDEV_STANDBY_REQ_EVENTID: + ath10k_wmi_event_vdev_standby_req(ar, skb); + break; + case WMI_10_2_VDEV_RESUME_REQ_EVENTID: + ath10k_wmi_event_vdev_resume_req(ar, skb); + break; + case WMI_10_2_SERVICE_READY_EVENTID: + ath10k_wmi_10x_service_ready_event_rx(ar, skb); + break; + case WMI_10_2_READY_EVENTID: + ath10k_wmi_ready_event_rx(ar, skb); + break; + case WMI_10_2_RTT_KEEPALIVE_EVENTID: + case WMI_10_2_GPIO_INPUT_EVENTID: + case WMI_10_2_PEER_RATECODE_LIST_EVENTID: + case WMI_10_2_GENERIC_BUFFER_EVENTID: + case WMI_10_2_MCAST_BUF_RELEASE_EVENTID: + case WMI_10_2_MCAST_LIST_AGEOUT_EVENTID: + case WMI_10_2_WDS_PEER_EVENTID: + ath10k_dbg(ATH10K_DBG_WMI, + "received event id %d not implemented\n", id); + break; + default: + ath10k_warn("Unknown eventid: %d\n", id); + break; + } + + dev_kfree_skb(skb); +} static void ath10k_wmi_process_rx(struct ath10k *ar, struct sk_buff *skb) { - if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) - ath10k_wmi_10x_process_rx(ar, skb); - else + if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) { + if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features)) + ath10k_wmi_10_2_process_rx(ar, skb); + else + ath10k_wmi_10x_process_rx(ar, skb); + } else { ath10k_wmi_main_process_rx(ar, skb); + } } /* WMI Initialization functions */ int ath10k_wmi_attach(struct ath10k *ar) { if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) { - ar->wmi.cmd = &wmi_10x_cmd_map; + if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features)) + ar->wmi.cmd = &wmi_10_2_cmd_map; + else + ar->wmi.cmd = &wmi_10x_cmd_map; + ar->wmi.vdev_param = &wmi_10x_vdev_param_map; ar->wmi.pdev_param = &wmi_10x_pdev_param_map; } else { @@ -2738,14 +2983,109 @@ out: return ath10k_wmi_cmd_send(ar, buf, ar->wmi.cmd->init_cmdid); } +static int ath10k_wmi_10_2_cmd_init(struct ath10k *ar) +{ + struct wmi_init_cmd_10_2 *cmd; + struct sk_buff *buf; + struct wmi_resource_config_10x config = {}; + u32 len, val; + int i; + + config.num_vdevs = __cpu_to_le32(TARGET_10X_NUM_VDEVS); + config.num_peers = __cpu_to_le32(TARGET_10X_NUM_PEERS); + config.num_peer_keys = __cpu_to_le32(TARGET_10X_NUM_PEER_KEYS); + config.num_tids = __cpu_to_le32(TARGET_10X_NUM_TIDS); + config.ast_skid_limit = __cpu_to_le32(TARGET_10X_AST_SKID_LIMIT); + config.tx_chain_mask = __cpu_to_le32(TARGET_10X_TX_CHAIN_MASK); + config.rx_chain_mask = __cpu_to_le32(TARGET_10X_RX_CHAIN_MASK); + config.rx_timeout_pri_vo = __cpu_to_le32(TARGET_10X_RX_TIMEOUT_LO_PRI); + config.rx_timeout_pri_vi = __cpu_to_le32(TARGET_10X_RX_TIMEOUT_LO_PRI); + config.rx_timeout_pri_be = __cpu_to_le32(TARGET_10X_RX_TIMEOUT_LO_PRI); + config.rx_timeout_pri_bk = __cpu_to_le32(TARGET_10X_RX_TIMEOUT_HI_PRI); + config.rx_decap_mode = __cpu_to_le32(TARGET_10X_RX_DECAP_MODE); + + config.scan_max_pending_reqs = + __cpu_to_le32(TARGET_10X_SCAN_MAX_PENDING_REQS); + + config.bmiss_offload_max_vdev = + __cpu_to_le32(TARGET_10X_BMISS_OFFLOAD_MAX_VDEV); + + config.roam_offload_max_vdev = + __cpu_to_le32(TARGET_10X_ROAM_OFFLOAD_MAX_VDEV); + + config.roam_offload_max_ap_profiles = + __cpu_to_le32(TARGET_10X_ROAM_OFFLOAD_MAX_AP_PROFILES); + + config.num_mcast_groups = __cpu_to_le32(TARGET_10X_NUM_MCAST_GROUPS); + config.num_mcast_table_elems = + __cpu_to_le32(TARGET_10X_NUM_MCAST_TABLE_ELEMS); + + config.mcast2ucast_mode = __cpu_to_le32(TARGET_10X_MCAST2UCAST_MODE); + config.tx_dbg_log_size = __cpu_to_le32(TARGET_10X_TX_DBG_LOG_SIZE); + config.num_wds_entries = __cpu_to_le32(TARGET_10X_NUM_WDS_ENTRIES); + config.dma_burst_size = __cpu_to_le32(TARGET_10X_DMA_BURST_SIZE); + config.mac_aggr_delim = __cpu_to_le32(TARGET_10X_MAC_AGGR_DELIM); + + val = TARGET_10X_RX_SKIP_DEFRAG_TIMEOUT_DUP_DETECTION_CHECK; + config.rx_skip_defrag_timeout_dup_detection_check = __cpu_to_le32(val); + + config.vow_config = __cpu_to_le32(TARGET_10X_VOW_CONFIG); + + config.num_msdu_desc = __cpu_to_le32(TARGET_10X_NUM_MSDU_DESC); + config.max_frag_entries = __cpu_to_le32(TARGET_10X_MAX_FRAG_ENTRIES); + + len = sizeof(*cmd) + + (sizeof(struct host_memory_chunk) * ar->wmi.num_mem_chunks); + + buf = ath10k_wmi_alloc_skb(len); + if (!buf) + return -ENOMEM; + + cmd = (struct wmi_init_cmd_10_2 *)buf->data; + + if (ar->wmi.num_mem_chunks == 0) { + cmd->num_host_mem_chunks = 0; + goto out; + } + + ath10k_dbg(ATH10K_DBG_WMI, "wmi sending %d memory chunks info.\n", + ar->wmi.num_mem_chunks); + + cmd->num_host_mem_chunks = __cpu_to_le32(ar->wmi.num_mem_chunks); + + for (i = 0; i < ar->wmi.num_mem_chunks; i++) { + cmd->host_mem_chunks[i].ptr = + __cpu_to_le32(ar->wmi.mem_chunks[i].paddr); + cmd->host_mem_chunks[i].size = + __cpu_to_le32(ar->wmi.mem_chunks[i].len); + cmd->host_mem_chunks[i].req_id = + __cpu_to_le32(ar->wmi.mem_chunks[i].req_id); + + ath10k_dbg(ATH10K_DBG_WMI, + "wmi chunk %d len %d requested, addr 0x%llx\n", + i, + ar->wmi.mem_chunks[i].len, + (unsigned long long)ar->wmi.mem_chunks[i].paddr); + } +out: + memcpy(&cmd->resource_config.common, &config, sizeof(config)); + + ath10k_dbg(ATH10K_DBG_WMI, "wmi init 10.2\n"); + return ath10k_wmi_cmd_send(ar, buf, ar->wmi.cmd->init_cmdid); +} + int ath10k_wmi_cmd_init(struct ath10k *ar) { int ret; - if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) - ret = ath10k_wmi_10x_cmd_init(ar); - else + if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) { + if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features)) + ret = ath10k_wmi_10_2_cmd_init(ar); + else + ret = ath10k_wmi_10x_cmd_init(ar); + } else { ret = ath10k_wmi_main_cmd_init(ar); + } return ret; } @@ -2865,8 +3205,8 @@ int ath10k_wmi_start_scan(struct ath10k *ar, channels->num_chan = __cpu_to_le32(arg->n_channels); for (i = 0; i < arg->n_channels; i++) - channels->channel_list[i] = - __cpu_to_le32(arg->channels[i]); + channels->channel_list[i].freq = + __cpu_to_le16(arg->channels[i]); off += sizeof(*channels); off += sizeof(__le32) * arg->n_channels; @@ -3447,24 +3787,12 @@ int ath10k_wmi_scan_chan_list(struct ath10k *ar, return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->scan_chan_list_cmdid); } -int ath10k_wmi_peer_assoc(struct ath10k *ar, - const struct wmi_peer_assoc_complete_arg *arg) +static void +ath10k_wmi_peer_assoc_fill(struct ath10k *ar, void *buf, + const struct wmi_peer_assoc_complete_arg *arg) { - struct wmi_peer_assoc_complete_cmd *cmd; - struct sk_buff *skb; + struct wmi_common_peer_assoc_complete_cmd *cmd = buf; - if (arg->peer_mpdu_density > 16) - return -EINVAL; - if (arg->peer_legacy_rates.num_rates > MAX_SUPPORTED_RATES) - return -EINVAL; - if (arg->peer_ht_rates.num_rates > MAX_SUPPORTED_RATES) - return -EINVAL; - - skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); - if (!skb) - return -ENOMEM; - - cmd = (struct wmi_peer_assoc_complete_cmd *)skb->data; cmd->vdev_id = __cpu_to_le32(arg->vdev_id); cmd->peer_new_assoc = __cpu_to_le32(arg->peer_reassoc ? 0 : 1); cmd->peer_associd = __cpu_to_le32(arg->peer_aid); @@ -3499,6 +3827,78 @@ int ath10k_wmi_peer_assoc(struct ath10k *ar, __cpu_to_le32(arg->peer_vht_rates.tx_max_rate); cmd->peer_vht_rates.tx_mcs_set = __cpu_to_le32(arg->peer_vht_rates.tx_mcs_set); +} + +static void +ath10k_wmi_peer_assoc_fill_main(struct ath10k *ar, void *buf, + const struct wmi_peer_assoc_complete_arg *arg) +{ + struct wmi_main_peer_assoc_complete_cmd *cmd = buf; + + ath10k_wmi_peer_assoc_fill(ar, buf, arg); + memset(cmd->peer_ht_info, 0, sizeof(cmd->peer_ht_info)); +} + +static void +ath10k_wmi_peer_assoc_fill_10_1(struct ath10k *ar, void *buf, + const struct wmi_peer_assoc_complete_arg *arg) +{ + ath10k_wmi_peer_assoc_fill(ar, buf, arg); +} + +static void +ath10k_wmi_peer_assoc_fill_10_2(struct ath10k *ar, void *buf, + const struct wmi_peer_assoc_complete_arg *arg) +{ + struct wmi_10_2_peer_assoc_complete_cmd *cmd = buf; + int max_mcs, max_nss; + u32 info0; + + /* TODO: Is using max values okay with firmware? */ + max_mcs = 0xf; + max_nss = 0xf; + + info0 = SM(max_mcs, WMI_PEER_ASSOC_INFO0_MAX_MCS_IDX) | + SM(max_nss, WMI_PEER_ASSOC_INFO0_MAX_NSS); + + ath10k_wmi_peer_assoc_fill(ar, buf, arg); + cmd->info0 = __cpu_to_le32(info0); +} + +int ath10k_wmi_peer_assoc(struct ath10k *ar, + const struct wmi_peer_assoc_complete_arg *arg) +{ + struct sk_buff *skb; + int len; + + if (arg->peer_mpdu_density > 16) + return -EINVAL; + if (arg->peer_legacy_rates.num_rates > MAX_SUPPORTED_RATES) + return -EINVAL; + if (arg->peer_ht_rates.num_rates > MAX_SUPPORTED_RATES) + return -EINVAL; + + if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) { + if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features)) + len = sizeof(struct wmi_10_2_peer_assoc_complete_cmd); + else + len = sizeof(struct wmi_10_1_peer_assoc_complete_cmd); + } else { + len = sizeof(struct wmi_main_peer_assoc_complete_cmd); + } + + skb = ath10k_wmi_alloc_skb(len); + if (!skb) + return -ENOMEM; + + if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) { + if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features)) + ath10k_wmi_peer_assoc_fill_10_1(ar, skb->data, arg); + else + ath10k_wmi_peer_assoc_fill_10_2(ar, skb->data, arg); + } else { + ath10k_wmi_peer_assoc_fill_main(ar, skb->data, arg); + } ath10k_dbg(ATH10K_DBG_WMI, "wmi peer assoc vdev %d addr %pM (%s)\n", @@ -3532,6 +3932,7 @@ int ath10k_wmi_beacon_send_ref_nowait(struct ath10k_vif *arvif) cmd->msdu_id = 0; cmd->frame_control = __cpu_to_le32(fc); cmd->flags = 0; + cmd->antenna_mask = __cpu_to_le32(WMI_BCN_TX_REF_DEF_ANTENNA); if (ATH10K_SKB_CB(beacon)->bcn.dtim_zero) cmd->flags |= __cpu_to_le32(WMI_BCN_TX_REF_FLAG_DTIM_ZERO); diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index e93df2c10413..c9ac11cbc5d2 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -803,6 +803,159 @@ enum wmi_10x_event_id { WMI_10X_PDEV_UTF_EVENTID = WMI_10X_END_EVENTID-1, }; +enum wmi_10_2_cmd_id { + WMI_10_2_START_CMDID = 0x9000, + WMI_10_2_END_CMDID = 0x9FFF, + WMI_10_2_INIT_CMDID, + WMI_10_2_START_SCAN_CMDID = WMI_10_2_START_CMDID, + WMI_10_2_STOP_SCAN_CMDID, + WMI_10_2_SCAN_CHAN_LIST_CMDID, + WMI_10_2_ECHO_CMDID, + WMI_10_2_PDEV_SET_REGDOMAIN_CMDID, + WMI_10_2_PDEV_SET_CHANNEL_CMDID, + WMI_10_2_PDEV_SET_PARAM_CMDID, + WMI_10_2_PDEV_PKTLOG_ENABLE_CMDID, + WMI_10_2_PDEV_PKTLOG_DISABLE_CMDID, + WMI_10_2_PDEV_SET_WMM_PARAMS_CMDID, + WMI_10_2_PDEV_SET_HT_CAP_IE_CMDID, + WMI_10_2_PDEV_SET_VHT_CAP_IE_CMDID, + WMI_10_2_PDEV_SET_BASE_MACADDR_CMDID, + WMI_10_2_PDEV_SET_QUIET_MODE_CMDID, + WMI_10_2_PDEV_GREEN_AP_PS_ENABLE_CMDID, + WMI_10_2_PDEV_GET_TPC_CONFIG_CMDID, + WMI_10_2_VDEV_CREATE_CMDID, + WMI_10_2_VDEV_DELETE_CMDID, + WMI_10_2_VDEV_START_REQUEST_CMDID, + WMI_10_2_VDEV_RESTART_REQUEST_CMDID, + WMI_10_2_VDEV_UP_CMDID, + WMI_10_2_VDEV_STOP_CMDID, + WMI_10_2_VDEV_DOWN_CMDID, + WMI_10_2_VDEV_STANDBY_RESPONSE_CMDID, + WMI_10_2_VDEV_RESUME_RESPONSE_CMDID, + WMI_10_2_VDEV_SET_PARAM_CMDID, + WMI_10_2_VDEV_INSTALL_KEY_CMDID, + WMI_10_2_VDEV_SET_DSCP_TID_MAP_CMDID, + WMI_10_2_PEER_CREATE_CMDID, + WMI_10_2_PEER_DELETE_CMDID, + WMI_10_2_PEER_FLUSH_TIDS_CMDID, + WMI_10_2_PEER_SET_PARAM_CMDID, + WMI_10_2_PEER_ASSOC_CMDID, + WMI_10_2_PEER_ADD_WDS_ENTRY_CMDID, + WMI_10_2_PEER_UPDATE_WDS_ENTRY_CMDID, + WMI_10_2_PEER_REMOVE_WDS_ENTRY_CMDID, + WMI_10_2_PEER_MCAST_GROUP_CMDID, + WMI_10_2_BCN_TX_CMDID, + WMI_10_2_BCN_PRB_TMPL_CMDID, + WMI_10_2_BCN_FILTER_RX_CMDID, + WMI_10_2_PRB_REQ_FILTER_RX_CMDID, + WMI_10_2_MGMT_TX_CMDID, + WMI_10_2_ADDBA_CLEAR_RESP_CMDID, + WMI_10_2_ADDBA_SEND_CMDID, + WMI_10_2_ADDBA_STATUS_CMDID, + WMI_10_2_DELBA_SEND_CMDID, + WMI_10_2_ADDBA_SET_RESP_CMDID, + WMI_10_2_SEND_SINGLEAMSDU_CMDID, + WMI_10_2_STA_POWERSAVE_MODE_CMDID, + WMI_10_2_STA_POWERSAVE_PARAM_CMDID, + WMI_10_2_STA_MIMO_PS_MODE_CMDID, + WMI_10_2_DBGLOG_CFG_CMDID, + WMI_10_2_PDEV_DFS_ENABLE_CMDID, + WMI_10_2_PDEV_DFS_DISABLE_CMDID, + WMI_10_2_PDEV_QVIT_CMDID, + WMI_10_2_ROAM_SCAN_MODE, + WMI_10_2_ROAM_SCAN_RSSI_THRESHOLD, + WMI_10_2_ROAM_SCAN_PERIOD, + WMI_10_2_ROAM_SCAN_RSSI_CHANGE_THRESHOLD, + WMI_10_2_ROAM_AP_PROFILE, + WMI_10_2_OFL_SCAN_ADD_AP_PROFILE, + WMI_10_2_OFL_SCAN_REMOVE_AP_PROFILE, + WMI_10_2_OFL_SCAN_PERIOD, + WMI_10_2_P2P_DEV_SET_DEVICE_INFO, + WMI_10_2_P2P_DEV_SET_DISCOVERABILITY, + WMI_10_2_P2P_GO_SET_BEACON_IE, + WMI_10_2_P2P_GO_SET_PROBE_RESP_IE, + WMI_10_2_AP_PS_PEER_PARAM_CMDID, + WMI_10_2_AP_PS_PEER_UAPSD_COEX_CMDID, + WMI_10_2_PEER_RATE_RETRY_SCHED_CMDID, + WMI_10_2_WLAN_PROFILE_TRIGGER_CMDID, + WMI_10_2_WLAN_PROFILE_SET_HIST_INTVL_CMDID, + WMI_10_2_WLAN_PROFILE_GET_PROFILE_DATA_CMDID, + WMI_10_2_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID, + WMI_10_2_WLAN_PROFILE_LIST_PROFILE_ID_CMDID, + WMI_10_2_PDEV_SUSPEND_CMDID, + WMI_10_2_PDEV_RESUME_CMDID, + WMI_10_2_ADD_BCN_FILTER_CMDID, + WMI_10_2_RMV_BCN_FILTER_CMDID, + WMI_10_2_WOW_ADD_WAKE_PATTERN_CMDID, + WMI_10_2_WOW_DEL_WAKE_PATTERN_CMDID, + WMI_10_2_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID, + WMI_10_2_WOW_ENABLE_CMDID, + WMI_10_2_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID, + WMI_10_2_RTT_MEASREQ_CMDID, + WMI_10_2_RTT_TSF_CMDID, + WMI_10_2_RTT_KEEPALIVE_CMDID, + WMI_10_2_PDEV_SEND_BCN_CMDID, + WMI_10_2_VDEV_SPECTRAL_SCAN_CONFIGURE_CMDID, + WMI_10_2_VDEV_SPECTRAL_SCAN_ENABLE_CMDID, + WMI_10_2_REQUEST_STATS_CMDID, + WMI_10_2_GPIO_CONFIG_CMDID, + WMI_10_2_GPIO_OUTPUT_CMDID, + WMI_10_2_VDEV_RATEMASK_CMDID, + WMI_10_2_PDEV_SMART_ANT_ENABLE_CMDID, + WMI_10_2_PDEV_SMART_ANT_SET_RX_ANTENNA_CMDID, + WMI_10_2_PEER_SMART_ANT_SET_TX_ANTENNA_CMDID, + WMI_10_2_PEER_SMART_ANT_SET_TRAIN_INFO_CMDID, + WMI_10_2_PEER_SMART_ANT_SET_NODE_CONFIG_OPS_CMDID, + WMI_10_2_FORCE_FW_HANG_CMDID, + WMI_10_2_PDEV_SET_ANTENNA_SWITCH_TABLE_CMDID, + WMI_10_2_PDEV_SET_CTL_TABLE_CMDID, + WMI_10_2_PDEV_SET_MIMOGAIN_TABLE_CMDID, + WMI_10_2_PDEV_RATEPWR_TABLE_CMDID, + WMI_10_2_PDEV_RATEPWR_CHAINMSK_TABLE_CMDID, + WMI_10_2_PDEV_UTF_CMDID = WMI_10_2_END_CMDID - 1, +}; + +enum wmi_10_2_event_id { + WMI_10_2_SERVICE_READY_EVENTID = 0x8000, + WMI_10_2_READY_EVENTID, + WMI_10_2_DEBUG_MESG_EVENTID, + WMI_10_2_START_EVENTID = 0x9000, + WMI_10_2_END_EVENTID = 0x9FFF, + WMI_10_2_SCAN_EVENTID = WMI_10_2_START_EVENTID, + WMI_10_2_ECHO_EVENTID, + WMI_10_2_UPDATE_STATS_EVENTID, + WMI_10_2_INST_RSSI_STATS_EVENTID, + WMI_10_2_VDEV_START_RESP_EVENTID, + WMI_10_2_VDEV_STANDBY_REQ_EVENTID, + WMI_10_2_VDEV_RESUME_REQ_EVENTID, + WMI_10_2_VDEV_STOPPED_EVENTID, + WMI_10_2_PEER_STA_KICKOUT_EVENTID, + WMI_10_2_HOST_SWBA_EVENTID, + WMI_10_2_TBTTOFFSET_UPDATE_EVENTID, + WMI_10_2_MGMT_RX_EVENTID, + WMI_10_2_CHAN_INFO_EVENTID, + WMI_10_2_PHYERR_EVENTID, + WMI_10_2_ROAM_EVENTID, + WMI_10_2_PROFILE_MATCH, + WMI_10_2_DEBUG_PRINT_EVENTID, + WMI_10_2_PDEV_QVIT_EVENTID, + WMI_10_2_WLAN_PROFILE_DATA_EVENTID, + WMI_10_2_RTT_MEASUREMENT_REPORT_EVENTID, + WMI_10_2_TSF_MEASUREMENT_REPORT_EVENTID, + WMI_10_2_RTT_ERROR_REPORT_EVENTID, + WMI_10_2_RTT_KEEPALIVE_EVENTID, + WMI_10_2_WOW_WAKEUP_HOST_EVENTID, + WMI_10_2_DCS_INTERFERENCE_EVENTID, + WMI_10_2_PDEV_TPC_CONFIG_EVENTID, + WMI_10_2_GPIO_INPUT_EVENTID, + WMI_10_2_PEER_RATECODE_LIST_EVENTID, + WMI_10_2_GENERIC_BUFFER_EVENTID, + WMI_10_2_MCAST_BUF_RELEASE_EVENTID, + WMI_10_2_MCAST_LIST_AGEOUT_EVENTID, + WMI_10_2_WDS_PEER_EVENTID, + WMI_10_2_PDEV_UTF_EVENTID = WMI_10_2_END_EVENTID - 1, +}; + enum wmi_phy_mode { MODE_11A = 0, /* 11a Mode */ MODE_11G = 1, /* 11b/g Mode */ @@ -1551,6 +1704,16 @@ struct wmi_resource_config_10x { __le32 max_frag_entries; } __packed; +struct wmi_resource_config_10_2 { + struct wmi_resource_config_10x common; + __le32 max_peer_ext_stats; + __le32 smart_ant_cap; /* 0-disable, 1-enable */ + __le32 bk_min_free; + __le32 be_min_free; + __le32 vi_min_free; + __le32 vo_min_free; + __le32 rx_batchmode; /* 0-disable, 1-enable */ +} __packed; #define NUM_UNITS_IS_NUM_VDEVS 0x1 #define NUM_UNITS_IS_NUM_PEERS 0x2 @@ -1588,11 +1751,28 @@ struct wmi_init_cmd_10x { struct host_memory_chunk host_mem_chunks[1]; } __packed; +struct wmi_init_cmd_10_2 { + struct wmi_resource_config_10_2 resource_config; + __le32 num_host_mem_chunks; + + /* + * variable number of host memory chunks. + * This should be the last element in the structure + */ + struct host_memory_chunk host_mem_chunks[1]; +} __packed; + +struct wmi_chan_list_entry { + __le16 freq; + u8 phy_mode; /* valid for 10.2 only */ + u8 reserved; +} __packed; + /* TLV for channel list */ struct wmi_chan_list { __le32 tag; /* WMI_CHAN_LIST_TAG */ __le32 num_chan; - __le32 channel_list[0]; + struct wmi_chan_list_entry channel_list[0]; } __packed; struct wmi_bssid_list { @@ -1821,7 +2001,7 @@ struct wmi_start_scan_arg { u32 n_bssids; u8 ie[WLAN_SCAN_PARAMS_MAX_IE_LEN]; - u32 channels[64]; + u16 channels[64]; struct wmi_ssid_arg ssids[WLAN_SCAN_PARAMS_MAX_SSID]; struct wmi_bssid_arg bssids[WLAN_SCAN_PARAMS_MAX_BSSID]; }; @@ -2515,6 +2695,19 @@ enum wmi_10x_pdev_param { WMI_10X_PDEV_PARAM_BURST_DUR, /* Set Bursting Enable*/ WMI_10X_PDEV_PARAM_BURST_ENABLE, + + /* following are available as of firmware 10.2 */ + WMI_10X_PDEV_PARAM_SMART_ANTENNA_DEFAULT_ANTENNA, + WMI_10X_PDEV_PARAM_IGMPMLD_OVERRIDE, + WMI_10X_PDEV_PARAM_IGMPMLD_TID, + WMI_10X_PDEV_PARAM_ANTENNA_GAIN, + WMI_10X_PDEV_PARAM_RX_DECAP_MODE, + WMI_10X_PDEV_PARAM_RX_FILTER, + WMI_10X_PDEV_PARAM_SET_MCAST_TO_UCAST_TID, + WMI_10X_PDEV_PARAM_PROXY_STA_MODE, + WMI_10X_PDEV_PARAM_SET_MCAST2UCAST_MODE, + WMI_10X_PDEV_PARAM_SET_MCAST2UCAST_BUFFER, + WMI_10X_PDEV_PARAM_REMOVE_MCAST2UCAST_BUFFER, }; struct wmi_pdev_set_param_cmd { @@ -3387,6 +3580,14 @@ enum wmi_10x_vdev_param { WMI_10X_VDEV_PARAM_ENABLE_RTSCTS, WMI_10X_VDEV_PARAM_AP_DETECT_OUT_OF_SYNC_SLEEPING_STA_TIME_SECS, + + /* following are available as of firmware 10.2 */ + WMI_10X_VDEV_PARAM_TX_ENCAP_TYPE, + WMI_10X_VDEV_PARAM_CABQ_MAXDUR, + WMI_10X_VDEV_PARAM_MFPTEST_SET, + WMI_10X_VDEV_PARAM_RTS_FIXED_RATE, + WMI_10X_VDEV_PARAM_VHT_SGIMASK, + WMI_10X_VDEV_PARAM_VHT80_RATEMASK, }; /* slot time long */ @@ -3470,6 +3671,11 @@ enum wmi_bcn_tx_ref_flags { WMI_BCN_TX_REF_FLAG_DELIVER_CAB = 0x2, }; +/* TODO: It is unclear why "no antenna" works while any other seemingly valid + * chainmask yields no beacons on the air at all. + */ +#define WMI_BCN_TX_REF_DEF_ANTENNA 0 + struct wmi_bcn_tx_ref_cmd { __le32 vdev_id; __le32 data_len; @@ -3481,6 +3687,8 @@ struct wmi_bcn_tx_ref_cmd { __le32 frame_control; /* to control CABQ traffic: WMI_BCN_TX_REF_FLAG_ */ __le32 flags; + /* introduced in 10.2 */ + __le32 antenna_mask; } __packed; /* Beacon filter */ @@ -4053,7 +4261,7 @@ struct wmi_peer_set_q_empty_callback_cmd { /* Maximum listen interval supported by hw in units of beacon interval */ #define ATH10K_MAX_HW_LISTEN_INTERVAL 5 -struct wmi_peer_assoc_complete_cmd { +struct wmi_common_peer_assoc_complete_cmd { struct wmi_mac_addr peer_macaddr; __le32 vdev_id; __le32 peer_new_assoc; /* 1=assoc, 0=reassoc */ @@ -4071,11 +4279,30 @@ struct wmi_peer_assoc_complete_cmd { __le32 peer_vht_caps; __le32 peer_phymode; struct wmi_vht_rate_set peer_vht_rates; +}; + +struct wmi_main_peer_assoc_complete_cmd { + struct wmi_common_peer_assoc_complete_cmd cmd; + /* HT Operation Element of the peer. Five bytes packed in 2 * INT32 array and filled from lsb to msb. */ __le32 peer_ht_info[2]; } __packed; +struct wmi_10_1_peer_assoc_complete_cmd { + struct wmi_common_peer_assoc_complete_cmd cmd; +} __packed; + +#define WMI_PEER_ASSOC_INFO0_MAX_MCS_IDX_LSB 0 +#define WMI_PEER_ASSOC_INFO0_MAX_MCS_IDX_MASK 0x0f +#define WMI_PEER_ASSOC_INFO0_MAX_NSS_LSB 4 +#define WMI_PEER_ASSOC_INFO0_MAX_NSS_MASK 0xf0 + +struct wmi_10_2_peer_assoc_complete_cmd { + struct wmi_common_peer_assoc_complete_cmd cmd; + __le32 info0; /* WMI_PEER_ASSOC_INFO0_ */ +} __packed; + struct wmi_peer_assoc_complete_arg { u8 addr[ETH_ALEN]; u32 vdev_id; From 72bdeb86552f8d992aa854af4e320401d8dd5cb5 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Mon, 28 Jul 2014 23:59:42 +0300 Subject: [PATCH 003/221] ath10k: fix aggregated 4addr Rx A-MSDU 4addr frames weren't reconstructed properly and in some cases this resulted in a warning: br0: received packet on wlan0.sta1 with own address as source address Since this was only related to A-MSDU it would trigger when more intense traffic was generated. Reported-by: Vu Hai NGUYEN Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt_rx.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 80cdac15588a..e31d93e3e98b 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -866,7 +866,7 @@ static void ath10k_htt_rx_amsdu(struct ath10k_htt *htt, enum rx_msdu_decap_format fmt; enum htt_rx_mpdu_encrypt_type enctype; struct ieee80211_hdr *hdr; - u8 hdr_buf[64], addr[ETH_ALEN], *qos; + u8 hdr_buf[64], da[ETH_ALEN], sa[ETH_ALEN], *qos; unsigned int hdr_len; rxd = (void *)skb->data - sizeof(*rxd); @@ -904,10 +904,11 @@ static void ath10k_htt_rx_amsdu(struct ath10k_htt *htt, skb_trim(skb, skb->len - FCS_LEN); break; case RX_MSDU_DECAP_NATIVE_WIFI: - /* pull decapped header and copy DA */ + /* pull decapped header and copy SA & DA */ hdr = (struct ieee80211_hdr *)skb->data; hdr_len = ath10k_htt_rx_nwifi_hdrlen(hdr); - memcpy(addr, ieee80211_get_DA(hdr), ETH_ALEN); + memcpy(da, ieee80211_get_DA(hdr), ETH_ALEN); + memcpy(sa, ieee80211_get_SA(hdr), ETH_ALEN); skb_pull(skb, hdr_len); /* push original 802.11 header */ @@ -921,8 +922,11 @@ static void ath10k_htt_rx_amsdu(struct ath10k_htt *htt, qos = ieee80211_get_qos_ctl(hdr); qos[0] &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT; - /* original 802.11 header has a different DA */ - memcpy(ieee80211_get_DA(hdr), addr, ETH_ALEN); + /* original 802.11 header has a different DA and in + * case of 4addr it may also have different SA + */ + memcpy(ieee80211_get_DA(hdr), da, ETH_ALEN); + memcpy(ieee80211_get_SA(hdr), sa, ETH_ALEN); break; case RX_MSDU_DECAP_ETHERNET2_DIX: /* strip ethernet header and insert decapped 802.11 From 76f5329a3dfe2f95dcc5664db603a2f1b0c9b825 Mon Sep 17 00:00:00 2001 From: Janusz Dziedzic Date: Mon, 28 Jul 2014 23:59:43 +0300 Subject: [PATCH 004/221] ath10k: extend debug code for RX path Print sequence number, AMSDU_MORE flag and AC when additional debug enabled in RX path. This is usefull for debugging purpose. Signed-off-by: Janusz Dziedzic Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt_rx.c | 41 ++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index e31d93e3e98b..763d6a228a13 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -819,19 +819,55 @@ static bool ath10k_htt_rx_h_channel(struct ath10k *ar, return true; } +static const char * const tid_to_ac[] = { + "BE", + "BK", + "BK", + "BE", + "VI", + "VI", + "VO", + "VO", +}; + +static char *ath10k_get_tid(struct ieee80211_hdr *hdr, char *out, size_t size) +{ + u8 *qc; + int tid; + + if (!ieee80211_is_data_qos(hdr->frame_control)) + return ""; + + qc = ieee80211_get_qos_ctl(hdr); + tid = *qc & IEEE80211_QOS_CTL_TID_MASK; + if (tid < 8) + snprintf(out, size, "tid %d (%s)", tid, tid_to_ac[tid]); + else + snprintf(out, size, "tid %d", tid); + + return out; +} + static void ath10k_process_rx(struct ath10k *ar, struct ieee80211_rx_status *rx_status, struct sk_buff *skb) { struct ieee80211_rx_status *status; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + char tid[32]; status = IEEE80211_SKB_RXCB(skb); *status = *rx_status; ath10k_dbg(ATH10K_DBG_DATA, - "rx skb %p len %u %s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %imic-err %i\n", + "rx skb %p len %u peer %pM %s %s sn %u %s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i mic-err %i amsdu-more %i\n", skb, skb->len, + ieee80211_get_SA(hdr), + ath10k_get_tid(hdr, tid, sizeof(tid)), + is_multicast_ether_addr(ieee80211_get_DA(hdr)) ? + "mcast" : "ucast", + (__le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4, status->flag == 0 ? "legacy" : "", status->flag & RX_FLAG_HT ? "ht" : "", status->flag & RX_FLAG_VHT ? "vht" : "", @@ -843,7 +879,8 @@ static void ath10k_process_rx(struct ath10k *ar, status->freq, status->band, status->flag, !!(status->flag & RX_FLAG_FAILED_FCS_CRC), - !!(status->flag & RX_FLAG_MMIC_ERROR)); + !!(status->flag & RX_FLAG_MMIC_ERROR), + !!(status->flag & RX_FLAG_AMSDU_MORE)); ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "rx skb: ", skb->data, skb->len); From dc55e3074ca150d5820fd4be5d4afd6cb5e876ad Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Tue, 29 Jul 2014 12:53:36 +0300 Subject: [PATCH 005/221] ath10k: improve channel switching In some cases during heavy tx vdev stop-start would timeout on vdev synchronization causing traffic to stall for a few seconds. Instead of stop-starting use a dedicated vdev restart command and down vdevs explicitly before doing so. This gets rid of the synchronization warnings/timeouts and makes channel switching smoother during traffic. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 31 +++++++++++++++++++++------ 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 9d61bb157189..b76efe25f54b 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -796,7 +796,7 @@ static void ath10k_recalc_radar_detection(struct ath10k *ar) } } -static int ath10k_vdev_start(struct ath10k_vif *arvif) +static int ath10k_vdev_start_restart(struct ath10k_vif *arvif, bool restart) { struct ath10k *ar = arvif->ar; struct cfg80211_chan_def *chandef = &ar->chandef; @@ -838,7 +838,11 @@ static int ath10k_vdev_start(struct ath10k_vif *arvif) arg.vdev_id, arg.channel.freq, ath10k_wmi_phymode_str(arg.channel.mode)); - ret = ath10k_wmi_vdev_start(ar, &arg); + if (restart) + ret = ath10k_wmi_vdev_restart(ar, &arg); + else + ret = ath10k_wmi_vdev_start(ar, &arg); + if (ret) { ath10k_warn("failed to start WMI vdev %i: %d\n", arg.vdev_id, ret); @@ -858,6 +862,16 @@ static int ath10k_vdev_start(struct ath10k_vif *arvif) return ret; } +static int ath10k_vdev_start(struct ath10k_vif *arvif) +{ + return ath10k_vdev_start_restart(arvif, false); +} + +static int ath10k_vdev_restart(struct ath10k_vif *arvif) +{ + return ath10k_vdev_start_restart(arvif, true); +} + static int ath10k_vdev_stop(struct ath10k_vif *arvif) { struct ath10k *ar = arvif->ar; @@ -2582,18 +2596,21 @@ static void ath10k_config_chan(struct ath10k *ar) if (!arvif->is_started) continue; + if (!arvif->is_up) + continue; + if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) continue; - ret = ath10k_vdev_stop(arvif); + ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id); if (ret) { - ath10k_warn("failed to stop vdev %d: %d\n", + ath10k_warn("failed to down vdev %d: %d\n", arvif->vdev_id, ret); continue; } } - /* all vdevs are now stopped - now attempt to restart them */ + /* all vdevs are downed now - attempt to restart and re-up them */ list_for_each_entry(arvif, &ar->arvifs, list) { if (!arvif->is_started) @@ -2602,9 +2619,9 @@ static void ath10k_config_chan(struct ath10k *ar) if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) continue; - ret = ath10k_vdev_start(arvif); + ret = ath10k_vdev_restart(arvif); if (ret) { - ath10k_warn("failed to start vdev %d: %d\n", + ath10k_warn("failed to restart vdev %d: %d\n", arvif->vdev_id, ret); continue; } From 95752b759e2e1d9c590252a92e080eeb611fdbcd Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Sat, 2 Aug 2014 09:12:53 +0300 Subject: [PATCH 006/221] ath: Move spectral debugfs structs to shared header The ath9k and ath10k will share the definitions of the debugfs spectral structures and enums. Having them in the same place helps to avoid conflicts. Signed-off-by: Sven Eckelmann Signed-off-by: Simon Wunderlich Signed-off-by: Mathias Kretschmer Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/spectral.h | 71 +---------------- drivers/net/wireless/ath/spectral_common.h | 88 ++++++++++++++++++++++ 2 files changed, 90 insertions(+), 69 deletions(-) create mode 100644 drivers/net/wireless/ath/spectral_common.h diff --git a/drivers/net/wireless/ath/ath9k/spectral.h b/drivers/net/wireless/ath/ath9k/spectral.h index ead63412ee1a..7b410c6858b0 100644 --- a/drivers/net/wireless/ath/ath9k/spectral.h +++ b/drivers/net/wireless/ath/ath9k/spectral.h @@ -17,6 +17,8 @@ #ifndef SPECTRAL_H #define SPECTRAL_H +#include "../spectral_common.h" + /* enum spectral_mode: * * @SPECTRAL_DISABLED: spectral mode is disabled @@ -54,8 +56,6 @@ struct ath_ht20_mag_info { u8 max_exp; } __packed; -#define SPECTRAL_HT20_NUM_BINS 56 - /* WARNING: don't actually use this struct! MAC may vary the amount of * data by -1/+2. This struct is for reference only. */ @@ -83,8 +83,6 @@ struct ath_ht20_40_mag_info { u8 max_exp; } __packed; -#define SPECTRAL_HT20_40_NUM_BINS 128 - /* WARNING: don't actually use this struct! MAC may vary the amount of * data. This struct is for reference only. */ @@ -125,71 +123,6 @@ static inline u8 spectral_bitmap_weight(u8 *bins) return bins[0] & 0x3f; } -/* FFT sample format given to userspace via debugfs. - * - * Please keep the type/length at the front position and change - * other fields after adding another sample type - * - * TODO: this might need rework when switching to nl80211-based - * interface. - */ -enum ath_fft_sample_type { - ATH_FFT_SAMPLE_HT20 = 1, - ATH_FFT_SAMPLE_HT20_40, -}; - -struct fft_sample_tlv { - u8 type; /* see ath_fft_sample */ - __be16 length; - /* type dependent data follows */ -} __packed; - -struct fft_sample_ht20 { - struct fft_sample_tlv tlv; - - u8 max_exp; - - __be16 freq; - s8 rssi; - s8 noise; - - __be16 max_magnitude; - u8 max_index; - u8 bitmap_weight; - - __be64 tsf; - - u8 data[SPECTRAL_HT20_NUM_BINS]; -} __packed; - -struct fft_sample_ht20_40 { - struct fft_sample_tlv tlv; - - u8 channel_type; - __be16 freq; - - s8 lower_rssi; - s8 upper_rssi; - - __be64 tsf; - - s8 lower_noise; - s8 upper_noise; - - __be16 lower_max_magnitude; - __be16 upper_max_magnitude; - - u8 lower_max_index; - u8 upper_max_index; - - u8 lower_bitmap_weight; - u8 upper_bitmap_weight; - - u8 max_exp; - - u8 data[SPECTRAL_HT20_40_NUM_BINS]; -} __packed; - void ath9k_spectral_init_debug(struct ath_softc *sc); void ath9k_spectral_deinit_debug(struct ath_softc *sc); diff --git a/drivers/net/wireless/ath/spectral_common.h b/drivers/net/wireless/ath/spectral_common.h new file mode 100644 index 000000000000..b9ab722747bd --- /dev/null +++ b/drivers/net/wireless/ath/spectral_common.h @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2013 Qualcomm Atheros, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef SPECTRAL_COMMON_H +#define SPECTRAL_COMMON_H + +#define SPECTRAL_HT20_NUM_BINS 56 +#define SPECTRAL_HT20_40_NUM_BINS 128 + +/* FFT sample format given to userspace via debugfs. + * + * Please keep the type/length at the front position and change + * other fields after adding another sample type + * + * TODO: this might need rework when switching to nl80211-based + * interface. + */ +enum ath_fft_sample_type { + ATH_FFT_SAMPLE_HT20 = 1, + ATH_FFT_SAMPLE_HT20_40, +}; + +struct fft_sample_tlv { + u8 type; /* see ath_fft_sample */ + __be16 length; + /* type dependent data follows */ +} __packed; + +struct fft_sample_ht20 { + struct fft_sample_tlv tlv; + + u8 max_exp; + + __be16 freq; + s8 rssi; + s8 noise; + + __be16 max_magnitude; + u8 max_index; + u8 bitmap_weight; + + __be64 tsf; + + u8 data[SPECTRAL_HT20_NUM_BINS]; +} __packed; + +struct fft_sample_ht20_40 { + struct fft_sample_tlv tlv; + + u8 channel_type; + __be16 freq; + + s8 lower_rssi; + s8 upper_rssi; + + __be64 tsf; + + s8 lower_noise; + s8 upper_noise; + + __be16 lower_max_magnitude; + __be16 upper_max_magnitude; + + u8 lower_max_index; + u8 upper_max_index; + + u8 lower_bitmap_weight; + u8 upper_bitmap_weight; + + u8 max_exp; + + u8 data[SPECTRAL_HT20_40_NUM_BINS]; +} __packed; + +#endif /* SPECTRAL_COMMON_H */ From 855aed1220d2c94425ab01a85fe7a6f5c436940f Mon Sep 17 00:00:00 2001 From: Simon Wunderlich Date: Sat, 2 Aug 2014 09:12:54 +0300 Subject: [PATCH 007/221] ath10k: add spectral scan feature Adds the spectral scan feature for ath10k. The spectral scan is triggered by configuring a mode through a debugfs control file. Samples can be gathered via another relay debugfs file. Essentially, to try it out: ip link set dev wlan0 up echo background > /sys/kernel/debug/ieee80211/phy0/ath10k/spectral_scan_ctl echo trigger > /sys/kernel/debug/ieee80211/phy0/ath10k/spectral_scan_ctl iw dev wlan0 scan echo disable > /sys/kernel/debug/ieee80211/phy0/ath10k/spectral_scan_ctl cat /sys/kernel/debug/ieee80211/phy0/ath10k/spectral_scan0 > samples This feature is still experimental. Based on the original RFC patch of Sven Eckelmann. Signed-off-by: Simon Wunderlich Signed-off-by: Mathias Kretschmer Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/Kconfig | 1 + drivers/net/wireless/ath/ath10k/Makefile | 1 + drivers/net/wireless/ath/ath10k/core.c | 10 + drivers/net/wireless/ath/ath10k/core.h | 11 + drivers/net/wireless/ath/ath10k/mac.c | 8 + drivers/net/wireless/ath/ath10k/spectral.c | 561 +++++++++++++++++++++ drivers/net/wireless/ath/ath10k/spectral.h | 90 ++++ drivers/net/wireless/ath/ath10k/wmi.c | 105 +++- drivers/net/wireless/ath/ath10k/wmi.h | 97 ++++ drivers/net/wireless/ath/spectral_common.h | 25 + 10 files changed, 908 insertions(+), 1 deletion(-) create mode 100644 drivers/net/wireless/ath/ath10k/spectral.c create mode 100644 drivers/net/wireless/ath/ath10k/spectral.h diff --git a/drivers/net/wireless/ath/ath10k/Kconfig b/drivers/net/wireless/ath/ath10k/Kconfig index a6f5285235af..1053bb5f2cdc 100644 --- a/drivers/net/wireless/ath/ath10k/Kconfig +++ b/drivers/net/wireless/ath/ath10k/Kconfig @@ -25,6 +25,7 @@ config ATH10K_DEBUG config ATH10K_DEBUGFS bool "Atheros ath10k debugfs support" depends on ATH10K + select RELAY ---help--- Enabled debugfs support diff --git a/drivers/net/wireless/ath/ath10k/Makefile b/drivers/net/wireless/ath/ath10k/Makefile index a4179f49ee1f..2cfb63ca9327 100644 --- a/drivers/net/wireless/ath/ath10k/Makefile +++ b/drivers/net/wireless/ath/ath10k/Makefile @@ -10,6 +10,7 @@ ath10k_core-y += mac.o \ wmi.o \ bmi.o +ath10k_core-$(CONFIG_ATH10K_DEBUGFS) += spectral.o ath10k_core-$(CONFIG_ATH10K_TRACING) += trace.o obj-$(CONFIG_ATH10K_PCI) += ath10k_pci.o diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index bef797d5f4d3..440c3ff03aec 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -1000,9 +1000,17 @@ static void ath10k_core_register_work(struct work_struct *work) goto err_unregister_mac; } + status = ath10k_spectral_create(ar); + if (status) { + ath10k_err("failed to initialize spectral\n"); + goto err_debug_destroy; + } + set_bit(ATH10K_FLAG_CORE_REGISTERED, &ar->dev_flags); return; +err_debug_destroy: + ath10k_debug_destroy(ar); err_unregister_mac: ath10k_mac_unregister(ar); err_release_fw: @@ -1046,6 +1054,8 @@ void ath10k_core_unregister(struct ath10k *ar) ath10k_core_free_firmware_files(ar); + ath10k_spectral_destroy(ar); + ath10k_debug_destroy(ar); } EXPORT_SYMBOL(ath10k_core_unregister); diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index ded3af2266d0..d5c95d46e841 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -31,6 +31,7 @@ #include "../ath.h" #include "../regd.h" #include "../dfs_pattern_detector.h" +#include "spectral.h" #define MS(_v, _f) (((_v) & _f##_MASK) >> _f##_LSB) #define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK) @@ -237,6 +238,7 @@ struct ath10k_vif { bool is_started; bool is_up; + bool spectral_enabled; u32 aid; u8 bssid[ETH_ALEN]; @@ -499,6 +501,15 @@ struct ath10k { #ifdef CONFIG_ATH10K_DEBUGFS struct ath10k_debug debug; #endif + + struct { + /* relay(fs) channel for spectral scan */ + struct rchan *rfs_chan_spec_scan; + + /* spectral_mode and spec_config are protected by conf_mutex */ + enum ath10k_spectral_mode mode; + struct ath10k_spec_scan config; + } spectral; }; struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev, diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index b76efe25f54b..3c7942030361 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -2499,6 +2499,8 @@ static int ath10k_start(struct ieee80211_hw *hw) ar->num_started_vdevs = 0; ath10k_regd_update(ar); + ath10k_spectral_start(ar); + mutex_unlock(&ar->conf_mutex); return 0; @@ -2909,8 +2911,14 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw, dev_kfree_skb_any(arvif->beacon); arvif->beacon = NULL; } + spin_unlock_bh(&ar->data_lock); + ret = ath10k_spectral_vif_stop(arvif); + if (ret) + ath10k_warn("failed to stop spectral for vdev %i: %d\n", + arvif->vdev_id, ret); + ar->free_vdev_map |= 1 << (arvif->vdev_id); list_del(&arvif->list); diff --git a/drivers/net/wireless/ath/ath10k/spectral.c b/drivers/net/wireless/ath/ath10k/spectral.c new file mode 100644 index 000000000000..a53afc23864f --- /dev/null +++ b/drivers/net/wireless/ath/ath10k/spectral.c @@ -0,0 +1,561 @@ +/* + * Copyright (c) 2013 Qualcomm Atheros, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include "core.h" +#include "debug.h" + +static void send_fft_sample(struct ath10k *ar, + const struct fft_sample_tlv *fft_sample_tlv) +{ + int length; + + if (!ar->spectral.rfs_chan_spec_scan) + return; + + length = __be16_to_cpu(fft_sample_tlv->length) + + sizeof(*fft_sample_tlv); + relay_write(ar->spectral.rfs_chan_spec_scan, fft_sample_tlv, length); +} + +static uint8_t get_max_exp(s8 max_index, u16 max_magnitude, size_t bin_len, + u8 *data) +{ + int dc_pos; + u8 max_exp; + + dc_pos = bin_len / 2; + + /* peak index outside of bins */ + if (dc_pos < max_index || -dc_pos >= max_index) + return 0; + + for (max_exp = 0; max_exp < 8; max_exp++) { + if (data[dc_pos + max_index] == (max_magnitude >> max_exp)) + break; + } + + /* max_exp not found */ + if (data[dc_pos + max_index] != (max_magnitude >> max_exp)) + return 0; + + return max_exp; +} + +int ath10k_spectral_process_fft(struct ath10k *ar, + struct wmi_single_phyerr_rx_event *event, + struct phyerr_fft_report *fftr, + size_t bin_len, u64 tsf) +{ + struct fft_sample_ath10k *fft_sample; + u8 buf[sizeof(*fft_sample) + SPECTRAL_ATH10K_MAX_NUM_BINS]; + u16 freq1, freq2, total_gain_db, base_pwr_db, length, peak_mag; + u32 reg0, reg1, nf_list1, nf_list2; + u8 chain_idx, *bins; + int dc_pos; + + fft_sample = (struct fft_sample_ath10k *)&buf; + + if (bin_len < 64 || bin_len > SPECTRAL_ATH10K_MAX_NUM_BINS) + return -EINVAL; + + reg0 = __le32_to_cpu(fftr->reg0); + reg1 = __le32_to_cpu(fftr->reg1); + + length = sizeof(*fft_sample) - sizeof(struct fft_sample_tlv) + bin_len; + fft_sample->tlv.type = ATH_FFT_SAMPLE_ATH10K; + fft_sample->tlv.length = __cpu_to_be16(length); + + /* TODO: there might be a reason why the hardware reports 20/40/80 MHz, + * but the results/plots suggest that its actually 22/44/88 MHz. + */ + switch (event->hdr.chan_width_mhz) { + case 20: + fft_sample->chan_width_mhz = 22; + break; + case 40: + fft_sample->chan_width_mhz = 44; + break; + case 80: + /* TODO: As experiments with an analogue sender and various + * configuaritions (fft-sizes of 64/128/256 and 20/40/80 Mhz) + * show, the particular configuration of 80 MHz/64 bins does + * not match with the other smaples at all. Until the reason + * for that is found, don't report these samples. + */ + if (bin_len == 64) + return -EINVAL; + fft_sample->chan_width_mhz = 88; + break; + default: + fft_sample->chan_width_mhz = event->hdr.chan_width_mhz; + } + + fft_sample->relpwr_db = MS(reg1, SEARCH_FFT_REPORT_REG1_RELPWR_DB); + fft_sample->avgpwr_db = MS(reg1, SEARCH_FFT_REPORT_REG1_AVGPWR_DB); + + peak_mag = MS(reg1, SEARCH_FFT_REPORT_REG1_PEAK_MAG); + fft_sample->max_magnitude = __cpu_to_be16(peak_mag); + fft_sample->max_index = MS(reg0, SEARCH_FFT_REPORT_REG0_PEAK_SIDX); + fft_sample->rssi = event->hdr.rssi_combined; + + total_gain_db = MS(reg0, SEARCH_FFT_REPORT_REG0_TOTAL_GAIN_DB); + base_pwr_db = MS(reg0, SEARCH_FFT_REPORT_REG0_BASE_PWR_DB); + fft_sample->total_gain_db = __cpu_to_be16(total_gain_db); + fft_sample->base_pwr_db = __cpu_to_be16(base_pwr_db); + + freq1 = __le16_to_cpu(event->hdr.freq1); + freq2 = __le16_to_cpu(event->hdr.freq2); + fft_sample->freq1 = __cpu_to_be16(freq1); + fft_sample->freq2 = __cpu_to_be16(freq2); + + nf_list1 = __le32_to_cpu(event->hdr.nf_list_1); + nf_list2 = __le32_to_cpu(event->hdr.nf_list_2); + chain_idx = MS(reg0, SEARCH_FFT_REPORT_REG0_FFT_CHN_IDX); + + switch (chain_idx) { + case 0: + fft_sample->noise = __cpu_to_be16(nf_list1 & 0xffffu); + break; + case 1: + fft_sample->noise = __cpu_to_be16((nf_list1 >> 16) & 0xffffu); + break; + case 2: + fft_sample->noise = __cpu_to_be16(nf_list2 & 0xffffu); + break; + case 3: + fft_sample->noise = __cpu_to_be16((nf_list2 >> 16) & 0xffffu); + break; + } + + bins = (u8 *)fftr; + bins += sizeof(*fftr); + + fft_sample->tsf = __cpu_to_be64(tsf); + + /* max_exp has been directly reported by previous hardware (ath9k), + * maybe its possible to get it by other means? + */ + fft_sample->max_exp = get_max_exp(fft_sample->max_index, peak_mag, + bin_len, bins); + + memcpy(fft_sample->data, bins, bin_len); + + /* DC value (value in the middle) is the blind spot of the spectral + * sample and invalid, interpolate it. + */ + dc_pos = bin_len / 2; + fft_sample->data[dc_pos] = (fft_sample->data[dc_pos + 1] + + fft_sample->data[dc_pos - 1]) / 2; + + send_fft_sample(ar, &fft_sample->tlv); + + return 0; +} + +static struct ath10k_vif *ath10k_get_spectral_vdev(struct ath10k *ar) +{ + struct ath10k_vif *arvif; + + lockdep_assert_held(&ar->conf_mutex); + + if (list_empty(&ar->arvifs)) + return NULL; + + /* if there already is a vif doing spectral, return that. */ + list_for_each_entry(arvif, &ar->arvifs, list) + if (arvif->spectral_enabled) + return arvif; + + /* otherwise, return the first vif. */ + return list_first_entry(&ar->arvifs, typeof(*arvif), list); +} + +static int ath10k_spectral_scan_trigger(struct ath10k *ar) +{ + struct ath10k_vif *arvif; + int res; + int vdev_id; + + lockdep_assert_held(&ar->conf_mutex); + + arvif = ath10k_get_spectral_vdev(ar); + if (!arvif) + return -ENODEV; + vdev_id = arvif->vdev_id; + + if (ar->spectral.mode == SPECTRAL_DISABLED) + return 0; + + res = ath10k_wmi_vdev_spectral_enable(ar, vdev_id, + WMI_SPECTRAL_TRIGGER_CMD_CLEAR, + WMI_SPECTRAL_ENABLE_CMD_ENABLE); + if (res < 0) + return res; + + res = ath10k_wmi_vdev_spectral_enable(ar, vdev_id, + WMI_SPECTRAL_TRIGGER_CMD_TRIGGER, + WMI_SPECTRAL_ENABLE_CMD_ENABLE); + if (res < 0) + return res; + + return 0; +} + +static int ath10k_spectral_scan_config(struct ath10k *ar, + enum ath10k_spectral_mode mode) +{ + struct wmi_vdev_spectral_conf_arg arg; + struct ath10k_vif *arvif; + int vdev_id, count, res = 0; + + lockdep_assert_held(&ar->conf_mutex); + + arvif = ath10k_get_spectral_vdev(ar); + if (!arvif) + return -ENODEV; + + vdev_id = arvif->vdev_id; + + arvif->spectral_enabled = (mode != SPECTRAL_DISABLED); + ar->spectral.mode = mode; + + res = ath10k_wmi_vdev_spectral_enable(ar, vdev_id, + WMI_SPECTRAL_TRIGGER_CMD_CLEAR, + WMI_SPECTRAL_ENABLE_CMD_DISABLE); + if (res < 0) { + ath10k_warn("failed to enable spectral scan: %d\n", res); + return res; + } + + if (mode == SPECTRAL_DISABLED) + return 0; + + if (mode == SPECTRAL_BACKGROUND) + count = WMI_SPECTRAL_COUNT_DEFAULT; + else + count = max_t(u8, 1, ar->spectral.config.count); + + arg.vdev_id = vdev_id; + arg.scan_count = count; + arg.scan_period = WMI_SPECTRAL_PERIOD_DEFAULT; + arg.scan_priority = WMI_SPECTRAL_PRIORITY_DEFAULT; + arg.scan_fft_size = ar->spectral.config.fft_size; + arg.scan_gc_ena = WMI_SPECTRAL_GC_ENA_DEFAULT; + arg.scan_restart_ena = WMI_SPECTRAL_RESTART_ENA_DEFAULT; + arg.scan_noise_floor_ref = WMI_SPECTRAL_NOISE_FLOOR_REF_DEFAULT; + arg.scan_init_delay = WMI_SPECTRAL_INIT_DELAY_DEFAULT; + arg.scan_nb_tone_thr = WMI_SPECTRAL_NB_TONE_THR_DEFAULT; + arg.scan_str_bin_thr = WMI_SPECTRAL_STR_BIN_THR_DEFAULT; + arg.scan_wb_rpt_mode = WMI_SPECTRAL_WB_RPT_MODE_DEFAULT; + arg.scan_rssi_rpt_mode = WMI_SPECTRAL_RSSI_RPT_MODE_DEFAULT; + arg.scan_rssi_thr = WMI_SPECTRAL_RSSI_THR_DEFAULT; + arg.scan_pwr_format = WMI_SPECTRAL_PWR_FORMAT_DEFAULT; + arg.scan_rpt_mode = WMI_SPECTRAL_RPT_MODE_DEFAULT; + arg.scan_bin_scale = WMI_SPECTRAL_BIN_SCALE_DEFAULT; + arg.scan_dbm_adj = WMI_SPECTRAL_DBM_ADJ_DEFAULT; + arg.scan_chn_mask = WMI_SPECTRAL_CHN_MASK_DEFAULT; + + res = ath10k_wmi_vdev_spectral_conf(ar, &arg); + if (res < 0) { + ath10k_warn("failed to configure spectral scan: %d\n", res); + return res; + } + + return 0; +} + +static ssize_t read_file_spec_scan_ctl(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath10k *ar = file->private_data; + char *mode = ""; + unsigned int len; + enum ath10k_spectral_mode spectral_mode; + + mutex_lock(&ar->conf_mutex); + spectral_mode = ar->spectral.mode; + mutex_unlock(&ar->conf_mutex); + + switch (spectral_mode) { + case SPECTRAL_DISABLED: + mode = "disable"; + break; + case SPECTRAL_BACKGROUND: + mode = "background"; + break; + case SPECTRAL_MANUAL: + mode = "manual"; + break; + } + + len = strlen(mode); + return simple_read_from_buffer(user_buf, count, ppos, mode, len); +} + +static ssize_t write_file_spec_scan_ctl(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath10k *ar = file->private_data; + char buf[32]; + ssize_t len; + int res; + + len = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, len)) + return -EFAULT; + + buf[len] = '\0'; + + mutex_lock(&ar->conf_mutex); + + if (strncmp("trigger", buf, 7) == 0) { + if (ar->spectral.mode == SPECTRAL_MANUAL || + ar->spectral.mode == SPECTRAL_BACKGROUND) { + /* reset the configuration to adopt possibly changed + * debugfs parameters + */ + res = ath10k_spectral_scan_config(ar, + ar->spectral.mode); + if (res < 0) { + ath10k_warn("failed to reconfigure spectral scan: %d\n", + res); + } + res = ath10k_spectral_scan_trigger(ar); + if (res < 0) { + ath10k_warn("failed to trigger spectral scan: %d\n", + res); + } + } else { + res = -EINVAL; + } + } else if (strncmp("background", buf, 9) == 0) { + res = ath10k_spectral_scan_config(ar, SPECTRAL_BACKGROUND); + } else if (strncmp("manual", buf, 6) == 0) { + res = ath10k_spectral_scan_config(ar, SPECTRAL_MANUAL); + } else if (strncmp("disable", buf, 7) == 0) { + res = ath10k_spectral_scan_config(ar, SPECTRAL_DISABLED); + } else { + res = -EINVAL; + } + + mutex_unlock(&ar->conf_mutex); + + if (res < 0) + return res; + + return count; +} + +static const struct file_operations fops_spec_scan_ctl = { + .read = read_file_spec_scan_ctl, + .write = write_file_spec_scan_ctl, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +static ssize_t read_file_spectral_count(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath10k *ar = file->private_data; + char buf[32]; + unsigned int len; + u8 spectral_count; + + mutex_lock(&ar->conf_mutex); + spectral_count = ar->spectral.config.count; + mutex_unlock(&ar->conf_mutex); + + len = sprintf(buf, "%d\n", spectral_count); + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t write_file_spectral_count(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath10k *ar = file->private_data; + unsigned long val; + char buf[32]; + ssize_t len; + + len = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, len)) + return -EFAULT; + + buf[len] = '\0'; + if (kstrtoul(buf, 0, &val)) + return -EINVAL; + + if (val < 0 || val > 255) + return -EINVAL; + + mutex_lock(&ar->conf_mutex); + ar->spectral.config.count = val; + mutex_unlock(&ar->conf_mutex); + + return count; +} + +static const struct file_operations fops_spectral_count = { + .read = read_file_spectral_count, + .write = write_file_spectral_count, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +static ssize_t read_file_spectral_bins(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath10k *ar = file->private_data; + char buf[32]; + unsigned int len, bins, fft_size, bin_scale; + + mutex_lock(&ar->conf_mutex); + + fft_size = ar->spectral.config.fft_size; + bin_scale = WMI_SPECTRAL_BIN_SCALE_DEFAULT; + bins = 1 << (fft_size - bin_scale); + + mutex_unlock(&ar->conf_mutex); + + len = sprintf(buf, "%d\n", bins); + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t write_file_spectral_bins(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath10k *ar = file->private_data; + unsigned long val; + char buf[32]; + ssize_t len; + + len = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, len)) + return -EFAULT; + + buf[len] = '\0'; + if (kstrtoul(buf, 0, &val)) + return -EINVAL; + + if (val < 64 || val > SPECTRAL_ATH10K_MAX_NUM_BINS) + return -EINVAL; + + if (!is_power_of_2(val)) + return -EINVAL; + + mutex_lock(&ar->conf_mutex); + ar->spectral.config.fft_size = ilog2(val); + ar->spectral.config.fft_size += WMI_SPECTRAL_BIN_SCALE_DEFAULT; + mutex_unlock(&ar->conf_mutex); + + return count; +} + +static const struct file_operations fops_spectral_bins = { + .read = read_file_spectral_bins, + .write = write_file_spectral_bins, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +static struct dentry *create_buf_file_handler(const char *filename, + struct dentry *parent, + umode_t mode, + struct rchan_buf *buf, + int *is_global) +{ + struct dentry *buf_file; + + buf_file = debugfs_create_file(filename, mode, parent, buf, + &relay_file_operations); + *is_global = 1; + return buf_file; +} + +static int remove_buf_file_handler(struct dentry *dentry) +{ + debugfs_remove(dentry); + + return 0; +} + +static struct rchan_callbacks rfs_spec_scan_cb = { + .create_buf_file = create_buf_file_handler, + .remove_buf_file = remove_buf_file_handler, +}; + +int ath10k_spectral_start(struct ath10k *ar) +{ + struct ath10k_vif *arvif; + + lockdep_assert_held(&ar->conf_mutex); + + list_for_each_entry(arvif, &ar->arvifs, list) + arvif->spectral_enabled = 0; + + ar->spectral.mode = SPECTRAL_DISABLED; + ar->spectral.config.count = WMI_SPECTRAL_COUNT_DEFAULT; + ar->spectral.config.fft_size = WMI_SPECTRAL_FFT_SIZE_DEFAULT; + + return 0; +} + +int ath10k_spectral_vif_stop(struct ath10k_vif *arvif) +{ + if (!arvif->spectral_enabled) + return 0; + + return ath10k_spectral_scan_config(arvif->ar, SPECTRAL_DISABLED); +} + +int ath10k_spectral_create(struct ath10k *ar) +{ + ar->spectral.rfs_chan_spec_scan = relay_open("spectral_scan", + ar->debug.debugfs_phy, + 1024, 256, + &rfs_spec_scan_cb, NULL); + debugfs_create_file("spectral_scan_ctl", + S_IRUSR | S_IWUSR, + ar->debug.debugfs_phy, ar, + &fops_spec_scan_ctl); + debugfs_create_file("spectral_count", + S_IRUSR | S_IWUSR, + ar->debug.debugfs_phy, ar, + &fops_spectral_count); + debugfs_create_file("spectral_bins", + S_IRUSR | S_IWUSR, + ar->debug.debugfs_phy, ar, + &fops_spectral_bins); + + return 0; +} + +void ath10k_spectral_destroy(struct ath10k *ar) +{ + if (ar->spectral.rfs_chan_spec_scan) { + relay_close(ar->spectral.rfs_chan_spec_scan); + ar->spectral.rfs_chan_spec_scan = NULL; + } +} diff --git a/drivers/net/wireless/ath/ath10k/spectral.h b/drivers/net/wireless/ath/ath10k/spectral.h new file mode 100644 index 000000000000..ddc57c557272 --- /dev/null +++ b/drivers/net/wireless/ath/ath10k/spectral.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2013 Qualcomm Atheros, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef SPECTRAL_H +#define SPECTRAL_H + +#include "../spectral_common.h" + +/** + * struct ath10k_spec_scan - parameters for Atheros spectral scan + * + * @count: number of scan results requested for manual mode + * @fft_size: number of bins to be requested = 2^(fft_size - bin_scale) + */ +struct ath10k_spec_scan { + u8 count; + u8 fft_size; +}; + +/* enum ath10k_spectral_mode: + * + * @SPECTRAL_DISABLED: spectral mode is disabled + * @SPECTRAL_BACKGROUND: hardware sends samples when it is not busy with + * something else. + * @SPECTRAL_MANUAL: spectral scan is enabled, triggering for samples + * is performed manually. + */ +enum ath10k_spectral_mode { + SPECTRAL_DISABLED = 0, + SPECTRAL_BACKGROUND, + SPECTRAL_MANUAL, +}; + +#ifdef CONFIG_ATH10K_DEBUGFS + +int ath10k_spectral_process_fft(struct ath10k *ar, + struct wmi_single_phyerr_rx_event *event, + struct phyerr_fft_report *fftr, + size_t bin_len, u64 tsf); +int ath10k_spectral_start(struct ath10k *ar); +int ath10k_spectral_vif_stop(struct ath10k_vif *arvif); +int ath10k_spectral_create(struct ath10k *ar); +void ath10k_spectral_destroy(struct ath10k *ar); + +#else + +static inline int +ath10k_spectral_process_fft(struct ath10k *ar, + struct wmi_single_phyerr_rx_event *event, + struct phyerr_fft_report *fftr, + size_t bin_len, u64 tsf) +{ + return 0; +} + +static inline int ath10k_spectral_start(struct ath10k *ar) +{ + return 0; +} + +static inline int ath10k_spectral_vif_stop(struct ath10k_vif *arvif) +{ + return 0; +} + +static inline int ath10k_spectral_create(struct ath10k *ar) +{ + return 0; +} + +static inline void ath10k_spectral_destroy(struct ath10k *ar) +{ +} + +#endif /* CONFIG_ATH10K_DEBUGFS */ + +#endif /* SPECTRAL_H */ diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index b09661db9447..fffb15b1b50b 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -1780,7 +1780,54 @@ static void ath10k_wmi_event_spectral_scan(struct ath10k *ar, struct wmi_single_phyerr_rx_event *event, u64 tsf) { - ath10k_dbg(ATH10K_DBG_WMI, "wmi event spectral scan\n"); + int buf_len, tlv_len, res, i = 0; + struct phyerr_tlv *tlv; + u8 *tlv_buf; + struct phyerr_fft_report *fftr; + size_t fftr_len; + + buf_len = __le32_to_cpu(event->hdr.buf_len); + + while (i < buf_len) { + if (i + sizeof(*tlv) > buf_len) { + ath10k_warn("failed to parse phyerr tlv header at byte %d\n", + i); + return; + } + + tlv = (struct phyerr_tlv *)&event->bufp[i]; + tlv_len = __le16_to_cpu(tlv->len); + tlv_buf = &event->bufp[i + sizeof(*tlv)]; + + if (i + sizeof(*tlv) + tlv_len > buf_len) { + ath10k_warn("failed to parse phyerr tlv payload at byte %d\n", + i); + return; + } + + switch (tlv->tag) { + case PHYERR_TLV_TAG_SEARCH_FFT_REPORT: + if (sizeof(*fftr) > tlv_len) { + ath10k_warn("failed to parse fft report at byte %d\n", + i); + return; + } + + fftr_len = tlv_len - sizeof(*fftr); + fftr = (struct phyerr_fft_report *)tlv_buf; + res = ath10k_spectral_process_fft(ar, event, + fftr, fftr_len, + tsf); + if (res < 0) { + ath10k_warn("failed to process fft report: %d\n", + res); + return; + } + break; + } + + i += sizeof(*tlv) + tlv_len; + } } static void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb) @@ -3576,6 +3623,62 @@ int ath10k_wmi_vdev_install_key(struct ath10k *ar, ar->wmi.cmd->vdev_install_key_cmdid); } +int ath10k_wmi_vdev_spectral_conf(struct ath10k *ar, + const struct wmi_vdev_spectral_conf_arg *arg) +{ + struct wmi_vdev_spectral_conf_cmd *cmd; + struct sk_buff *skb; + u32 cmdid; + + skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_vdev_spectral_conf_cmd *)skb->data; + cmd->vdev_id = __cpu_to_le32(arg->vdev_id); + cmd->scan_count = __cpu_to_le32(arg->scan_count); + cmd->scan_period = __cpu_to_le32(arg->scan_period); + cmd->scan_priority = __cpu_to_le32(arg->scan_priority); + cmd->scan_fft_size = __cpu_to_le32(arg->scan_fft_size); + cmd->scan_gc_ena = __cpu_to_le32(arg->scan_gc_ena); + cmd->scan_restart_ena = __cpu_to_le32(arg->scan_restart_ena); + cmd->scan_noise_floor_ref = __cpu_to_le32(arg->scan_noise_floor_ref); + cmd->scan_init_delay = __cpu_to_le32(arg->scan_init_delay); + cmd->scan_nb_tone_thr = __cpu_to_le32(arg->scan_nb_tone_thr); + cmd->scan_str_bin_thr = __cpu_to_le32(arg->scan_str_bin_thr); + cmd->scan_wb_rpt_mode = __cpu_to_le32(arg->scan_wb_rpt_mode); + cmd->scan_rssi_rpt_mode = __cpu_to_le32(arg->scan_rssi_rpt_mode); + cmd->scan_rssi_thr = __cpu_to_le32(arg->scan_rssi_thr); + cmd->scan_pwr_format = __cpu_to_le32(arg->scan_pwr_format); + cmd->scan_rpt_mode = __cpu_to_le32(arg->scan_rpt_mode); + cmd->scan_bin_scale = __cpu_to_le32(arg->scan_bin_scale); + cmd->scan_dbm_adj = __cpu_to_le32(arg->scan_dbm_adj); + cmd->scan_chn_mask = __cpu_to_le32(arg->scan_chn_mask); + + cmdid = ar->wmi.cmd->vdev_spectral_scan_configure_cmdid; + return ath10k_wmi_cmd_send(ar, skb, cmdid); +} + +int ath10k_wmi_vdev_spectral_enable(struct ath10k *ar, u32 vdev_id, u32 trigger, + u32 enable) +{ + struct wmi_vdev_spectral_enable_cmd *cmd; + struct sk_buff *skb; + u32 cmdid; + + skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_vdev_spectral_enable_cmd *)skb->data; + cmd->vdev_id = __cpu_to_le32(vdev_id); + cmd->trigger_cmd = __cpu_to_le32(trigger); + cmd->enable_cmd = __cpu_to_le32(enable); + + cmdid = ar->wmi.cmd->vdev_spectral_scan_enable_cmdid; + return ath10k_wmi_cmd_send(ar, skb, cmdid); +} + int ath10k_wmi_peer_create(struct ath10k *ar, u32 vdev_id, const u8 peer_addr[ETH_ALEN]) { diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index c9ac11cbc5d2..1d8dda3240a5 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -2247,6 +2247,7 @@ struct wmi_comb_phyerr_rx_event { #define PHYERR_TLV_SIG 0xBB #define PHYERR_TLV_TAG_SEARCH_FFT_REPORT 0xFB #define PHYERR_TLV_TAG_RADAR_PULSE_SUMMARY 0xF8 +#define PHYERR_TLV_TAG_SPECTRAL_SUMMARY_REPORT 0xF9 struct phyerr_radar_report { __le32 reg0; /* RADAR_REPORT_REG0_* */ @@ -3645,6 +3646,98 @@ struct wmi_vdev_simple_event { /* unsupported VDEV combination */ #define WMI_INIFIED_VDEV_START_RESPONSE_NOT_SUPPORTED 0x2 +/* TODO: please add more comments if you have in-depth information */ +struct wmi_vdev_spectral_conf_cmd { + __le32 vdev_id; + + /* number of fft samples to send (0 for infinite) */ + __le32 scan_count; + __le32 scan_period; + __le32 scan_priority; + + /* number of bins in the FFT: 2^(fft_size - bin_scale) */ + __le32 scan_fft_size; + __le32 scan_gc_ena; + __le32 scan_restart_ena; + __le32 scan_noise_floor_ref; + __le32 scan_init_delay; + __le32 scan_nb_tone_thr; + __le32 scan_str_bin_thr; + __le32 scan_wb_rpt_mode; + __le32 scan_rssi_rpt_mode; + __le32 scan_rssi_thr; + __le32 scan_pwr_format; + + /* rpt_mode: Format of FFT report to software for spectral scan + * triggered FFTs: + * 0: No FFT report (only spectral scan summary report) + * 1: 2-dword summary of metrics for each completed FFT + spectral + * scan summary report + * 2: 2-dword summary of metrics for each completed FFT + + * 1x- oversampled bins(in-band) per FFT + spectral scan summary + * report + * 3: 2-dword summary of metrics for each completed FFT + + * 2x- oversampled bins (all) per FFT + spectral scan summary + */ + __le32 scan_rpt_mode; + __le32 scan_bin_scale; + __le32 scan_dbm_adj; + __le32 scan_chn_mask; +} __packed; + +struct wmi_vdev_spectral_conf_arg { + u32 vdev_id; + u32 scan_count; + u32 scan_period; + u32 scan_priority; + u32 scan_fft_size; + u32 scan_gc_ena; + u32 scan_restart_ena; + u32 scan_noise_floor_ref; + u32 scan_init_delay; + u32 scan_nb_tone_thr; + u32 scan_str_bin_thr; + u32 scan_wb_rpt_mode; + u32 scan_rssi_rpt_mode; + u32 scan_rssi_thr; + u32 scan_pwr_format; + u32 scan_rpt_mode; + u32 scan_bin_scale; + u32 scan_dbm_adj; + u32 scan_chn_mask; +}; + +#define WMI_SPECTRAL_ENABLE_DEFAULT 0 +#define WMI_SPECTRAL_COUNT_DEFAULT 0 +#define WMI_SPECTRAL_PERIOD_DEFAULT 35 +#define WMI_SPECTRAL_PRIORITY_DEFAULT 1 +#define WMI_SPECTRAL_FFT_SIZE_DEFAULT 7 +#define WMI_SPECTRAL_GC_ENA_DEFAULT 1 +#define WMI_SPECTRAL_RESTART_ENA_DEFAULT 0 +#define WMI_SPECTRAL_NOISE_FLOOR_REF_DEFAULT -96 +#define WMI_SPECTRAL_INIT_DELAY_DEFAULT 80 +#define WMI_SPECTRAL_NB_TONE_THR_DEFAULT 12 +#define WMI_SPECTRAL_STR_BIN_THR_DEFAULT 8 +#define WMI_SPECTRAL_WB_RPT_MODE_DEFAULT 0 +#define WMI_SPECTRAL_RSSI_RPT_MODE_DEFAULT 0 +#define WMI_SPECTRAL_RSSI_THR_DEFAULT 0xf0 +#define WMI_SPECTRAL_PWR_FORMAT_DEFAULT 0 +#define WMI_SPECTRAL_RPT_MODE_DEFAULT 2 +#define WMI_SPECTRAL_BIN_SCALE_DEFAULT 1 +#define WMI_SPECTRAL_DBM_ADJ_DEFAULT 1 +#define WMI_SPECTRAL_CHN_MASK_DEFAULT 1 + +struct wmi_vdev_spectral_enable_cmd { + __le32 vdev_id; + __le32 trigger_cmd; + __le32 enable_cmd; +} __packed; + +#define WMI_SPECTRAL_TRIGGER_CMD_TRIGGER 1 +#define WMI_SPECTRAL_TRIGGER_CMD_CLEAR 2 +#define WMI_SPECTRAL_ENABLE_CMD_ENABLE 1 +#define WMI_SPECTRAL_ENABLE_CMD_DISABLE 2 + /* Beacon processing related command and event structures */ struct wmi_bcn_tx_hdr { __le32 vdev_id; @@ -4517,6 +4610,10 @@ int ath10k_wmi_vdev_set_param(struct ath10k *ar, u32 vdev_id, u32 param_id, u32 param_value); int ath10k_wmi_vdev_install_key(struct ath10k *ar, const struct wmi_vdev_install_key_arg *arg); +int ath10k_wmi_vdev_spectral_conf(struct ath10k *ar, + const struct wmi_vdev_spectral_conf_arg *arg); +int ath10k_wmi_vdev_spectral_enable(struct ath10k *ar, u32 vdev_id, u32 trigger, + u32 enable); int ath10k_wmi_peer_create(struct ath10k *ar, u32 vdev_id, const u8 peer_addr[ETH_ALEN]); int ath10k_wmi_peer_delete(struct ath10k *ar, u32 vdev_id, diff --git a/drivers/net/wireless/ath/spectral_common.h b/drivers/net/wireless/ath/spectral_common.h index b9ab722747bd..0d742acb1599 100644 --- a/drivers/net/wireless/ath/spectral_common.h +++ b/drivers/net/wireless/ath/spectral_common.h @@ -20,6 +20,11 @@ #define SPECTRAL_HT20_NUM_BINS 56 #define SPECTRAL_HT20_40_NUM_BINS 128 +/* TODO: could possibly be 512, but no samples this large + * could be acquired so far. + */ +#define SPECTRAL_ATH10K_MAX_NUM_BINS 256 + /* FFT sample format given to userspace via debugfs. * * Please keep the type/length at the front position and change @@ -31,6 +36,7 @@ enum ath_fft_sample_type { ATH_FFT_SAMPLE_HT20 = 1, ATH_FFT_SAMPLE_HT20_40, + ATH_FFT_SAMPLE_ATH10K, }; struct fft_sample_tlv { @@ -85,4 +91,23 @@ struct fft_sample_ht20_40 { u8 data[SPECTRAL_HT20_40_NUM_BINS]; } __packed; +struct fft_sample_ath10k { + struct fft_sample_tlv tlv; + u8 chan_width_mhz; + __be16 freq1; + __be16 freq2; + __be16 noise; + __be16 max_magnitude; + __be16 total_gain_db; + __be16 base_pwr_db; + __be64 tsf; + s8 max_index; + u8 rssi; + u8 relpwr_db; + u8 avgpwr_db; + u8 max_exp; + + u8 data[0]; +} __packed; + #endif /* SPECTRAL_COMMON_H */ From 17dc0b8068f9f01c56b0ade5c36b4c45a3339dda Mon Sep 17 00:00:00 2001 From: Himangi Saraogi Date: Fri, 1 Aug 2014 21:41:15 +0530 Subject: [PATCH 008/221] ath6kl: convert a driver to use module_usb_driver() This converts a driver in drivers/net/* to use the module_usb_driver() macro which makes the code smaller and a bit simpler. Signed-off-by: Himangi Saraogi Acked-by: Julia Lawall Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/usb.c | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/drivers/net/wireless/ath/ath6kl/usb.c b/drivers/net/wireless/ath/ath6kl/usb.c index c44325856b81..a6a5e40b3e98 100644 --- a/drivers/net/wireless/ath/ath6kl/usb.c +++ b/drivers/net/wireless/ath/ath6kl/usb.c @@ -1229,26 +1229,7 @@ static struct usb_driver ath6kl_usb_driver = { .disable_hub_initiated_lpm = 1, }; -static int ath6kl_usb_init(void) -{ - int ret; - - ret = usb_register(&ath6kl_usb_driver); - if (ret) { - ath6kl_err("usb registration failed: %d\n", ret); - return ret; - } - - return 0; -} - -static void ath6kl_usb_exit(void) -{ - usb_deregister(&ath6kl_usb_driver); -} - -module_init(ath6kl_usb_init); -module_exit(ath6kl_usb_exit); +module_usb_driver(ath6kl_usb_driver); MODULE_AUTHOR("Atheros Communications, Inc."); MODULE_DESCRIPTION("Driver support for Atheros AR600x USB devices"); From cff990ce7ddd6a43f86757867399a8a64aa29af9 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Mon, 4 Aug 2014 09:18:33 +0300 Subject: [PATCH 009/221] ath10k: fix wmi service bitmap debug The 10.x and main firmware branches have conflicting WMI service bitmap definitions. This also fixes WMI services parsing on big-endian hosts and changes debugfs output to be more human friendly. kvalo: remove braces and the last semicolon from SVCSTR() Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.h | 2 +- drivers/net/wireless/ath/ath10k/debug.c | 26 +- drivers/net/wireless/ath/ath10k/wmi.c | 14 +- drivers/net/wireless/ath/ath10k/wmi.h | 367 +++++++++++++++++------- 4 files changed, 291 insertions(+), 118 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index d5c95d46e841..94b1ff2082cf 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -282,7 +282,7 @@ struct ath10k_debug { struct dentry *debugfs_phy; struct ath10k_target_stats target_stats; - u32 wmi_service_bitmap[WMI_SERVICE_BM_SIZE]; + DECLARE_BITMAP(wmi_service_bitmap, WMI_SERVICE_BM_SIZE); struct completion event_stats_compl; diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index c9e35c87edfb..df1abe7f1fef 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -115,9 +115,10 @@ static ssize_t ath10k_read_wmi_services(struct file *file, { struct ath10k *ar = file->private_data; char *buf; - unsigned int len = 0, buf_len = 1500; - const char *status; + unsigned int len = 0, buf_len = 4096; + const char *name; ssize_t ret_cnt; + bool enabled; int i; buf = kzalloc(buf_len, GFP_KERNEL); @@ -129,15 +130,22 @@ static ssize_t ath10k_read_wmi_services(struct file *file, if (len > buf_len) len = buf_len; - for (i = 0; i < WMI_SERVICE_LAST; i++) { - if (WMI_SERVICE_IS_ENABLED(ar->debug.wmi_service_bitmap, i)) - status = "enabled"; - else - status = "disabled"; + for (i = 0; i < WMI_MAX_SERVICE; i++) { + enabled = test_bit(i, ar->debug.wmi_service_bitmap); + name = wmi_service_name(i); + + if (!name) { + if (enabled) + len += scnprintf(buf + len, buf_len - len, + "%-40s %s (bit %d)\n", + "unknown", "enabled", i); + + continue; + } len += scnprintf(buf + len, buf_len - len, - "0x%02x - %20s - %s\n", - i, wmi_service_name(i), status); + "%-40s %s\n", + name, enabled ? "enabled" : "-"); } ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len); diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index fffb15b1b50b..a381006c8124 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -2080,6 +2080,7 @@ static void ath10k_wmi_service_ready_event_rx(struct ath10k *ar, struct sk_buff *skb) { struct wmi_service_ready_event *ev = (void *)skb->data; + DECLARE_BITMAP(svc_bmap, WMI_SERVICE_BM_SIZE) = {}; if (skb->len < sizeof(*ev)) { ath10k_warn("Service ready event was %d B but expected %zu B. Wrong firmware version?\n", @@ -2113,8 +2114,10 @@ static void ath10k_wmi_service_ready_event_rx(struct ath10k *ar, ar->ath_common.regulatory.current_rd = __le32_to_cpu(ev->hal_reg_capabilities.eeprom_rd); - ath10k_debug_read_service_map(ar, ev->wmi_service_bitmap, - sizeof(ev->wmi_service_bitmap)); + wmi_10x_svc_map(ev->wmi_service_bitmap, svc_bmap); + ath10k_debug_read_service_map(ar, svc_bmap, sizeof(svc_bmap)); + ath10k_dbg_dump(ATH10K_DBG_WMI, NULL, "ath10k: wmi svc: ", + ev->wmi_service_bitmap, sizeof(ev->wmi_service_bitmap)); if (strlen(ar->hw->wiphy->fw_version) == 0) { snprintf(ar->hw->wiphy->fw_version, @@ -2154,6 +2157,7 @@ static void ath10k_wmi_10x_service_ready_event_rx(struct ath10k *ar, u32 num_units, req_id, unit_size, num_mem_reqs, num_unit_info, i; int ret; struct wmi_service_ready_event_10x *ev = (void *)skb->data; + DECLARE_BITMAP(svc_bmap, WMI_SERVICE_BM_SIZE) = {}; if (skb->len < sizeof(*ev)) { ath10k_warn("Service ready event was %d B but expected %zu B. Wrong firmware version?\n", @@ -2180,8 +2184,10 @@ static void ath10k_wmi_10x_service_ready_event_rx(struct ath10k *ar, ar->ath_common.regulatory.current_rd = __le32_to_cpu(ev->hal_reg_capabilities.eeprom_rd); - ath10k_debug_read_service_map(ar, ev->wmi_service_bitmap, - sizeof(ev->wmi_service_bitmap)); + wmi_main_svc_map(ev->wmi_service_bitmap, svc_bmap); + ath10k_debug_read_service_map(ar, svc_bmap, sizeof(svc_bmap)); + ath10k_dbg_dump(ATH10K_DBG_WMI, NULL, "ath10k: wmi svc: ", + ev->wmi_service_bitmap, sizeof(ev->wmi_service_bitmap)); if (strlen(ar->hw->wiphy->fw_version) == 0) { snprintf(ar->hw->wiphy->fw_version, diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 1d8dda3240a5..e70836586756 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -73,116 +73,279 @@ struct wmi_cmd_hdr { #define HTC_PROTOCOL_VERSION 0x0002 #define WMI_PROTOCOL_VERSION 0x0002 -enum wmi_service_id { - WMI_SERVICE_BEACON_OFFLOAD = 0, /* beacon offload */ - WMI_SERVICE_SCAN_OFFLOAD, /* scan offload */ - WMI_SERVICE_ROAM_OFFLOAD, /* roam offload */ - WMI_SERVICE_BCN_MISS_OFFLOAD, /* beacon miss offload */ - WMI_SERVICE_STA_PWRSAVE, /* fake sleep + basic power save */ - WMI_SERVICE_STA_ADVANCED_PWRSAVE, /* uapsd, pspoll, force sleep */ - WMI_SERVICE_AP_UAPSD, /* uapsd on AP */ - WMI_SERVICE_AP_DFS, /* DFS on AP */ - WMI_SERVICE_11AC, /* supports 11ac */ - WMI_SERVICE_BLOCKACK, /* Supports triggering ADDBA/DELBA from host*/ - WMI_SERVICE_PHYERR, /* PHY error */ - WMI_SERVICE_BCN_FILTER, /* Beacon filter support */ - WMI_SERVICE_RTT, /* RTT (round trip time) support */ - WMI_SERVICE_RATECTRL, /* Rate-control */ - WMI_SERVICE_WOW, /* WOW Support */ - WMI_SERVICE_RATECTRL_CACHE, /* Rate-control caching */ - WMI_SERVICE_IRAM_TIDS, /* TIDs in IRAM */ - WMI_SERVICE_ARPNS_OFFLOAD, /* ARP NS Offload support */ - WMI_SERVICE_NLO, /* Network list offload service */ - WMI_SERVICE_GTK_OFFLOAD, /* GTK offload */ - WMI_SERVICE_SCAN_SCH, /* Scan Scheduler Service */ - WMI_SERVICE_CSA_OFFLOAD, /* CSA offload service */ - WMI_SERVICE_CHATTER, /* Chatter service */ - WMI_SERVICE_COEX_FREQAVOID, /* FW report freq range to avoid */ - WMI_SERVICE_PACKET_POWER_SAVE, /* packet power save service */ - WMI_SERVICE_FORCE_FW_HANG, /* To test fw recovery mechanism */ - WMI_SERVICE_GPIO, /* GPIO service */ - WMI_SERVICE_STA_DTIM_PS_MODULATED_DTIM, /* Modulated DTIM support */ - WMI_STA_UAPSD_BASIC_AUTO_TRIG, /* UAPSD AC Trigger Generation */ - WMI_STA_UAPSD_VAR_AUTO_TRIG, /* -do- */ - WMI_SERVICE_STA_KEEP_ALIVE, /* STA keep alive mechanism support */ - WMI_SERVICE_TX_ENCAP, /* Packet type for TX encapsulation */ +enum wmi_service { + WMI_SERVICE_BEACON_OFFLOAD = 0, + WMI_SERVICE_SCAN_OFFLOAD, + WMI_SERVICE_ROAM_OFFLOAD, + WMI_SERVICE_BCN_MISS_OFFLOAD, + WMI_SERVICE_STA_PWRSAVE, + WMI_SERVICE_STA_ADVANCED_PWRSAVE, + WMI_SERVICE_AP_UAPSD, + WMI_SERVICE_AP_DFS, + WMI_SERVICE_11AC, + WMI_SERVICE_BLOCKACK, + WMI_SERVICE_PHYERR, + WMI_SERVICE_BCN_FILTER, + WMI_SERVICE_RTT, + WMI_SERVICE_RATECTRL, + WMI_SERVICE_WOW, + WMI_SERVICE_RATECTRL_CACHE, + WMI_SERVICE_IRAM_TIDS, + WMI_SERVICE_ARPNS_OFFLOAD, + WMI_SERVICE_NLO, + WMI_SERVICE_GTK_OFFLOAD, + WMI_SERVICE_SCAN_SCH, + WMI_SERVICE_CSA_OFFLOAD, + WMI_SERVICE_CHATTER, + WMI_SERVICE_COEX_FREQAVOID, + WMI_SERVICE_PACKET_POWER_SAVE, + WMI_SERVICE_FORCE_FW_HANG, + WMI_SERVICE_GPIO, + WMI_SERVICE_STA_DTIM_PS_MODULATED_DTIM, + WMI_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG, + WMI_SERVICE_STA_UAPSD_VAR_AUTO_TRIG, + WMI_SERVICE_STA_KEEP_ALIVE, + WMI_SERVICE_TX_ENCAP, + WMI_SERVICE_BURST, + WMI_SERVICE_SMART_ANTENNA_SW_SUPPORT, + WMI_SERVICE_SMART_ANTENNA_HW_SUPPORT, +}; - WMI_SERVICE_LAST, - WMI_MAX_SERVICE = 64 /* max service */ +enum wmi_10x_service { + WMI_10X_SERVICE_BEACON_OFFLOAD = 0, + WMI_10X_SERVICE_SCAN_OFFLOAD, + WMI_10X_SERVICE_ROAM_OFFLOAD, + WMI_10X_SERVICE_BCN_MISS_OFFLOAD, + WMI_10X_SERVICE_STA_PWRSAVE, + WMI_10X_SERVICE_STA_ADVANCED_PWRSAVE, + WMI_10X_SERVICE_AP_UAPSD, + WMI_10X_SERVICE_AP_DFS, + WMI_10X_SERVICE_11AC, + WMI_10X_SERVICE_BLOCKACK, + WMI_10X_SERVICE_PHYERR, + WMI_10X_SERVICE_BCN_FILTER, + WMI_10X_SERVICE_RTT, + WMI_10X_SERVICE_RATECTRL, + WMI_10X_SERVICE_WOW, + WMI_10X_SERVICE_RATECTRL_CACHE, + WMI_10X_SERVICE_IRAM_TIDS, + WMI_10X_SERVICE_BURST, + + /* introduced in 10.2 */ + WMI_10X_SERVICE_SMART_ANTENNA_SW_SUPPORT, + WMI_10X_SERVICE_FORCE_FW_HANG, + WMI_10X_SERVICE_SMART_ANTENNA_HW_SUPPORT, +}; + +enum wmi_main_service { + WMI_MAIN_SERVICE_BEACON_OFFLOAD = 0, + WMI_MAIN_SERVICE_SCAN_OFFLOAD, + WMI_MAIN_SERVICE_ROAM_OFFLOAD, + WMI_MAIN_SERVICE_BCN_MISS_OFFLOAD, + WMI_MAIN_SERVICE_STA_PWRSAVE, + WMI_MAIN_SERVICE_STA_ADVANCED_PWRSAVE, + WMI_MAIN_SERVICE_AP_UAPSD, + WMI_MAIN_SERVICE_AP_DFS, + WMI_MAIN_SERVICE_11AC, + WMI_MAIN_SERVICE_BLOCKACK, + WMI_MAIN_SERVICE_PHYERR, + WMI_MAIN_SERVICE_BCN_FILTER, + WMI_MAIN_SERVICE_RTT, + WMI_MAIN_SERVICE_RATECTRL, + WMI_MAIN_SERVICE_WOW, + WMI_MAIN_SERVICE_RATECTRL_CACHE, + WMI_MAIN_SERVICE_IRAM_TIDS, + WMI_MAIN_SERVICE_ARPNS_OFFLOAD, + WMI_MAIN_SERVICE_NLO, + WMI_MAIN_SERVICE_GTK_OFFLOAD, + WMI_MAIN_SERVICE_SCAN_SCH, + WMI_MAIN_SERVICE_CSA_OFFLOAD, + WMI_MAIN_SERVICE_CHATTER, + WMI_MAIN_SERVICE_COEX_FREQAVOID, + WMI_MAIN_SERVICE_PACKET_POWER_SAVE, + WMI_MAIN_SERVICE_FORCE_FW_HANG, + WMI_MAIN_SERVICE_GPIO, + WMI_MAIN_SERVICE_STA_DTIM_PS_MODULATED_DTIM, + WMI_MAIN_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG, + WMI_MAIN_SERVICE_STA_UAPSD_VAR_AUTO_TRIG, + WMI_MAIN_SERVICE_STA_KEEP_ALIVE, + WMI_MAIN_SERVICE_TX_ENCAP, }; static inline char *wmi_service_name(int service_id) { +#define SVCSTR(x) case x: return #x + switch (service_id) { - case WMI_SERVICE_BEACON_OFFLOAD: - return "BEACON_OFFLOAD"; - case WMI_SERVICE_SCAN_OFFLOAD: - return "SCAN_OFFLOAD"; - case WMI_SERVICE_ROAM_OFFLOAD: - return "ROAM_OFFLOAD"; - case WMI_SERVICE_BCN_MISS_OFFLOAD: - return "BCN_MISS_OFFLOAD"; - case WMI_SERVICE_STA_PWRSAVE: - return "STA_PWRSAVE"; - case WMI_SERVICE_STA_ADVANCED_PWRSAVE: - return "STA_ADVANCED_PWRSAVE"; - case WMI_SERVICE_AP_UAPSD: - return "AP_UAPSD"; - case WMI_SERVICE_AP_DFS: - return "AP_DFS"; - case WMI_SERVICE_11AC: - return "11AC"; - case WMI_SERVICE_BLOCKACK: - return "BLOCKACK"; - case WMI_SERVICE_PHYERR: - return "PHYERR"; - case WMI_SERVICE_BCN_FILTER: - return "BCN_FILTER"; - case WMI_SERVICE_RTT: - return "RTT"; - case WMI_SERVICE_RATECTRL: - return "RATECTRL"; - case WMI_SERVICE_WOW: - return "WOW"; - case WMI_SERVICE_RATECTRL_CACHE: - return "RATECTRL CACHE"; - case WMI_SERVICE_IRAM_TIDS: - return "IRAM TIDS"; - case WMI_SERVICE_ARPNS_OFFLOAD: - return "ARPNS_OFFLOAD"; - case WMI_SERVICE_NLO: - return "NLO"; - case WMI_SERVICE_GTK_OFFLOAD: - return "GTK_OFFLOAD"; - case WMI_SERVICE_SCAN_SCH: - return "SCAN_SCH"; - case WMI_SERVICE_CSA_OFFLOAD: - return "CSA_OFFLOAD"; - case WMI_SERVICE_CHATTER: - return "CHATTER"; - case WMI_SERVICE_COEX_FREQAVOID: - return "COEX_FREQAVOID"; - case WMI_SERVICE_PACKET_POWER_SAVE: - return "PACKET_POWER_SAVE"; - case WMI_SERVICE_FORCE_FW_HANG: - return "FORCE FW HANG"; - case WMI_SERVICE_GPIO: - return "GPIO"; - case WMI_SERVICE_STA_DTIM_PS_MODULATED_DTIM: - return "MODULATED DTIM"; - case WMI_STA_UAPSD_BASIC_AUTO_TRIG: - return "BASIC UAPSD"; - case WMI_STA_UAPSD_VAR_AUTO_TRIG: - return "VAR UAPSD"; - case WMI_SERVICE_STA_KEEP_ALIVE: - return "STA KEEP ALIVE"; - case WMI_SERVICE_TX_ENCAP: - return "TX ENCAP"; + SVCSTR(WMI_SERVICE_BEACON_OFFLOAD); + SVCSTR(WMI_SERVICE_SCAN_OFFLOAD); + SVCSTR(WMI_SERVICE_ROAM_OFFLOAD); + SVCSTR(WMI_SERVICE_BCN_MISS_OFFLOAD); + SVCSTR(WMI_SERVICE_STA_PWRSAVE); + SVCSTR(WMI_SERVICE_STA_ADVANCED_PWRSAVE); + SVCSTR(WMI_SERVICE_AP_UAPSD); + SVCSTR(WMI_SERVICE_AP_DFS); + SVCSTR(WMI_SERVICE_11AC); + SVCSTR(WMI_SERVICE_BLOCKACK); + SVCSTR(WMI_SERVICE_PHYERR); + SVCSTR(WMI_SERVICE_BCN_FILTER); + SVCSTR(WMI_SERVICE_RTT); + SVCSTR(WMI_SERVICE_RATECTRL); + SVCSTR(WMI_SERVICE_WOW); + SVCSTR(WMI_SERVICE_RATECTRL_CACHE); + SVCSTR(WMI_SERVICE_IRAM_TIDS); + SVCSTR(WMI_SERVICE_ARPNS_OFFLOAD); + SVCSTR(WMI_SERVICE_NLO); + SVCSTR(WMI_SERVICE_GTK_OFFLOAD); + SVCSTR(WMI_SERVICE_SCAN_SCH); + SVCSTR(WMI_SERVICE_CSA_OFFLOAD); + SVCSTR(WMI_SERVICE_CHATTER); + SVCSTR(WMI_SERVICE_COEX_FREQAVOID); + SVCSTR(WMI_SERVICE_PACKET_POWER_SAVE); + SVCSTR(WMI_SERVICE_FORCE_FW_HANG); + SVCSTR(WMI_SERVICE_GPIO); + SVCSTR(WMI_SERVICE_STA_DTIM_PS_MODULATED_DTIM); + SVCSTR(WMI_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG); + SVCSTR(WMI_SERVICE_STA_UAPSD_VAR_AUTO_TRIG); + SVCSTR(WMI_SERVICE_STA_KEEP_ALIVE); + SVCSTR(WMI_SERVICE_TX_ENCAP); + SVCSTR(WMI_SERVICE_BURST); + SVCSTR(WMI_SERVICE_SMART_ANTENNA_SW_SUPPORT); + SVCSTR(WMI_SERVICE_SMART_ANTENNA_HW_SUPPORT); default: - return "UNKNOWN SERVICE\n"; + return NULL; } + +#undef SVCSTR } +#define WMI_MAX_SERVICE 64 + +#define WMI_SERVICE_IS_ENABLED(wmi_svc_bmap, svc_id) \ + (__le32_to_cpu((wmi_svc_bmap)[(svc_id)/(sizeof(u32))]) & \ + BIT((svc_id)%(sizeof(u32)))) + +#define SVCMAP(x, y) \ + do { \ + if (WMI_SERVICE_IS_ENABLED((in), (x))) \ + __set_bit(y, out); \ + } while (0) + +static inline void wmi_10x_svc_map(const __le32 *in, unsigned long *out) +{ + SVCMAP(WMI_10X_SERVICE_BEACON_OFFLOAD, + WMI_SERVICE_BEACON_OFFLOAD); + SVCMAP(WMI_10X_SERVICE_SCAN_OFFLOAD, + WMI_SERVICE_SCAN_OFFLOAD); + SVCMAP(WMI_10X_SERVICE_ROAM_OFFLOAD, + WMI_SERVICE_ROAM_OFFLOAD); + SVCMAP(WMI_10X_SERVICE_BCN_MISS_OFFLOAD, + WMI_SERVICE_BCN_MISS_OFFLOAD); + SVCMAP(WMI_10X_SERVICE_STA_PWRSAVE, + WMI_SERVICE_STA_PWRSAVE); + SVCMAP(WMI_10X_SERVICE_STA_ADVANCED_PWRSAVE, + WMI_SERVICE_STA_ADVANCED_PWRSAVE); + SVCMAP(WMI_10X_SERVICE_AP_UAPSD, + WMI_SERVICE_AP_UAPSD); + SVCMAP(WMI_10X_SERVICE_AP_DFS, + WMI_SERVICE_AP_DFS); + SVCMAP(WMI_10X_SERVICE_11AC, + WMI_SERVICE_11AC); + SVCMAP(WMI_10X_SERVICE_BLOCKACK, + WMI_SERVICE_BLOCKACK); + SVCMAP(WMI_10X_SERVICE_PHYERR, + WMI_SERVICE_PHYERR); + SVCMAP(WMI_10X_SERVICE_BCN_FILTER, + WMI_SERVICE_BCN_FILTER); + SVCMAP(WMI_10X_SERVICE_RTT, + WMI_SERVICE_RTT); + SVCMAP(WMI_10X_SERVICE_RATECTRL, + WMI_SERVICE_RATECTRL); + SVCMAP(WMI_10X_SERVICE_WOW, + WMI_SERVICE_WOW); + SVCMAP(WMI_10X_SERVICE_RATECTRL_CACHE, + WMI_SERVICE_RATECTRL_CACHE); + SVCMAP(WMI_10X_SERVICE_IRAM_TIDS, + WMI_SERVICE_IRAM_TIDS); + SVCMAP(WMI_10X_SERVICE_BURST, + WMI_SERVICE_BURST); + SVCMAP(WMI_10X_SERVICE_SMART_ANTENNA_SW_SUPPORT, + WMI_SERVICE_SMART_ANTENNA_SW_SUPPORT); + SVCMAP(WMI_10X_SERVICE_FORCE_FW_HANG, + WMI_SERVICE_FORCE_FW_HANG); + SVCMAP(WMI_10X_SERVICE_SMART_ANTENNA_HW_SUPPORT, + WMI_SERVICE_SMART_ANTENNA_HW_SUPPORT); +} + +static inline void wmi_main_svc_map(const __le32 *in, unsigned long *out) +{ + SVCMAP(WMI_MAIN_SERVICE_BEACON_OFFLOAD, + WMI_SERVICE_BEACON_OFFLOAD); + SVCMAP(WMI_MAIN_SERVICE_SCAN_OFFLOAD, + WMI_SERVICE_SCAN_OFFLOAD); + SVCMAP(WMI_MAIN_SERVICE_ROAM_OFFLOAD, + WMI_SERVICE_ROAM_OFFLOAD); + SVCMAP(WMI_MAIN_SERVICE_BCN_MISS_OFFLOAD, + WMI_SERVICE_BCN_MISS_OFFLOAD); + SVCMAP(WMI_MAIN_SERVICE_STA_PWRSAVE, + WMI_SERVICE_STA_PWRSAVE); + SVCMAP(WMI_MAIN_SERVICE_STA_ADVANCED_PWRSAVE, + WMI_SERVICE_STA_ADVANCED_PWRSAVE); + SVCMAP(WMI_MAIN_SERVICE_AP_UAPSD, + WMI_SERVICE_AP_UAPSD); + SVCMAP(WMI_MAIN_SERVICE_AP_DFS, + WMI_SERVICE_AP_DFS); + SVCMAP(WMI_MAIN_SERVICE_11AC, + WMI_SERVICE_11AC); + SVCMAP(WMI_MAIN_SERVICE_BLOCKACK, + WMI_SERVICE_BLOCKACK); + SVCMAP(WMI_MAIN_SERVICE_PHYERR, + WMI_SERVICE_PHYERR); + SVCMAP(WMI_MAIN_SERVICE_BCN_FILTER, + WMI_SERVICE_BCN_FILTER); + SVCMAP(WMI_MAIN_SERVICE_RTT, + WMI_SERVICE_RTT); + SVCMAP(WMI_MAIN_SERVICE_RATECTRL, + WMI_SERVICE_RATECTRL); + SVCMAP(WMI_MAIN_SERVICE_WOW, + WMI_SERVICE_WOW); + SVCMAP(WMI_MAIN_SERVICE_RATECTRL_CACHE, + WMI_SERVICE_RATECTRL_CACHE); + SVCMAP(WMI_MAIN_SERVICE_IRAM_TIDS, + WMI_SERVICE_IRAM_TIDS); + SVCMAP(WMI_MAIN_SERVICE_ARPNS_OFFLOAD, + WMI_SERVICE_ARPNS_OFFLOAD); + SVCMAP(WMI_MAIN_SERVICE_NLO, + WMI_SERVICE_NLO); + SVCMAP(WMI_MAIN_SERVICE_GTK_OFFLOAD, + WMI_SERVICE_GTK_OFFLOAD); + SVCMAP(WMI_MAIN_SERVICE_SCAN_SCH, + WMI_SERVICE_SCAN_SCH); + SVCMAP(WMI_MAIN_SERVICE_CSA_OFFLOAD, + WMI_SERVICE_CSA_OFFLOAD); + SVCMAP(WMI_MAIN_SERVICE_CHATTER, + WMI_SERVICE_CHATTER); + SVCMAP(WMI_MAIN_SERVICE_COEX_FREQAVOID, + WMI_SERVICE_COEX_FREQAVOID); + SVCMAP(WMI_MAIN_SERVICE_PACKET_POWER_SAVE, + WMI_SERVICE_PACKET_POWER_SAVE); + SVCMAP(WMI_MAIN_SERVICE_FORCE_FW_HANG, + WMI_SERVICE_FORCE_FW_HANG); + SVCMAP(WMI_MAIN_SERVICE_GPIO, + WMI_SERVICE_GPIO); + SVCMAP(WMI_MAIN_SERVICE_STA_DTIM_PS_MODULATED_DTIM, + WMI_SERVICE_STA_DTIM_PS_MODULATED_DTIM); + SVCMAP(WMI_MAIN_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG, + WMI_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG); + SVCMAP(WMI_MAIN_SERVICE_STA_UAPSD_VAR_AUTO_TRIG, + WMI_SERVICE_STA_UAPSD_VAR_AUTO_TRIG); + SVCMAP(WMI_MAIN_SERVICE_STA_KEEP_ALIVE, + WMI_SERVICE_STA_KEEP_ALIVE); + SVCMAP(WMI_MAIN_SERVICE_TX_ENCAP, + WMI_SERVICE_TX_ENCAP); +} + +#undef SVCMAP #define WMI_SERVICE_BM_SIZE \ ((WMI_MAX_SERVICE + sizeof(u32) - 1)/sizeof(u32)) @@ -1229,10 +1392,6 @@ struct wlan_host_mem_req { __le32 num_units; } __packed; -#define WMI_SERVICE_IS_ENABLED(wmi_svc_bmap, svc_id) \ - ((((wmi_svc_bmap)[(svc_id)/(sizeof(u32))]) & \ - (1 << ((svc_id)%(sizeof(u32))))) != 0) - /* * The following struct holds optional payload for * wmi_service_ready_event,e.g., 11ac pass some of the From 9ff8b7247dd211158410af4bb5ebbc507182729f Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Tue, 5 Aug 2014 14:54:43 +0200 Subject: [PATCH 010/221] ath10k: simplify scan debug prints This also reduces the cruft of printing scan event names in capitals. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 67 +++++++++++++++------------ 1 file changed, 38 insertions(+), 29 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index a381006c8124..f48f29563a4d 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -811,6 +811,42 @@ int ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *skb) return ret; } +static const char * +ath10k_wmi_event_scan_type_str(enum wmi_scan_event_type type, + enum wmi_scan_completion_reason reason) +{ + switch (type) { + case WMI_SCAN_EVENT_STARTED: + return "started"; + case WMI_SCAN_EVENT_COMPLETED: + switch (reason) { + case WMI_SCAN_REASON_COMPLETED: + return "completed"; + case WMI_SCAN_REASON_CANCELLED: + return "completed [cancelled]"; + case WMI_SCAN_REASON_PREEMPTED: + return "completed [preempted]"; + case WMI_SCAN_REASON_TIMEDOUT: + return "completed [timedout]"; + case WMI_SCAN_REASON_MAX: + break; + } + return "completed [unknown]"; + case WMI_SCAN_EVENT_BSS_CHANNEL: + return "bss channel"; + case WMI_SCAN_EVENT_FOREIGN_CHANNEL: + return "foreign channel"; + case WMI_SCAN_EVENT_DEQUEUED: + return "dequeued"; + case WMI_SCAN_EVENT_PREEMPTED: + return "preempted"; + case WMI_SCAN_EVENT_START_FAILED: + return "start failed"; + default: + return "unknown"; + } +} + static int ath10k_wmi_event_scan(struct ath10k *ar, struct sk_buff *skb) { struct wmi_scan_event *event = (struct wmi_scan_event *)skb->data; @@ -828,41 +864,22 @@ static int ath10k_wmi_event_scan(struct ath10k *ar, struct sk_buff *skb) scan_id = __le32_to_cpu(event->scan_id); vdev_id = __le32_to_cpu(event->vdev_id); - ath10k_dbg(ATH10K_DBG_WMI, "WMI_SCAN_EVENTID\n"); ath10k_dbg(ATH10K_DBG_WMI, - "scan event type %d reason %d freq %d req_id %d " + "scan event %s type %d reason %d freq %d req_id %d " "scan_id %d vdev_id %d\n", + ath10k_wmi_event_scan_type_str(event_type, reason), event_type, reason, freq, req_id, scan_id, vdev_id); spin_lock_bh(&ar->data_lock); switch (event_type) { case WMI_SCAN_EVENT_STARTED: - ath10k_dbg(ATH10K_DBG_WMI, "SCAN_EVENT_STARTED\n"); if (ar->scan.in_progress && ar->scan.is_roc) ieee80211_ready_on_channel(ar->hw); complete(&ar->scan.started); break; case WMI_SCAN_EVENT_COMPLETED: - ath10k_dbg(ATH10K_DBG_WMI, "SCAN_EVENT_COMPLETED\n"); - switch (reason) { - case WMI_SCAN_REASON_COMPLETED: - ath10k_dbg(ATH10K_DBG_WMI, "SCAN_REASON_COMPLETED\n"); - break; - case WMI_SCAN_REASON_CANCELLED: - ath10k_dbg(ATH10K_DBG_WMI, "SCAN_REASON_CANCELED\n"); - break; - case WMI_SCAN_REASON_PREEMPTED: - ath10k_dbg(ATH10K_DBG_WMI, "SCAN_REASON_PREEMPTED\n"); - break; - case WMI_SCAN_REASON_TIMEDOUT: - ath10k_dbg(ATH10K_DBG_WMI, "SCAN_REASON_TIMEDOUT\n"); - break; - default: - break; - } - ar->scan_channel = NULL; if (!ar->scan.in_progress) { ath10k_warn("no scan requested, ignoring\n"); @@ -883,11 +900,9 @@ static int ath10k_wmi_event_scan(struct ath10k *ar, struct sk_buff *skb) ar->scan.in_progress = false; break; case WMI_SCAN_EVENT_BSS_CHANNEL: - ath10k_dbg(ATH10K_DBG_WMI, "SCAN_EVENT_BSS_CHANNEL\n"); ar->scan_channel = NULL; break; case WMI_SCAN_EVENT_FOREIGN_CHANNEL: - ath10k_dbg(ATH10K_DBG_WMI, "SCAN_EVENT_FOREIGN_CHANNEL\n"); ar->scan_channel = ieee80211_get_channel(ar->hw->wiphy, freq); if (ar->scan.in_progress && ar->scan.is_roc && ar->scan.roc_freq == freq) { @@ -895,14 +910,8 @@ static int ath10k_wmi_event_scan(struct ath10k *ar, struct sk_buff *skb) } break; case WMI_SCAN_EVENT_DEQUEUED: - ath10k_dbg(ATH10K_DBG_WMI, "SCAN_EVENT_DEQUEUED\n"); - break; case WMI_SCAN_EVENT_PREEMPTED: - ath10k_dbg(ATH10K_DBG_WMI, "WMI_SCAN_EVENT_PREEMPTED\n"); - break; case WMI_SCAN_EVENT_START_FAILED: - ath10k_dbg(ATH10K_DBG_WMI, "WMI_SCAN_EVENT_START_FAILED\n"); - break; default: break; } From 5c81c7fd62004be13a3c9345ca25607d14862cc4 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Tue, 5 Aug 2014 14:54:44 +0200 Subject: [PATCH 011/221] ath10k: introduce a stricter scan state machine This aims at fixing some rare scan bugs related to firmware reporting unexpected scan event sequences. One such bug was if spectral scan phyerr reporting prevented firmware from properly propagating scan events to host. This led to scan timeout. After that next scan would trigger scan completed event first (before scan started event) leading to ar->scan.in_progress and timeout timer states to be overwritten incorrectly and making the very next scan to hang forever. Reported-by: Janusz Dziedzic Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 5 +- drivers/net/wireless/ath/ath10k/core.h | 28 ++- drivers/net/wireless/ath/ath10k/mac.c | 240 +++++++++++++++---------- drivers/net/wireless/ath/ath10k/mac.h | 4 +- drivers/net/wireless/ath/ath10k/wmi.c | 145 +++++++++++---- 5 files changed, 283 insertions(+), 139 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 440c3ff03aec..c090913d10d1 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -665,8 +665,7 @@ static void ath10k_core_restart(struct work_struct *work) switch (ar->state) { case ATH10K_STATE_ON: ar->state = ATH10K_STATE_RESTARTING; - del_timer_sync(&ar->scan.timeout); - ath10k_reset_scan((unsigned long)ar); + ath10k_scan_finish(ar); ieee80211_restart_hw(ar->hw); break; case ATH10K_STATE_OFF: @@ -1086,7 +1085,7 @@ struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev, init_completion(&ar->install_key_done); init_completion(&ar->vdev_setup_done); - setup_timer(&ar->scan.timeout, ath10k_reset_scan, (unsigned long)ar); + INIT_DELAYED_WORK(&ar->scan.timeout, ath10k_scan_timeout_work); ar->workqueue = create_singlethread_workqueue("ath10k_wq"); if (!ar->workqueue) diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 94b1ff2082cf..95c611db43b8 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -348,6 +348,29 @@ enum ath10k_dev_flags { ATH10K_FLAG_CORE_REGISTERED, }; +enum ath10k_scan_state { + ATH10K_SCAN_IDLE, + ATH10K_SCAN_STARTING, + ATH10K_SCAN_RUNNING, + ATH10K_SCAN_ABORTING, +}; + +static inline const char *ath10k_scan_state_str(enum ath10k_scan_state state) +{ + switch (state) { + case ATH10K_SCAN_IDLE: + return "idle"; + case ATH10K_SCAN_STARTING: + return "starting"; + case ATH10K_SCAN_RUNNING: + return "running"; + case ATH10K_SCAN_ABORTING: + return "aborting"; + } + + return "unknown"; +} + struct ath10k { struct ath_common ath_common; struct ieee80211_hw *hw; @@ -417,10 +440,9 @@ struct ath10k { struct completion started; struct completion completed; struct completion on_channel; - struct timer_list timeout; + struct delayed_work timeout; + enum ath10k_scan_state state; bool is_roc; - bool in_progress; - bool aborting; int vdev_id; int roc_freq; } scan; diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 3c7942030361..3bf7ddeb3271 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -2159,34 +2159,40 @@ void ath10k_mgmt_over_wmi_tx_work(struct work_struct *work) /* Scanning */ /************/ -/* - * This gets called if we dont get a heart-beat during scan. - * This may indicate the FW has hung and we need to abort the - * scan manually to prevent cancel_hw_scan() from deadlocking - */ -void ath10k_reset_scan(unsigned long ptr) +void __ath10k_scan_finish(struct ath10k *ar) { - struct ath10k *ar = (struct ath10k *)ptr; + lockdep_assert_held(&ar->data_lock); - spin_lock_bh(&ar->data_lock); - if (!ar->scan.in_progress) { - spin_unlock_bh(&ar->data_lock); - return; + switch (ar->scan.state) { + case ATH10K_SCAN_IDLE: + break; + case ATH10K_SCAN_RUNNING: + case ATH10K_SCAN_ABORTING: + if (ar->scan.is_roc) + ieee80211_remain_on_channel_expired(ar->hw); + else + ieee80211_scan_completed(ar->hw, + (ar->scan.state == + ATH10K_SCAN_ABORTING)); + /* fall through */ + case ATH10K_SCAN_STARTING: + ar->scan.state = ATH10K_SCAN_IDLE; + ar->scan_channel = NULL; + ath10k_offchan_tx_purge(ar); + cancel_delayed_work(&ar->scan.timeout); + complete_all(&ar->scan.completed); + break; } +} - ath10k_warn("scan timed out, firmware problem?\n"); - - if (ar->scan.is_roc) - ieee80211_remain_on_channel_expired(ar->hw); - else - ieee80211_scan_completed(ar->hw, 1 /* aborted */); - - ar->scan.in_progress = false; - complete_all(&ar->scan.completed); +void ath10k_scan_finish(struct ath10k *ar) +{ + spin_lock_bh(&ar->data_lock); + __ath10k_scan_finish(ar); spin_unlock_bh(&ar->data_lock); } -static int ath10k_abort_scan(struct ath10k *ar) +static int ath10k_scan_stop(struct ath10k *ar) { struct wmi_stop_scan_arg arg = { .req_id = 1, /* FIXME */ @@ -2197,49 +2203,81 @@ static int ath10k_abort_scan(struct ath10k *ar) lockdep_assert_held(&ar->conf_mutex); - del_timer_sync(&ar->scan.timeout); - - spin_lock_bh(&ar->data_lock); - if (!ar->scan.in_progress) { - spin_unlock_bh(&ar->data_lock); - return 0; - } - - ar->scan.aborting = true; - spin_unlock_bh(&ar->data_lock); - ret = ath10k_wmi_stop_scan(ar, &arg); if (ret) { ath10k_warn("failed to stop wmi scan: %d\n", ret); - spin_lock_bh(&ar->data_lock); - ar->scan.in_progress = false; - ath10k_offchan_tx_purge(ar); - spin_unlock_bh(&ar->data_lock); - return -EIO; + goto out; } ret = wait_for_completion_timeout(&ar->scan.completed, 3*HZ); - if (ret == 0) - ath10k_warn("timed out while waiting for scan to stop\n"); - - /* scan completion may be done right after we timeout here, so let's - * check the in_progress and tell mac80211 scan is completed. if we - * don't do that and FW fails to send us scan completion indication - * then userspace won't be able to scan anymore */ - ret = 0; - - spin_lock_bh(&ar->data_lock); - if (ar->scan.in_progress) { - ath10k_warn("failed to stop scan, it's still in progress\n"); - ar->scan.in_progress = false; - ath10k_offchan_tx_purge(ar); + if (ret == 0) { + ath10k_warn("failed to receive scan abortion completion: timed out\n"); ret = -ETIMEDOUT; + } else if (ret > 0) { + ret = 0; } + +out: + /* Scan state should be updated upon scan completion but in case + * firmware fails to deliver the event (for whatever reason) it is + * desired to clean up scan state anyway. Firmware may have just + * dropped the scan completion event delivery due to transport pipe + * being overflown with data and/or it can recover on its own before + * next scan request is submitted. + */ + spin_lock_bh(&ar->data_lock); + if (ar->scan.state != ATH10K_SCAN_IDLE) + __ath10k_scan_finish(ar); spin_unlock_bh(&ar->data_lock); return ret; } +static void ath10k_scan_abort(struct ath10k *ar) +{ + int ret; + + lockdep_assert_held(&ar->conf_mutex); + + spin_lock_bh(&ar->data_lock); + + switch (ar->scan.state) { + case ATH10K_SCAN_IDLE: + /* This can happen if timeout worker kicked in and called + * abortion while scan completion was being processed. + */ + break; + case ATH10K_SCAN_STARTING: + case ATH10K_SCAN_ABORTING: + ath10k_warn("refusing scan abortion due to invalid scan state: %s (%d)\n", + ath10k_scan_state_str(ar->scan.state), + ar->scan.state); + break; + case ATH10K_SCAN_RUNNING: + ar->scan.state = ATH10K_SCAN_ABORTING; + spin_unlock_bh(&ar->data_lock); + + ret = ath10k_scan_stop(ar); + if (ret) + ath10k_warn("failed to abort scan: %d\n", ret); + + spin_lock_bh(&ar->data_lock); + break; + } + + spin_unlock_bh(&ar->data_lock); +} + +void ath10k_scan_timeout_work(struct work_struct *work) +{ + struct ath10k *ar = container_of(work, struct ath10k, + scan.timeout.work); + + mutex_lock(&ar->conf_mutex); + ath10k_scan_abort(ar); + mutex_unlock(&ar->conf_mutex); +} + static int ath10k_start_scan(struct ath10k *ar, const struct wmi_start_scan_arg *arg) { @@ -2253,17 +2291,16 @@ static int ath10k_start_scan(struct ath10k *ar, ret = wait_for_completion_timeout(&ar->scan.started, 1*HZ); if (ret == 0) { - ath10k_abort_scan(ar); - return ret; + ret = ath10k_scan_stop(ar); + if (ret) + ath10k_warn("failed to stop scan: %d\n", ret); + + return -ETIMEDOUT; } - /* the scan can complete earlier, before we even - * start the timer. in that case the timer handler - * checks ar->scan.in_progress and bails out if its - * false. Add a 200ms margin to account event/command - * processing. */ - mod_timer(&ar->scan.timeout, jiffies + - msecs_to_jiffies(arg->max_scan_time+200)); + /* Add a 200ms margin to account for event/command processing */ + ieee80211_queue_delayed_work(ar->hw, &ar->scan.timeout, + msecs_to_jiffies(arg->max_scan_time+200)); return 0; } @@ -2339,8 +2376,7 @@ void ath10k_halt(struct ath10k *ar) ath10k_monitor_stop(ar); } - del_timer_sync(&ar->scan.timeout); - ath10k_reset_scan((unsigned long)ar); + ath10k_scan_finish(ar); ath10k_peer_cleanup_all(ar); ath10k_core_stop(ar); ath10k_hif_power_down(ar); @@ -2531,6 +2567,7 @@ static void ath10k_stop(struct ieee80211_hw *hw) } mutex_unlock(&ar->conf_mutex); + cancel_delayed_work_sync(&ar->scan.timeout); cancel_work_sync(&ar->restart_work); } @@ -3176,20 +3213,26 @@ static int ath10k_hw_scan(struct ieee80211_hw *hw, mutex_lock(&ar->conf_mutex); spin_lock_bh(&ar->data_lock); - if (ar->scan.in_progress) { - spin_unlock_bh(&ar->data_lock); + switch (ar->scan.state) { + case ATH10K_SCAN_IDLE: + reinit_completion(&ar->scan.started); + reinit_completion(&ar->scan.completed); + ar->scan.state = ATH10K_SCAN_STARTING; + ar->scan.is_roc = false; + ar->scan.vdev_id = arvif->vdev_id; + ret = 0; + break; + case ATH10K_SCAN_STARTING: + case ATH10K_SCAN_RUNNING: + case ATH10K_SCAN_ABORTING: ret = -EBUSY; - goto exit; + break; } - - reinit_completion(&ar->scan.started); - reinit_completion(&ar->scan.completed); - ar->scan.in_progress = true; - ar->scan.aborting = false; - ar->scan.is_roc = false; - ar->scan.vdev_id = arvif->vdev_id; spin_unlock_bh(&ar->data_lock); + if (ret) + goto exit; + memset(&arg, 0, sizeof(arg)); ath10k_wmi_start_scan_init(ar, &arg); arg.vdev_id = arvif->vdev_id; @@ -3223,7 +3266,7 @@ static int ath10k_hw_scan(struct ieee80211_hw *hw, if (ret) { ath10k_warn("failed to start hw scan: %d\n", ret); spin_lock_bh(&ar->data_lock); - ar->scan.in_progress = false; + ar->scan.state = ATH10K_SCAN_IDLE; spin_unlock_bh(&ar->data_lock); } @@ -3236,14 +3279,10 @@ static void ath10k_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct ath10k *ar = hw->priv; - int ret; mutex_lock(&ar->conf_mutex); - ret = ath10k_abort_scan(ar); - if (ret) { - ath10k_warn("failed to abort scan: %d\n", ret); - ieee80211_scan_completed(hw, 1 /* aborted */); - } + cancel_delayed_work_sync(&ar->scan.timeout); + ath10k_scan_abort(ar); mutex_unlock(&ar->conf_mutex); } @@ -3666,27 +3705,33 @@ static int ath10k_remain_on_channel(struct ieee80211_hw *hw, struct ath10k *ar = hw->priv; struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); struct wmi_start_scan_arg arg; - int ret; + int ret = 0; mutex_lock(&ar->conf_mutex); spin_lock_bh(&ar->data_lock); - if (ar->scan.in_progress) { - spin_unlock_bh(&ar->data_lock); + switch (ar->scan.state) { + case ATH10K_SCAN_IDLE: + reinit_completion(&ar->scan.started); + reinit_completion(&ar->scan.completed); + reinit_completion(&ar->scan.on_channel); + ar->scan.state = ATH10K_SCAN_STARTING; + ar->scan.is_roc = true; + ar->scan.vdev_id = arvif->vdev_id; + ar->scan.roc_freq = chan->center_freq; + ret = 0; + break; + case ATH10K_SCAN_STARTING: + case ATH10K_SCAN_RUNNING: + case ATH10K_SCAN_ABORTING: ret = -EBUSY; - goto exit; + break; } - - reinit_completion(&ar->scan.started); - reinit_completion(&ar->scan.completed); - reinit_completion(&ar->scan.on_channel); - ar->scan.in_progress = true; - ar->scan.aborting = false; - ar->scan.is_roc = true; - ar->scan.vdev_id = arvif->vdev_id; - ar->scan.roc_freq = chan->center_freq; spin_unlock_bh(&ar->data_lock); + if (ret) + goto exit; + memset(&arg, 0, sizeof(arg)); ath10k_wmi_start_scan_init(ar, &arg); arg.vdev_id = arvif->vdev_id; @@ -3703,7 +3748,7 @@ static int ath10k_remain_on_channel(struct ieee80211_hw *hw, if (ret) { ath10k_warn("failed to start roc scan: %d\n", ret); spin_lock_bh(&ar->data_lock); - ar->scan.in_progress = false; + ar->scan.state = ATH10K_SCAN_IDLE; spin_unlock_bh(&ar->data_lock); goto exit; } @@ -3711,7 +3756,11 @@ static int ath10k_remain_on_channel(struct ieee80211_hw *hw, ret = wait_for_completion_timeout(&ar->scan.on_channel, 3*HZ); if (ret == 0) { ath10k_warn("failed to switch to channel for roc scan\n"); - ath10k_abort_scan(ar); + + ret = ath10k_scan_stop(ar); + if (ret) + ath10k_warn("failed to stop scan: %d\n", ret); + ret = -ETIMEDOUT; goto exit; } @@ -3727,7 +3776,8 @@ static int ath10k_cancel_remain_on_channel(struct ieee80211_hw *hw) struct ath10k *ar = hw->priv; mutex_lock(&ar->conf_mutex); - ath10k_abort_scan(ar); + cancel_delayed_work_sync(&ar->scan.timeout); + ath10k_scan_abort(ar); mutex_unlock(&ar->conf_mutex); return 0; diff --git a/drivers/net/wireless/ath/ath10k/mac.h b/drivers/net/wireless/ath/ath10k/mac.h index ef4f84376d7c..e64fce70e9eb 100644 --- a/drivers/net/wireless/ath/ath10k/mac.h +++ b/drivers/net/wireless/ath/ath10k/mac.h @@ -31,7 +31,9 @@ void ath10k_mac_destroy(struct ath10k *ar); int ath10k_mac_register(struct ath10k *ar); void ath10k_mac_unregister(struct ath10k *ar); struct ath10k_vif *ath10k_get_arvif(struct ath10k *ar, u32 vdev_id); -void ath10k_reset_scan(unsigned long ptr); +void __ath10k_scan_finish(struct ath10k *ar); +void ath10k_scan_finish(struct ath10k *ar); +void ath10k_scan_timeout_work(struct work_struct *work); void ath10k_offchan_tx_purge(struct ath10k *ar); void ath10k_offchan_tx_work(struct work_struct *work); void ath10k_mgmt_over_wmi_tx_purge(struct ath10k *ar); diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index f48f29563a4d..23acbadeb8fa 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -811,6 +811,94 @@ int ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *skb) return ret; } +static void ath10k_wmi_event_scan_started(struct ath10k *ar) +{ + lockdep_assert_held(&ar->data_lock); + + switch (ar->scan.state) { + case ATH10K_SCAN_IDLE: + case ATH10K_SCAN_RUNNING: + case ATH10K_SCAN_ABORTING: + ath10k_warn("received scan started event in an invalid scan state: %s (%d)\n", + ath10k_scan_state_str(ar->scan.state), + ar->scan.state); + break; + case ATH10K_SCAN_STARTING: + ar->scan.state = ATH10K_SCAN_RUNNING; + + if (ar->scan.is_roc) + ieee80211_ready_on_channel(ar->hw); + + complete(&ar->scan.started); + break; + } +} + +static void ath10k_wmi_event_scan_completed(struct ath10k *ar) +{ + lockdep_assert_held(&ar->data_lock); + + switch (ar->scan.state) { + case ATH10K_SCAN_IDLE: + case ATH10K_SCAN_STARTING: + /* One suspected reason scan can be completed while starting is + * if firmware fails to deliver all scan events to the host, + * e.g. when transport pipe is full. This has been observed + * with spectral scan phyerr events starving wmi transport + * pipe. In such case the "scan completed" event should be (and + * is) ignored by the host as it may be just firmware's scan + * state machine recovering. + */ + ath10k_warn("received scan completed event in an invalid scan state: %s (%d)\n", + ath10k_scan_state_str(ar->scan.state), + ar->scan.state); + break; + case ATH10K_SCAN_RUNNING: + case ATH10K_SCAN_ABORTING: + __ath10k_scan_finish(ar); + break; + } +} + +static void ath10k_wmi_event_scan_bss_chan(struct ath10k *ar) +{ + lockdep_assert_held(&ar->data_lock); + + switch (ar->scan.state) { + case ATH10K_SCAN_IDLE: + case ATH10K_SCAN_STARTING: + ath10k_warn("received scan bss chan event in an invalid scan state: %s (%d)\n", + ath10k_scan_state_str(ar->scan.state), + ar->scan.state); + break; + case ATH10K_SCAN_RUNNING: + case ATH10K_SCAN_ABORTING: + ar->scan_channel = NULL; + break; + } +} + +static void ath10k_wmi_event_scan_foreign_chan(struct ath10k *ar, u32 freq) +{ + lockdep_assert_held(&ar->data_lock); + + switch (ar->scan.state) { + case ATH10K_SCAN_IDLE: + case ATH10K_SCAN_STARTING: + ath10k_warn("received scan foreign chan event in an invalid scan state: %s (%d)\n", + ath10k_scan_state_str(ar->scan.state), + ar->scan.state); + break; + case ATH10K_SCAN_RUNNING: + case ATH10K_SCAN_ABORTING: + ar->scan_channel = ieee80211_get_channel(ar->hw->wiphy, freq); + + if (ar->scan.is_roc && ar->scan.roc_freq == freq) + complete(&ar->scan.on_channel); + break; + } +} + static const char * ath10k_wmi_event_scan_type_str(enum wmi_scan_event_type type, enum wmi_scan_completion_reason reason) @@ -864,54 +952,32 @@ static int ath10k_wmi_event_scan(struct ath10k *ar, struct sk_buff *skb) scan_id = __le32_to_cpu(event->scan_id); vdev_id = __le32_to_cpu(event->vdev_id); - ath10k_dbg(ATH10K_DBG_WMI, - "scan event %s type %d reason %d freq %d req_id %d " - "scan_id %d vdev_id %d\n", - ath10k_wmi_event_scan_type_str(event_type, reason), - event_type, reason, freq, req_id, scan_id, vdev_id); - spin_lock_bh(&ar->data_lock); + ath10k_dbg(ATH10K_DBG_WMI, + "scan event %s type %d reason %d freq %d req_id %d scan_id %d vdev_id %d state %s (%d)\n", + ath10k_wmi_event_scan_type_str(event_type, reason), + event_type, reason, freq, req_id, scan_id, vdev_id, + ath10k_scan_state_str(ar->scan.state), ar->scan.state); + switch (event_type) { case WMI_SCAN_EVENT_STARTED: - if (ar->scan.in_progress && ar->scan.is_roc) - ieee80211_ready_on_channel(ar->hw); - - complete(&ar->scan.started); + ath10k_wmi_event_scan_started(ar); break; case WMI_SCAN_EVENT_COMPLETED: - ar->scan_channel = NULL; - if (!ar->scan.in_progress) { - ath10k_warn("no scan requested, ignoring\n"); - break; - } - - if (ar->scan.is_roc) { - ath10k_offchan_tx_purge(ar); - - if (!ar->scan.aborting) - ieee80211_remain_on_channel_expired(ar->hw); - } else { - ieee80211_scan_completed(ar->hw, ar->scan.aborting); - } - - del_timer(&ar->scan.timeout); - complete_all(&ar->scan.completed); - ar->scan.in_progress = false; + ath10k_wmi_event_scan_completed(ar); break; case WMI_SCAN_EVENT_BSS_CHANNEL: - ar->scan_channel = NULL; + ath10k_wmi_event_scan_bss_chan(ar); break; case WMI_SCAN_EVENT_FOREIGN_CHANNEL: - ar->scan_channel = ieee80211_get_channel(ar->hw->wiphy, freq); - if (ar->scan.in_progress && ar->scan.is_roc && - ar->scan.roc_freq == freq) { - complete(&ar->scan.on_channel); - } + ath10k_wmi_event_scan_foreign_chan(ar, freq); + break; + case WMI_SCAN_EVENT_START_FAILED: + ath10k_warn("received scan start failure event\n"); break; case WMI_SCAN_EVENT_DEQUEUED: case WMI_SCAN_EVENT_PREEMPTED: - case WMI_SCAN_EVENT_START_FAILED: default: break; } @@ -1171,9 +1237,14 @@ static void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb) spin_lock_bh(&ar->data_lock); - if (!ar->scan.in_progress) { - ath10k_warn("chan info event without a scan request?\n"); + switch (ar->scan.state) { + case ATH10K_SCAN_IDLE: + case ATH10K_SCAN_STARTING: + ath10k_warn("received chan info event without a scan request, ignoring\n"); goto exit; + case ATH10K_SCAN_RUNNING: + case ATH10K_SCAN_ABORTING: + break; } idx = freq_to_idx(ar, freq); From e7b541948b7ae542267257a6183341f6a92ed1b8 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Thu, 7 Aug 2014 11:03:27 +0200 Subject: [PATCH 012/221] ath10k: embed ar_pci inside ar Use the common convention of embedding private structures inside parent structures. This reduces allocations and simplifies pci probing code. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 5 ++--- drivers/net/wireless/ath/ath10k/core.h | 6 ++++-- drivers/net/wireless/ath/ath10k/mac.c | 4 ++-- drivers/net/wireless/ath/ath10k/mac.h | 2 +- drivers/net/wireless/ath/ath10k/pci.c | 25 +++++++++---------------- drivers/net/wireless/ath/ath10k/pci.h | 2 +- 6 files changed, 19 insertions(+), 25 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index c090913d10d1..7f95bd05e343 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -1059,12 +1059,12 @@ void ath10k_core_unregister(struct ath10k *ar) } EXPORT_SYMBOL(ath10k_core_unregister); -struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev, +struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev, const struct ath10k_hif_ops *hif_ops) { struct ath10k *ar; - ar = ath10k_mac_create(); + ar = ath10k_mac_create(priv_size); if (!ar) return NULL; @@ -1074,7 +1074,6 @@ struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev, ar->p2p = !!ath10k_p2p; ar->dev = dev; - ar->hif.priv = hif_priv; ar->hif.ops = hif_ops; init_completion(&ar->scan.started); diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 95c611db43b8..cca6060dbf30 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -398,7 +398,6 @@ struct ath10k { bool p2p; struct { - void *priv; const struct ath10k_hif_ops *ops; } hif; @@ -532,9 +531,12 @@ struct ath10k { enum ath10k_spectral_mode mode; struct ath10k_spec_scan config; } spectral; + + /* must be last */ + u8 drv_priv[0] __aligned(sizeof(void *)); }; -struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev, +struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev, const struct ath10k_hif_ops *hif_ops); void ath10k_core_destroy(struct ath10k *ar); diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 3bf7ddeb3271..a5ec7c2502b5 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -4564,12 +4564,12 @@ static struct ieee80211_rate ath10k_rates[] = { #define ath10k_g_rates (ath10k_rates + 0) #define ath10k_g_rates_size (ARRAY_SIZE(ath10k_rates)) -struct ath10k *ath10k_mac_create(void) +struct ath10k *ath10k_mac_create(size_t priv_size) { struct ieee80211_hw *hw; struct ath10k *ar; - hw = ieee80211_alloc_hw(sizeof(struct ath10k), &ath10k_ops); + hw = ieee80211_alloc_hw(sizeof(struct ath10k) + priv_size, &ath10k_ops); if (!hw) return NULL; diff --git a/drivers/net/wireless/ath/ath10k/mac.h b/drivers/net/wireless/ath/ath10k/mac.h index e64fce70e9eb..6c80eeada3e2 100644 --- a/drivers/net/wireless/ath/ath10k/mac.h +++ b/drivers/net/wireless/ath/ath10k/mac.h @@ -26,7 +26,7 @@ struct ath10k_generic_iter { int ret; }; -struct ath10k *ath10k_mac_create(void); +struct ath10k *ath10k_mac_create(size_t priv_size); void ath10k_mac_destroy(struct ath10k *ar); int ath10k_mac_register(struct ath10k *ar); void ath10k_mac_unregister(struct ath10k *ar); diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 2d340cc522e3..a2003b66a8bc 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -2621,10 +2621,14 @@ static int ath10k_pci_probe(struct pci_dev *pdev, ath10k_dbg(ATH10K_DBG_PCI, "pci probe\n"); - ar_pci = kzalloc(sizeof(*ar_pci), GFP_KERNEL); - if (ar_pci == NULL) + ar = ath10k_core_create(sizeof(*ar_pci), &pdev->dev, + &ath10k_pci_hif_ops); + if (!ar) { + ath10k_err("failed to allocate core\n"); return -ENOMEM; + } + ar_pci = ath10k_pci_priv(ar); ar_pci->pdev = pdev; ar_pci->dev = &pdev->dev; @@ -2635,7 +2639,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev, default: ret = -ENODEV; ath10k_err("Unknown device ID: %d\n", pci_dev->device); - goto err_ar_pci; + goto err_core_destroy; } if (ath10k_pci_target_ps) @@ -2643,13 +2647,6 @@ static int ath10k_pci_probe(struct pci_dev *pdev, ath10k_pci_dump_features(ar_pci); - ar = ath10k_core_create(ar_pci, ar_pci->dev, &ath10k_pci_hif_ops); - if (!ar) { - ath10k_err("failed to create driver core\n"); - ret = -EINVAL; - goto err_ar_pci; - } - ar_pci->ar = ar; atomic_set(&ar_pci->keep_awake_count, 0); @@ -2658,7 +2655,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev, ret = pci_enable_device(pdev); if (ret) { ath10k_err("failed to enable PCI device: %d\n", ret); - goto err_ar; + goto err_core_destroy; } /* Request MMIO resources */ @@ -2742,11 +2739,8 @@ err_region: pci_release_region(pdev, BAR_NUM); err_device: pci_disable_device(pdev); -err_ar: +err_core_destroy: ath10k_core_destroy(ar); -err_ar_pci: - /* call HIF PCI free here */ - kfree(ar_pci); return ret; } @@ -2775,7 +2769,6 @@ static void ath10k_pci_remove(struct pci_dev *pdev) pci_disable_device(pdev); ath10k_core_destroy(ar); - kfree(ar_pci); } MODULE_DEVICE_TABLE(pci, ath10k_pci_id_table); diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h index 940129209990..531c98aa4a86 100644 --- a/drivers/net/wireless/ath/ath10k/pci.h +++ b/drivers/net/wireless/ath/ath10k/pci.h @@ -202,7 +202,7 @@ struct ath10k_pci { static inline struct ath10k_pci *ath10k_pci_priv(struct ath10k *ar) { - return ar->hif.priv; + return (struct ath10k_pci *)ar->drv_priv; } static inline u32 ath10k_pci_reg_read32(struct ath10k *ar, u32 addr) From c0c378f9907c9e52aa95a87ac4622039a84bac99 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Thu, 7 Aug 2014 11:03:28 +0200 Subject: [PATCH 013/221] ath10k: remove target soc ps code The soc powersave was disabled by default. It never was fully tested. Some hw apparently had problems with it and the implementation itself had a possible race. Just remove the refcounting and simply wake up the device when probing and put to sleep when removing. kvalo: make ath10k_pci_wake() and _sleep() static Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/ce.c | 68 +--------- drivers/net/wireless/ath/ath10k/pci.c | 185 ++++++-------------------- drivers/net/wireless/ath/ath10k/pci.h | 67 ++-------- 3 files changed, 55 insertions(+), 265 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index 4333107ecf37..5117705f7f3d 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c @@ -287,10 +287,6 @@ int ath10k_ce_send_nolock(struct ath10k_ce_pipe *ce_state, ath10k_warn("%s: send more we can (nbytes: %d, max: %d)\n", __func__, nbytes, ce_state->src_sz_max); - ret = ath10k_pci_wake(ar); - if (ret) - return ret; - if (unlikely(CE_RING_DELTA(nentries_mask, write_index, sw_index - 1) <= 0)) { ret = -ENOSR; @@ -325,7 +321,6 @@ int ath10k_ce_send_nolock(struct ath10k_ce_pipe *ce_state, src_ring->write_index = write_index; exit: - ath10k_pci_sleep(ar); return ret; } @@ -407,10 +402,6 @@ int ath10k_ce_recv_buf_enqueue(struct ath10k_ce_pipe *ce_state, write_index = dest_ring->write_index; sw_index = dest_ring->sw_index; - ret = ath10k_pci_wake(ar); - if (ret) - goto out; - if (CE_RING_DELTA(nentries_mask, write_index, sw_index - 1) > 0) { struct ce_desc *base = dest_ring->base_addr_owner_space; struct ce_desc *desc = CE_DEST_RING_TO_DESC(base, write_index); @@ -430,11 +421,8 @@ int ath10k_ce_recv_buf_enqueue(struct ath10k_ce_pipe *ce_state, } else { ret = -EIO; } - ath10k_pci_sleep(ar); -out: spin_unlock_bh(&ar_pci->ce_lock); - return ret; } @@ -588,7 +576,6 @@ static int ath10k_ce_completed_send_next_nolock(struct ath10k_ce_pipe *ce_state, unsigned int sw_index = src_ring->sw_index; struct ce_desc *sdesc, *sbase; unsigned int read_index; - int ret; if (src_ring->hw_index == sw_index) { /* @@ -599,18 +586,12 @@ static int ath10k_ce_completed_send_next_nolock(struct ath10k_ce_pipe *ce_state, * value of the HW index has become stale. */ - ret = ath10k_pci_wake(ar); - if (ret) - return ret; - read_index = ath10k_ce_src_ring_read_index_get(ar, ctrl_addr); if (read_index == 0xffffffff) return -ENODEV; read_index &= nentries_mask; src_ring->hw_index = read_index; - - ath10k_pci_sleep(ar); } read_index = src_ring->hw_index; @@ -731,11 +712,6 @@ void ath10k_ce_per_engine_service(struct ath10k *ar, unsigned int ce_id) struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id]; u32 ctrl_addr = ce_state->ctrl_addr; - int ret; - - ret = ath10k_pci_wake(ar); - if (ret) - return; spin_lock_bh(&ar_pci->ce_lock); @@ -760,7 +736,6 @@ void ath10k_ce_per_engine_service(struct ath10k *ar, unsigned int ce_id) ath10k_ce_engine_int_status_clear(ar, ctrl_addr, CE_WATERMARK_MASK); spin_unlock_bh(&ar_pci->ce_lock); - ath10k_pci_sleep(ar); } /* @@ -771,13 +746,9 @@ void ath10k_ce_per_engine_service(struct ath10k *ar, unsigned int ce_id) void ath10k_ce_per_engine_service_any(struct ath10k *ar) { - int ce_id, ret; + int ce_id; u32 intr_summary; - ret = ath10k_pci_wake(ar); - if (ret) - return; - intr_summary = CE_INTERRUPT_SUMMARY(ar); for (ce_id = 0; intr_summary && (ce_id < CE_COUNT); ce_id++) { @@ -789,8 +760,6 @@ void ath10k_ce_per_engine_service_any(struct ath10k *ar) ath10k_ce_per_engine_service(ar, ce_id); } - - ath10k_pci_sleep(ar); } /* @@ -805,11 +774,6 @@ static void ath10k_ce_per_engine_handler_adjust(struct ath10k_ce_pipe *ce_state, { u32 ctrl_addr = ce_state->ctrl_addr; struct ath10k *ar = ce_state->ar; - int ret; - - ret = ath10k_pci_wake(ar); - if (ret) - return; if ((!disable_copy_compl_intr) && (ce_state->send_cb || ce_state->recv_cb)) @@ -818,17 +782,11 @@ static void ath10k_ce_per_engine_handler_adjust(struct ath10k_ce_pipe *ce_state, ath10k_ce_copy_complete_intr_disable(ar, ctrl_addr); ath10k_ce_watermark_intr_disable(ar, ctrl_addr); - - ath10k_pci_sleep(ar); } int ath10k_ce_disable_interrupts(struct ath10k *ar) { - int ce_id, ret; - - ret = ath10k_pci_wake(ar); - if (ret) - return ret; + int ce_id; for (ce_id = 0; ce_id < CE_COUNT; ce_id++) { u32 ctrl_addr = ath10k_ce_base_address(ce_id); @@ -838,8 +796,6 @@ int ath10k_ce_disable_interrupts(struct ath10k *ar) ath10k_ce_watermark_intr_disable(ar, ctrl_addr); } - ath10k_pci_sleep(ar); - return 0; } @@ -1084,10 +1040,6 @@ int ath10k_ce_init_pipe(struct ath10k *ar, unsigned int ce_id, BUILD_BUG_ON(2*TARGET_10X_NUM_MSDU_DESC > (CE_HTT_H2T_MSG_SRC_NENTRIES - 1)); - ret = ath10k_pci_wake(ar); - if (ret) - return ret; - spin_lock_bh(&ar_pci->ce_lock); ce_state->ar = ar; ce_state->id = ce_id; @@ -1101,7 +1053,7 @@ int ath10k_ce_init_pipe(struct ath10k *ar, unsigned int ce_id, if (ret) { ath10k_err("Failed to initialize CE src ring for ID: %d (%d)\n", ce_id, ret); - goto out; + return ret; } } @@ -1110,13 +1062,11 @@ int ath10k_ce_init_pipe(struct ath10k *ar, unsigned int ce_id, if (ret) { ath10k_err("Failed to initialize CE dest ring for ID: %d (%d)\n", ce_id, ret); - goto out; + return ret; } } -out: - ath10k_pci_sleep(ar); - return ret; + return 0; } static void ath10k_ce_deinit_src_ring(struct ath10k *ar, unsigned int ce_id) @@ -1140,16 +1090,8 @@ static void ath10k_ce_deinit_dest_ring(struct ath10k *ar, unsigned int ce_id) void ath10k_ce_deinit_pipe(struct ath10k *ar, unsigned int ce_id) { - int ret; - - ret = ath10k_pci_wake(ar); - if (ret) - return; - ath10k_ce_deinit_src_ring(ar, ce_id); ath10k_ce_deinit_dest_ring(ar, ce_id); - - ath10k_pci_sleep(ar); } int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id, diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index a2003b66a8bc..42be18c054ef 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -44,13 +44,9 @@ enum ath10k_pci_reset_mode { ATH10K_PCI_RESET_WARM_ONLY = 1, }; -static unsigned int ath10k_pci_target_ps; static unsigned int ath10k_pci_irq_mode = ATH10K_PCI_IRQ_AUTO; static unsigned int ath10k_pci_reset_mode = ATH10K_PCI_RESET_AUTO; -module_param_named(target_ps, ath10k_pci_target_ps, uint, 0644); -MODULE_PARM_DESC(target_ps, "Enable ath10k Target (SoC) PS option"); - module_param_named(irq_mode, ath10k_pci_irq_mode, uint, 0644); MODULE_PARM_DESC(irq_mode, "0: auto, 1: legacy, 2: msi (default: 0)"); @@ -389,10 +385,8 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data, * convert it from Target CPU virtual address space * to CE address space */ - ath10k_pci_wake(ar); address = TARG_CPU_SPACE_TO_CE_SPACE(ar, ar_pci->mem, address); - ath10k_pci_sleep(ar); ret = ath10k_ce_send(ce_diag, NULL, (u32)address, nbytes, 0, 0); @@ -474,9 +468,7 @@ static int ath10k_pci_diag_read_access(struct ath10k *ar, u32 address, if (address >= DRAM_BASE_ADDRESS) return ath10k_pci_diag_read_mem(ar, address, data, sizeof(u32)); - ath10k_pci_wake(ar); *data = ath10k_pci_read32(ar, address); - ath10k_pci_sleep(ar); return 0; } @@ -528,9 +520,7 @@ static int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address, * to * CE address space */ - ath10k_pci_wake(ar); address = TARG_CPU_SPACE_TO_CE_SPACE(ar, ar_pci->mem, address); - ath10k_pci_sleep(ar); remaining_bytes = orig_nbytes; ce_data = ce_data_base; @@ -623,51 +613,25 @@ static int ath10k_pci_diag_write_access(struct ath10k *ar, u32 address, return ath10k_pci_diag_write_mem(ar, address, &data, sizeof(u32)); - ath10k_pci_wake(ar); ath10k_pci_write32(ar, address, data); - ath10k_pci_sleep(ar); return 0; } -static bool ath10k_pci_target_is_awake(struct ath10k *ar) +static bool ath10k_pci_is_awake(struct ath10k *ar) { - void __iomem *mem = ath10k_pci_priv(ar)->mem; - u32 val; - val = ioread32(mem + PCIE_LOCAL_BASE_ADDRESS + - RTC_STATE_ADDRESS); - return (RTC_STATE_V_GET(val) == RTC_STATE_V_ON); + u32 val = ath10k_pci_reg_read32(ar, RTC_STATE_ADDRESS); + + return RTC_STATE_V_GET(val) == RTC_STATE_V_ON; } -int ath10k_do_pci_wake(struct ath10k *ar) +static int ath10k_pci_wake_wait(struct ath10k *ar) { - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - void __iomem *pci_addr = ar_pci->mem; int tot_delay = 0; int curr_delay = 5; - if (atomic_read(&ar_pci->keep_awake_count) == 0) { - /* Force AWAKE */ - iowrite32(PCIE_SOC_WAKE_V_MASK, - pci_addr + PCIE_LOCAL_BASE_ADDRESS + - PCIE_SOC_WAKE_ADDRESS); - } - atomic_inc(&ar_pci->keep_awake_count); - - if (ar_pci->verified_awake) - return 0; - - for (;;) { - if (ath10k_pci_target_is_awake(ar)) { - ar_pci->verified_awake = true; + while (tot_delay < PCIE_WAKE_TIMEOUT) { + if (ath10k_pci_is_awake(ar)) return 0; - } - - if (tot_delay > PCIE_WAKE_TIMEOUT) { - ath10k_warn("target took longer %d us to wake up (awake count %d)\n", - PCIE_WAKE_TIMEOUT, - atomic_read(&ar_pci->keep_awake_count)); - return -ETIMEDOUT; - } udelay(curr_delay); tot_delay += curr_delay; @@ -675,20 +639,21 @@ int ath10k_do_pci_wake(struct ath10k *ar) if (curr_delay < 50) curr_delay += 5; } + + return -ETIMEDOUT; } -void ath10k_do_pci_sleep(struct ath10k *ar) +static int ath10k_pci_wake(struct ath10k *ar) { - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - void __iomem *pci_addr = ar_pci->mem; + ath10k_pci_reg_write32(ar, PCIE_SOC_WAKE_ADDRESS, + PCIE_SOC_WAKE_V_MASK); + return ath10k_pci_wake_wait(ar); +} - if (atomic_dec_and_test(&ar_pci->keep_awake_count)) { - /* Allow sleep */ - ar_pci->verified_awake = false; - iowrite32(PCIE_SOC_WAKE_RESET, - pci_addr + PCIE_LOCAL_BASE_ADDRESS + - PCIE_SOC_WAKE_ADDRESS); - } +static void ath10k_pci_sleep(struct ath10k *ar) +{ + ath10k_pci_reg_write32(ar, PCIE_SOC_WAKE_ADDRESS, + PCIE_SOC_WAKE_RESET); } /* Called by lower (CE) layer when a send to Target completes. */ @@ -1788,8 +1753,6 @@ static void ath10k_pci_fw_interrupt_handler(struct ath10k *ar) struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); u32 fw_indicator; - ath10k_pci_wake(ar); - fw_indicator = ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS); if (fw_indicator & FW_IND_EVENT_PENDING) { @@ -1807,8 +1770,6 @@ static void ath10k_pci_fw_interrupt_handler(struct ath10k *ar) ath10k_warn("early firmware event indicated\n"); } } - - ath10k_pci_sleep(ar); } /* this function effectively clears target memory controller assert line */ @@ -1833,17 +1794,10 @@ static void ath10k_pci_warm_reset_si0(struct ath10k *ar) static int ath10k_pci_warm_reset(struct ath10k *ar) { - int ret = 0; u32 val; ath10k_dbg(ATH10K_DBG_BOOT, "boot warm reset\n"); - ret = ath10k_do_pci_wake(ar); - if (ret) { - ath10k_err("failed to wake up target: %d\n", ret); - return ret; - } - /* debug */ val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + PCIE_INTR_CAUSE_ADDRESS); @@ -1915,8 +1869,7 @@ static int ath10k_pci_warm_reset(struct ath10k *ar) ath10k_dbg(ATH10K_DBG_BOOT, "boot warm reset complete\n"); - ath10k_do_pci_sleep(ar); - return ret; + return 0; } static int __ath10k_pci_hif_power_up(struct ath10k *ar, bool cold_reset) @@ -1945,14 +1898,10 @@ static int __ath10k_pci_hif_power_up(struct ath10k *ar, bool cold_reset) goto err; } - if (!test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features)) - /* Force AWAKE forever */ - ath10k_do_pci_wake(ar); - ret = ath10k_pci_ce_init(ar); if (ret) { ath10k_err("failed to initialize CE: %d\n", ret); - goto err_ps; + goto err; } ret = ath10k_ce_disable_interrupts(ar); @@ -2012,9 +1961,6 @@ err_deinit_irq: err_ce: ath10k_pci_ce_deinit(ar); ath10k_pci_warm_reset(ar); -err_ps: - if (!test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features)) - ath10k_do_pci_sleep(ar); err: return ret; } @@ -2078,8 +2024,6 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar) static void ath10k_pci_hif_power_down(struct ath10k *ar) { - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - ath10k_dbg(ATH10K_DBG_BOOT, "boot hif power down\n"); ath10k_pci_free_early_irq(ar); @@ -2087,9 +2031,6 @@ static void ath10k_pci_hif_power_down(struct ath10k *ar) ath10k_pci_deinit_irq(ar); ath10k_pci_ce_deinit(ar); ath10k_pci_warm_reset(ar); - - if (!test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features)) - ath10k_do_pci_sleep(ar); } #ifdef CONFIG_PM @@ -2236,14 +2177,6 @@ static void ath10k_pci_early_irq_tasklet(unsigned long data) { struct ath10k *ar = (struct ath10k *)data; u32 fw_ind; - int ret; - - ret = ath10k_pci_wake(ar); - if (ret) { - ath10k_warn("failed to wake target in early irq tasklet: %d\n", - ret); - return; - } fw_ind = ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS); if (fw_ind & FW_IND_EVENT_PENDING) { @@ -2252,7 +2185,6 @@ static void ath10k_pci_early_irq_tasklet(unsigned long data) ath10k_pci_hif_dump_area(ar); } - ath10k_pci_sleep(ar); ath10k_pci_enable_legacy_irq(ar); } @@ -2426,34 +2358,16 @@ static int ath10k_pci_init_irq(struct ath10k *ar) * synchronization checking. */ ar_pci->num_msi_intrs = 0; - ret = ath10k_pci_wake(ar); - if (ret) { - ath10k_warn("failed to wake target: %d\n", ret); - return ret; - } - ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + PCIE_INTR_ENABLE_ADDRESS, PCIE_INTR_FIRMWARE_MASK | PCIE_INTR_CE_MASK_ALL); - ath10k_pci_sleep(ar); return 0; } -static int ath10k_pci_deinit_irq_legacy(struct ath10k *ar) +static void ath10k_pci_deinit_irq_legacy(struct ath10k *ar) { - int ret; - - ret = ath10k_pci_wake(ar); - if (ret) { - ath10k_warn("failed to wake target: %d\n", ret); - return ret; - } - ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + PCIE_INTR_ENABLE_ADDRESS, 0); - ath10k_pci_sleep(ar); - - return 0; } static int ath10k_pci_deinit_irq(struct ath10k *ar) @@ -2462,7 +2376,8 @@ static int ath10k_pci_deinit_irq(struct ath10k *ar) switch (ar_pci->num_msi_intrs) { case 0: - return ath10k_pci_deinit_irq_legacy(ar); + ath10k_pci_deinit_irq_legacy(ar); + return 0; case 1: /* fall-through */ case MSI_NUM_REQUEST: @@ -2480,17 +2395,10 @@ static int ath10k_pci_wait_for_target_init(struct ath10k *ar) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); unsigned long timeout; - int ret; u32 val; ath10k_dbg(ATH10K_DBG_BOOT, "boot waiting target to initialise\n"); - ret = ath10k_pci_wake(ar); - if (ret) { - ath10k_err("failed to wake up target for init: %d\n", ret); - return ret; - } - timeout = jiffies + msecs_to_jiffies(ATH10K_PCI_TARGET_WAIT); do { @@ -2520,8 +2428,7 @@ static int ath10k_pci_wait_for_target_init(struct ath10k *ar) if (val == 0xffffffff) { ath10k_err("failed to read device register, device is gone\n"); - ret = -EIO; - goto out; + return -EIO; } if (val & FW_IND_EVENT_PENDING) { @@ -2529,38 +2436,26 @@ static int ath10k_pci_wait_for_target_init(struct ath10k *ar) ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS, val & ~FW_IND_EVENT_PENDING); ath10k_pci_hif_dump_area(ar); - ret = -ECOMM; - goto out; + return -ECOMM; } if (!(val & FW_IND_INITIALIZED)) { ath10k_err("failed to receive initialized event from target: %08x\n", val); - ret = -ETIMEDOUT; - goto out; + return -ETIMEDOUT; } ath10k_dbg(ATH10K_DBG_BOOT, "boot target initialised\n"); - -out: - ath10k_pci_sleep(ar); - return ret; + return 0; } static int ath10k_pci_cold_reset(struct ath10k *ar) { - int i, ret; + int i; u32 val; ath10k_dbg(ATH10K_DBG_BOOT, "boot cold reset\n"); - ret = ath10k_do_pci_wake(ar); - if (ret) { - ath10k_err("failed to wake up target: %d\n", - ret); - return ret; - } - /* Put Target, including PCIe, into RESET. */ val = ath10k_pci_reg_read32(ar, SOC_GLOBAL_RESET_ADDRESS); val |= 1; @@ -2584,8 +2479,6 @@ static int ath10k_pci_cold_reset(struct ath10k *ar) msleep(1); } - ath10k_do_pci_sleep(ar); - ath10k_dbg(ATH10K_DBG_BOOT, "boot cold reset complete\n"); return 0; @@ -2603,9 +2496,6 @@ static void ath10k_pci_dump_features(struct ath10k_pci *ar_pci) case ATH10K_PCI_FEATURE_MSI_X: ath10k_dbg(ATH10K_DBG_BOOT, "device supports MSI-X\n"); break; - case ATH10K_PCI_FEATURE_SOC_POWER_SAVE: - ath10k_dbg(ATH10K_DBG_BOOT, "QCA98XX SoC power save enabled\n"); - break; } } } @@ -2642,13 +2532,9 @@ static int ath10k_pci_probe(struct pci_dev *pdev, goto err_core_destroy; } - if (ath10k_pci_target_ps) - set_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features); - ath10k_pci_dump_features(ar_pci); ar_pci->ar = ar; - atomic_set(&ar_pci->keep_awake_count, 0); pci_set_drvdata(pdev, ar); @@ -2703,20 +2589,22 @@ static int ath10k_pci_probe(struct pci_dev *pdev, spin_lock_init(&ar_pci->ce_lock); - ret = ath10k_do_pci_wake(ar); + ret = ath10k_pci_wake(ar); if (ret) { - ath10k_err("Failed to get chip id: %d\n", ret); + ath10k_err("failed to wake up: %d\n", ret); goto err_iomap; } chip_id = ath10k_pci_soc_read32(ar, SOC_CHIP_ID_ADDRESS); - - ath10k_do_pci_sleep(ar); + if (chip_id == 0xffffffff) { + ath10k_err("failed to get chip id\n"); + goto err_sleep; + } ret = ath10k_pci_alloc_ce(ar); if (ret) { ath10k_err("failed to allocate copy engine pipes: %d\n", ret); - goto err_iomap; + goto err_sleep; } ath10k_dbg(ATH10K_DBG_BOOT, "boot pci_mem 0x%p\n", ar_pci->mem); @@ -2731,6 +2619,8 @@ static int ath10k_pci_probe(struct pci_dev *pdev, err_free_ce: ath10k_pci_free_ce(ar); +err_sleep: + ath10k_pci_sleep(ar); err_iomap: pci_iounmap(pdev, mem); err_master: @@ -2762,6 +2652,7 @@ static void ath10k_pci_remove(struct pci_dev *pdev) ath10k_core_unregister(ar); ath10k_pci_free_ce(ar); + ath10k_pci_sleep(ar); pci_iounmap(pdev, ar_pci->mem); pci_release_region(pdev, BAR_NUM); diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h index 531c98aa4a86..65b1b90cd5d3 100644 --- a/drivers/net/wireless/ath/ath10k/pci.h +++ b/drivers/net/wireless/ath/ath10k/pci.h @@ -137,7 +137,6 @@ struct service_to_pipe { enum ath10k_pci_features { ATH10K_PCI_FEATURE_MSI_X = 0, - ATH10K_PCI_FEATURE_SOC_POWER_SAVE = 1, /* keep last */ ATH10K_PCI_FEATURE_COUNT @@ -183,9 +182,6 @@ struct ath10k_pci { int started; - atomic_t keep_awake_count; - bool verified_awake; - struct ath10k_pci_pipe pipe_info[CE_COUNT_MAX]; struct ath10k_hif_cb msg_callbacks_current; @@ -205,20 +201,6 @@ static inline struct ath10k_pci *ath10k_pci_priv(struct ath10k *ar) return (struct ath10k_pci *)ar->drv_priv; } -static inline u32 ath10k_pci_reg_read32(struct ath10k *ar, u32 addr) -{ - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - - return ioread32(ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS + addr); -} - -static inline void ath10k_pci_reg_write32(struct ath10k *ar, u32 addr, u32 val) -{ - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - - iowrite32(val, ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS + addr); -} - #define ATH_PCI_RESET_WAIT_MAX 10 /* ms */ #define PCIE_WAKE_TIMEOUT 5000 /* 5ms */ @@ -242,35 +224,17 @@ static inline void ath10k_pci_reg_write32(struct ath10k *ar, u32 addr, u32 val) /* Wait up to this many Ms for a Diagnostic Access CE operation to complete */ #define DIAG_ACCESS_CE_TIMEOUT_MS 10 -/* - * This API allows the Host to access Target registers directly - * and relatively efficiently over PCIe. - * This allows the Host to avoid extra overhead associated with - * sending a message to firmware and waiting for a response message - * from firmware, as is done on other interconnects. +/* Target exposes its registers for direct access. However before host can + * access them it needs to make sure the target is awake (ath10k_pci_wake, + * ath10k_pci_wake_wait, ath10k_pci_is_awake). Once target is awake it won't go + * to sleep unless host tells it to (ath10k_pci_sleep). * - * Yet there is some complexity with direct accesses because the - * Target's power state is not known a priori. The Host must issue - * special PCIe reads/writes in order to explicitly wake the Target - * and to verify that it is awake and will remain awake. + * If host tries to access target registers without waking it up it can + * scribble over host memory. * - * Usage: - * - * Use ath10k_pci_read32 and ath10k_pci_write32 to access Target space. - * These calls must be bracketed by ath10k_pci_wake and - * ath10k_pci_sleep. A single BEGIN/END pair is adequate for - * multiple READ/WRITE operations. - * - * Use ath10k_pci_wake to put the Target in a state in - * which it is legal for the Host to directly access it. This - * may involve waking the Target from a low power state, which - * may take up to 2Ms! - * - * Use ath10k_pci_sleep to tell the Target that as far as - * this code path is concerned, it no longer needs to remain - * directly accessible. BEGIN/END is under a reference counter; - * multiple code paths may issue BEGIN/END on a single targid. + * If target is asleep waking it up may take up to even 2ms. */ + static inline void ath10k_pci_write32(struct ath10k *ar, u32 offset, u32 value) { @@ -296,25 +260,18 @@ static inline void ath10k_pci_soc_write32(struct ath10k *ar, u32 addr, u32 val) ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + addr, val); } -int ath10k_do_pci_wake(struct ath10k *ar); -void ath10k_do_pci_sleep(struct ath10k *ar); - -static inline int ath10k_pci_wake(struct ath10k *ar) +static inline u32 ath10k_pci_reg_read32(struct ath10k *ar, u32 addr) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - if (test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features)) - return ath10k_do_pci_wake(ar); - - return 0; + return ioread32(ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS + addr); } -static inline void ath10k_pci_sleep(struct ath10k *ar) +static inline void ath10k_pci_reg_write32(struct ath10k *ar, u32 addr, u32 val) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - if (test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features)) - ath10k_do_pci_sleep(ar); + iowrite32(val, ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS + addr); } #endif /* _PCI_H_ */ From 0edf2577a5927aa8d1521f22da753e1d0c2a4db4 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Thu, 7 Aug 2014 11:03:29 +0200 Subject: [PATCH 014/221] ath10k: remove pci features var The ATH10K_PCI_FEATURE_MSI_X was originally introduced to support both chips QCA988Xv1 and QCA988Xv2. Since v1 isn't supported anymore it doesn't make sense to keep the feature flag around. Since this is the last one remove the whole thing. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 33 +-------------------------- drivers/net/wireless/ath/ath10k/pci.h | 9 -------- 2 files changed, 1 insertion(+), 41 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 42be18c054ef..bbad9662b0fd 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -2317,8 +2317,6 @@ static void ath10k_pci_init_irq_tasklets(struct ath10k *ar) static int ath10k_pci_init_irq(struct ath10k *ar) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - bool msix_supported = test_bit(ATH10K_PCI_FEATURE_MSI_X, - ar_pci->features); int ret; ath10k_pci_init_irq_tasklets(ar); @@ -2328,7 +2326,7 @@ static int ath10k_pci_init_irq(struct ath10k *ar) ath10k_info("limiting irq mode to: %d\n", ath10k_pci_irq_mode); /* Try MSI-X */ - if (ath10k_pci_irq_mode == ATH10K_PCI_IRQ_AUTO && msix_supported) { + if (ath10k_pci_irq_mode == ATH10K_PCI_IRQ_AUTO) { ar_pci->num_msi_intrs = MSI_NUM_REQUEST; ret = pci_enable_msi_range(ar_pci->pdev, ar_pci->num_msi_intrs, ar_pci->num_msi_intrs); @@ -2484,22 +2482,6 @@ static int ath10k_pci_cold_reset(struct ath10k *ar) return 0; } -static void ath10k_pci_dump_features(struct ath10k_pci *ar_pci) -{ - int i; - - for (i = 0; i < ATH10K_PCI_FEATURE_COUNT; i++) { - if (!test_bit(i, ar_pci->features)) - continue; - - switch (i) { - case ATH10K_PCI_FEATURE_MSI_X: - ath10k_dbg(ATH10K_DBG_BOOT, "device supports MSI-X\n"); - break; - } - } -} - static int ath10k_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pci_dev) { @@ -2521,19 +2503,6 @@ static int ath10k_pci_probe(struct pci_dev *pdev, ar_pci = ath10k_pci_priv(ar); ar_pci->pdev = pdev; ar_pci->dev = &pdev->dev; - - switch (pci_dev->device) { - case QCA988X_2_0_DEVICE_ID: - set_bit(ATH10K_PCI_FEATURE_MSI_X, ar_pci->features); - break; - default: - ret = -ENODEV; - ath10k_err("Unknown device ID: %d\n", pci_dev->device); - goto err_core_destroy; - } - - ath10k_pci_dump_features(ar_pci); - ar_pci->ar = ar; pci_set_drvdata(pdev, ar); diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h index 65b1b90cd5d3..662bca3922ef 100644 --- a/drivers/net/wireless/ath/ath10k/pci.h +++ b/drivers/net/wireless/ath/ath10k/pci.h @@ -135,13 +135,6 @@ struct service_to_pipe { u32 pipenum; }; -enum ath10k_pci_features { - ATH10K_PCI_FEATURE_MSI_X = 0, - - /* keep last */ - ATH10K_PCI_FEATURE_COUNT -}; - /* Per-pipe state. */ struct ath10k_pci_pipe { /* Handle of underlying Copy Engine */ @@ -168,8 +161,6 @@ struct ath10k_pci { struct ath10k *ar; void __iomem *mem; - DECLARE_BITMAP(features, ATH10K_PCI_FEATURE_COUNT); - /* * Number of MSI interrupts granted, 0 --> using legacy PCI line * interrupts. From 2986e3efb84fc79e798c1967beec6bb5eede7dee Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Thu, 7 Aug 2014 11:03:30 +0200 Subject: [PATCH 015/221] ath10k: group some pci probing helpers Make probe/remove functions shorter and easier to understand. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 154 +++++++++++++++----------- 1 file changed, 87 insertions(+), 67 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index bbad9662b0fd..98c029b7d0ab 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -2482,14 +2482,89 @@ static int ath10k_pci_cold_reset(struct ath10k *ar) return 0; } +static int ath10k_pci_claim(struct ath10k *ar) +{ + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + struct pci_dev *pdev = ar_pci->pdev; + u32 lcr_val; + int ret; + + pci_set_drvdata(pdev, ar); + + ret = pci_enable_device(pdev); + if (ret) { + ath10k_err("failed to enable pci device: %d\n", ret); + return ret; + } + + ret = pci_request_region(pdev, BAR_NUM, "ath"); + if (ret) { + ath10k_err("failed to request region BAR%d: %d\n", BAR_NUM, + ret); + goto err_device; + } + + /* Target expects 32 bit DMA. Enforce it. */ + ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + if (ret) { + ath10k_err("failed to set dma mask to 32-bit: %d\n", ret); + goto err_region; + } + + ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); + if (ret) { + ath10k_err("failed to set consistent dma mask to 32-bit: %d\n", + ret); + goto err_region; + } + + pci_set_master(pdev); + + /* Workaround: Disable ASPM */ + pci_read_config_dword(pdev, 0x80, &lcr_val); + pci_write_config_dword(pdev, 0x80, (lcr_val & 0xffffff00)); + + /* Arrange for access to Target SoC registers. */ + ar_pci->mem = pci_iomap(pdev, BAR_NUM, 0); + if (!ar_pci->mem) { + ath10k_err("failed to iomap BAR%d\n", BAR_NUM); + ret = -EIO; + goto err_master; + } + + ath10k_dbg(ATH10K_DBG_BOOT, "boot pci_mem 0x%p\n", ar_pci->mem); + return 0; + +err_master: + pci_clear_master(pdev); + +err_region: + pci_release_region(pdev, BAR_NUM); + +err_device: + pci_disable_device(pdev); + + return ret; +} + +static void ath10k_pci_release(struct ath10k *ar) +{ + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + struct pci_dev *pdev = ar_pci->pdev; + + pci_iounmap(pdev, ar_pci->mem); + pci_release_region(pdev, BAR_NUM); + pci_clear_master(pdev); + pci_disable_device(pdev); +} + static int ath10k_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pci_dev) { - void __iomem *mem; int ret = 0; struct ath10k *ar; struct ath10k_pci *ar_pci; - u32 lcr_val, chip_id; + u32 chip_id; ath10k_dbg(ATH10K_DBG_PCI, "pci probe\n"); @@ -2505,63 +2580,18 @@ static int ath10k_pci_probe(struct pci_dev *pdev, ar_pci->dev = &pdev->dev; ar_pci->ar = ar; - pci_set_drvdata(pdev, ar); + spin_lock_init(&ar_pci->ce_lock); - ret = pci_enable_device(pdev); + ret = ath10k_pci_claim(ar); if (ret) { - ath10k_err("failed to enable PCI device: %d\n", ret); + ath10k_err("failed to claim device: %d\n", ret); goto err_core_destroy; } - /* Request MMIO resources */ - ret = pci_request_region(pdev, BAR_NUM, "ath"); - if (ret) { - ath10k_err("failed to request MMIO region: %d\n", ret); - goto err_device; - } - - /* - * Target structures have a limit of 32 bit DMA pointers. - * DMA pointers can be wider than 32 bits by default on some systems. - */ - ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); - if (ret) { - ath10k_err("failed to set DMA mask to 32-bit: %d\n", ret); - goto err_region; - } - - ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); - if (ret) { - ath10k_err("failed to set consistent DMA mask to 32-bit\n"); - goto err_region; - } - - /* Set bus master bit in PCI_COMMAND to enable DMA */ - pci_set_master(pdev); - - /* - * Temporary FIX: disable ASPM - * Will be removed after the OTP is programmed - */ - pci_read_config_dword(pdev, 0x80, &lcr_val); - pci_write_config_dword(pdev, 0x80, (lcr_val & 0xffffff00)); - - /* Arrange for access to Target SoC registers. */ - mem = pci_iomap(pdev, BAR_NUM, 0); - if (!mem) { - ath10k_err("failed to perform IOMAP for BAR%d\n", BAR_NUM); - ret = -EIO; - goto err_master; - } - - ar_pci->mem = mem; - - spin_lock_init(&ar_pci->ce_lock); - ret = ath10k_pci_wake(ar); if (ret) { ath10k_err("failed to wake up: %d\n", ret); - goto err_iomap; + goto err_release; } chip_id = ath10k_pci_soc_read32(ar, SOC_CHIP_ID_ADDRESS); @@ -2576,8 +2606,6 @@ static int ath10k_pci_probe(struct pci_dev *pdev, goto err_sleep; } - ath10k_dbg(ATH10K_DBG_BOOT, "boot pci_mem 0x%p\n", ar_pci->mem); - ret = ath10k_core_register(ar, chip_id); if (ret) { ath10k_err("failed to register driver core: %d\n", ret); @@ -2588,16 +2616,13 @@ static int ath10k_pci_probe(struct pci_dev *pdev, err_free_ce: ath10k_pci_free_ce(ar); + err_sleep: ath10k_pci_sleep(ar); -err_iomap: - pci_iounmap(pdev, mem); -err_master: - pci_clear_master(pdev); -err_region: - pci_release_region(pdev, BAR_NUM); -err_device: - pci_disable_device(pdev); + +err_release: + ath10k_pci_release(ar); + err_core_destroy: ath10k_core_destroy(ar); @@ -2622,12 +2647,7 @@ static void ath10k_pci_remove(struct pci_dev *pdev) ath10k_core_unregister(ar); ath10k_pci_free_ce(ar); ath10k_pci_sleep(ar); - - pci_iounmap(pdev, ar_pci->mem); - pci_release_region(pdev, BAR_NUM); - pci_clear_master(pdev); - pci_disable_device(pdev); - + ath10k_pci_release(ar); ath10k_core_destroy(ar); } From b7967dc79fbd32ef198b429b2597459a4130207f Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Thu, 7 Aug 2014 11:03:31 +0200 Subject: [PATCH 016/221] ath10k: remove htc->stopped This is not necessary anymore. There are no more uncontrolled htc tx entry points. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 13 +++++-------- drivers/net/wireless/ath/ath10k/htc.c | 16 ---------------- drivers/net/wireless/ath/ath10k/htc.h | 5 +---- 3 files changed, 6 insertions(+), 28 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 7f95bd05e343..d3474b43ac47 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -779,7 +779,7 @@ int ath10k_core_start(struct ath10k *ar) if (status <= 0) { ath10k_warn("wmi service ready event not received"); status = -ETIMEDOUT; - goto err_htc_stop; + goto err_hif_stop; } ath10k_dbg(ATH10K_DBG_BOOT, "firmware %s booted\n", @@ -788,25 +788,25 @@ int ath10k_core_start(struct ath10k *ar) status = ath10k_wmi_cmd_init(ar); if (status) { ath10k_err("could not send WMI init command (%d)\n", status); - goto err_htc_stop; + goto err_hif_stop; } status = ath10k_wmi_wait_for_unified_ready(ar); if (status <= 0) { ath10k_err("wmi unified ready event not received\n"); status = -ETIMEDOUT; - goto err_htc_stop; + goto err_hif_stop; } status = ath10k_htt_setup(&ar->htt); if (status) { ath10k_err("failed to setup htt: %d\n", status); - goto err_htc_stop; + goto err_hif_stop; } status = ath10k_debug_start(ar); if (status) - goto err_htc_stop; + goto err_hif_stop; if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) ar->free_vdev_map = (1 << TARGET_10X_NUM_VDEVS) - 1; @@ -835,8 +835,6 @@ int ath10k_core_start(struct ath10k *ar) return 0; -err_htc_stop: - ath10k_htc_stop(&ar->htc); err_hif_stop: ath10k_hif_stop(ar); err_htt_rx_detach: @@ -881,7 +879,6 @@ void ath10k_core_stop(struct ath10k *ar) ath10k_wait_for_suspend(ar, WMI_PDEV_SUSPEND_AND_DISABLE_INTR); ath10k_debug_stop(ar); - ath10k_htc_stop(&ar->htc); ath10k_hif_stop(ar); ath10k_htt_tx_free(&ar->htt); ath10k_htt_rx_free(&ar->htt); diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c index 5fdc40d3b378..7e08bb328847 100644 --- a/drivers/net/wireless/ath/ath10k/htc.c +++ b/drivers/net/wireless/ath/ath10k/htc.c @@ -138,14 +138,6 @@ int ath10k_htc_send(struct ath10k_htc *htc, return -ENOENT; } - /* FIXME: This looks ugly, can we fix it? */ - spin_lock_bh(&htc->tx_lock); - if (htc->stopped) { - spin_unlock_bh(&htc->tx_lock); - return -ESHUTDOWN; - } - spin_unlock_bh(&htc->tx_lock); - skb_push(skb, sizeof(struct ath10k_htc_hdr)); if (ep->tx_credit_flow_enabled) { @@ -846,13 +838,6 @@ int ath10k_htc_start(struct ath10k_htc *htc) return 0; } -void ath10k_htc_stop(struct ath10k_htc *htc) -{ - spin_lock_bh(&htc->tx_lock); - htc->stopped = true; - spin_unlock_bh(&htc->tx_lock); -} - /* registered target arrival callback from the HIF layer */ int ath10k_htc_init(struct ath10k *ar) { @@ -862,7 +847,6 @@ int ath10k_htc_init(struct ath10k *ar) spin_lock_init(&htc->tx_lock); - htc->stopped = false; ath10k_htc_reset_endpoint_states(htc); /* setup HIF layer callbacks */ diff --git a/drivers/net/wireless/ath/ath10k/htc.h b/drivers/net/wireless/ath/ath10k/htc.h index 4716d331e6b6..b5a9daacc2c2 100644 --- a/drivers/net/wireless/ath/ath10k/htc.h +++ b/drivers/net/wireless/ath/ath10k/htc.h @@ -332,7 +332,7 @@ struct ath10k_htc { struct ath10k *ar; struct ath10k_htc_ep endpoint[ATH10K_HTC_EP_COUNT]; - /* protects endpoint and stopped fields */ + /* protects endpoints */ spinlock_t tx_lock; struct ath10k_htc_ops htc_ops; @@ -345,8 +345,6 @@ struct ath10k_htc { int total_transmit_credits; struct ath10k_htc_svc_tx_credits service_tx_alloc[ATH10K_HTC_EP_COUNT]; int target_credit_size; - - bool stopped; }; int ath10k_htc_init(struct ath10k *ar); @@ -357,7 +355,6 @@ int ath10k_htc_connect_service(struct ath10k_htc *htc, struct ath10k_htc_svc_conn_resp *conn_resp); int ath10k_htc_send(struct ath10k_htc *htc, enum ath10k_htc_ep_id eid, struct sk_buff *packet); -void ath10k_htc_stop(struct ath10k_htc *htc); struct sk_buff *ath10k_htc_alloc_skb(int size); #endif From 84c61d92bb6e9048eecc0738a83f1bf66f053026 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 1 Aug 2014 11:13:30 +0300 Subject: [PATCH 017/221] Bluetooth: Add convenience function to check for pending power off There are several situations where we're interested in knowing whether we're currently in the process of powering off an adapter. This patch adds a convenience function for the purpose and makes it public since we'll soon need to access it from hci_event.c as well. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 1 + net/bluetooth/mgmt.c | 52 +++++++++++++++++--------------- 2 files changed, 29 insertions(+), 24 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index b5d5af3aa469..8394abc4fd87 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1351,6 +1351,7 @@ void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type, s8 rssi, u8 *name, u8 name_len); void mgmt_discovering(struct hci_dev *hdev, u8 discovering); +bool mgmt_powering_down(struct hci_dev *hdev); void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, bool persistent); void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk); void mgmt_new_csrk(struct hci_dev *hdev, struct smp_csrk *csrk, diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index b8554d429d88..c9de0d9945f5 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -6281,25 +6281,35 @@ static void unpair_device_rsp(struct pending_cmd *cmd, void *data) mgmt_pending_remove(cmd); } +bool mgmt_powering_down(struct hci_dev *hdev) +{ + struct pending_cmd *cmd; + struct mgmt_mode *cp; + + cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev); + if (!cmd) + return false; + + cp = cmd->param; + if (!cp->val) + return true; + + return false; +} + void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type, u8 reason, bool mgmt_connected) { struct mgmt_ev_device_disconnected ev; - struct pending_cmd *power_off; struct sock *sk = NULL; - power_off = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev); - if (power_off) { - struct mgmt_mode *cp = power_off->param; - - /* The connection is still in hci_conn_hash so test for 1 - * instead of 0 to know if this is the last one. - */ - if (!cp->val && hci_conn_count(hdev) == 1) { - cancel_delayed_work(&hdev->power_off); - queue_work(hdev->req_workqueue, &hdev->power_off.work); - } + /* The connection is still in hci_conn_hash so test for 1 + * instead of 0 to know if this is the last one. + */ + if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) { + cancel_delayed_work(&hdev->power_off); + queue_work(hdev->req_workqueue, &hdev->power_off.work); } if (!mgmt_connected) @@ -6359,19 +6369,13 @@ void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type, u8 status) { struct mgmt_ev_connect_failed ev; - struct pending_cmd *power_off; - power_off = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev); - if (power_off) { - struct mgmt_mode *cp = power_off->param; - - /* The connection is still in hci_conn_hash so test for 1 - * instead of 0 to know if this is the last one. - */ - if (!cp->val && hci_conn_count(hdev) == 1) { - cancel_delayed_work(&hdev->power_off); - queue_work(hdev->req_workqueue, &hdev->power_off.work); - } + /* The connection is still in hci_conn_hash so test for 1 + * instead of 0 to know if this is the last one. + */ + if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) { + cancel_delayed_work(&hdev->power_off); + queue_work(hdev->req_workqueue, &hdev->power_off.work); } bacpy(&ev.addr.bdaddr, bdaddr); From 432df05eb1e57adfc46df08abbedca6c3b8862f7 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 1 Aug 2014 11:13:31 +0300 Subject: [PATCH 018/221] Bluetooth: Create unified helper function for updating page scan Similar to our hci_update_background_scan() function we can simplify a lot of code by creating a unified helper function for doing page scan updates. This patch adds such a function to hci_core.c and updates all the relevant places to use it. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 5 +++ net/bluetooth/hci_core.c | 31 ++++++++++++++ net/bluetooth/mgmt.c | 72 ++++++-------------------------- 3 files changed, 48 insertions(+), 60 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 8394abc4fd87..cc2eb7730fbc 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -968,6 +968,9 @@ void hci_conn_del_sysfs(struct hci_conn *conn); #define lmp_host_le_capable(dev) (!!((dev)->features[1][0] & LMP_HOST_LE)) #define lmp_host_le_br_capable(dev) (!!((dev)->features[1][0] & LMP_HOST_LE_BREDR)) +#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \ + !test_bit(HCI_AUTO_OFF, &hdev->dev_flags)) + /* ----- HCI protocols ----- */ #define HCI_PROTO_DEFER 0x01 @@ -1256,6 +1259,8 @@ bool hci_req_pending(struct hci_dev *hdev); void hci_req_add_le_scan_disable(struct hci_request *req); void hci_req_add_le_passive_scan(struct hci_request *req); +void hci_update_page_scan(struct hci_dev *hdev, struct hci_request *req); + struct sk_buff *__hci_cmd_sync(struct hci_dev *hdev, u16 opcode, u32 plen, const void *param, u32 timeout); struct sk_buff *__hci_cmd_sync_ev(struct hci_dev *hdev, u16 opcode, u32 plen, diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index c32d361c0cf7..a031589598b2 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -5680,3 +5680,34 @@ void hci_update_background_scan(struct hci_dev *hdev) if (err) BT_ERR("Failed to run HCI request: err %d", err); } + +void hci_update_page_scan(struct hci_dev *hdev, struct hci_request *req) +{ + u8 scan; + + if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) + return; + + if (!hdev_is_powered(hdev)) + return; + + if (mgmt_powering_down(hdev)) + return; + + if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags) || + !list_empty(&hdev->whitelist)) + scan = SCAN_PAGE; + else + scan = SCAN_DISABLED; + + if (test_bit(HCI_PSCAN, &hdev->flags) == !!(scan & SCAN_PAGE)) + return; + + if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) + scan |= SCAN_INQUIRY; + + if (req) + hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan); + else + hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan); +} diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index c9de0d9945f5..c2457435a670 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -129,9 +129,6 @@ static const u16 mgmt_events[] = { #define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000) -#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \ - !test_bit(HCI_AUTO_OFF, &hdev->dev_flags)) - struct pending_cmd { struct list_head list; u16 opcode; @@ -1536,9 +1533,11 @@ static void set_discoverable_complete(struct hci_dev *hdev, u8 status) /* When the discoverable mode gets changed, make sure * that class of device has the limited discoverable - * bit correctly set. + * bit correctly set. Also update page scan based on whitelist + * entries. */ hci_req_init(&req, hdev); + hci_update_page_scan(hdev, &req); update_class(&req); hci_req_run(&req, NULL); @@ -1785,6 +1784,7 @@ static void set_connectable_complete(struct hci_dev *hdev, u8 status) if (conn_changed || discov_changed) { new_settings(hdev, cmd->sk); + hci_update_page_scan(hdev, NULL); if (discov_changed) mgmt_update_adv_data(hdev); hci_update_background_scan(hdev); @@ -1818,6 +1818,7 @@ static int set_connectable_update_settings(struct hci_dev *hdev, return err; if (changed) { + hci_update_page_scan(hdev, NULL); hci_update_background_scan(hdev); return new_settings(hdev, sk); } @@ -4381,27 +4382,6 @@ unlock: return err; } -static void set_bredr_scan(struct hci_request *req) -{ - struct hci_dev *hdev = req->hdev; - u8 scan = 0; - - /* Ensure that fast connectable is disabled. This function will - * not do anything if the page scan parameters are already what - * they should be. - */ - write_fast_connectable(req, false); - - if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags) || - !list_empty(&hdev->whitelist)) - scan |= SCAN_PAGE; - if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) - scan |= SCAN_INQUIRY; - - if (scan) - hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan); -} - static void set_bredr_complete(struct hci_dev *hdev, u8 status) { struct pending_cmd *cmd; @@ -4507,9 +4487,8 @@ static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) hci_req_init(&req, hdev); - if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags) || - !list_empty(&hdev->whitelist)) - set_bredr_scan(&req); + write_fast_connectable(&req, false); + hci_update_page_scan(hdev, &req); /* Since only the advertising data flags will change, there * is no need to update the scan response data. @@ -5235,27 +5214,6 @@ unlock: return err; } -/* Helper for Add/Remove Device commands */ -static void update_page_scan(struct hci_dev *hdev, u8 scan) -{ - if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) - return; - - if (!hdev_is_powered(hdev)) - return; - - /* If HCI_CONNECTABLE is set then Add/Remove Device should not - * make any changes to page scanning. - */ - if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) - return; - - if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) - scan |= SCAN_INQUIRY; - - hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan); -} - static void device_added(struct sock *sk, struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type, u8 action) { @@ -5291,8 +5249,6 @@ static int add_device(struct sock *sk, struct hci_dev *hdev, hci_dev_lock(hdev); if (cp->addr.type == BDADDR_BREDR) { - bool update_scan; - /* Only incoming connections action is supported for now */ if (cp->action != 0x01) { err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE, @@ -5301,15 +5257,12 @@ static int add_device(struct sock *sk, struct hci_dev *hdev, goto unlock; } - update_scan = list_empty(&hdev->whitelist); - err = hci_bdaddr_list_add(&hdev->whitelist, &cp->addr.bdaddr, cp->addr.type); if (err) goto unlock; - if (update_scan) - update_page_scan(hdev, SCAN_PAGE); + hci_update_page_scan(hdev, NULL); goto added; } @@ -5392,8 +5345,7 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev, goto unlock; } - if (list_empty(&hdev->whitelist)) - update_page_scan(hdev, SCAN_DISABLED); + hci_update_page_scan(hdev, NULL); device_removed(sk, hdev, &cp->addr.bdaddr, cp->addr.type); @@ -5444,7 +5396,7 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev, kfree(b); } - update_page_scan(hdev, SCAN_DISABLED); + hci_update_page_scan(hdev, NULL); list_for_each_entry_safe(p, tmp, &hdev->le_conn_params, list) { if (p->auto_connect == HCI_AUTO_CONN_DISABLED) @@ -5969,8 +5921,8 @@ static int powered_update_hci(struct hci_dev *hdev) sizeof(link_sec), &link_sec); if (lmp_bredr_capable(hdev)) { - if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) - set_bredr_scan(&req); + write_fast_connectable(&req, false); + hci_update_page_scan(hdev, &req); update_class(&req); update_name(&req); update_eir(&req); From 22f433dcf7c71cf075e4c42b5f36ea4352978a6d Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 1 Aug 2014 11:13:32 +0300 Subject: [PATCH 019/221] Bluetooth: Disable page scan if all whitelisted devices are connected When we're not connectable and all whitelisted (BR/EDR) devices are connected it doesn't make sense to keep page scan enabled. This patch adds code to check for any disconnected whitelist devices and if there are none take the appropriate action in the hci_update_page_scan() function to disable page scan. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 20 +++++++++++++++++++- net/bluetooth/hci_event.c | 11 ++++++++--- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index a031589598b2..217ef83fb541 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -5681,6 +5681,24 @@ void hci_update_background_scan(struct hci_dev *hdev) BT_ERR("Failed to run HCI request: err %d", err); } +static bool disconnected_whitelist_entries(struct hci_dev *hdev) +{ + struct bdaddr_list *b; + + list_for_each_entry(b, &hdev->whitelist, list) { + struct hci_conn *conn; + + conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &b->bdaddr); + if (!conn) + return true; + + if (conn->state != BT_CONNECTED && conn->state != BT_CONFIG) + return true; + } + + return false; +} + void hci_update_page_scan(struct hci_dev *hdev, struct hci_request *req) { u8 scan; @@ -5695,7 +5713,7 @@ void hci_update_page_scan(struct hci_dev *hdev, struct hci_request *req) return; if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags) || - !list_empty(&hdev->whitelist)) + disconnected_whitelist_entries(hdev)) scan = SCAN_PAGE; else scan = SCAN_DISABLED; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index be35598984d9..da7ab6b9bb69 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2071,6 +2071,8 @@ static void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) cp.handle = ev->handle; hci_send_cmd(hdev, HCI_OP_READ_REMOTE_FEATURES, sizeof(cp), &cp); + + hci_update_page_scan(hdev, NULL); } /* Set packet type for incoming connection */ @@ -2247,9 +2249,12 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) mgmt_device_disconnected(hdev, &conn->dst, conn->type, conn->dst_type, reason, mgmt_connected); - if (conn->type == ACL_LINK && - test_bit(HCI_CONN_FLUSH_KEY, &conn->flags)) - hci_remove_link_key(hdev, &conn->dst); + if (conn->type == ACL_LINK) { + if (test_bit(HCI_CONN_FLUSH_KEY, &conn->flags)) + hci_remove_link_key(hdev, &conn->dst); + + hci_update_page_scan(hdev, NULL); + } params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type); if (params) { From 5fcb93475697911eb239f68241903eb5540803ac Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 7 Aug 2014 10:03:31 +0300 Subject: [PATCH 020/221] Bluetooth: Remove redundant check for remote_key_dist In the smp_cmd_sign_info() function the SMP_DIST_SIGN bit is explicitly cleared early on in the function. This means that there's no need to check for it again before calling smp_distribute_keys(). Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index fd3294300803..40db728f044b 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -1168,8 +1168,7 @@ static int smp_cmd_sign_info(struct l2cap_conn *conn, struct sk_buff *skb) memcpy(csrk->val, rp->csrk, sizeof(csrk->val)); } smp->csrk = csrk; - if (!(smp->remote_key_dist & SMP_DIST_SIGN)) - smp_distribute_keys(conn); + smp_distribute_keys(conn); hci_dev_unlock(hdev); return 0; From 2b29349044cc2cf74d4c6e23e26cd27977d91353 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 7 Aug 2014 10:03:32 +0300 Subject: [PATCH 021/221] Bluetooth: Fix confusion between parent and child channel for 6lowpan The new_connection L2CAP channel callback creates a new channel based on the provided parent channel. The 6lowpan code was confusingly naming the child channel "pchan" and the parent channel "chan". This patch swaps the names. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/6lowpan.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c index 206b65ccd5b8..35ebe79c87b0 100644 --- a/net/bluetooth/6lowpan.c +++ b/net/bluetooth/6lowpan.c @@ -772,16 +772,16 @@ static inline void chan_ready_cb(struct l2cap_chan *chan) ifup(dev->netdev); } -static inline struct l2cap_chan *chan_new_conn_cb(struct l2cap_chan *chan) +static inline struct l2cap_chan *chan_new_conn_cb(struct l2cap_chan *pchan) { - struct l2cap_chan *pchan; + struct l2cap_chan *chan; - pchan = chan_open(chan); - pchan->ops = chan->ops; + chan = chan_open(pchan); + chan->ops = pchan->ops; BT_DBG("chan %p pchan %p", chan, pchan); - return pchan; + return chan; } static void delete_netdev(struct work_struct *work) From a24cce144b9814a17f46006dbad6056f1f5f481e Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 7 Aug 2014 22:56:42 +0300 Subject: [PATCH 022/221] Bluetooth: Fix reference counting of global L2CAP channels When looking up entries from the global L2CAP channel list there needs to be a guarantee that other code doesn't go and remove the entry after a channel has been returned by the lookup function. This patch makes sure that the channel reference is incremented before the read lock is released in the global channel lookup functions. The patch also adds the corresponding l2cap_chan_put() calls once the channels pointers are no-longer needed. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 46547b920f88..a47a14efd5aa 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1440,6 +1440,7 @@ static struct l2cap_chan *l2cap_global_chan_by_scid(int state, u16 cid, src_match = !bacmp(&c->src, src); dst_match = !bacmp(&c->dst, dst); if (src_match && dst_match) { + l2cap_chan_hold(c); read_unlock(&chan_list_lock); return c; } @@ -1453,6 +1454,9 @@ static struct l2cap_chan *l2cap_global_chan_by_scid(int state, u16 cid, } } + if (c1) + l2cap_chan_hold(c1); + read_unlock(&chan_list_lock); return c1; @@ -1475,13 +1479,13 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) /* Client ATT sockets should override the server one */ if (__l2cap_get_chan_by_dcid(conn, L2CAP_CID_ATT)) - return; + goto put; dst_type = bdaddr_type(hcon, hcon->dst_type); /* If device is blocked, do not create a channel for it */ if (hci_bdaddr_list_lookup(&hdev->blacklist, &hcon->dst, dst_type)) - return; + goto put; /* For LE slave connections, make sure the connection interval * is in the range of the minium and maximum interval that has @@ -1517,6 +1521,8 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) clean: l2cap_chan_unlock(pchan); +put: + l2cap_chan_put(pchan); } static void l2cap_conn_ready(struct l2cap_conn *conn) @@ -1794,6 +1800,7 @@ static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, src_match = !bacmp(&c->src, src); dst_match = !bacmp(&c->dst, dst); if (src_match && dst_match) { + l2cap_chan_hold(c); read_unlock(&chan_list_lock); return c; } @@ -1807,6 +1814,9 @@ static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, } } + if (c1) + l2cap_chan_hold(c1); + read_unlock(&chan_list_lock); return c1; @@ -3884,6 +3894,7 @@ static struct l2cap_chan *l2cap_connect(struct l2cap_conn *conn, response: l2cap_chan_unlock(pchan); mutex_unlock(&conn->chan_lock); + l2cap_chan_put(pchan); sendresp: rsp.scid = cpu_to_le16(scid); @@ -5497,6 +5508,7 @@ static int l2cap_le_connect_req(struct l2cap_conn *conn, response_unlock: l2cap_chan_unlock(pchan); mutex_unlock(&conn->chan_lock); + l2cap_chan_put(pchan); if (result == L2CAP_CR_PEND) return 0; @@ -6845,12 +6857,12 @@ static void l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, struct l2cap_chan *chan; if (hcon->type != ACL_LINK) - goto drop; + goto free_skb; chan = l2cap_global_chan_by_psm(0, psm, &hcon->src, &hcon->dst, ACL_LINK); if (!chan) - goto drop; + goto free_skb; BT_DBG("chan %p, len %d", chan, skb->len); @@ -6864,10 +6876,14 @@ static void l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, bacpy(&bt_cb(skb)->bdaddr, &hcon->dst); bt_cb(skb)->psm = psm; - if (!chan->ops->recv(chan, skb)) + if (!chan->ops->recv(chan, skb)) { + l2cap_chan_put(chan); return; + } drop: + l2cap_chan_put(chan); +free_skb: kfree_skb(skb); } @@ -6878,22 +6894,26 @@ static void l2cap_att_channel(struct l2cap_conn *conn, struct l2cap_chan *chan; if (hcon->type != LE_LINK) - goto drop; + goto free_skb; chan = l2cap_global_chan_by_scid(BT_CONNECTED, L2CAP_CID_ATT, &hcon->src, &hcon->dst); if (!chan) - goto drop; + goto free_skb; BT_DBG("chan %p, len %d", chan, skb->len); if (chan->imtu < skb->len) goto drop; - if (!chan->ops->recv(chan, skb)) + if (!chan->ops->recv(chan, skb)) { + l2cap_chan_put(chan); return; + } drop: + l2cap_chan_put(chan); +free_skb: kfree_skb(skb); } From 5ff6f34d4260c542df3712e29ead87cf071ad472 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 7 Aug 2014 22:56:43 +0300 Subject: [PATCH 023/221] Bluetooth: Fix __l2cap_no_conn_pending() usage with all channels The __l2cap_no_conn_pending() function would previously only return a meaningful value for connection oriented channels and was therefore not useful for anything else. As preparation of making the L2CAP code more generic allow the function to be called for other channel types as well by returning a meaningful value for them. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index a47a14efd5aa..a0a910eb897b 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1082,6 +1082,9 @@ static void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, bool poll) static inline int __l2cap_no_conn_pending(struct l2cap_chan *chan) { + if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) + return true; + return !test_bit(CONF_CONNECT_PEND, &chan->conf_state); } From d52deb17489b8155e031fb1a9f116c602d719e11 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 7 Aug 2014 22:56:44 +0300 Subject: [PATCH 024/221] Bluetooth: Resume BT_CONNECTED state after LE security elevation The LE ATT socket uses a special trick where it temporarily sets BT_CONFIG state for the duration of a security level elevation. In order to not require special hacks for going back to BT_CONNECTED state in the l2cap_core.c code the most reasonable place to resume the state is the resume callback. This patch adds a new flag to track the pending security level change and ensures that the state is set back to BT_CONNECTED in the resume callback in case the flag is set. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/l2cap.h | 1 + net/bluetooth/l2cap_sock.c | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 8df15ad0d43f..4a51e7596608 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -708,6 +708,7 @@ enum { FLAG_EFS_ENABLE, FLAG_DEFER_SETUP, FLAG_LE_CONN_REQ_SENT, + FLAG_PENDING_SECURITY, }; enum { diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 1884f72083c2..5a42f6a818c0 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -790,6 +790,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, if (chan->scid == L2CAP_CID_ATT) { if (smp_conn_security(conn->hcon, sec.level)) break; + set_bit(FLAG_PENDING_SECURITY, &chan->flags); sk->sk_state = BT_CONFIG; chan->state = BT_CONFIG; @@ -1359,6 +1360,11 @@ static void l2cap_sock_resume_cb(struct l2cap_chan *chan) { struct sock *sk = chan->data; + if (test_and_clear_bit(FLAG_PENDING_SECURITY, &chan->flags)) { + sk->sk_state = BT_CONNECTED; + chan->state = BT_CONNECTED; + } + clear_bit(BT_SK_SUSPEND, &bt_sk(sk)->flags); sk->sk_state_change(sk); } From 191eb398c677444bc08cb4497467ca9e2b8696bc Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 7 Aug 2014 22:56:45 +0300 Subject: [PATCH 025/221] Bluetooth: Remove special handling of ATT in l2cap_security_cfm() With the update to sk->resume() and __l2cap_no_conn_pending() we no-longer need to have special handling of ATT channels in the l2cap_security_cfm() function. The chan->sec_level update when encryption has been enabled is safe to do for any kind of channel, and the loop takes later care of calling chan->ready() or chan->resume() if necessary. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index a0a910eb897b..54cbfcd4da44 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -7341,15 +7341,8 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) continue; } - if (chan->scid == L2CAP_CID_ATT) { - if (!status && encrypt) { - chan->sec_level = hcon->sec_level; - l2cap_chan_ready(chan); - } - - l2cap_chan_unlock(chan); - continue; - } + if (!status && encrypt) + chan->sec_level = hcon->sec_level; if (!__l2cap_no_conn_pending(chan)) { l2cap_chan_unlock(chan); From dc0f5088182b2e48ae47629a55bdf35ad5d6ed44 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 7 Aug 2014 22:56:46 +0300 Subject: [PATCH 026/221] Bluetooth: Refactor l2cap_connect_cfm This patch is a simple refactoring of l2cap_connect_cfm to allow easier extension of the function. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 54cbfcd4da44..7a5cff89b792 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -7268,13 +7268,16 @@ void l2cap_connect_cfm(struct hci_conn *hcon, u8 status) BT_DBG("hcon %p bdaddr %pMR status %d", hcon, &hcon->dst, status); - if (!status) { - conn = l2cap_conn_add(hcon); - if (conn) - l2cap_conn_ready(conn); - } else { + if (status) { l2cap_conn_del(hcon, bt_to_errno(status)); + return; } + + conn = l2cap_conn_add(hcon); + if (!conn) + return; + + l2cap_conn_ready(conn); } int l2cap_disconn_ind(struct hci_conn *hcon) From e760ec12134d5736065c4e88b0e783cc1fe0d20a Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 7 Aug 2014 22:56:47 +0300 Subject: [PATCH 027/221] Bluetooth: Move L2CAP fixed channel creation into l2cap_conn_cfm In order to remove special handling of fixed L2CAP channels we need to start creating them in a single place instead of having per-channel exceptions. The most natural place is the l2cap_conn_cfm() function which is called whenever there is a new baseband link. The only really special case so far has been the ATT socket, so in order not to break the code in between this patch removes the ATT special handling at the same time as it adds the generic fixed channel handling from l2cap_le_conn_ready() into the hci_conn_cfm() function. As a related change the channel locking in l2cap_conn_ready() becomes simpler and we can thereby move the smp_conn_security() call into the l2cap_le_conn_ready() function. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 124 ++++++++++++++++++++++++------------- 1 file changed, 80 insertions(+), 44 deletions(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 7a5cff89b792..8c4767f91a23 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1469,26 +1469,14 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) { struct hci_conn *hcon = conn->hcon; struct hci_dev *hdev = hcon->hdev; - struct l2cap_chan *chan, *pchan; - u8 dst_type; - BT_DBG(""); + BT_DBG("%s conn %p", hdev->name, conn); - /* Check if we have socket listening on cid */ - pchan = l2cap_global_chan_by_scid(BT_LISTEN, L2CAP_CID_ATT, - &hcon->src, &hcon->dst); - if (!pchan) - return; - - /* Client ATT sockets should override the server one */ - if (__l2cap_get_chan_by_dcid(conn, L2CAP_CID_ATT)) - goto put; - - dst_type = bdaddr_type(hcon, hcon->dst_type); - - /* If device is blocked, do not create a channel for it */ - if (hci_bdaddr_list_lookup(&hdev->blacklist, &hcon->dst, dst_type)) - goto put; + /* For outgoing pairing which doesn't necessarily have an + * associated socket (e.g. mgmt_pair_device). + */ + if (hcon->out) + smp_conn_security(hcon, hcon->pending_sec_level); /* For LE slave connections, make sure the connection interval * is in the range of the minium and maximum interval that has @@ -1508,24 +1496,6 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONN_PARAM_UPDATE_REQ, sizeof(req), &req); } - - l2cap_chan_lock(pchan); - - chan = pchan->ops->new_connection(pchan); - if (!chan) - goto clean; - - bacpy(&chan->src, &hcon->src); - bacpy(&chan->dst, &hcon->dst); - chan->src_type = bdaddr_type(hcon, hcon->src_type); - chan->dst_type = dst_type; - - __l2cap_chan_add(conn, chan); - -clean: - l2cap_chan_unlock(pchan); -put: - l2cap_chan_put(pchan); } static void l2cap_conn_ready(struct l2cap_conn *conn) @@ -1535,17 +1505,11 @@ static void l2cap_conn_ready(struct l2cap_conn *conn) BT_DBG("conn %p", conn); - /* For outgoing pairing which doesn't necessarily have an - * associated socket (e.g. mgmt_pair_device). - */ - if (hcon->out && hcon->type == LE_LINK) - smp_conn_security(hcon, hcon->pending_sec_level); - - mutex_lock(&conn->chan_lock); - if (hcon->type == LE_LINK) l2cap_le_conn_ready(conn); + mutex_lock(&conn->chan_lock); + list_for_each_entry(chan, &conn->chan_l, list) { l2cap_chan_lock(chan); @@ -7262,9 +7226,44 @@ int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr) return exact ? lm1 : lm2; } +/* Find the next fixed channel in BT_LISTEN state, continue iteration + * from an existing channel in the list or from the beginning of the + * global list (by passing NULL as first parameter). + */ +static struct l2cap_chan *l2cap_global_fixed_chan(struct l2cap_chan *c, + bdaddr_t *src) +{ + read_lock(&chan_list_lock); + + if (c) + c = list_next_entry(c, global_l); + else + c = list_entry(chan_list.next, typeof(*c), global_l); + + list_for_each_entry_from(c, &chan_list, global_l) { + if (c->chan_type != L2CAP_CHAN_FIXED) + continue; + if (c->state != BT_LISTEN) + continue; + if (bacmp(&c->src, src) && bacmp(&c->src, BDADDR_ANY)) + continue; + + l2cap_chan_hold(c); + read_unlock(&chan_list_lock); + return c; + } + + read_unlock(&chan_list_lock); + + return NULL; +} + void l2cap_connect_cfm(struct hci_conn *hcon, u8 status) { + struct hci_dev *hdev = hcon->hdev; struct l2cap_conn *conn; + struct l2cap_chan *pchan; + u8 dst_type; BT_DBG("hcon %p bdaddr %pMR status %d", hcon, &hcon->dst, status); @@ -7277,6 +7276,43 @@ void l2cap_connect_cfm(struct hci_conn *hcon, u8 status) if (!conn) return; + dst_type = bdaddr_type(hcon, hcon->dst_type); + + /* If device is blocked, do not create channels for it */ + if (hci_bdaddr_list_lookup(&hdev->blacklist, &hcon->dst, dst_type)) + return; + + /* Find fixed channels and notify them of the new connection. We + * use multiple individual lookups, continuing each time where + * we left off, because the list lock would prevent calling the + * potentially sleeping l2cap_chan_lock() function. + */ + pchan = l2cap_global_fixed_chan(NULL, &hdev->bdaddr); + while (pchan) { + struct l2cap_chan *chan, *next; + + /* Client fixed channels should override server ones */ + if (__l2cap_get_chan_by_dcid(conn, pchan->scid)) + goto next; + + l2cap_chan_lock(pchan); + chan = pchan->ops->new_connection(pchan); + if (chan) { + bacpy(&chan->src, &hcon->src); + bacpy(&chan->dst, &hcon->dst); + chan->src_type = bdaddr_type(hcon, hcon->src_type); + chan->dst_type = dst_type; + + __l2cap_chan_add(conn, chan); + } + + l2cap_chan_unlock(pchan); +next: + next = l2cap_global_fixed_chan(pchan, &hdev->bdaddr); + l2cap_chan_put(pchan); + pchan = next; + } + l2cap_conn_ready(conn); } From 54a1b626c96039f172dd2ea15b2671053b3c5a68 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 7 Aug 2014 22:56:48 +0300 Subject: [PATCH 028/221] Bluetooth: Improve fixed channel lookup based on link type When notifying global fixed channels of new connections it doesn't make sense to consider channels meant for a different link type than the one available. This patch adds an extra parameter to the l2cap_global_fixed_chan() lookup function and ensures that only channels matching the current hci_conn type are looked up. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 8c4767f91a23..191b58f48245 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -7231,7 +7231,7 @@ int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr) * global list (by passing NULL as first parameter). */ static struct l2cap_chan *l2cap_global_fixed_chan(struct l2cap_chan *c, - bdaddr_t *src) + bdaddr_t *src, u8 link_type) { read_lock(&chan_list_lock); @@ -7247,6 +7247,10 @@ static struct l2cap_chan *l2cap_global_fixed_chan(struct l2cap_chan *c, continue; if (bacmp(&c->src, src) && bacmp(&c->src, BDADDR_ANY)) continue; + if (link_type == ACL_LINK && c->src_type != BDADDR_BREDR) + continue; + if (link_type == LE_LINK && c->src_type == BDADDR_BREDR) + continue; l2cap_chan_hold(c); read_unlock(&chan_list_lock); @@ -7287,7 +7291,7 @@ void l2cap_connect_cfm(struct hci_conn *hcon, u8 status) * we left off, because the list lock would prevent calling the * potentially sleeping l2cap_chan_lock() function. */ - pchan = l2cap_global_fixed_chan(NULL, &hdev->bdaddr); + pchan = l2cap_global_fixed_chan(NULL, &hdev->bdaddr, hcon->type); while (pchan) { struct l2cap_chan *chan, *next; @@ -7308,7 +7312,8 @@ void l2cap_connect_cfm(struct hci_conn *hcon, u8 status) l2cap_chan_unlock(pchan); next: - next = l2cap_global_fixed_chan(pchan, &hdev->bdaddr); + next = l2cap_global_fixed_chan(pchan, &hdev->bdaddr, + hcon->type); l2cap_chan_put(pchan); pchan = next; } From 06171e0546434b006a3857ea745b4258ad5d677c Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 7 Aug 2014 22:56:49 +0300 Subject: [PATCH 029/221] Bluetooth: Remove special ATT data channel handling Now that we've got the fixed channel infrastructure cleaned up in a generic way there's no longer a need to have a dedicated function for handling data on the ATT channel. Instead the generic l2cap_data_channel() handler will be able to do the exact same thing. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 79 -------------------------------------- 1 file changed, 79 deletions(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 191b58f48245..09eb4e3e8ab2 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1420,51 +1420,6 @@ static void l2cap_conn_start(struct l2cap_conn *conn) mutex_unlock(&conn->chan_lock); } -/* Find socket with cid and source/destination bdaddr. - * Returns closest match, locked. - */ -static struct l2cap_chan *l2cap_global_chan_by_scid(int state, u16 cid, - bdaddr_t *src, - bdaddr_t *dst) -{ - struct l2cap_chan *c, *c1 = NULL; - - read_lock(&chan_list_lock); - - list_for_each_entry(c, &chan_list, global_l) { - if (state && c->state != state) - continue; - - if (c->scid == cid) { - int src_match, dst_match; - int src_any, dst_any; - - /* Exact match. */ - src_match = !bacmp(&c->src, src); - dst_match = !bacmp(&c->dst, dst); - if (src_match && dst_match) { - l2cap_chan_hold(c); - read_unlock(&chan_list_lock); - return c; - } - - /* Closest match */ - src_any = !bacmp(&c->src, BDADDR_ANY); - dst_any = !bacmp(&c->dst, BDADDR_ANY); - if ((src_match && dst_any) || (src_any && dst_match) || - (src_any && dst_any)) - c1 = c; - } - } - - if (c1) - l2cap_chan_hold(c1); - - read_unlock(&chan_list_lock); - - return c1; -} - static void l2cap_le_conn_ready(struct l2cap_conn *conn) { struct hci_conn *hcon = conn->hcon; @@ -6854,36 +6809,6 @@ free_skb: kfree_skb(skb); } -static void l2cap_att_channel(struct l2cap_conn *conn, - struct sk_buff *skb) -{ - struct hci_conn *hcon = conn->hcon; - struct l2cap_chan *chan; - - if (hcon->type != LE_LINK) - goto free_skb; - - chan = l2cap_global_chan_by_scid(BT_CONNECTED, L2CAP_CID_ATT, - &hcon->src, &hcon->dst); - if (!chan) - goto free_skb; - - BT_DBG("chan %p, len %d", chan, skb->len); - - if (chan->imtu < skb->len) - goto drop; - - if (!chan->ops->recv(chan, skb)) { - l2cap_chan_put(chan); - return; - } - -drop: - l2cap_chan_put(chan); -free_skb: - kfree_skb(skb); -} - static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb) { struct l2cap_hdr *lh = (void *) skb->data; @@ -6929,10 +6854,6 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb) l2cap_conless_channel(conn, psm, skb); break; - case L2CAP_CID_ATT: - l2cap_att_channel(conn, skb); - break; - case L2CAP_CID_LE_SIGNALING: l2cap_le_sig_channel(conn, skb); break; From 148243087b3a5d95a32825da26858dc9d893b141 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 7 Aug 2014 22:56:50 +0300 Subject: [PATCH 030/221] Bluetooth: Move parts of fixed channel initialization to l2cap_add_scid The l2cap_add_scid function is used for registering a fixed L2CAP channel. Instead of having separate initialization of the channel type and outgoing MTU in l2cap_sock.c it's more intuitive to do these things in the l2cap_add_scid function itself (and thereby make the functionality available to other users besides l2cap_sock.c). Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 4 ++++ net/bluetooth/l2cap_sock.c | 9 --------- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 09eb4e3e8ab2..344a29c53227 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -210,6 +210,10 @@ int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid) { write_lock(&chan_list_lock); + /* Override the defaults (which are for conn-oriented) */ + chan->omtu = L2CAP_DEFAULT_MTU; + chan->chan_type = L2CAP_CHAN_FIXED; + chan->scid = scid; write_unlock(&chan_list_lock); diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 5a42f6a818c0..ed06f88e6f10 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -99,15 +99,6 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) if (!bdaddr_type_is_valid(la.l2_bdaddr_type)) return -EINVAL; - if (la.l2_cid) { - /* When the socket gets created it defaults to - * CHAN_CONN_ORIENTED, so we need to overwrite the - * default here. - */ - chan->chan_type = L2CAP_CHAN_FIXED; - chan->omtu = L2CAP_DEFAULT_MTU; - } - if (bdaddr_type_is_le(la.l2_bdaddr_type)) { /* We only allow ATT user space socket */ if (la.l2_cid && From 72847ce02180e8a0be1b23ba53ffe437cdb25d6a Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 8 Aug 2014 09:28:03 +0300 Subject: [PATCH 031/221] Bluetooth: Call L2CAP teardown callback before clearing chan->conn L2CAP channel implementations may want to still access the chan->conn pointer. This will particularly be the case for SMP that will want to clear a reference to the SMP channel in the l2cap_conn structure. The only user of the teardown callback so far is l2cap_sock.c and for the code there it makes no difference whether the callback is called before or after clearing the chan->conn pointer. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 344a29c53227..c6419f40cfba 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -566,6 +566,8 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err) BT_DBG("chan %p, conn %p, err %d", chan, conn, err); + chan->ops->teardown(chan, err); + if (conn) { struct amp_mgr *mgr = conn->hcon->amp_mgr; /* Delete from channel list */ @@ -589,8 +591,6 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err) amp_disconnect_logical_link(hs_hchan); } - chan->ops->teardown(chan, err); - if (test_bit(CONF_NOT_COMPLETE, &chan->conf_state)) return; From 79a0572736ad4b9cac7be72d4402f9c79db8ebaf Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 8 Aug 2014 09:28:04 +0300 Subject: [PATCH 032/221] Bluetooth: Call l2cap_le_conn_ready after notifying channels For most cases it makes no difference whether l2cap_le_conn_ready() is called before or after calling the channel ready() callbacks, however for upcoming SMP code we need this as the ready() callback initializes certain structures that a call to smp_conn_security() from l2cap_le_conn_ready() depends on. Therefore, move the call to l2cap_le_conn_ready() after iterating through and notifying channels. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index c6419f40cfba..8acfe6f57b5e 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1464,9 +1464,6 @@ static void l2cap_conn_ready(struct l2cap_conn *conn) BT_DBG("conn %p", conn); - if (hcon->type == LE_LINK) - l2cap_le_conn_ready(conn); - mutex_lock(&conn->chan_lock); list_for_each_entry(chan, &conn->chan_l, list) { @@ -1492,6 +1489,9 @@ static void l2cap_conn_ready(struct l2cap_conn *conn) mutex_unlock(&conn->chan_lock); + if (hcon->type == LE_LINK) + l2cap_le_conn_ready(conn); + queue_work(hcon->hdev->workqueue, &conn->pending_rx_work); } From d3368605591b88cd8af522adadb1c460a8f8e7bb Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 8 Aug 2014 09:28:05 +0300 Subject: [PATCH 033/221] Bluetooth: Fix using HCI_CONN_LE_SMP_PEND to check for SMP context The code is consistently using the HCI_CONN_LE_SMP_PEND flag check for the existence of the SMP context, with the exception of this one place in smp_sig_channel(). This patch converts the place to use the flag just like all other instances. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 40db728f044b..33016ec9b247 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -1206,7 +1206,7 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb) * returns an error). */ if (code != SMP_CMD_PAIRING_REQ && code != SMP_CMD_SECURITY_REQ && - !conn->smp_chan) { + !test_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) { BT_ERR("Unexpected SMP command 0x%02x. Disconnecting.", code); kfree_skb(skb); return -EOPNOTSUPP; From fabed38fcf456cc5d3e6946fab78855aa65bd40b Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 8 Aug 2014 09:32:48 +0300 Subject: [PATCH 034/221] Bluetooth: Fix hci_update_random_address() error return for no crypto If the AES crypto context is not available we cannot generate new RPAs. We should therefore cleanly return an error from the function responsible for updating the random address. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 217ef83fb541..860477090d78 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3882,6 +3882,12 @@ int hci_update_random_address(struct hci_request *req, bool require_privacy, !bacmp(&hdev->random_addr, &hdev->rpa)) return 0; + if (!hdev->tfm_aes) { + BT_ERR("%s crypto not available to generate RPA", + hdev->name); + return -EOPNOTSUPP; + } + err = smp_generate_rpa(hdev->tfm_aes, hdev->irk, &hdev->rpa); if (err < 0) { BT_ERR("%s failed to generate new RPA", hdev->name); From 893ededeb189aa48c308116a7acd793efae5c830 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 8 Aug 2014 09:32:49 +0300 Subject: [PATCH 035/221] Bluetooth: Fix IRK lookup when tfm_aes is not available If the AES crypto has not been initialized properly we should cleanly return from the hci_find_irk_by_rpa() function. Right now this will not happen in practice, but once (in subsequent patches) SMP init is moved to after the HCI init procedure it is possible that the pointer is NULL. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 860477090d78..4a1ec259099e 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3232,6 +3232,9 @@ struct smp_irk *hci_find_irk_by_rpa(struct hci_dev *hdev, bdaddr_t *rpa) return irk; } + if (!hdev->tfm_aes) + return NULL; + list_for_each_entry(irk, &hdev->identity_resolving_keys, list) { if (smp_irk_matches(hdev->tfm_aes, irk->val, rpa)) { bacpy(&irk->rpa, rpa); From 222916e3e509f04678d0b6f13f7b17bbc8dd14b6 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 8 Aug 2014 09:32:50 +0300 Subject: [PATCH 036/221] Bluetooth: Refactor SMP (de)initialization into separate functions As preparation for converting SMP to use the l2cap_chan infrastructure refactor the (de)initialization into separate functions. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 46 +++++++++++++++++++++++++++++----------- 1 file changed, 34 insertions(+), 12 deletions(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 4a1ec259099e..1f691c50abbc 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1764,6 +1764,34 @@ static void hci_init4_req(struct hci_request *req, unsigned long opt) } } +static int hci_register_smp(struct hci_dev *hdev) +{ + int err; + + BT_DBG("%s", hdev->name); + + hdev->tfm_aes = crypto_alloc_blkcipher("ecb(aes)", 0, + CRYPTO_ALG_ASYNC); + if (IS_ERR(hdev->tfm_aes)) { + BT_ERR("Unable to create crypto context"); + err = PTR_ERR(hdev->tfm_aes); + hdev->tfm_aes = NULL; + return err; + } + + return 0; +} + +static void hci_unregister_smp(struct hci_dev *hdev) +{ + BT_DBG("%s", hdev->name); + + if (hdev->tfm_aes) { + crypto_free_blkcipher(hdev->tfm_aes); + hdev->tfm_aes = NULL; + } +} + static int __hci_init(struct hci_dev *hdev) { int err; @@ -4099,18 +4127,13 @@ int hci_register_dev(struct hci_dev *hdev) dev_set_name(&hdev->dev, "%s", hdev->name); - hdev->tfm_aes = crypto_alloc_blkcipher("ecb(aes)", 0, - CRYPTO_ALG_ASYNC); - if (IS_ERR(hdev->tfm_aes)) { - BT_ERR("Unable to create crypto context"); - error = PTR_ERR(hdev->tfm_aes); - hdev->tfm_aes = NULL; + error = hci_register_smp(hdev); + if (error) goto err_wqueue; - } error = device_add(&hdev->dev); if (error < 0) - goto err_tfm; + goto err_smp; hdev->rfkill = rfkill_alloc(hdev->name, &hdev->dev, RFKILL_TYPE_BLUETOOTH, &hci_rfkill_ops, @@ -4152,8 +4175,8 @@ int hci_register_dev(struct hci_dev *hdev) return id; -err_tfm: - crypto_free_blkcipher(hdev->tfm_aes); +err_smp: + hci_unregister_smp(hdev); err_wqueue: destroy_workqueue(hdev->workqueue); destroy_workqueue(hdev->req_workqueue); @@ -4205,8 +4228,7 @@ void hci_unregister_dev(struct hci_dev *hdev) rfkill_destroy(hdev->rfkill); } - if (hdev->tfm_aes) - crypto_free_blkcipher(hdev->tfm_aes); + hci_unregister_smp(hdev); device_del(&hdev->dev); From 54506918059a5bdbf396f34f2e0a2735803024db Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 8 Aug 2014 09:32:51 +0300 Subject: [PATCH 037/221] Bluetooth: Move SMP initialization after HCI init First of all, it's wasteful to initialize SMP if it's never going to be used (e.g. on non-LE controllers). Second of all, when we move to use l2cap_chan we need to know the real local address, meaning we must have completed at least part of the HCI init. This patch moves the SMP initialization to after the HCI init procedure and makes it depend on whether the controller actually supports LE. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 1f691c50abbc..9eb2869b183b 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1926,6 +1926,8 @@ static int __hci_init(struct hci_dev *hdev) debugfs_create_u16("discov_interleaved_timeout", 0644, hdev->debugfs, &hdev->discov_interleaved_timeout); + + hci_register_smp(hdev); } return 0; @@ -4127,13 +4129,9 @@ int hci_register_dev(struct hci_dev *hdev) dev_set_name(&hdev->dev, "%s", hdev->name); - error = hci_register_smp(hdev); - if (error) - goto err_wqueue; - error = device_add(&hdev->dev); if (error < 0) - goto err_smp; + goto err_wqueue; hdev->rfkill = rfkill_alloc(hdev->name, &hdev->dev, RFKILL_TYPE_BLUETOOTH, &hci_rfkill_ops, @@ -4175,8 +4173,6 @@ int hci_register_dev(struct hci_dev *hdev) return id; -err_smp: - hci_unregister_smp(hdev); err_wqueue: destroy_workqueue(hdev->workqueue); destroy_workqueue(hdev->req_workqueue); From 711eafe345d993cf4831e890fa989d02c06cad62 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 8 Aug 2014 09:32:52 +0300 Subject: [PATCH 038/221] Bluetooth: Move SMP (de)initialization to smp.c As preparation for moving SMP to use l2cap_chan infrastructure we need to move the (de)initialization functions to smp.c (where they'll eventually need access to the local L2CAP channel callbacks). Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 32 ++------------------------------ net/bluetooth/smp.c | 26 ++++++++++++++++++++++++++ net/bluetooth/smp.h | 3 +++ 3 files changed, 31 insertions(+), 30 deletions(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 9eb2869b183b..88575a633601 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1764,34 +1764,6 @@ static void hci_init4_req(struct hci_request *req, unsigned long opt) } } -static int hci_register_smp(struct hci_dev *hdev) -{ - int err; - - BT_DBG("%s", hdev->name); - - hdev->tfm_aes = crypto_alloc_blkcipher("ecb(aes)", 0, - CRYPTO_ALG_ASYNC); - if (IS_ERR(hdev->tfm_aes)) { - BT_ERR("Unable to create crypto context"); - err = PTR_ERR(hdev->tfm_aes); - hdev->tfm_aes = NULL; - return err; - } - - return 0; -} - -static void hci_unregister_smp(struct hci_dev *hdev) -{ - BT_DBG("%s", hdev->name); - - if (hdev->tfm_aes) { - crypto_free_blkcipher(hdev->tfm_aes); - hdev->tfm_aes = NULL; - } -} - static int __hci_init(struct hci_dev *hdev) { int err; @@ -1927,7 +1899,7 @@ static int __hci_init(struct hci_dev *hdev) hdev->debugfs, &hdev->discov_interleaved_timeout); - hci_register_smp(hdev); + smp_register(hdev); } return 0; @@ -4224,7 +4196,7 @@ void hci_unregister_dev(struct hci_dev *hdev) rfkill_destroy(hdev->rfkill); } - hci_unregister_smp(hdev); + smp_unregister(hdev); device_del(&hdev->dev); diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 33016ec9b247..ab07649ecc77 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -1455,3 +1455,29 @@ int smp_distribute_keys(struct l2cap_conn *conn) return 0; } + +int smp_register(struct hci_dev *hdev) +{ + BT_DBG("%s", hdev->name); + + hdev->tfm_aes = crypto_alloc_blkcipher("ecb(aes)", 0, + CRYPTO_ALG_ASYNC); + if (IS_ERR(hdev->tfm_aes)) { + int err = PTR_ERR(hdev->tfm_aes); + BT_ERR("Unable to create crypto context"); + hdev->tfm_aes = NULL; + return err; + } + + return 0; +} + +void smp_unregister(struct hci_dev *hdev) +{ + BT_DBG("%s", hdev->name); + + if (hdev->tfm_aes) { + crypto_free_blkcipher(hdev->tfm_aes); + hdev->tfm_aes = NULL; + } +} diff --git a/net/bluetooth/smp.h b/net/bluetooth/smp.h index 796f4f45f92f..6e29359f60a3 100644 --- a/net/bluetooth/smp.h +++ b/net/bluetooth/smp.h @@ -136,4 +136,7 @@ bool smp_irk_matches(struct crypto_blkcipher *tfm, u8 irk[16], bdaddr_t *bdaddr); int smp_generate_rpa(struct crypto_blkcipher *tfm, u8 irk[16], bdaddr_t *rpa); +int smp_register(struct hci_dev *hdev); +void smp_unregister(struct hci_dev *hdev); + #endif /* __SMP_H */ From f193844c51e88ea3d2137bb0c1d38d27d37691a2 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 8 Aug 2014 09:37:15 +0300 Subject: [PATCH 039/221] Bluetooth: Add more L2CAP convenience callbacks In preparation for converting SMP to use l2cap_chan it's useful to add a few more callback helpers so that smp.c won't need to define all of its own. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/l2cap.h | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 4a51e7596608..a72965f6bc2f 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -838,18 +838,43 @@ static inline struct l2cap_chan *l2cap_chan_no_new_connection(struct l2cap_chan return NULL; } +static inline int l2cap_chan_no_recv(struct l2cap_chan *chan, struct sk_buff *skb) +{ + return -ENOSYS; +} + +static inline struct sk_buff *l2cap_chan_no_alloc_skb(struct l2cap_chan *chan, + unsigned long hdr_len, + unsigned long len, int nb) +{ + return ERR_PTR(-ENOSYS); +} + static inline void l2cap_chan_no_teardown(struct l2cap_chan *chan, int err) { } +static inline void l2cap_chan_no_close(struct l2cap_chan *chan) +{ +} + static inline void l2cap_chan_no_ready(struct l2cap_chan *chan) { } +static inline void l2cap_chan_no_state_change(struct l2cap_chan *chan, + int state, int err) +{ +} + static inline void l2cap_chan_no_defer(struct l2cap_chan *chan) { } +static inline void l2cap_chan_no_suspend(struct l2cap_chan *chan) +{ +} + static inline void l2cap_chan_no_resume(struct l2cap_chan *chan) { } From 70db83c4bcdc1447bbcb318389561c90d7056b18 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 8 Aug 2014 09:37:16 +0300 Subject: [PATCH 040/221] Bluetooth: Add SMP L2CAP channel skeleton This patch creates the initial SMP L2CAP channels and a skeleton for their callbacks. There is one per-adapter channel created upon adapter registration, and then one channel per-connection created through the new_connection callback. The channels are registered with the reserved CID 0x1f for now in order to not conflict with existing SMP functionality. Once everything is in place the value can be changed to what it should be, i.e. L2CAP_CID_SMP. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 1 + include/net/bluetooth/l2cap.h | 1 + net/bluetooth/smp.c | 131 ++++++++++++++++++++++++++++++- 3 files changed, 132 insertions(+), 1 deletion(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index cc2eb7730fbc..2571fc1cb1c5 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -303,6 +303,7 @@ struct hci_dev { __u32 req_result; struct crypto_blkcipher *tfm_aes; + void *smp_data; struct discovery_state discovery; struct hci_conn_hash conn_hash; diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index a72965f6bc2f..1a037ba4b6f4 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -637,6 +637,7 @@ struct l2cap_conn { struct delayed_work security_timer; struct smp_chan *smp_chan; + struct l2cap_chan *smp; struct list_head chan_l; struct mutex chan_lock; diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index ab07649ecc77..2362ae35a4d5 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -1456,8 +1456,106 @@ int smp_distribute_keys(struct l2cap_conn *conn) return 0; } +static void smp_teardown_cb(struct l2cap_chan *chan, int err) +{ + struct l2cap_conn *conn = chan->conn; + + BT_DBG("chan %p", chan); + + conn->smp = NULL; + l2cap_chan_put(chan); +} + +static void smp_ready_cb(struct l2cap_chan *chan) +{ + struct l2cap_conn *conn = chan->conn; + + BT_DBG("chan %p", chan); + + conn->smp = chan; + l2cap_chan_hold(chan); +} + +static struct sk_buff *smp_alloc_skb_cb(struct l2cap_chan *chan, + unsigned long hdr_len, + unsigned long len, int nb) +{ + struct sk_buff *skb; + + skb = bt_skb_alloc(hdr_len + len, GFP_KERNEL); + if (!skb) + return ERR_PTR(-ENOMEM); + + skb->priority = HCI_PRIO_MAX; + bt_cb(skb)->chan = chan; + + return skb; +} + +static const struct l2cap_ops smp_chan_ops = { + .name = "Security Manager", + .ready = smp_ready_cb, + .alloc_skb = smp_alloc_skb_cb, + .teardown = smp_teardown_cb, + + .new_connection = l2cap_chan_no_new_connection, + .recv = l2cap_chan_no_recv, + .state_change = l2cap_chan_no_state_change, + .close = l2cap_chan_no_close, + .defer = l2cap_chan_no_defer, + .suspend = l2cap_chan_no_suspend, + .resume = l2cap_chan_no_resume, + .set_shutdown = l2cap_chan_no_set_shutdown, + .get_sndtimeo = l2cap_chan_no_get_sndtimeo, + .memcpy_fromiovec = l2cap_chan_no_memcpy_fromiovec, +}; + +static inline struct l2cap_chan *smp_new_conn_cb(struct l2cap_chan *pchan) +{ + struct l2cap_chan *chan; + + BT_DBG("pchan %p", pchan); + + chan = l2cap_chan_create(); + if (!chan) + return NULL; + + chan->chan_type = pchan->chan_type; + chan->ops = &smp_chan_ops; + chan->scid = pchan->scid; + chan->dcid = chan->scid; + chan->imtu = pchan->imtu; + chan->omtu = pchan->omtu; + chan->mode = pchan->mode; + + BT_DBG("created chan %p", chan); + + return chan; +} + +static const struct l2cap_ops smp_root_chan_ops = { + .name = "Security Manager Root", + .new_connection = smp_new_conn_cb, + + /* None of these are implemented for the root channel */ + .close = l2cap_chan_no_close, + .alloc_skb = l2cap_chan_no_alloc_skb, + .recv = l2cap_chan_no_recv, + .state_change = l2cap_chan_no_state_change, + .teardown = l2cap_chan_no_teardown, + .ready = l2cap_chan_no_ready, + .defer = l2cap_chan_no_defer, + .suspend = l2cap_chan_no_suspend, + .resume = l2cap_chan_no_resume, + .set_shutdown = l2cap_chan_no_set_shutdown, + .get_sndtimeo = l2cap_chan_no_get_sndtimeo, + .memcpy_fromiovec = l2cap_chan_no_memcpy_fromiovec, +}; + int smp_register(struct hci_dev *hdev) { + struct l2cap_chan *chan; + BT_DBG("%s", hdev->name); hdev->tfm_aes = crypto_alloc_blkcipher("ecb(aes)", 0, @@ -1469,15 +1567,46 @@ int smp_register(struct hci_dev *hdev) return err; } + chan = l2cap_chan_create(); + if (!chan) { + crypto_free_blkcipher(hdev->tfm_aes); + hdev->tfm_aes = NULL; + return -ENOMEM; + } + + /* FIXME: Using reserved 0x1f value for now - to be changed to + * L2CAP_CID_SMP once all functionality is in place. + */ + l2cap_add_scid(chan, 0x1f); + + l2cap_chan_set_defaults(chan); + + bacpy(&chan->src, &hdev->bdaddr); + chan->src_type = BDADDR_LE_PUBLIC; + chan->state = BT_LISTEN; + chan->mode = L2CAP_MODE_BASIC; + chan->imtu = L2CAP_DEFAULT_MTU; + chan->ops = &smp_root_chan_ops; + + hdev->smp_data = chan; + return 0; } void smp_unregister(struct hci_dev *hdev) { - BT_DBG("%s", hdev->name); + struct l2cap_chan *chan = hdev->smp_data; + + if (!chan) + return; + + BT_DBG("%s chan %p", hdev->name, chan); if (hdev->tfm_aes) { crypto_free_blkcipher(hdev->tfm_aes); hdev->tfm_aes = NULL; } + + hdev->smp_data = NULL; + l2cap_chan_put(chan); } From defce9e83666658d4420d65e45ab1ad190992f72 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 8 Aug 2014 09:37:17 +0300 Subject: [PATCH 041/221] Bluetooth: Make AES crypto context private to SMP Now that we have per-adapter SMP data thanks to the root SMP L2CAP channel we can take advantage of it and attach the AES crypto context (only used for SMP) to it. This means that the smp_irk_matches() and smp_generate_rpa() function can be converted to internally handle the AES context. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 1 - net/bluetooth/hci_core.c | 13 ++-------- net/bluetooth/smp.c | 41 ++++++++++++++++++++++---------- net/bluetooth/smp.h | 5 ++-- 4 files changed, 32 insertions(+), 28 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 2571fc1cb1c5..5f0b77b71b45 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -302,7 +302,6 @@ struct hci_dev { __u32 req_status; __u32 req_result; - struct crypto_blkcipher *tfm_aes; void *smp_data; struct discovery_state discovery; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 88575a633601..abeb5e47311e 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3234,11 +3234,8 @@ struct smp_irk *hci_find_irk_by_rpa(struct hci_dev *hdev, bdaddr_t *rpa) return irk; } - if (!hdev->tfm_aes) - return NULL; - list_for_each_entry(irk, &hdev->identity_resolving_keys, list) { - if (smp_irk_matches(hdev->tfm_aes, irk->val, rpa)) { + if (smp_irk_matches(hdev, irk->val, rpa)) { bacpy(&irk->rpa, rpa); return irk; } @@ -3887,13 +3884,7 @@ int hci_update_random_address(struct hci_request *req, bool require_privacy, !bacmp(&hdev->random_addr, &hdev->rpa)) return 0; - if (!hdev->tfm_aes) { - BT_ERR("%s crypto not available to generate RPA", - hdev->name); - return -EOPNOTSUPP; - } - - err = smp_generate_rpa(hdev->tfm_aes, hdev->irk, &hdev->rpa); + err = smp_generate_rpa(hdev, hdev->irk, &hdev->rpa); if (err < 0) { BT_ERR("%s failed to generate new RPA", hdev->name); return err; diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 2362ae35a4d5..6925fc4caaee 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -139,12 +139,18 @@ static int smp_ah(struct crypto_blkcipher *tfm, u8 irk[16], u8 r[3], u8 res[3]) return 0; } -bool smp_irk_matches(struct crypto_blkcipher *tfm, u8 irk[16], - bdaddr_t *bdaddr) +bool smp_irk_matches(struct hci_dev *hdev, u8 irk[16], bdaddr_t *bdaddr) { + struct l2cap_chan *chan = hdev->smp_data; + struct crypto_blkcipher *tfm; u8 hash[3]; int err; + if (!chan || !chan->data) + return false; + + tfm = chan->data; + BT_DBG("RPA %pMR IRK %*phN", bdaddr, 16, irk); err = smp_ah(tfm, irk, &bdaddr->b[3], hash); @@ -154,10 +160,17 @@ bool smp_irk_matches(struct crypto_blkcipher *tfm, u8 irk[16], return !memcmp(bdaddr->b, hash, 3); } -int smp_generate_rpa(struct crypto_blkcipher *tfm, u8 irk[16], bdaddr_t *rpa) +int smp_generate_rpa(struct hci_dev *hdev, u8 irk[16], bdaddr_t *rpa) { + struct l2cap_chan *chan = hdev->smp_data; + struct crypto_blkcipher *tfm; int err; + if (!chan || !chan->data) + return -EOPNOTSUPP; + + tfm = chan->data; + get_random_bytes(&rpa->b[3], 3); rpa->b[5] &= 0x3f; /* Clear two most significant bits */ @@ -1555,25 +1568,25 @@ static const struct l2cap_ops smp_root_chan_ops = { int smp_register(struct hci_dev *hdev) { struct l2cap_chan *chan; + struct crypto_blkcipher *tfm_aes; BT_DBG("%s", hdev->name); - hdev->tfm_aes = crypto_alloc_blkcipher("ecb(aes)", 0, - CRYPTO_ALG_ASYNC); - if (IS_ERR(hdev->tfm_aes)) { - int err = PTR_ERR(hdev->tfm_aes); + tfm_aes = crypto_alloc_blkcipher("ecb(aes)", 0, CRYPTO_ALG_ASYNC); + if (IS_ERR(tfm_aes)) { + int err = PTR_ERR(tfm_aes); BT_ERR("Unable to create crypto context"); - hdev->tfm_aes = NULL; return err; } chan = l2cap_chan_create(); if (!chan) { - crypto_free_blkcipher(hdev->tfm_aes); - hdev->tfm_aes = NULL; + crypto_free_blkcipher(tfm_aes); return -ENOMEM; } + chan->data = tfm_aes; + /* FIXME: Using reserved 0x1f value for now - to be changed to * L2CAP_CID_SMP once all functionality is in place. */ @@ -1596,15 +1609,17 @@ int smp_register(struct hci_dev *hdev) void smp_unregister(struct hci_dev *hdev) { struct l2cap_chan *chan = hdev->smp_data; + struct crypto_blkcipher *tfm_aes; if (!chan) return; BT_DBG("%s chan %p", hdev->name, chan); - if (hdev->tfm_aes) { - crypto_free_blkcipher(hdev->tfm_aes); - hdev->tfm_aes = NULL; + tfm_aes = chan->data; + if (tfm_aes) { + chan->data = NULL; + crypto_free_blkcipher(tfm_aes); } hdev->smp_data = NULL; diff --git a/net/bluetooth/smp.h b/net/bluetooth/smp.h index 6e29359f60a3..d3f6bd617940 100644 --- a/net/bluetooth/smp.h +++ b/net/bluetooth/smp.h @@ -132,9 +132,8 @@ int smp_user_confirm_reply(struct hci_conn *conn, u16 mgmt_op, __le32 passkey); void smp_chan_destroy(struct l2cap_conn *conn); -bool smp_irk_matches(struct crypto_blkcipher *tfm, u8 irk[16], - bdaddr_t *bdaddr); -int smp_generate_rpa(struct crypto_blkcipher *tfm, u8 irk[16], bdaddr_t *rpa); +bool smp_irk_matches(struct hci_dev *hdev, u8 irk[16], bdaddr_t *bdaddr); +int smp_generate_rpa(struct hci_dev *hdev, u8 irk[16], bdaddr_t *rpa); int smp_register(struct hci_dev *hdev); void smp_unregister(struct hci_dev *hdev); From 5d88cc73dded31a93fcc4821f33a8c3d755bf454 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 8 Aug 2014 09:37:18 +0300 Subject: [PATCH 042/221] Bluetooth: Convert SMP to use l2cap_chan infrastructure Now that we have all the necessary pieces in place we can fully convert SMP to use the L2CAP channel infrastructure. This patch adds the necessary callbacks and removes the now unneeded conn->smp_chan pointer. One notable behavioral change in this patch comes from the following code snippet: - case L2CAP_CID_SMP: - if (smp_sig_channel(conn, skb)) - l2cap_conn_del(conn->hcon, EACCES); This piece of code was essentially forcing a disconnection if garbage SMP data was received. The l2cap_conn_del() function is private to l2cap_conn.c so we don't have access to it anymore when using the L2CAP channel callbacks. Therefore, the behavior of the new code is simply to return errors in the recv() callback (which is simply the old smp_sig_channel()), but no disconnection will occur. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/l2cap.h | 1 - net/bluetooth/l2cap_core.c | 10 --- net/bluetooth/smp.c | 126 ++++++++++++++++++---------------- net/bluetooth/smp.h | 1 - 4 files changed, 68 insertions(+), 70 deletions(-) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 1a037ba4b6f4..bda6252e3722 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -636,7 +636,6 @@ struct l2cap_conn { __u8 disc_reason; struct delayed_work security_timer; - struct smp_chan *smp_chan; struct l2cap_chan *smp; struct list_head chan_l; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 8acfe6f57b5e..40b6c06ab2c0 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1651,11 +1651,6 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err) if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) cancel_delayed_work_sync(&conn->info_timer); - if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) { - cancel_delayed_work_sync(&conn->security_timer); - smp_chan_destroy(conn); - } - hcon->l2cap_data = NULL; conn->hchan = NULL; l2cap_conn_put(conn); @@ -6862,11 +6857,6 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb) l2cap_le_sig_channel(conn, skb); break; - case L2CAP_CID_SMP: - if (smp_sig_channel(conn, skb)) - l2cap_conn_del(conn->hcon, EACCES); - break; - default: l2cap_data_channel(conn, cid, skb); break; diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 6925fc4caaee..744f678ac3e8 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -248,44 +248,29 @@ static int smp_s1(struct smp_chan *smp, u8 k[16], u8 r1[16], u8 r2[16], return err; } -static struct sk_buff *smp_build_cmd(struct l2cap_conn *conn, u8 code, - u16 dlen, void *data) -{ - struct sk_buff *skb; - struct l2cap_hdr *lh; - int len; - - len = L2CAP_HDR_SIZE + sizeof(code) + dlen; - - if (len > conn->mtu) - return NULL; - - skb = bt_skb_alloc(len, GFP_ATOMIC); - if (!skb) - return NULL; - - lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); - lh->len = cpu_to_le16(sizeof(code) + dlen); - lh->cid = cpu_to_le16(L2CAP_CID_SMP); - - memcpy(skb_put(skb, sizeof(code)), &code, sizeof(code)); - - memcpy(skb_put(skb, dlen), data, dlen); - - return skb; -} - static void smp_send_cmd(struct l2cap_conn *conn, u8 code, u16 len, void *data) { - struct sk_buff *skb = smp_build_cmd(conn, code, len, data); + struct l2cap_chan *chan = conn->smp; + struct kvec iv[2]; + struct msghdr msg; + + if (!chan) + return; BT_DBG("code 0x%2.2x", code); - if (!skb) - return; + iv[0].iov_base = &code; + iv[0].iov_len = 1; - skb->priority = HCI_PRIO_MAX; - hci_send_acl(conn->hchan, skb, 0); + iv[1].iov_base = data; + iv[1].iov_len = len; + + memset(&msg, 0, sizeof(msg)); + + msg.msg_iov = (struct iovec *) &iv; + msg.msg_iovlen = 2; + + l2cap_chan_send(chan, &msg, 1 + len); cancel_delayed_work_sync(&conn->security_timer); schedule_delayed_work(&conn->security_timer, SMP_TIMEOUT); @@ -315,7 +300,8 @@ static void build_pairing_cmd(struct l2cap_conn *conn, struct smp_cmd_pairing *req, struct smp_cmd_pairing *rsp, __u8 authreq) { - struct smp_chan *smp = conn->smp_chan; + struct l2cap_chan *chan = conn->smp; + struct smp_chan *smp = chan->data; struct hci_conn *hcon = conn->hcon; struct hci_dev *hdev = hcon->hdev; u8 local_dist = 0, remote_dist = 0; @@ -358,7 +344,8 @@ static void build_pairing_cmd(struct l2cap_conn *conn, static u8 check_enc_key_size(struct l2cap_conn *conn, __u8 max_key_size) { - struct smp_chan *smp = conn->smp_chan; + struct l2cap_chan *chan = conn->smp; + struct smp_chan *smp = chan->data; if ((max_key_size > SMP_MAX_ENC_KEY_SIZE) || (max_key_size < SMP_MIN_ENC_KEY_SIZE)) @@ -418,7 +405,8 @@ static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth, u8 local_io, u8 remote_io) { struct hci_conn *hcon = conn->hcon; - struct smp_chan *smp = conn->smp_chan; + struct l2cap_chan *chan = conn->smp; + struct smp_chan *smp = chan->data; u8 method; u32 passkey = 0; int ret = 0; @@ -589,6 +577,7 @@ static u8 smp_random(struct smp_chan *smp) static struct smp_chan *smp_chan_create(struct l2cap_conn *conn) { + struct l2cap_chan *chan = conn->smp; struct smp_chan *smp; smp = kzalloc(sizeof(*smp), GFP_ATOMIC); @@ -606,7 +595,7 @@ static struct smp_chan *smp_chan_create(struct l2cap_conn *conn) } smp->conn = conn; - conn->smp_chan = smp; + chan->data = smp; hci_conn_hold(conn->hcon); @@ -615,7 +604,8 @@ static struct smp_chan *smp_chan_create(struct l2cap_conn *conn) void smp_chan_destroy(struct l2cap_conn *conn) { - struct smp_chan *smp = conn->smp_chan; + struct l2cap_chan *chan = conn->smp; + struct smp_chan *smp = chan->data; bool complete; BUG_ON(!smp); @@ -646,14 +636,15 @@ void smp_chan_destroy(struct l2cap_conn *conn) } } + chan->data = NULL; kfree(smp); - conn->smp_chan = NULL; hci_conn_drop(conn->hcon); } int smp_user_confirm_reply(struct hci_conn *hcon, u16 mgmt_op, __le32 passkey) { struct l2cap_conn *conn = hcon->l2cap_data; + struct l2cap_chan *chan; struct smp_chan *smp; u32 value; @@ -662,7 +653,11 @@ int smp_user_confirm_reply(struct hci_conn *hcon, u16 mgmt_op, __le32 passkey) if (!conn || !test_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) return -ENOTCONN; - smp = conn->smp_chan; + chan = conn->smp; + if (!chan) + return -ENOTCONN; + + smp = chan->data; switch (mgmt_op) { case MGMT_OP_USER_PASSKEY_REPLY: @@ -709,10 +704,12 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) if (conn->hcon->role != HCI_ROLE_SLAVE) return SMP_CMD_NOTSUPP; - if (!test_and_set_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags)) + if (!test_and_set_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags)) { smp = smp_chan_create(conn); - else - smp = conn->smp_chan; + } else { + struct l2cap_chan *chan = conn->smp; + smp = chan->data; + } if (!smp) return SMP_UNSPECIFIED; @@ -766,7 +763,8 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb) { struct smp_cmd_pairing *req, *rsp = (void *) skb->data; - struct smp_chan *smp = conn->smp_chan; + struct l2cap_chan *chan = conn->smp; + struct smp_chan *smp = chan->data; u8 key_size, auth = SMP_AUTH_NONE; int ret; @@ -827,7 +825,8 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb) static u8 smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb) { - struct smp_chan *smp = conn->smp_chan; + struct l2cap_chan *chan = conn->smp; + struct smp_chan *smp = chan->data; BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave"); @@ -850,7 +849,8 @@ static u8 smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb) static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb) { - struct smp_chan *smp = conn->smp_chan; + struct l2cap_chan *chan = conn->smp; + struct smp_chan *smp = chan->data; BT_DBG("conn %p", conn); @@ -1023,7 +1023,8 @@ int smp_conn_security(struct hci_conn *hcon, __u8 sec_level) static int smp_cmd_encrypt_info(struct l2cap_conn *conn, struct sk_buff *skb) { struct smp_cmd_encrypt_info *rp = (void *) skb->data; - struct smp_chan *smp = conn->smp_chan; + struct l2cap_chan *chan = conn->smp; + struct smp_chan *smp = chan->data; BT_DBG("conn %p", conn); @@ -1044,7 +1045,8 @@ static int smp_cmd_encrypt_info(struct l2cap_conn *conn, struct sk_buff *skb) static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb) { struct smp_cmd_master_ident *rp = (void *) skb->data; - struct smp_chan *smp = conn->smp_chan; + struct l2cap_chan *chan = conn->smp; + struct smp_chan *smp = chan->data; struct hci_dev *hdev = conn->hcon->hdev; struct hci_conn *hcon = conn->hcon; struct smp_ltk *ltk; @@ -1080,7 +1082,8 @@ static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb) static int smp_cmd_ident_info(struct l2cap_conn *conn, struct sk_buff *skb) { struct smp_cmd_ident_info *info = (void *) skb->data; - struct smp_chan *smp = conn->smp_chan; + struct l2cap_chan *chan = conn->smp; + struct smp_chan *smp = chan->data; BT_DBG(""); @@ -1102,7 +1105,8 @@ static int smp_cmd_ident_addr_info(struct l2cap_conn *conn, struct sk_buff *skb) { struct smp_cmd_ident_addr_info *info = (void *) skb->data; - struct smp_chan *smp = conn->smp_chan; + struct l2cap_chan *chan = conn->smp; + struct smp_chan *smp = chan->data; struct hci_conn *hcon = conn->hcon; bdaddr_t rpa; @@ -1156,7 +1160,8 @@ distribute: static int smp_cmd_sign_info(struct l2cap_conn *conn, struct sk_buff *skb) { struct smp_cmd_sign_info *rp = (void *) skb->data; - struct smp_chan *smp = conn->smp_chan; + struct l2cap_chan *chan = conn->smp; + struct smp_chan *smp = chan->data; struct hci_dev *hdev = conn->hcon->hdev; struct smp_csrk *csrk; @@ -1187,8 +1192,9 @@ static int smp_cmd_sign_info(struct l2cap_conn *conn, struct sk_buff *skb) return 0; } -int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb) +static int smp_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb) { + struct l2cap_conn *conn = chan->conn; struct hci_conn *hcon = conn->hcon; __u8 code, reason; int err = 0; @@ -1290,7 +1296,8 @@ done: static void smp_notify_keys(struct l2cap_conn *conn) { - struct smp_chan *smp = conn->smp_chan; + struct l2cap_chan *chan = conn->smp; + struct smp_chan *smp = chan->data; struct hci_conn *hcon = conn->hcon; struct hci_dev *hdev = hcon->hdev; struct smp_cmd_pairing *req = (void *) &smp->preq[1]; @@ -1357,7 +1364,8 @@ static void smp_notify_keys(struct l2cap_conn *conn) int smp_distribute_keys(struct l2cap_conn *conn) { struct smp_cmd_pairing *req, *rsp; - struct smp_chan *smp = conn->smp_chan; + struct l2cap_chan *chan = conn->smp; + struct smp_chan *smp = chan->data; struct hci_conn *hcon = conn->hcon; struct hci_dev *hdev = hcon->hdev; __u8 *keydist; @@ -1475,6 +1483,11 @@ static void smp_teardown_cb(struct l2cap_chan *chan, int err) BT_DBG("chan %p", chan); + if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags)) { + cancel_delayed_work_sync(&conn->security_timer); + smp_chan_destroy(conn); + } + conn->smp = NULL; l2cap_chan_put(chan); } @@ -1508,11 +1521,11 @@ static struct sk_buff *smp_alloc_skb_cb(struct l2cap_chan *chan, static const struct l2cap_ops smp_chan_ops = { .name = "Security Manager", .ready = smp_ready_cb, + .recv = smp_recv_cb, .alloc_skb = smp_alloc_skb_cb, .teardown = smp_teardown_cb, .new_connection = l2cap_chan_no_new_connection, - .recv = l2cap_chan_no_recv, .state_change = l2cap_chan_no_state_change, .close = l2cap_chan_no_close, .defer = l2cap_chan_no_defer, @@ -1587,10 +1600,7 @@ int smp_register(struct hci_dev *hdev) chan->data = tfm_aes; - /* FIXME: Using reserved 0x1f value for now - to be changed to - * L2CAP_CID_SMP once all functionality is in place. - */ - l2cap_add_scid(chan, 0x1f); + l2cap_add_scid(chan, L2CAP_CID_SMP); l2cap_chan_set_defaults(chan); diff --git a/net/bluetooth/smp.h b/net/bluetooth/smp.h index d3f6bd617940..161ace3c3234 100644 --- a/net/bluetooth/smp.h +++ b/net/bluetooth/smp.h @@ -126,7 +126,6 @@ enum { /* SMP Commands */ bool smp_sufficient_security(struct hci_conn *hcon, u8 sec_level); int smp_conn_security(struct hci_conn *hcon, __u8 sec_level); -int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb); int smp_distribute_keys(struct l2cap_conn *conn); int smp_user_confirm_reply(struct hci_conn *conn, u16 mgmt_op, __le32 passkey); From 4807b51895dce8aa650ebebc51fa4a795ed6b8b8 Mon Sep 17 00:00:00 2001 From: Loic Poulain Date: Fri, 8 Aug 2014 19:07:16 +0200 Subject: [PATCH 043/221] Bluetooth: Fix HCI H5 corrupted ack value In this expression: seq = (seq - 1) % 8 seq (u8) is implicitly converted to an int in the arithmetic operation. So if seq value is 0, operation is ((0 - 1) % 8) => (-1 % 8) => -1. The new seq value is 0xff which is an invalid ACK value, we expect 0x07. It leads to frequent dropped ACK and retransmission. Fix this by using '&' binary operator instead of '%'. Signed-off-by: Loic Poulain Signed-off-by: Marcel Holtmann Cc: stable@vger.kernel.org --- drivers/bluetooth/hci_h5.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/bluetooth/hci_h5.c b/drivers/bluetooth/hci_h5.c index caacb422995d..a22838669b4e 100644 --- a/drivers/bluetooth/hci_h5.c +++ b/drivers/bluetooth/hci_h5.c @@ -237,7 +237,7 @@ static void h5_pkt_cull(struct h5 *h5) break; to_remove--; - seq = (seq - 1) % 8; + seq = (seq - 1) & 0x07; } if (seq != h5->rx_ack) From ebef9c1236170fb3ba4dc05ccb41f6d842eb1c12 Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Fri, 8 Aug 2014 17:32:45 +0530 Subject: [PATCH 044/221] MAINTAINERS: update maintainers info adds the mailing list address for bluetooth 6loWPAN and IEEE-802.15.4 subsystems. Also adds web page info. Signed-off-by: Varka Bhadram Signed-off-by: Marcel Holtmann --- MAINTAINERS | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 2f85f55c8fb8..5cc0b81e4a33 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -152,8 +152,8 @@ F: drivers/scsi/53c700* 6LOWPAN GENERIC (BTLE/IEEE 802.15.4) M: Alexander Aring -L: linux-zigbee-devel@lists.sourceforge.net (moderated for non-subscribers) L: linux-bluetooth@vger.kernel.org +L: linux-wpan@vger.kernel.org S: Maintained F: net/6lowpan/ F: include/net/6lowpan.h @@ -4564,13 +4564,14 @@ F: drivers/idle/i7300_idle.c IEEE 802.15.4 SUBSYSTEM M: Alexander Aring -L: linux-zigbee-devel@lists.sourceforge.net (moderated for non-subscribers) -W: http://apps.sourceforge.net/trac/linux-zigbee -T: git git://git.kernel.org/pub/scm/linux/kernel/git/lowpan/lowpan.git +L: linux-wpan@vger.kernel.org +W: https://github.com/linux-wpan +T: git git://github.com/linux-wpan/linux-wpan-next.git S: Maintained F: net/ieee802154/ F: net/mac802154/ F: drivers/net/ieee802154/ +F: Documentation/networking/ieee802154.txt IGUANAWORKS USB IR TRANSCEIVER M: Sean Young From 89d2975fa06e66ea0d3665d91f799fb1ce4b8bad Mon Sep 17 00:00:00 2001 From: Vincent Zwanenburg Date: Fri, 8 Aug 2014 12:33:56 +0100 Subject: [PATCH 045/221] Add a new PID/VID 0227/0930 for AR3012. usb devices info: T: Bus=01 Lev=02 Prnt=05 Port=00 Cnt=01 Dev#= 20 Spd=12 MxCh= 0 D: Ver= 1.10 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=0930 ProdID=0227 Rev= 0.02 C:* #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=100mA A: FirstIf#= 0 IfCount= 2 Cls=e0(wlcon) Sub=01 Prot=01 I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms Signed-off-by: Vincent Zwanenburg Signed-off-by: Marcel Holtmann --- drivers/bluetooth/ath3k.c | 2 ++ drivers/bluetooth/btusb.c | 1 + 2 files changed, 3 insertions(+) diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c index a0d7355ef127..d85ced27ebd5 100644 --- a/drivers/bluetooth/ath3k.c +++ b/drivers/bluetooth/ath3k.c @@ -88,6 +88,7 @@ static const struct usb_device_id ath3k_table[] = { { USB_DEVICE(0x04CA, 0x300b) }, { USB_DEVICE(0x0930, 0x0219) }, { USB_DEVICE(0x0930, 0x0220) }, + { USB_DEVICE(0x0930, 0x0227) }, { USB_DEVICE(0x0b05, 0x17d0) }, { USB_DEVICE(0x0CF3, 0x0036) }, { USB_DEVICE(0x0CF3, 0x3004) }, @@ -138,6 +139,7 @@ static const struct usb_device_id ath3k_blist_tbl[] = { { USB_DEVICE(0x04ca, 0x300b), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0930, 0x0220), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0930, 0x0227), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0b05, 0x17d0), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0CF3, 0x0036), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 }, diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 292c38e8aa17..0527b29c3954 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -165,6 +165,7 @@ static const struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x04ca, 0x300b), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0930, 0x0220), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0930, 0x0227), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0b05, 0x17d0), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x0036), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 }, From 44f1a7ab51ebe1ca189445837e0599a5edc6efb1 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 11 Aug 2014 22:06:36 +0300 Subject: [PATCH 046/221] Bluetooth: Use L2CAP resume callback to call smp_distribute_keys There's no need to export the smp_distribute_keys() function since the resume callback is called in the same scenario. This patch makes the smp_notify_keys function private (at the same time moving it higher up in smp.c to avoid forward declarations) and adds a resume callback for SMP to call it from there instead. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 6 - net/bluetooth/smp.c | 380 +++++++++++++++++++------------------ net/bluetooth/smp.h | 1 - 3 files changed, 196 insertions(+), 191 deletions(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 40b6c06ab2c0..4de1e1827055 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -7281,12 +7281,6 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) BT_DBG("conn %p status 0x%2.2x encrypt %u", conn, status, encrypt); - if (hcon->type == LE_LINK) { - if (!status && encrypt) - smp_distribute_keys(conn); - cancel_delayed_work(&conn->security_timer); - } - mutex_lock(&conn->chan_lock); list_for_each_entry(chan, &conn->chan_l, list) { diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 744f678ac3e8..28014ad3d2d3 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -575,6 +575,189 @@ static u8 smp_random(struct smp_chan *smp) return 0; } +static void smp_notify_keys(struct l2cap_conn *conn) +{ + struct l2cap_chan *chan = conn->smp; + struct smp_chan *smp = chan->data; + struct hci_conn *hcon = conn->hcon; + struct hci_dev *hdev = hcon->hdev; + struct smp_cmd_pairing *req = (void *) &smp->preq[1]; + struct smp_cmd_pairing *rsp = (void *) &smp->prsp[1]; + bool persistent; + + if (smp->remote_irk) { + mgmt_new_irk(hdev, smp->remote_irk); + /* Now that user space can be considered to know the + * identity address track the connection based on it + * from now on. + */ + bacpy(&hcon->dst, &smp->remote_irk->bdaddr); + hcon->dst_type = smp->remote_irk->addr_type; + l2cap_conn_update_id_addr(hcon); + + /* When receiving an indentity resolving key for + * a remote device that does not use a resolvable + * private address, just remove the key so that + * it is possible to use the controller white + * list for scanning. + * + * Userspace will have been told to not store + * this key at this point. So it is safe to + * just remove it. + */ + if (!bacmp(&smp->remote_irk->rpa, BDADDR_ANY)) { + list_del(&smp->remote_irk->list); + kfree(smp->remote_irk); + smp->remote_irk = NULL; + } + } + + /* The LTKs and CSRKs should be persistent only if both sides + * had the bonding bit set in their authentication requests. + */ + persistent = !!((req->auth_req & rsp->auth_req) & SMP_AUTH_BONDING); + + if (smp->csrk) { + smp->csrk->bdaddr_type = hcon->dst_type; + bacpy(&smp->csrk->bdaddr, &hcon->dst); + mgmt_new_csrk(hdev, smp->csrk, persistent); + } + + if (smp->slave_csrk) { + smp->slave_csrk->bdaddr_type = hcon->dst_type; + bacpy(&smp->slave_csrk->bdaddr, &hcon->dst); + mgmt_new_csrk(hdev, smp->slave_csrk, persistent); + } + + if (smp->ltk) { + smp->ltk->bdaddr_type = hcon->dst_type; + bacpy(&smp->ltk->bdaddr, &hcon->dst); + mgmt_new_ltk(hdev, smp->ltk, persistent); + } + + if (smp->slave_ltk) { + smp->slave_ltk->bdaddr_type = hcon->dst_type; + bacpy(&smp->slave_ltk->bdaddr, &hcon->dst); + mgmt_new_ltk(hdev, smp->slave_ltk, persistent); + } +} + +static int smp_distribute_keys(struct l2cap_conn *conn) +{ + struct smp_cmd_pairing *req, *rsp; + struct l2cap_chan *chan = conn->smp; + struct smp_chan *smp = chan->data; + struct hci_conn *hcon = conn->hcon; + struct hci_dev *hdev = hcon->hdev; + __u8 *keydist; + + BT_DBG("conn %p", conn); + + if (!test_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) + return 0; + + rsp = (void *) &smp->prsp[1]; + + /* The responder sends its keys first */ + if (hcon->out && (smp->remote_key_dist & 0x07)) + return 0; + + req = (void *) &smp->preq[1]; + + if (hcon->out) { + keydist = &rsp->init_key_dist; + *keydist &= req->init_key_dist; + } else { + keydist = &rsp->resp_key_dist; + *keydist &= req->resp_key_dist; + } + + BT_DBG("keydist 0x%x", *keydist); + + if (*keydist & SMP_DIST_ENC_KEY) { + struct smp_cmd_encrypt_info enc; + struct smp_cmd_master_ident ident; + struct smp_ltk *ltk; + u8 authenticated; + __le16 ediv; + __le64 rand; + + get_random_bytes(enc.ltk, sizeof(enc.ltk)); + get_random_bytes(&ediv, sizeof(ediv)); + get_random_bytes(&rand, sizeof(rand)); + + smp_send_cmd(conn, SMP_CMD_ENCRYPT_INFO, sizeof(enc), &enc); + + authenticated = hcon->sec_level == BT_SECURITY_HIGH; + ltk = hci_add_ltk(hdev, &hcon->dst, hcon->dst_type, + SMP_LTK_SLAVE, authenticated, enc.ltk, + smp->enc_key_size, ediv, rand); + smp->slave_ltk = ltk; + + ident.ediv = ediv; + ident.rand = rand; + + smp_send_cmd(conn, SMP_CMD_MASTER_IDENT, sizeof(ident), &ident); + + *keydist &= ~SMP_DIST_ENC_KEY; + } + + if (*keydist & SMP_DIST_ID_KEY) { + struct smp_cmd_ident_addr_info addrinfo; + struct smp_cmd_ident_info idinfo; + + memcpy(idinfo.irk, hdev->irk, sizeof(idinfo.irk)); + + smp_send_cmd(conn, SMP_CMD_IDENT_INFO, sizeof(idinfo), &idinfo); + + /* The hci_conn contains the local identity address + * after the connection has been established. + * + * This is true even when the connection has been + * established using a resolvable random address. + */ + bacpy(&addrinfo.bdaddr, &hcon->src); + addrinfo.addr_type = hcon->src_type; + + smp_send_cmd(conn, SMP_CMD_IDENT_ADDR_INFO, sizeof(addrinfo), + &addrinfo); + + *keydist &= ~SMP_DIST_ID_KEY; + } + + if (*keydist & SMP_DIST_SIGN) { + struct smp_cmd_sign_info sign; + struct smp_csrk *csrk; + + /* Generate a new random key */ + get_random_bytes(sign.csrk, sizeof(sign.csrk)); + + csrk = kzalloc(sizeof(*csrk), GFP_KERNEL); + if (csrk) { + csrk->master = 0x00; + memcpy(csrk->val, sign.csrk, sizeof(csrk->val)); + } + smp->slave_csrk = csrk; + + smp_send_cmd(conn, SMP_CMD_SIGN_INFO, sizeof(sign), &sign); + + *keydist &= ~SMP_DIST_SIGN; + } + + /* If there are still keys to be received wait for them */ + if ((smp->remote_key_dist & 0x07)) + return 0; + + clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags); + cancel_delayed_work_sync(&conn->security_timer); + set_bit(SMP_FLAG_COMPLETE, &smp->flags); + smp_notify_keys(conn); + + smp_chan_destroy(conn); + + return 0; +} + static struct smp_chan *smp_chan_create(struct l2cap_conn *conn) { struct l2cap_chan *chan = conn->smp; @@ -1294,189 +1477,6 @@ done: return err; } -static void smp_notify_keys(struct l2cap_conn *conn) -{ - struct l2cap_chan *chan = conn->smp; - struct smp_chan *smp = chan->data; - struct hci_conn *hcon = conn->hcon; - struct hci_dev *hdev = hcon->hdev; - struct smp_cmd_pairing *req = (void *) &smp->preq[1]; - struct smp_cmd_pairing *rsp = (void *) &smp->prsp[1]; - bool persistent; - - if (smp->remote_irk) { - mgmt_new_irk(hdev, smp->remote_irk); - /* Now that user space can be considered to know the - * identity address track the connection based on it - * from now on. - */ - bacpy(&hcon->dst, &smp->remote_irk->bdaddr); - hcon->dst_type = smp->remote_irk->addr_type; - l2cap_conn_update_id_addr(hcon); - - /* When receiving an indentity resolving key for - * a remote device that does not use a resolvable - * private address, just remove the key so that - * it is possible to use the controller white - * list for scanning. - * - * Userspace will have been told to not store - * this key at this point. So it is safe to - * just remove it. - */ - if (!bacmp(&smp->remote_irk->rpa, BDADDR_ANY)) { - list_del(&smp->remote_irk->list); - kfree(smp->remote_irk); - smp->remote_irk = NULL; - } - } - - /* The LTKs and CSRKs should be persistent only if both sides - * had the bonding bit set in their authentication requests. - */ - persistent = !!((req->auth_req & rsp->auth_req) & SMP_AUTH_BONDING); - - if (smp->csrk) { - smp->csrk->bdaddr_type = hcon->dst_type; - bacpy(&smp->csrk->bdaddr, &hcon->dst); - mgmt_new_csrk(hdev, smp->csrk, persistent); - } - - if (smp->slave_csrk) { - smp->slave_csrk->bdaddr_type = hcon->dst_type; - bacpy(&smp->slave_csrk->bdaddr, &hcon->dst); - mgmt_new_csrk(hdev, smp->slave_csrk, persistent); - } - - if (smp->ltk) { - smp->ltk->bdaddr_type = hcon->dst_type; - bacpy(&smp->ltk->bdaddr, &hcon->dst); - mgmt_new_ltk(hdev, smp->ltk, persistent); - } - - if (smp->slave_ltk) { - smp->slave_ltk->bdaddr_type = hcon->dst_type; - bacpy(&smp->slave_ltk->bdaddr, &hcon->dst); - mgmt_new_ltk(hdev, smp->slave_ltk, persistent); - } -} - -int smp_distribute_keys(struct l2cap_conn *conn) -{ - struct smp_cmd_pairing *req, *rsp; - struct l2cap_chan *chan = conn->smp; - struct smp_chan *smp = chan->data; - struct hci_conn *hcon = conn->hcon; - struct hci_dev *hdev = hcon->hdev; - __u8 *keydist; - - BT_DBG("conn %p", conn); - - if (!test_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) - return 0; - - rsp = (void *) &smp->prsp[1]; - - /* The responder sends its keys first */ - if (hcon->out && (smp->remote_key_dist & 0x07)) - return 0; - - req = (void *) &smp->preq[1]; - - if (hcon->out) { - keydist = &rsp->init_key_dist; - *keydist &= req->init_key_dist; - } else { - keydist = &rsp->resp_key_dist; - *keydist &= req->resp_key_dist; - } - - BT_DBG("keydist 0x%x", *keydist); - - if (*keydist & SMP_DIST_ENC_KEY) { - struct smp_cmd_encrypt_info enc; - struct smp_cmd_master_ident ident; - struct smp_ltk *ltk; - u8 authenticated; - __le16 ediv; - __le64 rand; - - get_random_bytes(enc.ltk, sizeof(enc.ltk)); - get_random_bytes(&ediv, sizeof(ediv)); - get_random_bytes(&rand, sizeof(rand)); - - smp_send_cmd(conn, SMP_CMD_ENCRYPT_INFO, sizeof(enc), &enc); - - authenticated = hcon->sec_level == BT_SECURITY_HIGH; - ltk = hci_add_ltk(hdev, &hcon->dst, hcon->dst_type, - SMP_LTK_SLAVE, authenticated, enc.ltk, - smp->enc_key_size, ediv, rand); - smp->slave_ltk = ltk; - - ident.ediv = ediv; - ident.rand = rand; - - smp_send_cmd(conn, SMP_CMD_MASTER_IDENT, sizeof(ident), &ident); - - *keydist &= ~SMP_DIST_ENC_KEY; - } - - if (*keydist & SMP_DIST_ID_KEY) { - struct smp_cmd_ident_addr_info addrinfo; - struct smp_cmd_ident_info idinfo; - - memcpy(idinfo.irk, hdev->irk, sizeof(idinfo.irk)); - - smp_send_cmd(conn, SMP_CMD_IDENT_INFO, sizeof(idinfo), &idinfo); - - /* The hci_conn contains the local identity address - * after the connection has been established. - * - * This is true even when the connection has been - * established using a resolvable random address. - */ - bacpy(&addrinfo.bdaddr, &hcon->src); - addrinfo.addr_type = hcon->src_type; - - smp_send_cmd(conn, SMP_CMD_IDENT_ADDR_INFO, sizeof(addrinfo), - &addrinfo); - - *keydist &= ~SMP_DIST_ID_KEY; - } - - if (*keydist & SMP_DIST_SIGN) { - struct smp_cmd_sign_info sign; - struct smp_csrk *csrk; - - /* Generate a new random key */ - get_random_bytes(sign.csrk, sizeof(sign.csrk)); - - csrk = kzalloc(sizeof(*csrk), GFP_KERNEL); - if (csrk) { - csrk->master = 0x00; - memcpy(csrk->val, sign.csrk, sizeof(csrk->val)); - } - smp->slave_csrk = csrk; - - smp_send_cmd(conn, SMP_CMD_SIGN_INFO, sizeof(sign), &sign); - - *keydist &= ~SMP_DIST_SIGN; - } - - /* If there are still keys to be received wait for them */ - if ((smp->remote_key_dist & 0x07)) - return 0; - - clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags); - cancel_delayed_work_sync(&conn->security_timer); - set_bit(SMP_FLAG_COMPLETE, &smp->flags); - smp_notify_keys(conn); - - smp_chan_destroy(conn); - - return 0; -} - static void smp_teardown_cb(struct l2cap_chan *chan, int err) { struct l2cap_conn *conn = chan->conn; @@ -1492,6 +1492,18 @@ static void smp_teardown_cb(struct l2cap_chan *chan, int err) l2cap_chan_put(chan); } +static void smp_resume_cb(struct l2cap_chan *chan) +{ + struct l2cap_conn *conn = chan->conn; + struct hci_conn *hcon = conn->hcon; + + BT_DBG("chan %p", chan); + + if (test_bit(HCI_CONN_ENCRYPT, &hcon->flags)) + smp_distribute_keys(conn); + cancel_delayed_work(&conn->security_timer); +} + static void smp_ready_cb(struct l2cap_chan *chan) { struct l2cap_conn *conn = chan->conn; @@ -1524,13 +1536,13 @@ static const struct l2cap_ops smp_chan_ops = { .recv = smp_recv_cb, .alloc_skb = smp_alloc_skb_cb, .teardown = smp_teardown_cb, + .resume = smp_resume_cb, .new_connection = l2cap_chan_no_new_connection, .state_change = l2cap_chan_no_state_change, .close = l2cap_chan_no_close, .defer = l2cap_chan_no_defer, .suspend = l2cap_chan_no_suspend, - .resume = l2cap_chan_no_resume, .set_shutdown = l2cap_chan_no_set_shutdown, .get_sndtimeo = l2cap_chan_no_get_sndtimeo, .memcpy_fromiovec = l2cap_chan_no_memcpy_fromiovec, diff --git a/net/bluetooth/smp.h b/net/bluetooth/smp.h index 161ace3c3234..59a594278a85 100644 --- a/net/bluetooth/smp.h +++ b/net/bluetooth/smp.h @@ -126,7 +126,6 @@ enum { /* SMP Commands */ bool smp_sufficient_security(struct hci_conn *hcon, u8 sec_level); int smp_conn_security(struct hci_conn *hcon, __u8 sec_level); -int smp_distribute_keys(struct l2cap_conn *conn); int smp_user_confirm_reply(struct hci_conn *conn, u16 mgmt_op, __le32 passkey); void smp_chan_destroy(struct l2cap_conn *conn); From dec5b49235e2526d7aacf5b93ea48f5e30c2f7c3 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 11 Aug 2014 22:06:37 +0300 Subject: [PATCH 047/221] Bluetooth: Add public l2cap_conn_shutdown() API to request disconnection Since we no-longer do special handling of SMP within l2cap_core.c we don't have any code for calling l2cap_conn_del() when smp.c doesn't like the data it gets. At the same time we cannot simply export l2cap_conn_del() since it will try to lock the channels it calls into whereas we already hold the lock in the smp.c l2cap_chan callbacks (i.e. it'd lead to a deadlock). This patch adds a new l2cap_conn_shutdown() API which is very similar to l2cap_conn_del() except that it defers the call to l2cap_conn_del() through a workqueue, thereby making it safe to use it from an L2CAP channel callback. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/l2cap.h | 4 ++++ net/bluetooth/l2cap_core.c | 25 +++++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index bda6252e3722..40f34866b6da 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -625,6 +625,9 @@ struct l2cap_conn { struct delayed_work info_timer; + int disconn_err; + struct work_struct disconn_work; + struct sk_buff *rx_skb; __u32 rx_len; __u8 tx_ident; @@ -944,6 +947,7 @@ void l2cap_logical_cfm(struct l2cap_chan *chan, struct hci_chan *hchan, u8 status); void __l2cap_physical_cfm(struct l2cap_chan *chan, int result); +void l2cap_conn_shutdown(struct l2cap_conn *conn, int err); void l2cap_conn_get(struct l2cap_conn *conn); void l2cap_conn_put(struct l2cap_conn *conn); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 4de1e1827055..404998efa7e2 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1627,6 +1627,9 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err) if (work_pending(&conn->pending_rx_work)) cancel_work_sync(&conn->pending_rx_work); + if (work_pending(&conn->disconn_work)) + cancel_work_sync(&conn->disconn_work); + l2cap_unregister_all_users(conn); mutex_lock(&conn->chan_lock); @@ -1669,6 +1672,26 @@ static void security_timeout(struct work_struct *work) } } +static void disconn_work(struct work_struct *work) +{ + struct l2cap_conn *conn = container_of(work, struct l2cap_conn, + disconn_work); + + BT_DBG("conn %p", conn); + + l2cap_conn_del(conn->hcon, conn->disconn_err); +} + +void l2cap_conn_shutdown(struct l2cap_conn *conn, int err) +{ + struct hci_dev *hdev = conn->hcon->hdev; + + BT_DBG("conn %p err %d", conn, err); + + conn->disconn_err = err; + queue_work(hdev->workqueue, &conn->disconn_work); +} + static void l2cap_conn_free(struct kref *ref) { struct l2cap_conn *conn = container_of(ref, struct l2cap_conn, ref); @@ -6930,6 +6953,8 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon) else INIT_DELAYED_WORK(&conn->info_timer, l2cap_info_timeout); + INIT_WORK(&conn->disconn_work, disconn_work); + skb_queue_head_init(&conn->pending_rx); INIT_WORK(&conn->pending_rx_work, process_pending_rx); From 4befb867b9de8adc56c683f4cf6c9e6c035e94e3 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 11 Aug 2014 22:06:38 +0300 Subject: [PATCH 048/221] Bluetooth: Call l2cap_conn_shutdown() when SMP recv callback fails To restore pre-l2cap_chan functionality we should be trying to disconnect the connection when receviving garbage SMP data (i.e. when the SMP command handler fails). This patch renames the command handler back to smp_sig_channel() and adds a smp_recv_cb() wrapper function for calling it. If smp_sig_channel() fails the code calls l2cap_conn_shutdown(). Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 28014ad3d2d3..7a295d7edc44 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -1375,7 +1375,7 @@ static int smp_cmd_sign_info(struct l2cap_conn *conn, struct sk_buff *skb) return 0; } -static int smp_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb) +static int smp_sig_channel(struct l2cap_chan *chan, struct sk_buff *skb) { struct l2cap_conn *conn = chan->conn; struct hci_conn *hcon = conn->hcon; @@ -1514,6 +1514,24 @@ static void smp_ready_cb(struct l2cap_chan *chan) l2cap_chan_hold(chan); } +static int smp_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb) +{ + int err; + + BT_DBG("chan %p", chan); + + err = smp_sig_channel(chan, skb); + if (err) { + struct l2cap_conn *conn = chan->conn; + + cancel_delayed_work_sync(&conn->security_timer); + + l2cap_conn_shutdown(chan->conn, -err); + } + + return err; +} + static struct sk_buff *smp_alloc_skb_cb(struct l2cap_chan *chan, unsigned long hdr_len, unsigned long len, int nb) From 8ae9b9845b3252216cf5d2e033e5cca41bae48ef Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 11 Aug 2014 22:06:39 +0300 Subject: [PATCH 049/221] Bluetooth: Fix double free of SMP data skb In the case that the SMP recv callback returns error the calling code in l2cap_core.c expects that it still owns the skb and will try to free it. The SMP code should therefore not try to free the skb if it return an error. This patch fixes such behavior in the SMP command handler function. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 7a295d7edc44..5103dc739a17 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -1387,10 +1387,8 @@ static int smp_sig_channel(struct l2cap_chan *chan, struct sk_buff *skb) return 0; } - if (skb->len < 1) { - kfree_skb(skb); + if (skb->len < 1) return -EILSEQ; - } if (!test_bit(HCI_LE_ENABLED, &hcon->hdev->dev_flags)) { err = -EOPNOTSUPP; @@ -1410,8 +1408,9 @@ static int smp_sig_channel(struct l2cap_chan *chan, struct sk_buff *skb) if (code != SMP_CMD_PAIRING_REQ && code != SMP_CMD_SECURITY_REQ && !test_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) { BT_ERR("Unexpected SMP command 0x%02x. Disconnecting.", code); - kfree_skb(skb); - return -EOPNOTSUPP; + reason = SMP_CMD_NOTSUPP; + err = -EOPNOTSUPP; + goto done; } switch (code) { @@ -1472,8 +1471,8 @@ static int smp_sig_channel(struct l2cap_chan *chan, struct sk_buff *skb) done: if (reason) smp_failure(conn, reason); - - kfree_skb(skb); + if (!err) + kfree_skb(skb); return err; } From b68fda6848ebef3499905500971d40b84faa8319 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 11 Aug 2014 22:06:40 +0300 Subject: [PATCH 050/221] Bluetooth: Add SMP-internal timeout callback This patch adds an SMP-internal timeout callback to remove the depenency on (the soon to be removed) l2cap_conn->security_timer. The behavior is the same as with l2cap_conn->security_timer except that the new l2cap_conn_shutdown() public function is used instead of the L2CAP core internal l2cap_conn_del(). Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 52 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 43 insertions(+), 9 deletions(-) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 5103dc739a17..7ab5f52955cb 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -44,7 +44,9 @@ enum { }; struct smp_chan { - struct l2cap_conn *conn; + struct l2cap_conn *conn; + struct delayed_work security_timer; + u8 preq[7]; /* SMP Pairing Request */ u8 prsp[7]; /* SMP Pairing Response */ u8 prnd[16]; /* SMP Pairing Random (local) */ @@ -251,6 +253,7 @@ static int smp_s1(struct smp_chan *smp, u8 k[16], u8 r1[16], u8 r2[16], static void smp_send_cmd(struct l2cap_conn *conn, u8 code, u16 len, void *data) { struct l2cap_chan *chan = conn->smp; + struct smp_chan *smp; struct kvec iv[2]; struct msghdr msg; @@ -272,8 +275,14 @@ static void smp_send_cmd(struct l2cap_conn *conn, u8 code, u16 len, void *data) l2cap_chan_send(chan, &msg, 1 + len); - cancel_delayed_work_sync(&conn->security_timer); - schedule_delayed_work(&conn->security_timer, SMP_TIMEOUT); + if (!chan->data) + return; + + smp = chan->data; + + cancel_delayed_work_sync(&smp->security_timer); + if (test_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags)) + schedule_delayed_work(&smp->security_timer, SMP_TIMEOUT); } static __u8 authreq_to_seclevel(__u8 authreq) @@ -359,6 +368,8 @@ static u8 check_enc_key_size(struct l2cap_conn *conn, __u8 max_key_size) static void smp_failure(struct l2cap_conn *conn, u8 reason) { struct hci_conn *hcon = conn->hcon; + struct l2cap_chan *chan = conn->smp; + struct smp_chan *smp; if (reason) smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason), @@ -368,7 +379,12 @@ static void smp_failure(struct l2cap_conn *conn, u8 reason) mgmt_auth_failed(hcon->hdev, &hcon->dst, hcon->type, hcon->dst_type, HCI_ERROR_AUTH_FAILURE); - cancel_delayed_work_sync(&conn->security_timer); + if (!chan->data) + return; + + smp = chan->data; + + cancel_delayed_work_sync(&smp->security_timer); if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) smp_chan_destroy(conn); @@ -749,7 +765,7 @@ static int smp_distribute_keys(struct l2cap_conn *conn) return 0; clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags); - cancel_delayed_work_sync(&conn->security_timer); + cancel_delayed_work_sync(&smp->security_timer); set_bit(SMP_FLAG_COMPLETE, &smp->flags); smp_notify_keys(conn); @@ -758,6 +774,17 @@ static int smp_distribute_keys(struct l2cap_conn *conn) return 0; } +static void smp_timeout(struct work_struct *work) +{ + struct smp_chan *smp = container_of(work, struct smp_chan, + security_timer.work); + struct l2cap_conn *conn = smp->conn; + + BT_DBG("conn %p", conn); + + l2cap_conn_shutdown(conn, ETIMEDOUT); +} + static struct smp_chan *smp_chan_create(struct l2cap_conn *conn) { struct l2cap_chan *chan = conn->smp; @@ -780,6 +807,8 @@ static struct smp_chan *smp_chan_create(struct l2cap_conn *conn) smp->conn = conn; chan->data = smp; + INIT_DELAYED_WORK(&smp->security_timer, smp_timeout); + hci_conn_hold(conn->hcon); return smp; @@ -1479,11 +1508,12 @@ done: static void smp_teardown_cb(struct l2cap_chan *chan, int err) { struct l2cap_conn *conn = chan->conn; + struct smp_chan *smp = chan->data; BT_DBG("chan %p", chan); if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags)) { - cancel_delayed_work_sync(&conn->security_timer); + cancel_delayed_work_sync(&smp->security_timer); smp_chan_destroy(conn); } @@ -1493,6 +1523,7 @@ static void smp_teardown_cb(struct l2cap_chan *chan, int err) static void smp_resume_cb(struct l2cap_chan *chan) { + struct smp_chan *smp = chan->data; struct l2cap_conn *conn = chan->conn; struct hci_conn *hcon = conn->hcon; @@ -1500,7 +1531,9 @@ static void smp_resume_cb(struct l2cap_chan *chan) if (test_bit(HCI_CONN_ENCRYPT, &hcon->flags)) smp_distribute_keys(conn); - cancel_delayed_work(&conn->security_timer); + + if (smp) + cancel_delayed_work(&smp->security_timer); } static void smp_ready_cb(struct l2cap_chan *chan) @@ -1521,9 +1554,10 @@ static int smp_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb) err = smp_sig_channel(chan, skb); if (err) { - struct l2cap_conn *conn = chan->conn; + struct smp_chan *smp = chan->data; - cancel_delayed_work_sync(&conn->security_timer); + if (smp) + cancel_delayed_work_sync(&smp->security_timer); l2cap_conn_shutdown(chan->conn, -err); } From 276d807317dead63ef2f13aa46e3c17d57ba0713 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 11 Aug 2014 22:06:41 +0300 Subject: [PATCH 051/221] Bluetooth: Remove unused l2cap_conn->security_timer Now that there are no-longer any users for l2cap_conn->security_timer we can go ahead and simply remove it. The patch makes initialization of the conn->info_timer unconditional since it's better not to leave any l2cap_conn data structures uninitialized no matter what the underlying transport. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/l2cap.h | 1 - net/bluetooth/l2cap_core.c | 18 +----------------- 2 files changed, 1 insertion(+), 18 deletions(-) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 40f34866b6da..cedda399f9c0 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -638,7 +638,6 @@ struct l2cap_conn { __u8 disc_reason; - struct delayed_work security_timer; struct l2cap_chan *smp; struct list_head chan_l; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 404998efa7e2..0cd7ed99558b 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1659,19 +1659,6 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err) l2cap_conn_put(conn); } -static void security_timeout(struct work_struct *work) -{ - struct l2cap_conn *conn = container_of(work, struct l2cap_conn, - security_timer.work); - - BT_DBG("conn %p", conn); - - if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags)) { - smp_chan_destroy(conn); - l2cap_conn_del(conn->hcon, ETIMEDOUT); - } -} - static void disconn_work(struct work_struct *work) { struct l2cap_conn *conn = container_of(work, struct l2cap_conn, @@ -6948,10 +6935,7 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon) INIT_LIST_HEAD(&conn->chan_l); INIT_LIST_HEAD(&conn->users); - if (hcon->type == LE_LINK) - INIT_DELAYED_WORK(&conn->security_timer, security_timeout); - else - INIT_DELAYED_WORK(&conn->info_timer, l2cap_info_timeout); + INIT_DELAYED_WORK(&conn->info_timer, l2cap_info_timeout); INIT_WORK(&conn->disconn_work, disconn_work); From 109ec2309eb996fbe03302fbd40dec9014c6f849 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 11 Aug 2014 22:06:42 +0300 Subject: [PATCH 052/221] Bluetooth: Move canceling security_timer into smp_chan_destroy() All places needing to cancel the security timer also call smp_chan_destroy() in the same go. To eliminate the need to do these two calls in multiple places simply move the timer cancellation into smp_chan_destroy(). Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 7ab5f52955cb..cdae40869447 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -384,8 +384,6 @@ static void smp_failure(struct l2cap_conn *conn, u8 reason) smp = chan->data; - cancel_delayed_work_sync(&smp->security_timer); - if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) smp_chan_destroy(conn); } @@ -765,7 +763,6 @@ static int smp_distribute_keys(struct l2cap_conn *conn) return 0; clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags); - cancel_delayed_work_sync(&smp->security_timer); set_bit(SMP_FLAG_COMPLETE, &smp->flags); smp_notify_keys(conn); @@ -822,6 +819,11 @@ void smp_chan_destroy(struct l2cap_conn *conn) BUG_ON(!smp); + cancel_delayed_work_sync(&smp->security_timer); + /* In case the timeout freed the SMP context */ + if (!chan->data) + return; + complete = test_bit(SMP_FLAG_COMPLETE, &smp->flags); mgmt_smp_complete(conn->hcon, complete); @@ -1512,10 +1514,8 @@ static void smp_teardown_cb(struct l2cap_chan *chan, int err) BT_DBG("chan %p", chan); - if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags)) { - cancel_delayed_work_sync(&smp->security_timer); + if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags)) smp_chan_destroy(conn); - } conn->smp = NULL; l2cap_chan_put(chan); From 86d1407cb9cd3cb866eae24a2aedb8006160db69 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 11 Aug 2014 22:06:43 +0300 Subject: [PATCH 053/221] Bluetooth: Always call smp_distribute_keys() from a workqueue The smp_distribute_keys() function calls smp_notify_keys() which in turn calls l2cap_conn_update_id_addr(). The l2cap_conn_update_id_addr() function will iterate through all L2CAP channels for the respective connection: lock the channel, update the address information and unlock the channel. Since SMP is now using l2cap_chan callbacks each callback is called with the channel lock held. Therefore, calling l2cap_conn_update_id_addr() would cause a deadlock calling l2cap_chan_lock() on the SMP channel. This patch moves calling smp_distribute_keys() through a workqueue so that it is never called from an L2CAP channel callback. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 42 ++++++++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index cdae40869447..312ea5ec2d7d 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -46,6 +46,7 @@ enum { struct smp_chan { struct l2cap_conn *conn; struct delayed_work security_timer; + struct work_struct distribute_work; u8 preq[7]; /* SMP Pairing Request */ u8 prsp[7]; /* SMP Pairing Response */ @@ -656,11 +657,12 @@ static void smp_notify_keys(struct l2cap_conn *conn) } } -static int smp_distribute_keys(struct l2cap_conn *conn) +static void smp_distribute_keys(struct work_struct *work) { + struct smp_chan *smp = container_of(work, struct smp_chan, + distribute_work); struct smp_cmd_pairing *req, *rsp; - struct l2cap_chan *chan = conn->smp; - struct smp_chan *smp = chan->data; + struct l2cap_conn *conn = smp->conn; struct hci_conn *hcon = conn->hcon; struct hci_dev *hdev = hcon->hdev; __u8 *keydist; @@ -668,13 +670,13 @@ static int smp_distribute_keys(struct l2cap_conn *conn) BT_DBG("conn %p", conn); if (!test_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) - return 0; + return; rsp = (void *) &smp->prsp[1]; /* The responder sends its keys first */ if (hcon->out && (smp->remote_key_dist & 0x07)) - return 0; + return; req = (void *) &smp->preq[1]; @@ -760,15 +762,13 @@ static int smp_distribute_keys(struct l2cap_conn *conn) /* If there are still keys to be received wait for them */ if ((smp->remote_key_dist & 0x07)) - return 0; + return; clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags); set_bit(SMP_FLAG_COMPLETE, &smp->flags); smp_notify_keys(conn); smp_chan_destroy(conn); - - return 0; } static void smp_timeout(struct work_struct *work) @@ -804,6 +804,7 @@ static struct smp_chan *smp_chan_create(struct l2cap_conn *conn) smp->conn = conn; chan->data = smp; + INIT_WORK(&smp->distribute_work, smp_distribute_keys); INIT_DELAYED_WORK(&smp->security_timer, smp_timeout); hci_conn_hold(conn->hcon); @@ -824,6 +825,12 @@ void smp_chan_destroy(struct l2cap_conn *conn) if (!chan->data) return; + if (work_pending(&smp->distribute_work)) { + cancel_work_sync(&smp->distribute_work); + if (!chan->data) + return; + } + complete = test_bit(SMP_FLAG_COMPLETE, &smp->flags); mgmt_smp_complete(conn->hcon, complete); @@ -1287,7 +1294,7 @@ static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb) rp->ediv, rp->rand); smp->ltk = ltk; if (!(smp->remote_key_dist & SMP_DIST_ID_KEY)) - smp_distribute_keys(conn); + queue_work(hdev->workqueue, &smp->distribute_work); hci_dev_unlock(hdev); return 0; @@ -1322,6 +1329,7 @@ static int smp_cmd_ident_addr_info(struct l2cap_conn *conn, struct l2cap_chan *chan = conn->smp; struct smp_chan *smp = chan->data; struct hci_conn *hcon = conn->hcon; + struct hci_dev *hdev = hcon->hdev; bdaddr_t rpa; BT_DBG(""); @@ -1364,7 +1372,7 @@ static int smp_cmd_ident_addr_info(struct l2cap_conn *conn, smp->id_addr_type, smp->irk, &rpa); distribute: - smp_distribute_keys(conn); + queue_work(hdev->workqueue, &smp->distribute_work); hci_dev_unlock(hcon->hdev); @@ -1400,7 +1408,7 @@ static int smp_cmd_sign_info(struct l2cap_conn *conn, struct sk_buff *skb) memcpy(csrk->val, rp->csrk, sizeof(csrk->val)); } smp->csrk = csrk; - smp_distribute_keys(conn); + queue_work(hdev->workqueue, &smp->distribute_work); hci_dev_unlock(hdev); return 0; @@ -1510,7 +1518,6 @@ done: static void smp_teardown_cb(struct l2cap_chan *chan, int err) { struct l2cap_conn *conn = chan->conn; - struct smp_chan *smp = chan->data; BT_DBG("chan %p", chan); @@ -1526,14 +1533,17 @@ static void smp_resume_cb(struct l2cap_chan *chan) struct smp_chan *smp = chan->data; struct l2cap_conn *conn = chan->conn; struct hci_conn *hcon = conn->hcon; + struct hci_dev *hdev = hcon->hdev; BT_DBG("chan %p", chan); - if (test_bit(HCI_CONN_ENCRYPT, &hcon->flags)) - smp_distribute_keys(conn); + if (!smp) + return; - if (smp) - cancel_delayed_work(&smp->security_timer); + cancel_delayed_work(&smp->security_timer); + + if (test_bit(HCI_CONN_ENCRYPT, &hcon->flags)) + queue_work(hdev->workqueue, &smp->distribute_work); } static void smp_ready_cb(struct l2cap_chan *chan) From 6f48e260a95c1a0161e5be39adb0f20c737fe459 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 11 Aug 2014 22:06:44 +0300 Subject: [PATCH 054/221] Bluetooth: Make smp_chan_destroy() private to smp.c There are no external users of smp_chan_destroy() so make it private to smp.c. The patch also moves the function higher up in the c-file in order to avoid forward declarations. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 100 ++++++++++++++++++++++---------------------- net/bluetooth/smp.h | 2 - 2 files changed, 50 insertions(+), 52 deletions(-) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 312ea5ec2d7d..07ca4ce0943b 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -366,6 +366,56 @@ static u8 check_enc_key_size(struct l2cap_conn *conn, __u8 max_key_size) return 0; } +static void smp_chan_destroy(struct l2cap_conn *conn) +{ + struct l2cap_chan *chan = conn->smp; + struct smp_chan *smp = chan->data; + bool complete; + + BUG_ON(!smp); + + cancel_delayed_work_sync(&smp->security_timer); + /* In case the timeout freed the SMP context */ + if (!chan->data) + return; + + if (work_pending(&smp->distribute_work)) { + cancel_work_sync(&smp->distribute_work); + if (!chan->data) + return; + } + + complete = test_bit(SMP_FLAG_COMPLETE, &smp->flags); + mgmt_smp_complete(conn->hcon, complete); + + kfree(smp->csrk); + kfree(smp->slave_csrk); + + crypto_free_blkcipher(smp->tfm_aes); + + /* If pairing failed clean up any keys we might have */ + if (!complete) { + if (smp->ltk) { + list_del(&smp->ltk->list); + kfree(smp->ltk); + } + + if (smp->slave_ltk) { + list_del(&smp->slave_ltk->list); + kfree(smp->slave_ltk); + } + + if (smp->remote_irk) { + list_del(&smp->remote_irk->list); + kfree(smp->remote_irk); + } + } + + chan->data = NULL; + kfree(smp); + hci_conn_drop(conn->hcon); +} + static void smp_failure(struct l2cap_conn *conn, u8 reason) { struct hci_conn *hcon = conn->hcon; @@ -812,56 +862,6 @@ static struct smp_chan *smp_chan_create(struct l2cap_conn *conn) return smp; } -void smp_chan_destroy(struct l2cap_conn *conn) -{ - struct l2cap_chan *chan = conn->smp; - struct smp_chan *smp = chan->data; - bool complete; - - BUG_ON(!smp); - - cancel_delayed_work_sync(&smp->security_timer); - /* In case the timeout freed the SMP context */ - if (!chan->data) - return; - - if (work_pending(&smp->distribute_work)) { - cancel_work_sync(&smp->distribute_work); - if (!chan->data) - return; - } - - complete = test_bit(SMP_FLAG_COMPLETE, &smp->flags); - mgmt_smp_complete(conn->hcon, complete); - - kfree(smp->csrk); - kfree(smp->slave_csrk); - - crypto_free_blkcipher(smp->tfm_aes); - - /* If pairing failed clean up any keys we might have */ - if (!complete) { - if (smp->ltk) { - list_del(&smp->ltk->list); - kfree(smp->ltk); - } - - if (smp->slave_ltk) { - list_del(&smp->slave_ltk->list); - kfree(smp->slave_ltk); - } - - if (smp->remote_irk) { - list_del(&smp->remote_irk->list); - kfree(smp->remote_irk); - } - } - - chan->data = NULL; - kfree(smp); - hci_conn_drop(conn->hcon); -} - int smp_user_confirm_reply(struct hci_conn *hcon, u16 mgmt_op, __le32 passkey) { struct l2cap_conn *conn = hcon->l2cap_data; diff --git a/net/bluetooth/smp.h b/net/bluetooth/smp.h index 59a594278a85..cf1094617c69 100644 --- a/net/bluetooth/smp.h +++ b/net/bluetooth/smp.h @@ -128,8 +128,6 @@ bool smp_sufficient_security(struct hci_conn *hcon, u8 sec_level); int smp_conn_security(struct hci_conn *hcon, __u8 sec_level); int smp_user_confirm_reply(struct hci_conn *conn, u16 mgmt_op, __le32 passkey); -void smp_chan_destroy(struct l2cap_conn *conn); - bool smp_irk_matches(struct hci_dev *hdev, u8 irk[16], bdaddr_t *bdaddr); int smp_generate_rpa(struct hci_dev *hdev, u8 irk[16], bdaddr_t *rpa); From 24bbd44a96c7a209fafbf1b28f0ac1a00cf4e551 Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Mon, 11 Aug 2014 13:25:07 +0200 Subject: [PATCH 055/221] mac802154: cleanup in rx path This patch replace the sizeof(struct rx_work) with sizeof(*work) and directly passing the skb in mac802154_subif_rx() Signed-off-by: Varka Bhadram Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- net/mac802154/rx.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/net/mac802154/rx.c b/net/mac802154/rx.c index 7f820a108a9c..a14cf9ede171 100644 --- a/net/mac802154/rx.c +++ b/net/mac802154/rx.c @@ -86,9 +86,8 @@ fail: static void mac802154_rx_worker(struct work_struct *work) { struct rx_work *rw = container_of(work, struct rx_work, work); - struct sk_buff *skb = rw->skb; - mac802154_subif_rx(rw->dev, skb, rw->lqi); + mac802154_subif_rx(rw->dev, rw->skb, rw->lqi); kfree(rw); } @@ -101,7 +100,7 @@ ieee802154_rx_irqsafe(struct ieee802154_dev *dev, struct sk_buff *skb, u8 lqi) if (!skb) return; - work = kzalloc(sizeof(struct rx_work), GFP_ATOMIC); + work = kzalloc(sizeof(*work), GFP_ATOMIC); if (!work) return; From b288a4963f09459c29cca240d3352cc7915710fc Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Mon, 11 Aug 2014 13:25:08 +0200 Subject: [PATCH 056/221] mac802154: common error path By introducing label fail, making the common error path for mac802154_llsec_decrypt() and packet type default case. Signed-off-by: Varka Bhadram Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- net/mac802154/wpan.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/net/mac802154/wpan.c b/net/mac802154/wpan.c index 3c3069fd6971..ce1757001917 100644 --- a/net/mac802154/wpan.c +++ b/net/mac802154/wpan.c @@ -472,8 +472,7 @@ mac802154_subif_frame(struct mac802154_sub_if_data *sdata, struct sk_buff *skb, rc = mac802154_llsec_decrypt(&sdata->sec, skb); if (rc) { pr_debug("decryption failed: %i\n", rc); - kfree_skb(skb); - return NET_RX_DROP; + goto fail; } sdata->dev->stats.rx_packets++; @@ -485,9 +484,12 @@ mac802154_subif_frame(struct mac802154_sub_if_data *sdata, struct sk_buff *skb, default: pr_warn("ieee802154: bad frame received (type = %d)\n", mac_cb(skb)->type); - kfree_skb(skb); - return NET_RX_DROP; + goto fail; } + +fail: + kfree_skb(skb); + return NET_RX_DROP; } static void mac802154_print_addr(const char *name, From 0ba1f94e72b811215ce2f4610fe0f6cf88f4b28a Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Mon, 11 Aug 2014 13:25:09 +0200 Subject: [PATCH 057/221] ieee802154: 6lowpan: remove unused function Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- net/ieee802154/6lowpan_rtnl.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/net/ieee802154/6lowpan_rtnl.c b/net/ieee802154/6lowpan_rtnl.c index 016b77ee88f0..509d7a625a4b 100644 --- a/net/ieee802154/6lowpan_rtnl.c +++ b/net/ieee802154/6lowpan_rtnl.c @@ -77,14 +77,6 @@ lowpan_dev_info *lowpan_dev_info(const struct net_device *dev) return netdev_priv(dev); } -static inline void lowpan_address_flip(u8 *src, u8 *dest) -{ - int i; - - for (i = 0; i < IEEE802154_ADDR_LEN; i++) - (dest)[IEEE802154_ADDR_LEN - i - 1] = (src)[i]; -} - static int lowpan_header_create(struct sk_buff *skb, struct net_device *dev, unsigned short type, const void *_daddr, const void *_saddr, unsigned int len) From f55889128a776b51581394b20abd0b470304cf95 Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Mon, 11 Aug 2014 13:25:10 +0200 Subject: [PATCH 058/221] mac802154: common tx error path This patch introduce the common error path on failure of Tx by inserting the label 'err_tx'. Signed-off-by: Varka Bhadram Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- net/mac802154/tx.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/net/mac802154/tx.c b/net/mac802154/tx.c index 8124353646ae..fdf4c0e67259 100644 --- a/net/mac802154/tx.c +++ b/net/mac802154/tx.c @@ -89,8 +89,7 @@ netdev_tx_t mac802154_tx(struct mac802154_priv *priv, struct sk_buff *skb, if (!(priv->phy->channels_supported[page] & (1 << chan))) { WARN_ON(1); - kfree_skb(skb); - return NETDEV_TX_OK; + goto err_tx; } mac802154_monitors_rx(mac802154_to_priv(&priv->hw), skb); @@ -103,12 +102,10 @@ netdev_tx_t mac802154_tx(struct mac802154_priv *priv, struct sk_buff *skb, data[1] = crc >> 8; } - if (skb_cow_head(skb, priv->hw.extra_tx_headroom)) { - kfree_skb(skb); - return NETDEV_TX_OK; - } + if (skb_cow_head(skb, priv->hw.extra_tx_headroom)) + goto err_tx; - work = kzalloc(sizeof(struct xmit_work), GFP_ATOMIC); + work = kzalloc(sizeof(*work), GFP_ATOMIC); if (!work) { kfree_skb(skb); return NETDEV_TX_BUSY; @@ -129,4 +126,8 @@ netdev_tx_t mac802154_tx(struct mac802154_priv *priv, struct sk_buff *skb, queue_work(priv->dev_workqueue, &work->work); return NETDEV_TX_OK; + +err_tx: + kfree_skb(skb); + return NETDEV_TX_OK; } From d664cd9895b498da4fea3b43c72b4aacfc4126a2 Mon Sep 17 00:00:00 2001 From: Himangi Saraogi Date: Wed, 13 Aug 2014 14:53:31 +0530 Subject: [PATCH 059/221] Bluetooth: Remove typedef bluecard_info_t The Linux kernel coding style guidelines suggest not using typedefs for structure types. This patch gets rid of the typedef for bluecard_info_t. Also, the name of the struct is changed to drop the _t, to make the name look less typedef-like. The following Coccinelle semantic patch detects the case: @tn@ identifier i; type td; @@ -typedef struct i { ... } -td ; @@ type tn.td; identifier tn.i; @@ -td + struct i Signed-off-by: Himangi Saraogi Acked-by: Julia Lawall Signed-off-by: Marcel Holtmann --- drivers/bluetooth/bluecard_cs.c | 35 +++++++++++++++++---------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c index dfa5043e68ba..35e63aaa6f80 100644 --- a/drivers/bluetooth/bluecard_cs.c +++ b/drivers/bluetooth/bluecard_cs.c @@ -61,7 +61,7 @@ MODULE_LICENSE("GPL"); /* ======================== Local structures ======================== */ -typedef struct bluecard_info_t { +struct bluecard_info { struct pcmcia_device *p_dev; struct hci_dev *hdev; @@ -78,7 +78,7 @@ typedef struct bluecard_info_t { unsigned char ctrl_reg; unsigned long hw_state; /* Status of the hardware and LED control */ -} bluecard_info_t; +}; static int bluecard_config(struct pcmcia_device *link); @@ -157,7 +157,7 @@ static void bluecard_detach(struct pcmcia_device *p_dev); static void bluecard_activity_led_timeout(u_long arg) { - bluecard_info_t *info = (bluecard_info_t *)arg; + struct bluecard_info *info = (struct bluecard_info *)arg; unsigned int iobase = info->p_dev->resource[0]->start; if (!test_bit(CARD_HAS_PCCARD_ID, &(info->hw_state))) @@ -173,7 +173,7 @@ static void bluecard_activity_led_timeout(u_long arg) } -static void bluecard_enable_activity_led(bluecard_info_t *info) +static void bluecard_enable_activity_led(struct bluecard_info *info) { unsigned int iobase = info->p_dev->resource[0]->start; @@ -215,7 +215,7 @@ static int bluecard_write(unsigned int iobase, unsigned int offset, __u8 *buf, i } -static void bluecard_write_wakeup(bluecard_info_t *info) +static void bluecard_write_wakeup(struct bluecard_info *info) { if (!info) { BT_ERR("Unknown device"); @@ -368,7 +368,8 @@ static int bluecard_read(unsigned int iobase, unsigned int offset, __u8 *buf, in } -static void bluecard_receive(bluecard_info_t *info, unsigned int offset) +static void bluecard_receive(struct bluecard_info *info, + unsigned int offset) { unsigned int iobase; unsigned char buf[31]; @@ -497,7 +498,7 @@ static void bluecard_receive(bluecard_info_t *info, unsigned int offset) static irqreturn_t bluecard_interrupt(int irq, void *dev_inst) { - bluecard_info_t *info = dev_inst; + struct bluecard_info *info = dev_inst; unsigned int iobase; unsigned char reg; @@ -562,7 +563,7 @@ static irqreturn_t bluecard_interrupt(int irq, void *dev_inst) static int bluecard_hci_set_baud_rate(struct hci_dev *hdev, int baud) { - bluecard_info_t *info = hci_get_drvdata(hdev); + struct bluecard_info *info = hci_get_drvdata(hdev); struct sk_buff *skb; /* Ericsson baud rate command */ @@ -611,7 +612,7 @@ static int bluecard_hci_set_baud_rate(struct hci_dev *hdev, int baud) static int bluecard_hci_flush(struct hci_dev *hdev) { - bluecard_info_t *info = hci_get_drvdata(hdev); + struct bluecard_info *info = hci_get_drvdata(hdev); /* Drop TX queue */ skb_queue_purge(&(info->txq)); @@ -622,7 +623,7 @@ static int bluecard_hci_flush(struct hci_dev *hdev) static int bluecard_hci_open(struct hci_dev *hdev) { - bluecard_info_t *info = hci_get_drvdata(hdev); + struct bluecard_info *info = hci_get_drvdata(hdev); if (test_bit(CARD_HAS_PCCARD_ID, &(info->hw_state))) bluecard_hci_set_baud_rate(hdev, DEFAULT_BAUD_RATE); @@ -643,7 +644,7 @@ static int bluecard_hci_open(struct hci_dev *hdev) static int bluecard_hci_close(struct hci_dev *hdev) { - bluecard_info_t *info = hci_get_drvdata(hdev); + struct bluecard_info *info = hci_get_drvdata(hdev); if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags))) return 0; @@ -663,7 +664,7 @@ static int bluecard_hci_close(struct hci_dev *hdev) static int bluecard_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb) { - bluecard_info_t *info = hci_get_drvdata(hdev); + struct bluecard_info *info = hci_get_drvdata(hdev); switch (bt_cb(skb)->pkt_type) { case HCI_COMMAND_PKT: @@ -691,7 +692,7 @@ static int bluecard_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb) /* ======================== Card services HCI interaction ======================== */ -static int bluecard_open(bluecard_info_t *info) +static int bluecard_open(struct bluecard_info *info) { unsigned int iobase = info->p_dev->resource[0]->start; struct hci_dev *hdev; @@ -806,7 +807,7 @@ static int bluecard_open(bluecard_info_t *info) } -static int bluecard_close(bluecard_info_t *info) +static int bluecard_close(struct bluecard_info *info) { unsigned int iobase = info->p_dev->resource[0]->start; struct hci_dev *hdev = info->hdev; @@ -833,7 +834,7 @@ static int bluecard_close(bluecard_info_t *info) static int bluecard_probe(struct pcmcia_device *link) { - bluecard_info_t *info; + struct bluecard_info *info; /* Create new info device */ info = devm_kzalloc(&link->dev, sizeof(*info), GFP_KERNEL); @@ -857,7 +858,7 @@ static void bluecard_detach(struct pcmcia_device *link) static int bluecard_config(struct pcmcia_device *link) { - bluecard_info_t *info = link->priv; + struct bluecard_info *info = link->priv; int i, n; link->config_index = 0x20; @@ -897,7 +898,7 @@ failed: static void bluecard_release(struct pcmcia_device *link) { - bluecard_info_t *info = link->priv; + struct bluecard_info *info = link->priv; bluecard_close(info); From ad709d4867985de0b239d01702f9ac6bb578099e Mon Sep 17 00:00:00 2001 From: Himangi Saraogi Date: Wed, 13 Aug 2014 14:51:39 +0530 Subject: [PATCH 060/221] Bluetooth: Remove typedef btuart_info_t The Linux kernel coding style guidelines suggest not using typedefs for structure types. This patch gets rid of the typedef for btuart_info_t. Also, the name of the struct is changed to drop the _t, to make the name look less typedef-like. The following Coccinelle semantic patch detects the case: @tn@ identifier i; type td; @@ -typedef struct i { ... } -td ; @@ type tn.td; identifier tn.i; @@ -td + struct i Signed-off-by: Himangi Saraogi Acked-by: Julia Lawall Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btuart_cs.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/drivers/bluetooth/btuart_cs.c b/drivers/bluetooth/btuart_cs.c index fb948f02eda5..abb4d2106db4 100644 --- a/drivers/bluetooth/btuart_cs.c +++ b/drivers/bluetooth/btuart_cs.c @@ -62,7 +62,7 @@ MODULE_LICENSE("GPL"); /* ======================== Local structures ======================== */ -typedef struct btuart_info_t { +struct btuart_info { struct pcmcia_device *p_dev; struct hci_dev *hdev; @@ -75,7 +75,7 @@ typedef struct btuart_info_t { unsigned long rx_state; unsigned long rx_count; struct sk_buff *rx_skb; -} btuart_info_t; +}; static int btuart_config(struct pcmcia_device *link); @@ -127,7 +127,7 @@ static int btuart_write(unsigned int iobase, int fifo_size, __u8 *buf, int len) } -static void btuart_write_wakeup(btuart_info_t *info) +static void btuart_write_wakeup(struct btuart_info *info) { if (!info) { BT_ERR("Unknown device"); @@ -172,7 +172,7 @@ static void btuart_write_wakeup(btuart_info_t *info) } -static void btuart_receive(btuart_info_t *info) +static void btuart_receive(struct btuart_info *info) { unsigned int iobase; int boguscount = 0; @@ -286,7 +286,7 @@ static void btuart_receive(btuart_info_t *info) static irqreturn_t btuart_interrupt(int irq, void *dev_inst) { - btuart_info_t *info = dev_inst; + struct btuart_info *info = dev_inst; unsigned int iobase; int boguscount = 0; int iir, lsr; @@ -340,7 +340,8 @@ static irqreturn_t btuart_interrupt(int irq, void *dev_inst) } -static void btuart_change_speed(btuart_info_t *info, unsigned int speed) +static void btuart_change_speed(struct btuart_info *info, + unsigned int speed) { unsigned long flags; unsigned int iobase; @@ -397,7 +398,7 @@ static void btuart_change_speed(btuart_info_t *info, unsigned int speed) static int btuart_hci_flush(struct hci_dev *hdev) { - btuart_info_t *info = hci_get_drvdata(hdev); + struct btuart_info *info = hci_get_drvdata(hdev); /* Drop TX queue */ skb_queue_purge(&(info->txq)); @@ -427,7 +428,7 @@ static int btuart_hci_close(struct hci_dev *hdev) static int btuart_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb) { - btuart_info_t *info = hci_get_drvdata(hdev); + struct btuart_info *info = hci_get_drvdata(hdev); switch (bt_cb(skb)->pkt_type) { case HCI_COMMAND_PKT: @@ -455,7 +456,7 @@ static int btuart_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb) /* ======================== Card services HCI interaction ======================== */ -static int btuart_open(btuart_info_t *info) +static int btuart_open(struct btuart_info *info) { unsigned long flags; unsigned int iobase = info->p_dev->resource[0]->start; @@ -521,7 +522,7 @@ static int btuart_open(btuart_info_t *info) } -static int btuart_close(btuart_info_t *info) +static int btuart_close(struct btuart_info *info) { unsigned long flags; unsigned int iobase = info->p_dev->resource[0]->start; @@ -550,7 +551,7 @@ static int btuart_close(btuart_info_t *info) static int btuart_probe(struct pcmcia_device *link) { - btuart_info_t *info; + struct btuart_info *info; /* Create new info device */ info = devm_kzalloc(&link->dev, sizeof(*info), GFP_KERNEL); @@ -613,7 +614,7 @@ static int btuart_check_config_notpicky(struct pcmcia_device *p_dev, static int btuart_config(struct pcmcia_device *link) { - btuart_info_t *info = link->priv; + struct btuart_info *info = link->priv; int i; int try; @@ -654,7 +655,7 @@ failed: static void btuart_release(struct pcmcia_device *link) { - btuart_info_t *info = link->priv; + struct btuart_info *info = link->priv; btuart_close(info); From 66f4e0e43a0389a7f2814f0cc6df39019aead54f Mon Sep 17 00:00:00 2001 From: Himangi Saraogi Date: Wed, 13 Aug 2014 14:52:27 +0530 Subject: [PATCH 061/221] Bluetooth: Remove typedefs nsh_t and dtl1_info_t The Linux kernel coding style guidelines suggest not using typedefs for structure types. This patch gets rid of the typedefs for nsh_t and dtl1_info_t. Also, the name of the struct is changed to drop the _t, to make the name look less typedef-like. The following Coccinelle semantic patch detects the case for dtl1_info_t and a similar patch finds the nsh_t case: @tn@ identifier i; type td; @@ -typedef struct i { ... } -td ; @@ type tn.td; identifier tn.i; @@ -td + struct i Signed-off-by: Himangi Saraogi Acked-by: Julia Lawall Signed-off-by: Marcel Holtmann --- drivers/bluetooth/dtl1_cs.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c index 2bd8fad17206..78e10f0c65b2 100644 --- a/drivers/bluetooth/dtl1_cs.c +++ b/drivers/bluetooth/dtl1_cs.c @@ -62,7 +62,7 @@ MODULE_LICENSE("GPL"); /* ======================== Local structures ======================== */ -typedef struct dtl1_info_t { +struct dtl1_info { struct pcmcia_device *p_dev; struct hci_dev *hdev; @@ -78,7 +78,7 @@ typedef struct dtl1_info_t { unsigned long rx_state; unsigned long rx_count; struct sk_buff *rx_skb; -} dtl1_info_t; +}; static int dtl1_config(struct pcmcia_device *link); @@ -94,11 +94,11 @@ static int dtl1_config(struct pcmcia_device *link); #define RECV_WAIT_DATA 1 -typedef struct { +struct nsh { u8 type; u8 zero; u16 len; -} __packed nsh_t; /* Nokia Specific Header */ +} __packed; /* Nokia Specific Header */ #define NSHL 4 /* Nokia Specific Header Length */ @@ -126,7 +126,7 @@ static int dtl1_write(unsigned int iobase, int fifo_size, __u8 *buf, int len) } -static void dtl1_write_wakeup(dtl1_info_t *info) +static void dtl1_write_wakeup(struct dtl1_info *info) { if (!info) { BT_ERR("Unknown device"); @@ -176,7 +176,7 @@ static void dtl1_write_wakeup(dtl1_info_t *info) } -static void dtl1_control(dtl1_info_t *info, struct sk_buff *skb) +static void dtl1_control(struct dtl1_info *info, struct sk_buff *skb) { u8 flowmask = *(u8 *)skb->data; int i; @@ -199,10 +199,10 @@ static void dtl1_control(dtl1_info_t *info, struct sk_buff *skb) } -static void dtl1_receive(dtl1_info_t *info) +static void dtl1_receive(struct dtl1_info *info) { unsigned int iobase; - nsh_t *nsh; + struct nsh *nsh; int boguscount = 0; if (!info) { @@ -227,7 +227,7 @@ static void dtl1_receive(dtl1_info_t *info) } *skb_put(info->rx_skb, 1) = inb(iobase + UART_RX); - nsh = (nsh_t *)info->rx_skb->data; + nsh = (struct nsh *)info->rx_skb->data; info->rx_count--; @@ -287,7 +287,7 @@ static void dtl1_receive(dtl1_info_t *info) static irqreturn_t dtl1_interrupt(int irq, void *dev_inst) { - dtl1_info_t *info = dev_inst; + struct dtl1_info *info = dev_inst; unsigned int iobase; unsigned char msr; int boguscount = 0; @@ -365,7 +365,7 @@ static int dtl1_hci_open(struct hci_dev *hdev) static int dtl1_hci_flush(struct hci_dev *hdev) { - dtl1_info_t *info = hci_get_drvdata(hdev); + struct dtl1_info *info = hci_get_drvdata(hdev); /* Drop TX queue */ skb_queue_purge(&(info->txq)); @@ -387,9 +387,9 @@ static int dtl1_hci_close(struct hci_dev *hdev) static int dtl1_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb) { - dtl1_info_t *info = hci_get_drvdata(hdev); + struct dtl1_info *info = hci_get_drvdata(hdev); struct sk_buff *s; - nsh_t nsh; + struct nsh nsh; switch (bt_cb(skb)->pkt_type) { case HCI_COMMAND_PKT: @@ -436,7 +436,7 @@ static int dtl1_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb) /* ======================== Card services HCI interaction ======================== */ -static int dtl1_open(dtl1_info_t *info) +static int dtl1_open(struct dtl1_info *info) { unsigned long flags; unsigned int iobase = info->p_dev->resource[0]->start; @@ -505,7 +505,7 @@ static int dtl1_open(dtl1_info_t *info) } -static int dtl1_close(dtl1_info_t *info) +static int dtl1_close(struct dtl1_info *info) { unsigned long flags; unsigned int iobase = info->p_dev->resource[0]->start; @@ -534,7 +534,7 @@ static int dtl1_close(dtl1_info_t *info) static int dtl1_probe(struct pcmcia_device *link) { - dtl1_info_t *info; + struct dtl1_info *info; /* Create new info device */ info = devm_kzalloc(&link->dev, sizeof(*info), GFP_KERNEL); @@ -552,7 +552,7 @@ static int dtl1_probe(struct pcmcia_device *link) static void dtl1_detach(struct pcmcia_device *link) { - dtl1_info_t *info = link->priv; + struct dtl1_info *info = link->priv; dtl1_close(info); pcmcia_disable_device(link); @@ -571,7 +571,7 @@ static int dtl1_confcheck(struct pcmcia_device *p_dev, void *priv_data) static int dtl1_config(struct pcmcia_device *link) { - dtl1_info_t *info = link->priv; + struct dtl1_info *info = link->priv; int ret; /* Look for a generic full-sized window */ From 3bbaf812065e8b0feca02b6c7e5117b731709008 Mon Sep 17 00:00:00 2001 From: Himangi Saraogi Date: Wed, 13 Aug 2014 14:49:56 +0530 Subject: [PATCH 062/221] Bluetooth: Remove typedef bt3c_info_t The Linux kernel coding style guidelines suggest not using typedefs for structure types. This patch gets rid of the typedef for bt3c_info_t. Also, the name of the struct is changed to drop the _t, to make the name look less typedef-like. The following Coccinelle semantic patch detects the case: @tn@ identifier i; type td; @@ -typedef struct i { ... } -td ; @@ type tn.td; identifier tn.i; @@ -td + struct i Signed-off-by: Himangi Saraogi Acked-by: Julia Lawall Signed-off-by: Marcel Holtmann --- drivers/bluetooth/bt3c_cs.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c index 1d82721cf9c6..4f7e8d400bc0 100644 --- a/drivers/bluetooth/bt3c_cs.c +++ b/drivers/bluetooth/bt3c_cs.c @@ -67,7 +67,7 @@ MODULE_FIRMWARE("BT3CPCC.bin"); /* ======================== Local structures ======================== */ -typedef struct bt3c_info_t { +struct bt3c_info { struct pcmcia_device *p_dev; struct hci_dev *hdev; @@ -80,7 +80,7 @@ typedef struct bt3c_info_t { unsigned long rx_state; unsigned long rx_count; struct sk_buff *rx_skb; -} bt3c_info_t; +}; static int bt3c_config(struct pcmcia_device *link); @@ -175,7 +175,7 @@ static int bt3c_write(unsigned int iobase, int fifo_size, __u8 *buf, int len) } -static void bt3c_write_wakeup(bt3c_info_t *info) +static void bt3c_write_wakeup(struct bt3c_info *info) { if (!info) { BT_ERR("Unknown device"); @@ -214,7 +214,7 @@ static void bt3c_write_wakeup(bt3c_info_t *info) } -static void bt3c_receive(bt3c_info_t *info) +static void bt3c_receive(struct bt3c_info *info) { unsigned int iobase; int size = 0, avail; @@ -336,7 +336,7 @@ static void bt3c_receive(bt3c_info_t *info) static irqreturn_t bt3c_interrupt(int irq, void *dev_inst) { - bt3c_info_t *info = dev_inst; + struct bt3c_info *info = dev_inst; unsigned int iobase; int iir; irqreturn_t r = IRQ_NONE; @@ -388,7 +388,7 @@ static irqreturn_t bt3c_interrupt(int irq, void *dev_inst) static int bt3c_hci_flush(struct hci_dev *hdev) { - bt3c_info_t *info = hci_get_drvdata(hdev); + struct bt3c_info *info = hci_get_drvdata(hdev); /* Drop TX queue */ skb_queue_purge(&(info->txq)); @@ -418,7 +418,7 @@ static int bt3c_hci_close(struct hci_dev *hdev) static int bt3c_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb) { - bt3c_info_t *info = hci_get_drvdata(hdev); + struct bt3c_info *info = hci_get_drvdata(hdev); unsigned long flags; switch (bt_cb(skb)->pkt_type) { @@ -451,7 +451,8 @@ static int bt3c_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb) /* ======================== Card services HCI interaction ======================== */ -static int bt3c_load_firmware(bt3c_info_t *info, const unsigned char *firmware, +static int bt3c_load_firmware(struct bt3c_info *info, + const unsigned char *firmware, int count) { char *ptr = (char *) firmware; @@ -536,7 +537,7 @@ error: } -static int bt3c_open(bt3c_info_t *info) +static int bt3c_open(struct bt3c_info *info) { const struct firmware *firmware; struct hci_dev *hdev; @@ -603,7 +604,7 @@ error: } -static int bt3c_close(bt3c_info_t *info) +static int bt3c_close(struct bt3c_info *info) { struct hci_dev *hdev = info->hdev; @@ -620,7 +621,7 @@ static int bt3c_close(bt3c_info_t *info) static int bt3c_probe(struct pcmcia_device *link) { - bt3c_info_t *info; + struct bt3c_info *info; /* Create new info device */ info = devm_kzalloc(&link->dev, sizeof(*info), GFP_KERNEL); @@ -683,7 +684,7 @@ static int bt3c_check_config_notpicky(struct pcmcia_device *p_dev, static int bt3c_config(struct pcmcia_device *link) { - bt3c_info_t *info = link->priv; + struct bt3c_info *info = link->priv; int i; unsigned long try; @@ -724,7 +725,7 @@ failed: static void bt3c_release(struct pcmcia_device *link) { - bt3c_info_t *info = link->priv; + struct bt3c_info *info = link->priv; bt3c_close(info); From 069cb27017de6476d47a70fbf144f69200d3e854 Mon Sep 17 00:00:00 2001 From: Lukasz Rymanowski Date: Wed, 13 Aug 2014 16:01:41 +0200 Subject: [PATCH 063/221] Bluetooth: Improve data packing in SAR mode There is no need to decrease pdu size with L2CAP SDU lenght in Start L2CAP SDU frame. Start packtet is just 2 bytes longer as specified and we can keep payload as long as possible. When testing SAR L2CAP against PTS, L2CAP channel is usually configured in that way, that SDU = MPS * 3. PTS expets then 3 I-Frames from IUT: Start, Continuation and End frame. Without this fix, we sent 4 I-Frames. We could pass a test by using -b option in l2test and send just two bytes less than SDU length. With this patch no need to use -b option. Signed-off-by: Lukasz Rymanowski Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 0cd7ed99558b..ebe7454362f0 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -2275,7 +2275,6 @@ static int l2cap_segment_sdu(struct l2cap_chan *chan, } else { sar = L2CAP_SAR_START; sdu_len = len; - pdu_len -= L2CAP_SDULEN_SIZE; } while (len > 0) { @@ -2290,10 +2289,8 @@ static int l2cap_segment_sdu(struct l2cap_chan *chan, __skb_queue_tail(seg_queue, skb); len -= pdu_len; - if (sdu_len) { + if (sdu_len) sdu_len = 0; - pdu_len += L2CAP_SDULEN_SIZE; - } if (len <= pdu_len) { sar = L2CAP_SAR_END; From 13cac15296afe7e42088ecfcd0f1d4b658248c46 Mon Sep 17 00:00:00 2001 From: Lukasz Rymanowski Date: Thu, 14 Aug 2014 09:35:34 +0200 Subject: [PATCH 064/221] Bluetooth: Fix ERTM L2CAP resend packet I-Frame which is going to be resend already has FCS field added and set (if it was required). Adding additional FCS field calculated from data + old FCS in resend function is incorrect. This patch fix that. Issue has been found during PTS testing. Signed-off-by: Lukasz Rymanowski Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index ebe7454362f0..4a90438d99df 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1968,10 +1968,12 @@ static void l2cap_ertm_resend(struct l2cap_chan *chan) tx_skb->data + L2CAP_HDR_SIZE); } + /* Update FCS */ if (chan->fcs == L2CAP_FCS_CRC16) { - u16 fcs = crc16(0, (u8 *) tx_skb->data, tx_skb->len); - put_unaligned_le16(fcs, skb_put(tx_skb, - L2CAP_FCS_SIZE)); + u16 fcs = crc16(0, (u8 *) tx_skb->data, + tx_skb->len - L2CAP_FCS_SIZE); + put_unaligned_le16(fcs, skb_tail_pointer(tx_skb) - + L2CAP_FCS_SIZE); } l2cap_do_send(chan, tx_skb); From a9aefb3b3761a55117c6d1a526ac0305c3be5f46 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Tue, 12 Aug 2014 11:02:19 +0300 Subject: [PATCH 065/221] ath10k: improve vdev map handling Check vdev map has space before calling ffs, fix invalid cleanup in failure to create vdev case. Open-code the BIT() logic since BIT does not properly handle 64-bit bitfields and future patches will make use of larger bitfields. Signed-off-by: Ben Greear Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 29 +++++++++++---------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index a5ec7c2502b5..4b62973f6276 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -597,14 +597,14 @@ static int ath10k_monitor_vdev_create(struct ath10k *ar) lockdep_assert_held(&ar->conf_mutex); - bit = ffs(ar->free_vdev_map); - if (bit == 0) { + if (ar->free_vdev_map == 0) { ath10k_warn("failed to find free vdev id for monitor vdev\n"); return -ENOMEM; } + bit = ffs(ar->free_vdev_map); + ar->monitor_vdev_id = bit - 1; - ar->free_vdev_map &= ~(1 << ar->monitor_vdev_id); ret = ath10k_wmi_vdev_create(ar, ar->monitor_vdev_id, WMI_VDEV_TYPE_MONITOR, @@ -612,20 +612,14 @@ static int ath10k_monitor_vdev_create(struct ath10k *ar) if (ret) { ath10k_warn("failed to request monitor vdev %i creation: %d\n", ar->monitor_vdev_id, ret); - goto vdev_fail; + return ret; } + ar->free_vdev_map &= ~(1 << ar->monitor_vdev_id); ath10k_dbg(ATH10K_DBG_MAC, "mac monitor vdev %d created\n", ar->monitor_vdev_id); return 0; - -vdev_fail: - /* - * Restore the ID to the global map. - */ - ar->free_vdev_map |= 1 << (ar->monitor_vdev_id); - return ret; } static int ath10k_monitor_vdev_delete(struct ath10k *ar) @@ -641,7 +635,7 @@ static int ath10k_monitor_vdev_delete(struct ath10k *ar) return ret; } - ar->free_vdev_map |= 1 << (ar->monitor_vdev_id); + ar->free_vdev_map |= 1 << ar->monitor_vdev_id; ath10k_dbg(ATH10K_DBG_MAC, "mac monitor vdev %d deleted\n", ar->monitor_vdev_id); @@ -2780,11 +2774,12 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, INIT_WORK(&arvif->wep_key_work, ath10k_tx_wep_key_work); INIT_LIST_HEAD(&arvif->list); - bit = ffs(ar->free_vdev_map); - if (bit == 0) { + if (ar->free_vdev_map == 0) { + ath10k_warn("Free vdev map is empty, no more interfaces allowed.\n"); ret = -EBUSY; goto err; } + bit = ffs(ar->free_vdev_map); arvif->vdev_id = bit - 1; arvif->vdev_subtype = WMI_VDEV_SUBTYPE_NONE; @@ -2827,7 +2822,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, goto err; } - ar->free_vdev_map &= ~BIT(arvif->vdev_id); + ar->free_vdev_map &= ~(1 << arvif->vdev_id); list_add(&arvif->list, &ar->arvifs); vdev_param = ar->wmi.vdev_param->def_keyid; @@ -2920,7 +2915,7 @@ err_peer_delete: err_vdev_delete: ath10k_wmi_vdev_delete(ar, arvif->vdev_id); - ar->free_vdev_map &= ~BIT(arvif->vdev_id); + ar->free_vdev_map |= 1 << arvif->vdev_id; list_del(&arvif->list); err: @@ -2956,7 +2951,7 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw, ath10k_warn("failed to stop spectral for vdev %i: %d\n", arvif->vdev_id, ret); - ar->free_vdev_map |= 1 << (arvif->vdev_id); + ar->free_vdev_map |= 1 << arvif->vdev_id; list_del(&arvif->list); if (arvif->vdev_type == WMI_VDEV_TYPE_AP) { From f2bc4d203edf2c5a6054134765ad5935454dc6ea Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Tue, 12 Aug 2014 11:02:20 +0300 Subject: [PATCH 066/221] ath10k: fix typo in error message tranmist -> transmit Signed-off-by: Ben Greear Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 4b62973f6276..e568882a17de 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -2003,7 +2003,7 @@ static void ath10k_tx_htt(struct ath10k *ar, struct sk_buff *skb) ar->fw_features)) { if (skb_queue_len(&ar->wmi_mgmt_tx_queue) >= ATH10K_MAX_NUM_MGMT_PENDING) { - ath10k_warn("reached WMI management tranmist queue limit\n"); + ath10k_warn("reached WMI management transmit queue limit\n"); ret = -EBUSY; goto exit; } From beb4be849a92172b4b95185a19db1691e6223f22 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Tue, 12 Aug 2014 11:45:59 +0100 Subject: [PATCH 067/221] ath6kl: Add SDIO device ID for QCA6234X Support This patch adds device ID 402 to support QCA6234X found in APQ8064 SOC in IFC6410 board. Tested with mainline mmci sdio driver. Signed-off-by: Srinivas Kandagatla Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/sdio.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/ath/ath6kl/sdio.c b/drivers/net/wireless/ath/ath6kl/sdio.c index 339d89f14d32..eab0ab976af2 100644 --- a/drivers/net/wireless/ath/ath6kl/sdio.c +++ b/drivers/net/wireless/ath/ath6kl/sdio.c @@ -1400,6 +1400,7 @@ static const struct sdio_device_id ath6kl_sdio_devices[] = { {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6003_BASE | 0x1))}, {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6004_BASE | 0x0))}, {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6004_BASE | 0x1))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6004_BASE | 0x2))}, {}, }; From 804eef14790f8917f74945f82db8b55903f76af4 Mon Sep 17 00:00:00 2001 From: Simon Wunderlich Date: Tue, 12 Aug 2014 17:12:17 +0200 Subject: [PATCH 068/221] ath10k: unregister spectral before mac If spectral is unregistered after mac80211, the relayfs file has already been removed recursively by mac/cfg80211, and spectral tries to remove the file once more, thus leading to double free problems. Better clean up spectral before to avoid that problem. Reported-by: Kalle Valo Signed-off-by: Simon Wunderlich Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index d3474b43ac47..ba2e87ab19bd 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -1043,6 +1043,12 @@ void ath10k_core_unregister(struct ath10k *ar) if (!test_bit(ATH10K_FLAG_CORE_REGISTERED, &ar->dev_flags)) return; + /* Stop spectral before unregistering from mac80211 to remove the + * relayfs debugfs file cleanly. Otherwise the parent debugfs tree + * would be already be free'd recursively, leading to a double free. + */ + ath10k_spectral_destroy(ar); + /* We must unregister from mac80211 before we stop HTC and HIF. * Otherwise we will fail to submit commands to FW and mac80211 will be * unhappy about callback failures. */ @@ -1050,8 +1056,6 @@ void ath10k_core_unregister(struct ath10k *ar) ath10k_core_free_firmware_files(ar); - ath10k_spectral_destroy(ar); - ath10k_debug_destroy(ar); } EXPORT_SYMBOL(ath10k_core_unregister); From a74a8c846fb699f3277c0c21278bd4c414074b4a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 22 Jul 2014 14:50:47 +0200 Subject: [PATCH 069/221] mac80211: don't duplicate station QoS capability data We currently track the QoS capability twice: for all peer stations in the WLAN_STA_WME flag, and for any clients associated to an AP interface separately for drivers in the sta->sta.wme field. Remove the WLAN_STA_WME flag and track the capability only in the driver-visible field, getting rid of the limitation that the field is only valid in AP mode. Reviewed-by: Arik Nemtsov Signed-off-by: Johannes Berg --- include/net/mac80211.h | 2 +- net/mac80211/cfg.c | 13 +++---------- net/mac80211/debugfs_sta.c | 3 ++- net/mac80211/ibss.c | 2 +- net/mac80211/mesh_plink.c | 4 +--- net/mac80211/mlme.c | 3 +-- net/mac80211/sta_info.c | 4 ++-- net/mac80211/sta_info.h | 2 -- net/mac80211/tdls.c | 3 +-- net/mac80211/tx.c | 6 +++--- net/mac80211/wme.c | 4 ++-- 11 files changed, 17 insertions(+), 29 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index dae2e24616e1..1cd84444665c 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1405,7 +1405,7 @@ struct ieee80211_sta_rates { * @supp_rates: Bitmap of supported rates (per band) * @ht_cap: HT capabilities of this STA; restricted to our own capabilities * @vht_cap: VHT capabilities of this STA; restricted to our own capabilities - * @wme: indicates whether the STA supports WME. Only valid during AP-mode. + * @wme: indicates whether the STA supports QoS/WME. * @drv_priv: data area for driver use, will always be aligned to * sizeof(void *), size is determined in hw information. * @uapsd_queues: bitmap of queues configured for uapsd. Only valid diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 927b4ea0128b..4d8989b87960 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1011,15 +1011,8 @@ static int sta_apply_parameters(struct ieee80211_local *local, clear_sta_flag(sta, WLAN_STA_SHORT_PREAMBLE); } - if (mask & BIT(NL80211_STA_FLAG_WME)) { - if (set & BIT(NL80211_STA_FLAG_WME)) { - set_sta_flag(sta, WLAN_STA_WME); - sta->sta.wme = true; - } else { - clear_sta_flag(sta, WLAN_STA_WME); - sta->sta.wme = false; - } - } + if (mask & BIT(NL80211_STA_FLAG_WME)) + sta->sta.wme = set & BIT(NL80211_STA_FLAG_WME); if (mask & BIT(NL80211_STA_FLAG_MFP)) { if (set & BIT(NL80211_STA_FLAG_MFP)) @@ -3352,7 +3345,7 @@ static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev, band = chanctx_conf->def.chan->band; sta = sta_info_get_bss(sdata, peer); if (sta) { - qos = test_sta_flag(sta, WLAN_STA_WME); + qos = sta->sta.wme; } else { rcu_read_unlock(); return -ENOLINK; diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 3db96648b45a..4a20fb8f1e23 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -77,7 +77,8 @@ static ssize_t sta_flags_read(struct file *file, char __user *userbuf, TEST(AUTH), TEST(ASSOC), TEST(PS_STA), TEST(PS_DRIVER), TEST(AUTHORIZED), TEST(SHORT_PREAMBLE), - TEST(WME), TEST(WDS), TEST(CLEAR_PS_FILT), + sta->sta.wme ? "WME\n" : "", + TEST(WDS), TEST(CLEAR_PS_FILT), TEST(MFP), TEST(BLOCK_BA), TEST(PSPOLL), TEST(UAPSD), TEST(SP), TEST(TDLS_PEER), TEST(TDLS_PEER_AUTH), TEST(4ADDR_EVENT), diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 9713dc54ea4b..5f9654d31a8d 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -1038,7 +1038,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, } if (sta && elems->wmm_info) - set_sta_flag(sta, WLAN_STA_WME); + sta->sta.wme = true; if (sta && elems->ht_operation && elems->ht_cap_elem && sdata->u.ibss.chandef.width != NL80211_CHAN_WIDTH_20_NOHT && diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 63b874101b27..8d67c1ebfbda 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -431,14 +431,12 @@ __mesh_sta_info_alloc(struct ieee80211_sub_if_data *sdata, u8 *hw_addr) return NULL; sta->plink_state = NL80211_PLINK_LISTEN; + sta->sta.wme = true; sta_info_pre_move_state(sta, IEEE80211_STA_AUTH); sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC); sta_info_pre_move_state(sta, IEEE80211_STA_AUTHORIZED); - set_sta_flag(sta, WLAN_STA_WME); - sta->sta.wme = true; - return sta; } diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 31a8afaf7332..0e8d59a0e17e 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2677,8 +2677,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, if (ifmgd->flags & IEEE80211_STA_MFP_ENABLED) set_sta_flag(sta, WLAN_STA_MFP); - if (elems.wmm_param) - set_sta_flag(sta, WLAN_STA_WME); + sta->sta.wme = elems.wmm_param; err = sta_info_move_state(sta, IEEE80211_STA_ASSOC); if (!err && !(ifmgd->flags & IEEE80211_STA_CONTROL_PORT)) diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index c6ee2139fbc5..e1f957d5935e 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -1179,7 +1179,7 @@ static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb; int size = sizeof(*nullfunc); __le16 fc; - bool qos = test_sta_flag(sta, WLAN_STA_WME); + bool qos = sta->sta.wme; struct ieee80211_tx_info *info; struct ieee80211_chanctx_conf *chanctx_conf; @@ -1834,7 +1834,7 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_AUTHORIZED); if (test_sta_flag(sta, WLAN_STA_SHORT_PREAMBLE)) sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE); - if (test_sta_flag(sta, WLAN_STA_WME)) + if (sta->sta.wme) sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_WME); if (test_sta_flag(sta, WLAN_STA_MFP)) sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_MFP); diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index d411bcc8ef08..89c40d5c0633 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -31,7 +31,6 @@ * when virtual port control is not in use. * @WLAN_STA_SHORT_PREAMBLE: Station is capable of receiving short-preamble * frames. - * @WLAN_STA_WME: Station is a QoS-STA. * @WLAN_STA_WDS: Station is one of our WDS peers. * @WLAN_STA_CLEAR_PS_FILT: Clear PS filter in hardware (using the * IEEE80211_TX_CTL_CLEAR_PS_FILT control flag) when the next @@ -69,7 +68,6 @@ enum ieee80211_sta_info_flags { WLAN_STA_PS_STA, WLAN_STA_AUTHORIZED, WLAN_STA_SHORT_PREAMBLE, - WLAN_STA_WME, WLAN_STA_WDS, WLAN_STA_CLEAR_PS_FILT, WLAN_STA_MFP, diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index 1b21050be174..f2cb3b6c1871 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c @@ -316,8 +316,7 @@ ieee80211_tdls_add_setup_cfm_ies(struct ieee80211_sub_if_data *sdata, } /* add the QoS param IE if both the peer and we support it */ - if (local->hw.queues >= IEEE80211_NUM_ACS && - test_sta_flag(sta, WLAN_STA_WME)) + if (local->hw.queues >= IEEE80211_NUM_ACS && sta->sta.wme) ieee80211_tdls_add_wmm_param_ie(sdata, skb); /* add any custom IEs that go before HT operation */ diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 464106c023d8..2051cc60f8ce 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1844,7 +1844,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN); hdrlen = 30; authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED); - wme_sta = test_sta_flag(sta, WLAN_STA_WME); + wme_sta = sta->sta.wme; } ap_sdata = container_of(sdata->bss, struct ieee80211_sub_if_data, u.ap); @@ -1957,7 +1957,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, if (sta) { authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED); - wme_sta = test_sta_flag(sta, WLAN_STA_WME); + wme_sta = sta->sta.wme; tdls_peer = test_sta_flag(sta, WLAN_STA_TDLS_PEER); tdls_auth = test_sta_flag(sta, @@ -2035,7 +2035,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, sta = sta_info_get(sdata, hdr.addr1); if (sta) { authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED); - wme_sta = test_sta_flag(sta, WLAN_STA_WME); + wme_sta = sta->sta.wme; } } diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index d51422c778de..6459946f0b74 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c @@ -118,7 +118,7 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata, case NL80211_IFTYPE_AP_VLAN: sta = rcu_dereference(sdata->u.vlan.sta); if (sta) { - qos = test_sta_flag(sta, WLAN_STA_WME); + qos = sta->sta.wme; break; } case NL80211_IFTYPE_AP: @@ -145,7 +145,7 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata, if (!sta && ra && !is_multicast_ether_addr(ra)) { sta = sta_info_get(sdata, ra); if (sta) - qos = test_sta_flag(sta, WLAN_STA_WME); + qos = sta->sta.wme; } rcu_read_unlock(); From 53b954ee4a71e782d7dfcdeee5bf4695caeeb112 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Thu, 24 Jul 2014 11:20:05 +0300 Subject: [PATCH 070/221] mac80211: disable 40MHz support in case of 20MHz AP If the AP only advertises support for 20MHz (in the ht operation ie), disable 40MHz and VHT. This can improve interoperability with APs that don't like stations exceeding their own advertised capabilities. Signed-off-by: Eliad Peller Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 0e8d59a0e17e..29fe91d6a094 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -149,6 +149,7 @@ static u32 ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata, struct ieee80211_supported_band *sband, struct ieee80211_channel *channel, + const struct ieee80211_ht_cap *ht_cap, const struct ieee80211_ht_operation *ht_oper, const struct ieee80211_vht_operation *vht_oper, struct cfg80211_chan_def *chandef, bool tracking) @@ -162,13 +163,19 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata, chandef->center_freq1 = channel->center_freq; chandef->center_freq2 = 0; - if (!ht_oper || !sband->ht_cap.ht_supported) { + if (!ht_cap || !ht_oper || !sband->ht_cap.ht_supported) { ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT; goto out; } chandef->width = NL80211_CHAN_WIDTH_20; + if (!(ht_cap->cap_info & + cpu_to_le16(IEEE80211_HT_CAP_SUP_WIDTH_20_40))) { + ret = IEEE80211_STA_DISABLE_40MHZ | IEEE80211_STA_DISABLE_VHT; + goto out; + } + ht_cfreq = ieee80211_channel_to_frequency(ht_oper->primary_chan, channel->band); /* check that channel matches the right operating channel */ @@ -328,6 +335,7 @@ out: static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata, struct sta_info *sta, + const struct ieee80211_ht_cap *ht_cap, const struct ieee80211_ht_operation *ht_oper, const struct ieee80211_vht_operation *vht_oper, const u8 *bssid, u32 *changed) @@ -367,8 +375,9 @@ static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata, sband = local->hw.wiphy->bands[chan->band]; /* calculate new channel (type) based on HT/VHT operation IEs */ - flags = ieee80211_determine_chantype(sdata, sband, chan, ht_oper, - vht_oper, &chandef, true); + flags = ieee80211_determine_chantype(sdata, sband, chan, + ht_cap, ht_oper, vht_oper, + &chandef, true); /* * Downgrade the new channel if we associated with restricted @@ -3173,7 +3182,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, mutex_lock(&local->sta_mtx); sta = sta_info_get(sdata, bssid); - if (ieee80211_config_bw(sdata, sta, elems.ht_operation, + if (ieee80211_config_bw(sdata, sta, + elems.ht_cap_elem, elems.ht_operation, elems.vht_operation, bssid, &changed)) { mutex_unlock(&local->sta_mtx); ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, @@ -3807,6 +3817,7 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, { struct ieee80211_local *local = sdata->local; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + const struct ieee80211_ht_cap *ht_cap = NULL; const struct ieee80211_ht_operation *ht_oper = NULL; const struct ieee80211_vht_operation *vht_oper = NULL; struct ieee80211_supported_band *sband; @@ -3823,14 +3834,17 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT) && sband->ht_cap.ht_supported) { - const u8 *ht_oper_ie, *ht_cap; + const u8 *ht_oper_ie, *ht_cap_ie; ht_oper_ie = ieee80211_bss_get_ie(cbss, WLAN_EID_HT_OPERATION); if (ht_oper_ie && ht_oper_ie[1] >= sizeof(*ht_oper)) ht_oper = (void *)(ht_oper_ie + 2); - ht_cap = ieee80211_bss_get_ie(cbss, WLAN_EID_HT_CAPABILITY); - if (!ht_cap || ht_cap[1] < sizeof(struct ieee80211_ht_cap)) { + ht_cap_ie = ieee80211_bss_get_ie(cbss, WLAN_EID_HT_CAPABILITY); + if (ht_cap_ie && ht_cap_ie[1] >= sizeof(*ht_cap)) + ht_cap = (void *)(ht_cap_ie + 2); + + if (!ht_cap) { ifmgd->flags |= IEEE80211_STA_DISABLE_HT; ht_oper = NULL; } @@ -3861,7 +3875,7 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, ifmgd->flags |= ieee80211_determine_chantype(sdata, sband, cbss->channel, - ht_oper, vht_oper, + ht_cap, ht_oper, vht_oper, &chandef, false); sdata->needed_rx_chains = min(ieee80211_ht_vht_rx_chains(sdata, cbss), From 10d49878971852111b49f59f6f56c3641b691173 Mon Sep 17 00:00:00 2001 From: Hans Wennborg Date: Sun, 17 Aug 2014 14:57:11 -0700 Subject: [PATCH 071/221] ath6kl: fix %d confusingly prefixed with 0x in format strings Signed-off-by: Hans Wennborg Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/init.c | 2 +- drivers/net/wireless/ath/ath6kl/main.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c index a61118484de6..6340afca9ad3 100644 --- a/drivers/net/wireless/ath/ath6kl/init.c +++ b/drivers/net/wireless/ath/ath6kl/init.c @@ -1049,7 +1049,7 @@ static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name) ar->hw.reserved_ram_size = le32_to_cpup(val); ath6kl_dbg(ATH6KL_DBG_BOOT, - "found reserved ram size ie 0x%d\n", + "found reserved ram size ie %d\n", ar->hw.reserved_ram_size); break; case ATH6KL_FW_IE_CAPABILITIES: diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c index 21516bc65785..933aef025698 100644 --- a/drivers/net/wireless/ath/ath6kl/main.c +++ b/drivers/net/wireless/ath/ath6kl/main.c @@ -225,7 +225,7 @@ int ath6kl_diag_write32(struct ath6kl *ar, u32 address, __le32 value) ret = ath6kl_hif_diag_write32(ar, address, value); if (ret) { - ath6kl_err("failed to write 0x%x during diagnose window to 0x%d\n", + ath6kl_err("failed to write 0x%x during diagnose window to 0x%x\n", address, value); return ret; } From 7a7b37328864286d0079d03198260e5f92d0a512 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Tue, 19 Aug 2014 13:22:32 +0200 Subject: [PATCH 072/221] ath10k: fix a conflict bug in wmi service bitmap Service mapping for main firmware branch was incorrectly used for 10.x firmware and vice-versa. This caused wmi_services in debugfs to print wrong values. This fixes commit cff990ce7ddd6 ("ath10k: fix wmi service bitmap debug") where for some reason there was either a conflict that wasn't resolved properly or git had a bad day. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 23acbadeb8fa..ec3bf4e00b4d 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -2194,7 +2194,7 @@ static void ath10k_wmi_service_ready_event_rx(struct ath10k *ar, ar->ath_common.regulatory.current_rd = __le32_to_cpu(ev->hal_reg_capabilities.eeprom_rd); - wmi_10x_svc_map(ev->wmi_service_bitmap, svc_bmap); + wmi_main_svc_map(ev->wmi_service_bitmap, svc_bmap); ath10k_debug_read_service_map(ar, svc_bmap, sizeof(svc_bmap)); ath10k_dbg_dump(ATH10K_DBG_WMI, NULL, "ath10k: wmi svc: ", ev->wmi_service_bitmap, sizeof(ev->wmi_service_bitmap)); @@ -2264,7 +2264,7 @@ static void ath10k_wmi_10x_service_ready_event_rx(struct ath10k *ar, ar->ath_common.regulatory.current_rd = __le32_to_cpu(ev->hal_reg_capabilities.eeprom_rd); - wmi_main_svc_map(ev->wmi_service_bitmap, svc_bmap); + wmi_10x_svc_map(ev->wmi_service_bitmap, svc_bmap); ath10k_debug_read_service_map(ar, svc_bmap, sizeof(svc_bmap)); ath10k_dbg_dump(ATH10K_DBG_WMI, NULL, "ath10k: wmi svc: ", ev->wmi_service_bitmap, sizeof(ev->wmi_service_bitmap)); From 3d29a3e04298e3883625c677f62f7f1e634eec10 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Mon, 25 Aug 2014 08:37:26 +0300 Subject: [PATCH 073/221] ath10k: add ath10k_pci_diag_* helpers ath10k_pci_diag_read32() is for reading u32 from a device and ath10k_pci_diag_read_hi() is a helper for reading data using "host interest" table. Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 55 ++++++++++++++++++--------- 1 file changed, 38 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 98c029b7d0ab..b4ae4bb3fc09 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -460,13 +460,46 @@ done: return ret; } +static int ath10k_pci_diag_read32(struct ath10k *ar, u32 address, u32 *value) +{ + return ath10k_pci_diag_read_mem(ar, address, value, sizeof(u32)); +} + +static int __ath10k_pci_diag_read_hi(struct ath10k *ar, void *dest, + u32 src, u32 len) +{ + u32 host_addr, addr; + int ret; + + host_addr = host_interest_item_address(src); + + ret = ath10k_pci_diag_read32(ar, host_addr, &addr); + if (ret != 0) { + ath10k_warn("failed to get memcpy hi address for firmware address %d: %d\n", + src, ret); + return ret; + } + + ret = ath10k_pci_diag_read_mem(ar, addr, dest, len); + if (ret != 0) { + ath10k_warn("failed to memcpy firmware memory from %d (%d B): %d\n", + addr, len, ret); + return ret; + } + + return 0; +} + +#define ath10k_pci_diag_read_hi(ar, dest, src, len) \ + __ath10k_pci_diag_read_hi(ar, dest, HI_ITEM(src), len); + /* Read 4-byte aligned data from Target memory or register */ static int ath10k_pci_diag_read_access(struct ath10k *ar, u32 address, u32 *data) { /* Assume range doesn't cross this boundary */ if (address >= DRAM_BASE_ADDRESS) - return ath10k_pci_diag_read_mem(ar, address, data, sizeof(u32)); + return ath10k_pci_diag_read32(ar, address, data); *data = ath10k_pci_read32(ar, address); return 0; @@ -801,9 +834,7 @@ static u16 ath10k_pci_hif_get_free_queue_number(struct ath10k *ar, u8 pipe) static void ath10k_pci_hif_dump_area(struct ath10k *ar) { - u32 reg_dump_area = 0; u32 reg_dump_values[REG_DUMP_COUNT_QCA988X] = {}; - u32 host_addr; int ret; u32 i; @@ -812,21 +843,11 @@ static void ath10k_pci_hif_dump_area(struct ath10k *ar) ar->hw_params.name, ar->target_version); ath10k_err("firmware version: %s\n", ar->hw->wiphy->fw_version); - host_addr = host_interest_item_address(HI_ITEM(hi_failure_state)); - ret = ath10k_pci_diag_read_mem(ar, host_addr, - ®_dump_area, sizeof(u32)); + ret = ath10k_pci_diag_read_hi(ar, ®_dump_values[0], + hi_failure_state, + REG_DUMP_COUNT_QCA988X * sizeof(u32)); if (ret) { - ath10k_err("failed to read FW dump area address: %d\n", ret); - return; - } - - ath10k_err("target register Dump Location: 0x%08X\n", reg_dump_area); - - ret = ath10k_pci_diag_read_mem(ar, reg_dump_area, - ®_dump_values[0], - REG_DUMP_COUNT_QCA988X * sizeof(u32)); - if (ret != 0) { - ath10k_err("failed to read FW dump area: %d\n", ret); + ath10k_err("failed to read firmware dump area: %d\n", ret); return; } From 384914b2e5566dfce25f3f38d992708a9ef6f51b Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Mon, 25 Aug 2014 08:37:32 +0300 Subject: [PATCH 074/221] ath10k: provide firmware crash info via debugfs Store the firmware registers and other relevant data to a firmware crash dump file and provide it to user-space via debugfs. Should help with figuring out why the firmware crashed. kvalo: remove dbglog support, rework and refactor the code to avoid ifdefs and otherwise simplify it as well Signed-off-by: Ben Greear Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.h | 13 ++ drivers/net/wireless/ath/ath10k/debug.c | 239 +++++++++++++++++++++++- drivers/net/wireless/ath/ath10k/debug.h | 15 ++ drivers/net/wireless/ath/ath10k/hw.h | 2 + drivers/net/wireless/ath/ath10k/pci.c | 43 ++++- drivers/net/wireless/ath/ath10k/pci.h | 3 - 6 files changed, 302 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index cca6060dbf30..8da77c706708 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -22,6 +22,8 @@ #include #include #include +#include +#include #include "htt.h" #include "htc.h" @@ -278,6 +280,15 @@ struct ath10k_vif_iter { struct ath10k_vif *arvif; }; +/* used for crash-dump storage, protected by data-lock */ +struct ath10k_fw_crash_data { + bool crashed_since_read; + + uuid_le uuid; + struct timespec timestamp; + __le32 registers[REG_DUMP_COUNT_QCA988X]; +}; + struct ath10k_debug { struct dentry *debugfs_phy; @@ -295,6 +306,8 @@ struct ath10k_debug { u8 htt_max_amsdu; u8 htt_max_ampdu; + + struct ath10k_fw_crash_data *fw_crash_data; }; enum ath10k_state { diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index df1abe7f1fef..2171744ba2fe 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -17,6 +17,9 @@ #include #include +#include +#include +#include #include "core.h" #include "debug.h" @@ -24,6 +27,85 @@ /* ms */ #define ATH10K_DEBUG_HTT_STATS_INTERVAL 1000 +#define ATH10K_FW_CRASH_DUMP_VERSION 1 + +/** + * enum ath10k_fw_crash_dump_type - types of data in the dump file + * @ATH10K_FW_CRASH_DUMP_REGDUMP: Register crash dump in binary format + */ +enum ath10k_fw_crash_dump_type { + ATH10K_FW_CRASH_DUMP_REGISTERS = 0, + + ATH10K_FW_CRASH_DUMP_MAX, +}; + +struct ath10k_tlv_dump_data { + /* see ath10k_fw_crash_dump_type above */ + __le32 type; + + /* in bytes */ + __le32 tlv_len; + + /* pad to 32-bit boundaries as needed */ + u8 tlv_data[]; +} __packed; + +struct ath10k_dump_file_data { + /* dump file information */ + + /* "ATH10K-FW-DUMP" */ + char df_magic[16]; + + __le32 len; + + /* file dump version */ + __le32 version; + + /* some info we can get from ath10k struct that might help */ + + u8 uuid[16]; + + __le32 chip_id; + + /* 0 for now, in place for later hardware */ + __le32 bus_type; + + __le32 target_version; + __le32 fw_version_major; + __le32 fw_version_minor; + __le32 fw_version_release; + __le32 fw_version_build; + __le32 phy_capability; + __le32 hw_min_tx_power; + __le32 hw_max_tx_power; + __le32 ht_cap_info; + __le32 vht_cap_info; + __le32 num_rf_chains; + + /* firmware version string */ + char fw_ver[ETHTOOL_FWVERS_LEN]; + + /* Kernel related information */ + + /* time-of-day stamp */ + __le64 tv_sec; + + /* time-of-day stamp, nano-seconds */ + __le64 tv_nsec; + + /* LINUX_VERSION_CODE */ + __le32 kernel_ver_code; + + /* VERMAGIC_STRING */ + char kernel_ver[64]; + + /* room for growth w/out changing binary format */ + u8 unused[128]; + + /* struct ath10k_tlv_dump_data + more */ + u8 data[0]; +} __packed; + static int ath10k_printk(const char *level, const char *fmt, ...) { struct va_format vaf; @@ -588,6 +670,138 @@ static const struct file_operations fops_chip_id = { .llseek = default_llseek, }; +struct ath10k_fw_crash_data * +ath10k_debug_get_new_fw_crash_data(struct ath10k *ar) +{ + struct ath10k_fw_crash_data *crash_data = ar->debug.fw_crash_data; + + lockdep_assert_held(&ar->data_lock); + + crash_data->crashed_since_read = true; + uuid_le_gen(&crash_data->uuid); + getnstimeofday(&crash_data->timestamp); + + return crash_data; +} +EXPORT_SYMBOL(ath10k_debug_get_new_fw_crash_data); + +static struct ath10k_dump_file_data *ath10k_build_dump_file(struct ath10k *ar) +{ + struct ath10k_fw_crash_data *crash_data = ar->debug.fw_crash_data; + struct ath10k_dump_file_data *dump_data; + struct ath10k_tlv_dump_data *dump_tlv; + int hdr_len = sizeof(*dump_data); + unsigned int len, sofar = 0; + unsigned char *buf; + + len = hdr_len; + len += sizeof(*dump_tlv) + sizeof(crash_data->registers); + + sofar += hdr_len; + + /* This is going to get big when we start dumping FW RAM and such, + * so go ahead and use vmalloc. + */ + buf = vzalloc(len); + if (!buf) + return NULL; + + spin_lock_bh(&ar->data_lock); + + if (!crash_data->crashed_since_read) { + spin_unlock_bh(&ar->data_lock); + vfree(buf); + return NULL; + } + + dump_data = (struct ath10k_dump_file_data *)(buf); + strlcpy(dump_data->df_magic, "ATH10K-FW-DUMP", + sizeof(dump_data->df_magic)); + dump_data->len = cpu_to_le32(len); + + dump_data->version = cpu_to_le32(ATH10K_FW_CRASH_DUMP_VERSION); + + memcpy(dump_data->uuid, &crash_data->uuid, sizeof(dump_data->uuid)); + dump_data->chip_id = cpu_to_le32(ar->chip_id); + dump_data->bus_type = cpu_to_le32(0); + dump_data->target_version = cpu_to_le32(ar->target_version); + dump_data->fw_version_major = cpu_to_le32(ar->fw_version_major); + dump_data->fw_version_minor = cpu_to_le32(ar->fw_version_minor); + dump_data->fw_version_release = cpu_to_le32(ar->fw_version_release); + dump_data->fw_version_build = cpu_to_le32(ar->fw_version_build); + dump_data->phy_capability = cpu_to_le32(ar->phy_capability); + dump_data->hw_min_tx_power = cpu_to_le32(ar->hw_min_tx_power); + dump_data->hw_max_tx_power = cpu_to_le32(ar->hw_max_tx_power); + dump_data->ht_cap_info = cpu_to_le32(ar->ht_cap_info); + dump_data->vht_cap_info = cpu_to_le32(ar->vht_cap_info); + dump_data->num_rf_chains = cpu_to_le32(ar->num_rf_chains); + + strlcpy(dump_data->fw_ver, ar->hw->wiphy->fw_version, + sizeof(dump_data->fw_ver)); + + dump_data->kernel_ver_code = cpu_to_le32(LINUX_VERSION_CODE); + strlcpy(dump_data->kernel_ver, VERMAGIC_STRING, + sizeof(dump_data->kernel_ver)); + + dump_data->tv_sec = cpu_to_le64(crash_data->timestamp.tv_sec); + dump_data->tv_nsec = cpu_to_le64(crash_data->timestamp.tv_nsec); + + /* Gather crash-dump */ + dump_tlv = (struct ath10k_tlv_dump_data *)(buf + sofar); + dump_tlv->type = cpu_to_le32(ATH10K_FW_CRASH_DUMP_REGISTERS); + dump_tlv->tlv_len = cpu_to_le32(sizeof(crash_data->registers)); + memcpy(dump_tlv->tlv_data, &crash_data->registers, + sizeof(crash_data->registers)); + sofar += sizeof(*dump_tlv) + sizeof(crash_data->registers); + + ar->debug.fw_crash_data->crashed_since_read = false; + + spin_unlock_bh(&ar->data_lock); + + return dump_data; +} + +static int ath10k_fw_crash_dump_open(struct inode *inode, struct file *file) +{ + struct ath10k *ar = inode->i_private; + struct ath10k_dump_file_data *dump; + + dump = ath10k_build_dump_file(ar); + if (!dump) + return -ENODATA; + + file->private_data = dump; + + return 0; +} + +static ssize_t ath10k_fw_crash_dump_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath10k_dump_file_data *dump_file = file->private_data; + + return simple_read_from_buffer(user_buf, count, ppos, + dump_file, + le32_to_cpu(dump_file->len)); +} + +static int ath10k_fw_crash_dump_release(struct inode *inode, + struct file *file) +{ + vfree(file->private_data); + + return 0; +} + +static const struct file_operations fops_fw_crash_dump = { + .open = ath10k_fw_crash_dump_open, + .read = ath10k_fw_crash_dump_read, + .release = ath10k_fw_crash_dump_release, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + static int ath10k_debug_htt_stats_req(struct ath10k *ar) { u64 cookie; @@ -921,11 +1135,20 @@ static const struct file_operations fops_dfs_stats = { int ath10k_debug_create(struct ath10k *ar) { + int ret; + + ar->debug.fw_crash_data = vzalloc(sizeof(*ar->debug.fw_crash_data)); + if (!ar->debug.fw_crash_data) { + ret = -ENOMEM; + goto err; + } + ar->debug.debugfs_phy = debugfs_create_dir("ath10k", ar->hw->wiphy->debugfsdir); - - if (!ar->debug.debugfs_phy) - return -ENOMEM; + if (!ar->debug.debugfs_phy) { + ret = -ENOMEM; + goto err_free_fw_crash_data; + } INIT_DELAYED_WORK(&ar->debug.htt_stats_dwork, ath10k_debug_htt_stats_dwork); @@ -941,6 +1164,9 @@ int ath10k_debug_create(struct ath10k *ar) debugfs_create_file("simulate_fw_crash", S_IRUSR, ar->debug.debugfs_phy, ar, &fops_simulate_fw_crash); + debugfs_create_file("fw_crash_dump", S_IRUSR, ar->debug.debugfs_phy, + ar, &fops_fw_crash_dump); + debugfs_create_file("chip_id", S_IRUSR, ar->debug.debugfs_phy, ar, &fops_chip_id); @@ -969,10 +1195,17 @@ int ath10k_debug_create(struct ath10k *ar) } return 0; + +err_free_fw_crash_data: + vfree(ar->debug.fw_crash_data); + +err: + return ret; } void ath10k_debug_destroy(struct ath10k *ar) { + vfree(ar->debug.fw_crash_data); cancel_delayed_work_sync(&ar->debug.htt_stats_dwork); } diff --git a/drivers/net/wireless/ath/ath10k/debug.h b/drivers/net/wireless/ath/ath10k/debug.h index a5824990bd2a..416c62bbbb26 100644 --- a/drivers/net/wireless/ath/ath10k/debug.h +++ b/drivers/net/wireless/ath/ath10k/debug.h @@ -53,6 +53,10 @@ void ath10k_debug_read_service_map(struct ath10k *ar, size_t map_size); void ath10k_debug_read_target_stats(struct ath10k *ar, struct wmi_stats_event *ev); +struct ath10k_fw_crash_data * +ath10k_debug_get_new_fw_crash_data(struct ath10k *ar); + +void ath10k_debug_dbglog_add(struct ath10k *ar, u8 *buffer, int len); #define ATH10K_DFS_STAT_INC(ar, c) (ar->debug.dfs_stats.c++) @@ -86,6 +90,17 @@ static inline void ath10k_debug_read_target_stats(struct ath10k *ar, { } +static inline void ath10k_debug_dbglog_add(struct ath10k *ar, u8 *buffer, + int len) +{ +} + +static inline struct ath10k_fw_crash_data * +ath10k_debug_get_new_fw_crash_data(struct ath10k *ar) +{ + return NULL; +} + #define ATH10K_DFS_STAT_INC(ar, c) do { } while (0) #endif /* CONFIG_ATH10K_DEBUGFS */ diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index ffd04890407e..13568b01de9f 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -39,6 +39,8 @@ /* includes also the null byte */ #define ATH10K_FIRMWARE_MAGIC "QCA-ATH10K" +#define REG_DUMP_COUNT_QCA988X 60 + struct ath10k_fw_ie { __le32 id; __le32 len; diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index b4ae4bb3fc09..36c4f4130027 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -832,16 +832,13 @@ static u16 ath10k_pci_hif_get_free_queue_number(struct ath10k *ar, u8 pipe) return ath10k_ce_num_free_src_entries(ar_pci->pipe_info[pipe].ce_hdl); } -static void ath10k_pci_hif_dump_area(struct ath10k *ar) +static void ath10k_pci_dump_registers(struct ath10k *ar, + struct ath10k_fw_crash_data *crash_data) { - u32 reg_dump_values[REG_DUMP_COUNT_QCA988X] = {}; + u32 i, reg_dump_values[REG_DUMP_COUNT_QCA988X] = {}; int ret; - u32 i; - ath10k_err("firmware crashed!\n"); - ath10k_err("hardware name %s version 0x%x\n", - ar->hw_params.name, ar->target_version); - ath10k_err("firmware version: %s\n", ar->hw->wiphy->fw_version); + lockdep_assert_held(&ar->data_lock); ret = ath10k_pci_diag_read_hi(ar, ®_dump_values[0], hi_failure_state, @@ -862,6 +859,38 @@ static void ath10k_pci_hif_dump_area(struct ath10k *ar) reg_dump_values[i + 2], reg_dump_values[i + 3]); + /* crash_data is in little endian */ + for (i = 0; i < REG_DUMP_COUNT_QCA988X; i++) + crash_data->registers[i] = cpu_to_le32(reg_dump_values[i]); +} + +static void ath10k_pci_hif_dump_area(struct ath10k *ar) +{ + struct ath10k_fw_crash_data *crash_data; + char uuid[50]; + + spin_lock_bh(&ar->data_lock); + + crash_data = ath10k_debug_get_new_fw_crash_data(ar); + + if (crash_data) + scnprintf(uuid, sizeof(uuid), "%pUl", &crash_data->uuid); + else + scnprintf(uuid, sizeof(uuid), "n/a"); + + ath10k_err("firmware crashed! (uuid %s)\n", uuid); + ath10k_err("hardware name %s version 0x%x\n", + ar->hw_params.name, ar->target_version); + ath10k_err("firmware version: %s\n", ar->hw->wiphy->fw_version); + + if (!crash_data) + goto exit; + + ath10k_pci_dump_registers(ar, crash_data); + +exit: + spin_unlock_bh(&ar->data_lock); + queue_work(ar->workqueue, &ar->restart_work); } diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h index 662bca3922ef..294a72e01909 100644 --- a/drivers/net/wireless/ath/ath10k/pci.h +++ b/drivers/net/wireless/ath/ath10k/pci.h @@ -23,9 +23,6 @@ #include "hw.h" #include "ce.h" -/* FW dump area */ -#define REG_DUMP_COUNT_QCA988X 60 - /* * maximum number of bytes that can be handled atomically by DiagRead/DiagWrite */ From 0e9848c0ec5a8f57e98264ae532b6adcaeecac3b Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Mon, 25 Aug 2014 08:37:37 +0300 Subject: [PATCH 075/221] ath10k: rename ath10k_pci_hif_dump_area() to ath10k_pci_fw_crashed_dump() Better to have a clear name for the function. While at it, clear up the title for the register dump. Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 36c4f4130027..bc8c3e3345c1 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -850,7 +850,7 @@ static void ath10k_pci_dump_registers(struct ath10k *ar, BUILD_BUG_ON(REG_DUMP_COUNT_QCA988X % 4); - ath10k_err("target Register Dump\n"); + ath10k_err("firmware register dump:\n"); for (i = 0; i < REG_DUMP_COUNT_QCA988X; i += 4) ath10k_err("[%02d]: 0x%08X 0x%08X 0x%08X 0x%08X\n", i, @@ -864,7 +864,7 @@ static void ath10k_pci_dump_registers(struct ath10k *ar, crash_data->registers[i] = cpu_to_le32(reg_dump_values[i]); } -static void ath10k_pci_hif_dump_area(struct ath10k *ar) +static void ath10k_pci_fw_crashed_dump(struct ath10k *ar) { struct ath10k_fw_crash_data *crash_data; char uuid[50]; @@ -1811,7 +1811,7 @@ static void ath10k_pci_fw_interrupt_handler(struct ath10k *ar) fw_indicator & ~FW_IND_EVENT_PENDING); if (ar_pci->started) { - ath10k_pci_hif_dump_area(ar); + ath10k_pci_fw_crashed_dump(ar); } else { /* * Probable Target failure before we're prepared @@ -2232,7 +2232,7 @@ static void ath10k_pci_early_irq_tasklet(unsigned long data) if (fw_ind & FW_IND_EVENT_PENDING) { ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS, fw_ind & ~FW_IND_EVENT_PENDING); - ath10k_pci_hif_dump_area(ar); + ath10k_pci_fw_crashed_dump(ar); } ath10k_pci_enable_legacy_irq(ar); @@ -2483,7 +2483,7 @@ static int ath10k_pci_wait_for_target_init(struct ath10k *ar) ath10k_warn("device has crashed during init\n"); ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS, val & ~FW_IND_EVENT_PENDING); - ath10k_pci_hif_dump_area(ar); + ath10k_pci_fw_crashed_dump(ar); return -ECOMM; } From 8a0c797edb65249a82fd6f2ede39785282b4901f Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Mon, 25 Aug 2014 08:37:45 +0300 Subject: [PATCH 076/221] ath10k: print more driver info when firmware crashes Sometimes users forget to include important info like firmware version, so better to print all the info. Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 17 ++--------------- drivers/net/wireless/ath/ath10k/debug.c | 18 ++++++++++++++++++ drivers/net/wireless/ath/ath10k/debug.h | 1 + drivers/net/wireless/ath/ath10k/pci.c | 4 +--- 4 files changed, 22 insertions(+), 18 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index ba2e87ab19bd..28f0adea73b6 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -815,21 +815,8 @@ int ath10k_core_start(struct ath10k *ar) INIT_LIST_HEAD(&ar->arvifs); - if (!test_bit(ATH10K_FLAG_FIRST_BOOT_DONE, &ar->dev_flags)) { - ath10k_info("%s (0x%08x, 0x%08x) fw %s api %d htt %d.%d\n", - ar->hw_params.name, - ar->target_version, - ar->chip_id, - ar->hw->wiphy->fw_version, - ar->fw_api, - ar->htt.target_version_major, - ar->htt.target_version_minor); - ath10k_info("debug %d debugfs %d tracing %d dfs %d\n", - config_enabled(CONFIG_ATH10K_DEBUG), - config_enabled(CONFIG_ATH10K_DEBUGFS), - config_enabled(CONFIG_ATH10K_TRACING), - config_enabled(CONFIG_ATH10K_DFS_CERTIFIED)); - } + if (!test_bit(ATH10K_FLAG_FIRST_BOOT_DONE, &ar->dev_flags)) + ath10k_print_driver_info(ar); __set_bit(ATH10K_FLAG_FIRST_BOOT_DONE, &ar->dev_flags); diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index 2171744ba2fe..442fe93d18be 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -142,6 +142,24 @@ int ath10k_info(const char *fmt, ...) } EXPORT_SYMBOL(ath10k_info); +void ath10k_print_driver_info(struct ath10k *ar) +{ + ath10k_info("%s (0x%08x, 0x%08x) fw %s api %d htt %d.%d\n", + ar->hw_params.name, + ar->target_version, + ar->chip_id, + ar->hw->wiphy->fw_version, + ar->fw_api, + ar->htt.target_version_major, + ar->htt.target_version_minor); + ath10k_info("debug %d debugfs %d tracing %d dfs %d\n", + config_enabled(CONFIG_ATH10K_DEBUG), + config_enabled(CONFIG_ATH10K_DEBUGFS), + config_enabled(CONFIG_ATH10K_TRACING), + config_enabled(CONFIG_ATH10K_DFS_CERTIFIED)); +} +EXPORT_SYMBOL(ath10k_print_driver_info); + int ath10k_err(const char *fmt, ...) { struct va_format vaf = { diff --git a/drivers/net/wireless/ath/ath10k/debug.h b/drivers/net/wireless/ath/ath10k/debug.h index 416c62bbbb26..47ee4a623af6 100644 --- a/drivers/net/wireless/ath/ath10k/debug.h +++ b/drivers/net/wireless/ath/ath10k/debug.h @@ -42,6 +42,7 @@ extern unsigned int ath10k_debug_mask; __printf(1, 2) int ath10k_info(const char *fmt, ...); __printf(1, 2) int ath10k_err(const char *fmt, ...); __printf(1, 2) int ath10k_warn(const char *fmt, ...); +void ath10k_print_driver_info(struct ath10k *ar); #ifdef CONFIG_ATH10K_DEBUGFS int ath10k_debug_start(struct ath10k *ar); diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index bc8c3e3345c1..bb1e4738add4 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -879,9 +879,7 @@ static void ath10k_pci_fw_crashed_dump(struct ath10k *ar) scnprintf(uuid, sizeof(uuid), "n/a"); ath10k_err("firmware crashed! (uuid %s)\n", uuid); - ath10k_err("hardware name %s version 0x%x\n", - ar->hw_params.name, ar->target_version); - ath10k_err("firmware version: %s\n", ar->hw->wiphy->fw_version); + ath10k_print_driver_info(ar); if (!crash_data) goto exit; From 8079de0daea7267f9064f1eb0e8c1bad6d37abad Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Fri, 22 Aug 2014 14:23:29 +0200 Subject: [PATCH 077/221] ath10k: move fw init print Firmware probing is done only once when driver is registered and firmware version is guaranteed to remain the same until driver is unregistered. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 28f0adea73b6..23ba32175fcc 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -815,11 +815,6 @@ int ath10k_core_start(struct ath10k *ar) INIT_LIST_HEAD(&ar->arvifs); - if (!test_bit(ATH10K_FLAG_FIRST_BOOT_DONE, &ar->dev_flags)) - ath10k_print_driver_info(ar); - - __set_bit(ATH10K_FLAG_FIRST_BOOT_DONE, &ar->dev_flags); - return 0; err_hif_stop: @@ -924,6 +919,7 @@ static int ath10k_core_probe_fw(struct ath10k *ar) return ret; } + ath10k_print_driver_info(ar); ath10k_core_stop(ar); mutex_unlock(&ar->conf_mutex); From c947a9e1c7b81f7d6a94f3bc3f16475d982e77ea Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Fri, 22 Aug 2014 14:23:30 +0200 Subject: [PATCH 078/221] ath10k: fix legacy irq workaround Wrong register was being set up. This could prevent firmware from booting in some rare cases when using legacy interrupts. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index bb1e4738add4..4a7a5fe60c65 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -2465,9 +2465,10 @@ static int ath10k_pci_wait_for_target_init(struct ath10k *ar) if (ar_pci->num_msi_intrs == 0) /* Fix potential race by repeating CORE_BASE writes */ - ath10k_pci_soc_write32(ar, PCIE_INTR_ENABLE_ADDRESS, - PCIE_INTR_FIRMWARE_MASK | - PCIE_INTR_CE_MASK_ALL); + ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + + PCIE_INTR_ENABLE_ADDRESS, + PCIE_INTR_FIRMWARE_MASK | + PCIE_INTR_CE_MASK_ALL); mdelay(10); } while (time_before(jiffies, timeout)); From 403d627be9a541437bfcf392c192b12f366ed2a2 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Fri, 22 Aug 2014 14:23:31 +0200 Subject: [PATCH 079/221] ath10k: setup irq method in probe It doesn't make sense to re-init irqs completely whenever transport is started/stopped. Do it just once upon probing/removing. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.h | 1 - drivers/net/wireless/ath/ath10k/pci.c | 75 ++++++++++++++------------ 2 files changed, 40 insertions(+), 36 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 8da77c706708..4ef476099225 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -357,7 +357,6 @@ enum ath10k_fw_features { enum ath10k_dev_flags { /* Indicates that ath10k device is during CAC phase of DFS */ ATH10K_CAC_RUNNING, - ATH10K_FLAG_FIRST_BOOT_DONE, ATH10K_FLAG_CORE_REGISTERED, }; diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 4a7a5fe60c65..c3b3f620ae69 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -306,6 +306,18 @@ static void ath10k_pci_free_early_irq(struct ath10k *ar) free_irq(ath10k_pci_priv(ar)->pdev->irq, ar); } +static inline const char *ath10k_pci_get_irq_method(struct ath10k *ar) +{ + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + + if (ar_pci->num_msi_intrs > 1) + return "msi-x"; + else if (ar_pci->num_msi_intrs == 1) + return "msi"; + else + return "legacy"; +} + /* * Diagnostic read/write access is provided for startup/config/debug usage. * Caller must guarantee proper alignment, when applicable, and single user @@ -1922,8 +1934,6 @@ static int ath10k_pci_warm_reset(struct ath10k *ar) static int __ath10k_pci_hif_power_up(struct ath10k *ar, bool cold_reset) { - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - const char *irq_mode; int ret; /* @@ -1952,22 +1962,10 @@ static int __ath10k_pci_hif_power_up(struct ath10k *ar, bool cold_reset) goto err; } - ret = ath10k_ce_disable_interrupts(ar); - if (ret) { - ath10k_err("failed to disable CE interrupts: %d\n", ret); - goto err_ce; - } - - ret = ath10k_pci_init_irq(ar); - if (ret) { - ath10k_err("failed to init irqs: %d\n", ret); - goto err_ce; - } - ret = ath10k_pci_request_early_irq(ar); if (ret) { ath10k_err("failed to request early irq: %d\n", ret); - goto err_deinit_irq; + goto err_ce; } ret = ath10k_pci_wait_for_target_init(ar); @@ -1988,24 +1986,10 @@ static int __ath10k_pci_hif_power_up(struct ath10k *ar, bool cold_reset) goto err_free_early_irq; } - if (ar_pci->num_msi_intrs > 1) - irq_mode = "MSI-X"; - else if (ar_pci->num_msi_intrs == 1) - irq_mode = "MSI"; - else - irq_mode = "legacy"; - - if (!test_bit(ATH10K_FLAG_FIRST_BOOT_DONE, &ar->dev_flags)) - ath10k_info("pci irq %s irq_mode %d reset_mode %d\n", - irq_mode, ath10k_pci_irq_mode, - ath10k_pci_reset_mode); - return 0; err_free_early_irq: ath10k_pci_free_early_irq(ar); -err_deinit_irq: - ath10k_pci_deinit_irq(ar); err_ce: ath10k_pci_ce_deinit(ar); ath10k_pci_warm_reset(ar); @@ -2076,8 +2060,6 @@ static void ath10k_pci_hif_power_down(struct ath10k *ar) ath10k_pci_free_early_irq(ar); ath10k_pci_kill_tasklet(ar); - ath10k_pci_deinit_irq(ar); - ath10k_pci_ce_deinit(ar); ath10k_pci_warm_reset(ar); } @@ -2369,8 +2351,7 @@ static int ath10k_pci_init_irq(struct ath10k *ar) ath10k_pci_init_irq_tasklets(ar); - if (ath10k_pci_irq_mode != ATH10K_PCI_IRQ_AUTO && - !test_bit(ATH10K_FLAG_FIRST_BOOT_DONE, &ar->dev_flags)) + if (ath10k_pci_irq_mode != ATH10K_PCI_IRQ_AUTO) ath10k_info("limiting irq mode to: %d\n", ath10k_pci_irq_mode); /* Try MSI-X */ @@ -2655,14 +2636,36 @@ static int ath10k_pci_probe(struct pci_dev *pdev, goto err_sleep; } - ret = ath10k_core_register(ar, chip_id); + ath10k_pci_ce_deinit(ar); + + ret = ath10k_ce_disable_interrupts(ar); if (ret) { - ath10k_err("failed to register driver core: %d\n", ret); + ath10k_err("failed to disable copy engine interrupts: %d\n", + ret); goto err_free_ce; } + ret = ath10k_pci_init_irq(ar); + if (ret) { + ath10k_err("failed to init irqs: %d\n", ret); + goto err_free_ce; + } + + ath10k_info("pci irq %s interrupts %d irq_mode %d reset_mode %d\n", + ath10k_pci_get_irq_method(ar), ar_pci->num_msi_intrs, + ath10k_pci_irq_mode, ath10k_pci_reset_mode); + + ret = ath10k_core_register(ar, chip_id); + if (ret) { + ath10k_err("failed to register driver core: %d\n", ret); + goto err_deinit_irq; + } + return 0; +err_deinit_irq: + ath10k_pci_deinit_irq(ar); + err_free_ce: ath10k_pci_free_ce(ar); @@ -2694,6 +2697,8 @@ static void ath10k_pci_remove(struct pci_dev *pdev) return; ath10k_core_unregister(ar); + ath10k_pci_deinit_irq(ar); + ath10k_pci_ce_deinit(ar); ath10k_pci_free_ce(ar); ath10k_pci_sleep(ar); ath10k_pci_release(ar); From 145cc1214a271c72b81a064f4d65c3cf612e941e Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Fri, 22 Aug 2014 14:23:32 +0200 Subject: [PATCH 080/221] ath10k: split ce irq/handler setup It doesn't make much sense to overwrite send_cb and recv_cb callbacks over and over again whenever transport starts. Just make sure to unmask copy engine interrupts when starting. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/ce.c | 36 +++++++++-------------- drivers/net/wireless/ath/ath10k/ce.h | 12 +++----- drivers/net/wireless/ath/ath10k/pci.c | 41 +++------------------------ 3 files changed, 21 insertions(+), 68 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index 5117705f7f3d..8cbc0ab8ad42 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c @@ -769,11 +769,11 @@ void ath10k_ce_per_engine_service_any(struct ath10k *ar) * * Called with ce_lock held. */ -static void ath10k_ce_per_engine_handler_adjust(struct ath10k_ce_pipe *ce_state, - int disable_copy_compl_intr) +static void ath10k_ce_per_engine_handler_adjust(struct ath10k_ce_pipe *ce_state) { u32 ctrl_addr = ce_state->ctrl_addr; struct ath10k *ar = ce_state->ar; + bool disable_copy_compl_intr = ce_state->attr_flags & CE_ATTR_DIS_INTR; if ((!disable_copy_compl_intr) && (ce_state->send_cb || ce_state->recv_cb)) @@ -799,29 +799,13 @@ int ath10k_ce_disable_interrupts(struct ath10k *ar) return 0; } -void ath10k_ce_send_cb_register(struct ath10k_ce_pipe *ce_state, - void (*send_cb)(struct ath10k_ce_pipe *), - int disable_interrupts) +void ath10k_ce_enable_interrupts(struct ath10k *ar) { - struct ath10k *ar = ce_state->ar; struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + int ce_id; - spin_lock_bh(&ar_pci->ce_lock); - ce_state->send_cb = send_cb; - ath10k_ce_per_engine_handler_adjust(ce_state, disable_interrupts); - spin_unlock_bh(&ar_pci->ce_lock); -} - -void ath10k_ce_recv_cb_register(struct ath10k_ce_pipe *ce_state, - void (*recv_cb)(struct ath10k_ce_pipe *)) -{ - struct ath10k *ar = ce_state->ar; - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - - spin_lock_bh(&ar_pci->ce_lock); - ce_state->recv_cb = recv_cb; - ath10k_ce_per_engine_handler_adjust(ce_state, 0); - spin_unlock_bh(&ar_pci->ce_lock); + for (ce_id = 0; ce_id < CE_COUNT; ce_id++) + ath10k_ce_per_engine_handler_adjust(&ar_pci->ce_states[ce_id]); } static int ath10k_ce_init_src_ring(struct ath10k *ar, @@ -1023,7 +1007,9 @@ ath10k_ce_alloc_dest_ring(struct ath10k *ar, unsigned int ce_id, * initialized by software/firmware. */ int ath10k_ce_init_pipe(struct ath10k *ar, unsigned int ce_id, - const struct ce_attr *attr) + const struct ce_attr *attr, + void (*send_cb)(struct ath10k_ce_pipe *), + void (*recv_cb)(struct ath10k_ce_pipe *)) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id]; @@ -1046,6 +1032,10 @@ int ath10k_ce_init_pipe(struct ath10k *ar, unsigned int ce_id, ce_state->ctrl_addr = ath10k_ce_base_address(ce_id); ce_state->attr_flags = attr->flags; ce_state->src_sz_max = attr->src_sz_max; + if (attr->src_nentries) + ce_state->send_cb = send_cb; + if (attr->dest_nentries) + ce_state->recv_cb = recv_cb; spin_unlock_bh(&ar_pci->ce_lock); if (attr->src_nentries) { diff --git a/drivers/net/wireless/ath/ath10k/ce.h b/drivers/net/wireless/ath/ath10k/ce.h index 7a5a36fc59c1..d48dbb972004 100644 --- a/drivers/net/wireless/ath/ath10k/ce.h +++ b/drivers/net/wireless/ath/ath10k/ce.h @@ -162,10 +162,6 @@ int ath10k_ce_send_nolock(struct ath10k_ce_pipe *ce_state, void __ath10k_ce_send_revert(struct ath10k_ce_pipe *pipe); -void ath10k_ce_send_cb_register(struct ath10k_ce_pipe *ce_state, - void (*send_cb)(struct ath10k_ce_pipe *), - int disable_interrupts); - int ath10k_ce_num_free_src_entries(struct ath10k_ce_pipe *pipe); /*==================Recv=======================*/ @@ -184,9 +180,6 @@ int ath10k_ce_recv_buf_enqueue(struct ath10k_ce_pipe *ce_state, void *per_transfer_recv_context, u32 buffer); -void ath10k_ce_recv_cb_register(struct ath10k_ce_pipe *ce_state, - void (*recv_cb)(struct ath10k_ce_pipe *)); - /* recv flags */ /* Data is byte-swapped */ #define CE_RECV_FLAG_SWAPPED 1 @@ -214,7 +207,9 @@ int ath10k_ce_completed_send_next(struct ath10k_ce_pipe *ce_state, /*==================CE Engine Initialization=======================*/ int ath10k_ce_init_pipe(struct ath10k *ar, unsigned int ce_id, - const struct ce_attr *attr); + const struct ce_attr *attr, + void (*send_cb)(struct ath10k_ce_pipe *), + void (*recv_cb)(struct ath10k_ce_pipe *)); void ath10k_ce_deinit_pipe(struct ath10k *ar, unsigned int ce_id); int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id, const struct ce_attr *attr); @@ -245,6 +240,7 @@ int ath10k_ce_cancel_send_next(struct ath10k_ce_pipe *ce_state, void ath10k_ce_per_engine_service_any(struct ath10k *ar); void ath10k_ce_per_engine_service(struct ath10k *ar, unsigned int ce_id); int ath10k_ce_disable_interrupts(struct ath10k *ar); +void ath10k_ce_enable_interrupts(struct ath10k *ar); /* ce_attr.flags values */ /* Use NonSnooping PCIe accesses? */ diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index c3b3f620ae69..c764dd713f00 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -941,37 +941,6 @@ static void ath10k_pci_hif_set_callbacks(struct ath10k *ar, sizeof(ar_pci->msg_callbacks_current)); } -static int ath10k_pci_setup_ce_irq(struct ath10k *ar) -{ - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - const struct ce_attr *attr; - struct ath10k_pci_pipe *pipe_info; - int pipe_num, disable_interrupts; - - for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) { - pipe_info = &ar_pci->pipe_info[pipe_num]; - - /* Handle Diagnostic CE specially */ - if (pipe_info->ce_hdl == ar_pci->ce_diag) - continue; - - attr = &host_ce_config_wlan[pipe_num]; - - if (attr->src_nentries) { - disable_interrupts = attr->flags & CE_ATTR_DIS_INTR; - ath10k_ce_send_cb_register(pipe_info->ce_hdl, - ath10k_pci_ce_send_done, - disable_interrupts); - } - - if (attr->dest_nentries) - ath10k_ce_recv_cb_register(pipe_info->ce_hdl, - ath10k_pci_ce_recv_data); - } - - return 0; -} - static void ath10k_pci_kill_tasklet(struct ath10k *ar) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); @@ -1169,11 +1138,7 @@ static int ath10k_pci_hif_start(struct ath10k *ar) goto err_early_irq; } - ret = ath10k_pci_setup_ce_irq(ar); - if (ret) { - ath10k_warn("failed to setup CE interrupts: %d\n", ret); - goto err_stop; - } + ath10k_ce_enable_interrupts(ar); /* Post buffers once to start things off. */ ret = ath10k_pci_post_rx(ar); @@ -1786,7 +1751,9 @@ static int ath10k_pci_ce_init(struct ath10k *ar) pipe_info->hif_ce_state = ar; attr = &host_ce_config_wlan[pipe_num]; - ret = ath10k_ce_init_pipe(ar, pipe_num, attr); + ret = ath10k_ce_init_pipe(ar, pipe_num, attr, + ath10k_pci_ce_send_done, + ath10k_pci_ce_recv_data); if (ret) { ath10k_err("failed to initialize copy engine pipe %d: %d\n", pipe_num, ret); From ec5ba4d3b6b60456b067e8c625e87e67cdde2d12 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Fri, 22 Aug 2014 14:23:33 +0200 Subject: [PATCH 081/221] ath10k: make sure to really disable irqs This fixes two corner cases. One is a race between disabling copy engine interrupts and unhandled pending interrupts on the host. This could end up with a runaway tasklet and consequently memory leak of a few copy engine rx buffers. The other one is an unexpected (and non-maskable via device CSR) MSI fw indication interrupt during teardown. This could trigger the same problem as the first corner case. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 43 +++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index c764dd713f00..6224952ba523 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -1121,6 +1121,40 @@ static int ath10k_pci_post_rx(struct ath10k *ar) return 0; } +static void ath10k_pci_irq_disable(struct ath10k *ar) +{ + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + int i; + + ath10k_ce_disable_interrupts(ar); + + /* Regardless how many interrupts were assigned for MSI the first one + * is always used for firmware indications (crashes). There's no way to + * mask the irq in the device so call disable_irq(). Legacy (shared) + * interrupts can be masked on the device though. + */ + if (ar_pci->num_msi_intrs > 0) + disable_irq(ar_pci->pdev->irq); + else + ath10k_pci_disable_and_clear_legacy_irq(ar); + + for (i = 0; i < max(1, ar_pci->num_msi_intrs); i++) + synchronize_irq(ar_pci->pdev->irq + i); +} + +static void ath10k_pci_irq_enable(struct ath10k *ar) +{ + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + + ath10k_ce_enable_interrupts(ar); + + /* See comment in ath10k_pci_irq_disable() */ + if (ar_pci->num_msi_intrs > 0) + enable_irq(ar_pci->pdev->irq); + else + ath10k_pci_enable_legacy_irq(ar); +} + static int ath10k_pci_hif_start(struct ath10k *ar) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); @@ -1138,7 +1172,7 @@ static int ath10k_pci_hif_start(struct ath10k *ar) goto err_early_irq; } - ath10k_ce_enable_interrupts(ar); + ath10k_pci_irq_enable(ar); /* Post buffers once to start things off. */ ret = ath10k_pci_post_rx(ar); @@ -1152,7 +1186,7 @@ static int ath10k_pci_hif_start(struct ath10k *ar) return 0; err_stop: - ath10k_ce_disable_interrupts(ar); + ath10k_pci_irq_disable(ar); ath10k_pci_free_irq(ar); ath10k_pci_kill_tasklet(ar); err_early_irq: @@ -1275,10 +1309,7 @@ static void ath10k_pci_hif_stop(struct ath10k *ar) if (WARN_ON(!ar_pci->started)) return; - ret = ath10k_ce_disable_interrupts(ar); - if (ret) - ath10k_warn("failed to disable CE interrupts: %d\n", ret); - + ath10k_pci_irq_disable(ar); ath10k_pci_free_irq(ar); ath10k_pci_kill_tasklet(ar); From 5c771e7454d148af35e8b4297d00f880de79ea49 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Fri, 22 Aug 2014 14:23:34 +0200 Subject: [PATCH 082/221] ath10k: remove early irq handling It's not really necessary to have a dedicated irq handler just for the sake of catching early fw crashes anymore. It is now safe to use one handler even during early stages of device boot up. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 176 ++++++++------------------ drivers/net/wireless/ath/ath10k/pci.h | 1 - 2 files changed, 50 insertions(+), 127 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 6224952ba523..ffb980c5080d 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -266,46 +266,6 @@ static void ath10k_pci_enable_legacy_irq(struct ath10k *ar) PCIE_INTR_ENABLE_ADDRESS); } -static irqreturn_t ath10k_pci_early_irq_handler(int irq, void *arg) -{ - struct ath10k *ar = arg; - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - - if (ar_pci->num_msi_intrs == 0) { - if (!ath10k_pci_irq_pending(ar)) - return IRQ_NONE; - - ath10k_pci_disable_and_clear_legacy_irq(ar); - } - - tasklet_schedule(&ar_pci->early_irq_tasklet); - - return IRQ_HANDLED; -} - -static int ath10k_pci_request_early_irq(struct ath10k *ar) -{ - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - int ret; - - /* Regardless whether MSI-X/MSI/legacy irqs have been set up the first - * interrupt from irq vector is triggered in all cases for FW - * indication/errors */ - ret = request_irq(ar_pci->pdev->irq, ath10k_pci_early_irq_handler, - IRQF_SHARED, "ath10k_pci (early)", ar); - if (ret) { - ath10k_warn("failed to request early irq: %d\n", ret); - return ret; - } - - return 0; -} - -static void ath10k_pci_free_early_irq(struct ath10k *ar) -{ - free_irq(ath10k_pci_priv(ar)->pdev->irq, ar); -} - static inline const char *ath10k_pci_get_irq_method(struct ath10k *ar) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); @@ -948,7 +908,6 @@ static void ath10k_pci_kill_tasklet(struct ath10k *ar) tasklet_kill(&ar_pci->intr_tq); tasklet_kill(&ar_pci->msi_fw_err); - tasklet_kill(&ar_pci->early_irq_tasklet); for (i = 0; i < CE_COUNT; i++) tasklet_kill(&ar_pci->pipe_info[i].intr); @@ -1158,20 +1117,10 @@ static void ath10k_pci_irq_enable(struct ath10k *ar) static int ath10k_pci_hif_start(struct ath10k *ar) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - int ret, ret_early; + int ret; ath10k_dbg(ATH10K_DBG_BOOT, "boot hif start\n"); - ath10k_pci_free_early_irq(ar); - ath10k_pci_kill_tasklet(ar); - - ret = ath10k_pci_request_irq(ar); - if (ret) { - ath10k_warn("failed to post RX buffers for all pipes: %d\n", - ret); - goto err_early_irq; - } - ath10k_pci_irq_enable(ar); /* Post buffers once to start things off. */ @@ -1187,15 +1136,7 @@ static int ath10k_pci_hif_start(struct ath10k *ar) err_stop: ath10k_pci_irq_disable(ar); - ath10k_pci_free_irq(ar); ath10k_pci_kill_tasklet(ar); -err_early_irq: - /* Though there should be no interrupts (device was reset) - * power_down() expects the early IRQ to be installed as per the - * driver lifecycle. */ - ret_early = ath10k_pci_request_early_irq(ar); - if (ret_early) - ath10k_warn("failed to re-enable early irq: %d\n", ret_early); return ret; } @@ -1302,7 +1243,6 @@ static void ath10k_pci_ce_deinit(struct ath10k *ar) static void ath10k_pci_hif_stop(struct ath10k *ar) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - int ret; ath10k_dbg(ATH10K_DBG_BOOT, "boot hif stop\n"); @@ -1310,17 +1250,7 @@ static void ath10k_pci_hif_stop(struct ath10k *ar) return; ath10k_pci_irq_disable(ar); - ath10k_pci_free_irq(ar); ath10k_pci_kill_tasklet(ar); - - ret = ath10k_pci_request_early_irq(ar); - if (ret) - ath10k_warn("failed to re-enable early irq: %d\n", ret); - - /* At this point, asynchronous threads are stopped, the target should - * not DMA nor interrupt. We process the leftovers and then free - * everything else up. */ - ath10k_pci_buffer_cleanup(ar); /* Make the sure the device won't access any structures on the host by @@ -1806,28 +1736,19 @@ static int ath10k_pci_ce_init(struct ath10k *ar) return 0; } -static void ath10k_pci_fw_interrupt_handler(struct ath10k *ar) +static bool ath10k_pci_has_fw_crashed(struct ath10k *ar) { - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - u32 fw_indicator; + return ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS) & + FW_IND_EVENT_PENDING; +} - fw_indicator = ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS); +static void ath10k_pci_fw_crashed_clear(struct ath10k *ar) +{ + u32 val; - if (fw_indicator & FW_IND_EVENT_PENDING) { - /* ACK: clear Target-side pending event */ - ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS, - fw_indicator & ~FW_IND_EVENT_PENDING); - - if (ar_pci->started) { - ath10k_pci_fw_crashed_dump(ar); - } else { - /* - * Probable Target failure before we're prepared - * to handle it. Generally unexpected. - */ - ath10k_warn("early firmware event indicated\n"); - } - } + val = ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS); + val &= ~FW_IND_EVENT_PENDING; + ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS, val); } /* this function effectively clears target memory controller assert line */ @@ -1960,34 +1881,26 @@ static int __ath10k_pci_hif_power_up(struct ath10k *ar, bool cold_reset) goto err; } - ret = ath10k_pci_request_early_irq(ar); - if (ret) { - ath10k_err("failed to request early irq: %d\n", ret); - goto err_ce; - } - ret = ath10k_pci_wait_for_target_init(ar); if (ret) { ath10k_err("failed to wait for target to init: %d\n", ret); - goto err_free_early_irq; + goto err_ce; } ret = ath10k_pci_init_config(ar); if (ret) { ath10k_err("failed to setup init config: %d\n", ret); - goto err_free_early_irq; + goto err_ce; } ret = ath10k_pci_wake_target_cpu(ar); if (ret) { ath10k_err("could not wake up target CPU: %d\n", ret); - goto err_free_early_irq; + goto err_ce; } return 0; -err_free_early_irq: - ath10k_pci_free_early_irq(ar); err_ce: ath10k_pci_ce_deinit(ar); ath10k_pci_warm_reset(ar); @@ -2056,8 +1969,6 @@ static void ath10k_pci_hif_power_down(struct ath10k *ar) { ath10k_dbg(ATH10K_DBG_BOOT, "boot hif power down\n"); - ath10k_pci_free_early_irq(ar); - ath10k_pci_kill_tasklet(ar); ath10k_pci_warm_reset(ar); } @@ -2140,7 +2051,13 @@ static void ath10k_msi_err_tasklet(unsigned long data) { struct ath10k *ar = (struct ath10k *)data; - ath10k_pci_fw_interrupt_handler(ar); + if (!ath10k_pci_has_fw_crashed(ar)) { + ath10k_warn("received unsolicited fw crash interrupt\n"); + return; + } + + ath10k_pci_fw_crashed_clear(ar); + ath10k_pci_fw_crashed_dump(ar); } /* @@ -2201,27 +2118,17 @@ static irqreturn_t ath10k_pci_interrupt_handler(int irq, void *arg) return IRQ_HANDLED; } -static void ath10k_pci_early_irq_tasklet(unsigned long data) -{ - struct ath10k *ar = (struct ath10k *)data; - u32 fw_ind; - - fw_ind = ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS); - if (fw_ind & FW_IND_EVENT_PENDING) { - ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS, - fw_ind & ~FW_IND_EVENT_PENDING); - ath10k_pci_fw_crashed_dump(ar); - } - - ath10k_pci_enable_legacy_irq(ar); -} - static void ath10k_pci_tasklet(unsigned long data) { struct ath10k *ar = (struct ath10k *)data; struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - ath10k_pci_fw_interrupt_handler(ar); /* FIXME: Handle FW error */ + if (ath10k_pci_has_fw_crashed(ar)) { + ath10k_pci_fw_crashed_clear(ar); + ath10k_pci_fw_crashed_dump(ar); + return; + } + ath10k_ce_per_engine_service_any(ar); /* Re-enable legacy irq that was disabled in the irq handler */ @@ -2332,8 +2239,6 @@ static void ath10k_pci_init_irq_tasklets(struct ath10k *ar) tasklet_init(&ar_pci->intr_tq, ath10k_pci_tasklet, (unsigned long)ar); tasklet_init(&ar_pci->msi_fw_err, ath10k_msi_err_tasklet, (unsigned long)ar); - tasklet_init(&ar_pci->early_irq_tasklet, ath10k_pci_early_irq_tasklet, - (unsigned long)ar); for (i = 0; i < CE_COUNT; i++) { ar_pci->pipe_info[i].ar_pci = ar_pci; @@ -2459,8 +2364,7 @@ static int ath10k_pci_wait_for_target_init(struct ath10k *ar) if (val & FW_IND_EVENT_PENDING) { ath10k_warn("device has crashed during init\n"); - ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS, - val & ~FW_IND_EVENT_PENDING); + ath10k_pci_fw_crashed_clear(ar); ath10k_pci_fw_crashed_dump(ar); return -ECOMM; } @@ -2643,6 +2547,13 @@ static int ath10k_pci_probe(struct pci_dev *pdev, goto err_free_ce; } + /* Workaround: There's no known way to mask all possible interrupts via + * device CSR. The only way to make sure device doesn't assert + * interrupts is to reset it. Interrupts are then disabled on host + * after handlers are registered. + */ + ath10k_pci_warm_reset(ar); + ret = ath10k_pci_init_irq(ar); if (ret) { ath10k_err("failed to init irqs: %d\n", ret); @@ -2653,14 +2564,26 @@ static int ath10k_pci_probe(struct pci_dev *pdev, ath10k_pci_get_irq_method(ar), ar_pci->num_msi_intrs, ath10k_pci_irq_mode, ath10k_pci_reset_mode); - ret = ath10k_core_register(ar, chip_id); + ret = ath10k_pci_request_irq(ar); if (ret) { - ath10k_err("failed to register driver core: %d\n", ret); + ath10k_warn("failed to request irqs: %d\n", ret); goto err_deinit_irq; } + /* This shouldn't race as the device has been reset above. */ + ath10k_pci_irq_disable(ar); + + ret = ath10k_core_register(ar, chip_id); + if (ret) { + ath10k_err("failed to register driver core: %d\n", ret); + goto err_free_irq; + } + return 0; +err_free_irq: + ath10k_pci_free_irq(ar); + err_deinit_irq: ath10k_pci_deinit_irq(ar); @@ -2695,6 +2618,7 @@ static void ath10k_pci_remove(struct pci_dev *pdev) return; ath10k_core_unregister(ar); + ath10k_pci_free_irq(ar); ath10k_pci_deinit_irq(ar); ath10k_pci_ce_deinit(ar); ath10k_pci_free_ce(ar); diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h index 294a72e01909..caed918c7102 100644 --- a/drivers/net/wireless/ath/ath10k/pci.h +++ b/drivers/net/wireless/ath/ath10k/pci.h @@ -166,7 +166,6 @@ struct ath10k_pci { struct tasklet_struct intr_tq; struct tasklet_struct msi_fw_err; - struct tasklet_struct early_irq_tasklet; int started; From 728f95eef5238bffdb20e511f5cd553321d404c3 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Fri, 22 Aug 2014 14:33:14 +0200 Subject: [PATCH 083/221] ath10k: rework posting pci rx buffers It was possible on a host system running low on memory to end up with no rx buffers on pci pipes. This makes the driver more robust as it won't fail to start if it can't allocate all rx buffers right away. If it is fatal then upper layers will notice trouble anyway. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/ce.c | 77 +++++---- drivers/net/wireless/ath/ath10k/ce.h | 16 +- drivers/net/wireless/ath/ath10k/pci.c | 232 +++++++++++++------------- drivers/net/wireless/ath/ath10k/pci.h | 2 + 4 files changed, 163 insertions(+), 164 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index 8cbc0ab8ad42..f6668162a0a8 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c @@ -385,44 +385,59 @@ int ath10k_ce_num_free_src_entries(struct ath10k_ce_pipe *pipe) return delta; } -int ath10k_ce_recv_buf_enqueue(struct ath10k_ce_pipe *ce_state, - void *per_recv_context, - u32 buffer) + +int __ath10k_ce_rx_num_free_bufs(struct ath10k_ce_pipe *pipe) { - struct ath10k_ce_ring *dest_ring = ce_state->dest_ring; - u32 ctrl_addr = ce_state->ctrl_addr; - struct ath10k *ar = ce_state->ar; + struct ath10k *ar = pipe->ar; struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + struct ath10k_ce_ring *dest_ring = pipe->dest_ring; unsigned int nentries_mask = dest_ring->nentries_mask; - unsigned int write_index; - unsigned int sw_index; + unsigned int write_index = dest_ring->write_index; + unsigned int sw_index = dest_ring->sw_index; + + lockdep_assert_held(&ar_pci->ce_lock); + + return CE_RING_DELTA(nentries_mask, write_index, sw_index - 1); +} + +int __ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, u32 paddr) +{ + struct ath10k *ar = pipe->ar; + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + struct ath10k_ce_ring *dest_ring = pipe->dest_ring; + unsigned int nentries_mask = dest_ring->nentries_mask; + unsigned int write_index = dest_ring->write_index; + unsigned int sw_index = dest_ring->sw_index; + struct ce_desc *base = dest_ring->base_addr_owner_space; + struct ce_desc *desc = CE_DEST_RING_TO_DESC(base, write_index); + u32 ctrl_addr = pipe->ctrl_addr; + + lockdep_assert_held(&ar_pci->ce_lock); + + if (CE_RING_DELTA(nentries_mask, write_index, sw_index - 1) == 0) + return -EIO; + + desc->addr = __cpu_to_le32(paddr); + desc->nbytes = 0; + + dest_ring->per_transfer_context[write_index] = ctx; + write_index = CE_RING_IDX_INCR(nentries_mask, write_index); + ath10k_ce_dest_ring_write_index_set(ar, ctrl_addr, write_index); + dest_ring->write_index = write_index; + + return 0; +} + +int ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, u32 paddr) +{ + struct ath10k *ar = pipe->ar; + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); int ret; spin_lock_bh(&ar_pci->ce_lock); - write_index = dest_ring->write_index; - sw_index = dest_ring->sw_index; - - if (CE_RING_DELTA(nentries_mask, write_index, sw_index - 1) > 0) { - struct ce_desc *base = dest_ring->base_addr_owner_space; - struct ce_desc *desc = CE_DEST_RING_TO_DESC(base, write_index); - - /* Update destination descriptor */ - desc->addr = __cpu_to_le32(buffer); - desc->nbytes = 0; - - dest_ring->per_transfer_context[write_index] = - per_recv_context; - - /* Update Destination Ring Write Index */ - write_index = CE_RING_IDX_INCR(nentries_mask, write_index); - ath10k_ce_dest_ring_write_index_set(ar, ctrl_addr, write_index); - dest_ring->write_index = write_index; - ret = 0; - } else { - ret = -EIO; - } - + ret = __ath10k_ce_rx_post_buf(pipe, ctx, paddr); spin_unlock_bh(&ar_pci->ce_lock); + return ret; } diff --git a/drivers/net/wireless/ath/ath10k/ce.h b/drivers/net/wireless/ath/ath10k/ce.h index d48dbb972004..82d1f23546b9 100644 --- a/drivers/net/wireless/ath/ath10k/ce.h +++ b/drivers/net/wireless/ath/ath10k/ce.h @@ -166,19 +166,9 @@ int ath10k_ce_num_free_src_entries(struct ath10k_ce_pipe *pipe); /*==================Recv=======================*/ -/* - * Make a buffer available to receive. The buffer must be at least of a - * minimal size appropriate for this copy engine (src_sz_max attribute). - * ce - which copy engine to use - * per_transfer_recv_context - context passed back to caller's recv_cb - * buffer - address of buffer in CE space - * Returns 0 on success; otherwise an error status. - * - * Implemenation note: Pushes a buffer to Dest ring. - */ -int ath10k_ce_recv_buf_enqueue(struct ath10k_ce_pipe *ce_state, - void *per_transfer_recv_context, - u32 buffer); +int __ath10k_ce_rx_num_free_bufs(struct ath10k_ce_pipe *pipe); +int __ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, u32 paddr); +int ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, u32 paddr); /* recv flags */ /* Data is byte-swapped */ diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index ffb980c5080d..21f7dc3fb57e 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -67,10 +67,7 @@ static DEFINE_PCI_DEVICE_TABLE(ath10k_pci_id_table) = { static int ath10k_pci_diag_read_access(struct ath10k *ar, u32 address, u32 *data); -static int ath10k_pci_post_rx(struct ath10k *ar); -static int ath10k_pci_post_rx_pipe(struct ath10k_pci_pipe *pipe_info, - int num); -static void ath10k_pci_rx_pipe_cleanup(struct ath10k_pci_pipe *pipe_info); +static void ath10k_pci_buffer_cleanup(struct ath10k *ar); static int ath10k_pci_cold_reset(struct ath10k *ar); static int ath10k_pci_warm_reset(struct ath10k *ar); static int ath10k_pci_wait_for_target_init(struct ath10k *ar); @@ -278,6 +275,101 @@ static inline const char *ath10k_pci_get_irq_method(struct ath10k *ar) return "legacy"; } +static int __ath10k_pci_rx_post_buf(struct ath10k_pci_pipe *pipe) +{ + struct ath10k *ar = pipe->hif_ce_state; + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + struct ath10k_ce_pipe *ce_pipe = pipe->ce_hdl; + struct sk_buff *skb; + dma_addr_t paddr; + int ret; + + lockdep_assert_held(&ar_pci->ce_lock); + + skb = dev_alloc_skb(pipe->buf_sz); + if (!skb) + return -ENOMEM; + + WARN_ONCE((unsigned long)skb->data & 3, "unaligned skb"); + + paddr = dma_map_single(ar->dev, skb->data, + skb->len + skb_tailroom(skb), + DMA_FROM_DEVICE); + if (unlikely(dma_mapping_error(ar->dev, paddr))) { + ath10k_warn("failed to dma map pci rx buf\n"); + dev_kfree_skb_any(skb); + return -EIO; + } + + ATH10K_SKB_CB(skb)->paddr = paddr; + + ret = __ath10k_ce_rx_post_buf(ce_pipe, skb, paddr); + if (ret) { + ath10k_warn("failed to post pci rx buf: %d\n", ret); + dma_unmap_single(ar->dev, paddr, skb->len + skb_tailroom(skb), + DMA_FROM_DEVICE); + dev_kfree_skb_any(skb); + return ret; + } + + return 0; +} + +static void __ath10k_pci_rx_post_pipe(struct ath10k_pci_pipe *pipe) +{ + struct ath10k *ar = pipe->hif_ce_state; + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + struct ath10k_ce_pipe *ce_pipe = pipe->ce_hdl; + int ret, num; + + lockdep_assert_held(&ar_pci->ce_lock); + + if (pipe->buf_sz == 0) + return; + + if (!ce_pipe->dest_ring) + return; + + num = __ath10k_ce_rx_num_free_bufs(ce_pipe); + while (num--) { + ret = __ath10k_pci_rx_post_buf(pipe); + if (ret) { + ath10k_warn("failed to post pci rx buf: %d\n", ret); + mod_timer(&ar_pci->rx_post_retry, jiffies + + ATH10K_PCI_RX_POST_RETRY_MS); + break; + } + } +} + +static void ath10k_pci_rx_post_pipe(struct ath10k_pci_pipe *pipe) +{ + struct ath10k *ar = pipe->hif_ce_state; + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + + spin_lock_bh(&ar_pci->ce_lock); + __ath10k_pci_rx_post_pipe(pipe); + spin_unlock_bh(&ar_pci->ce_lock); +} + +static void ath10k_pci_rx_post(struct ath10k *ar) +{ + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + int i; + + spin_lock_bh(&ar_pci->ce_lock); + for (i = 0; i < CE_COUNT; i++) + __ath10k_pci_rx_post_pipe(&ar_pci->pipe_info[i]); + spin_unlock_bh(&ar_pci->ce_lock); +} + +static void ath10k_pci_rx_replenish_retry(unsigned long ptr) +{ + struct ath10k *ar = (void *)ptr; + + ath10k_pci_rx_post(ar); +} + /* * Diagnostic read/write access is provided for startup/config/debug usage. * Caller must guarantee proper alignment, when applicable, and single user @@ -344,7 +436,7 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data, nbytes = min_t(unsigned int, remaining_bytes, DIAG_TRANSFER_LIMIT); - ret = ath10k_ce_recv_buf_enqueue(ce_diag, NULL, ce_data); + ret = ath10k_ce_rx_post_buf(ce_diag, NULL, ce_data); if (ret != 0) goto done; @@ -534,7 +626,7 @@ static int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address, nbytes = min_t(int, remaining_bytes, DIAG_TRANSFER_LIMIT); /* Set up to receive directly into Target(!) address */ - ret = ath10k_ce_recv_buf_enqueue(ce_diag, NULL, address); + ret = ath10k_ce_rx_post_buf(ce_diag, NULL, address); if (ret != 0) goto done; @@ -696,12 +788,10 @@ static void ath10k_pci_ce_recv_data(struct ath10k_ce_pipe *ce_state) unsigned int nbytes, max_nbytes; unsigned int transfer_id; unsigned int flags; - int err, num_replenish = 0; while (ath10k_ce_completed_recv_next(ce_state, &transfer_context, &ce_data, &nbytes, &transfer_id, &flags) == 0) { - num_replenish++; skb = transfer_context; max_nbytes = skb->len + skb_tailroom(skb); dma_unmap_single(ar->dev, ATH10K_SKB_CB(skb)->paddr, @@ -718,12 +808,7 @@ static void ath10k_pci_ce_recv_data(struct ath10k_ce_pipe *ce_state) cb->rx_completion(ar, skb, pipe_info->pipe_num); } - err = ath10k_pci_post_rx_pipe(pipe_info, num_replenish); - if (unlikely(err)) { - /* FIXME: retry */ - ath10k_warn("failed to replenish CE rx ring %d (%d bufs): %d\n", - pipe_info->pipe_num, num_replenish, err); - } + ath10k_pci_rx_post_pipe(pipe_info); } static int ath10k_pci_hif_tx_sg(struct ath10k *ar, u8 pipe_id, @@ -911,6 +996,8 @@ static void ath10k_pci_kill_tasklet(struct ath10k *ar) for (i = 0; i < CE_COUNT; i++) tasklet_kill(&ar_pci->pipe_info[i].intr); + + del_timer_sync(&ar_pci->rx_post_retry); } /* TODO - temporary mapping while we have too few CE's */ @@ -992,94 +1079,6 @@ static void ath10k_pci_hif_get_default_pipe(struct ath10k *ar, &dl_is_polled); } -static int ath10k_pci_post_rx_pipe(struct ath10k_pci_pipe *pipe_info, - int num) -{ - struct ath10k *ar = pipe_info->hif_ce_state; - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - struct ath10k_ce_pipe *ce_state = pipe_info->ce_hdl; - struct sk_buff *skb; - dma_addr_t ce_data; - int i, ret = 0; - - if (pipe_info->buf_sz == 0) - return 0; - - for (i = 0; i < num; i++) { - skb = dev_alloc_skb(pipe_info->buf_sz); - if (!skb) { - ath10k_warn("failed to allocate skbuff for pipe %d\n", - num); - ret = -ENOMEM; - goto err; - } - - WARN_ONCE((unsigned long)skb->data & 3, "unaligned skb"); - - ce_data = dma_map_single(ar->dev, skb->data, - skb->len + skb_tailroom(skb), - DMA_FROM_DEVICE); - - if (unlikely(dma_mapping_error(ar->dev, ce_data))) { - ath10k_warn("failed to DMA map sk_buff\n"); - dev_kfree_skb_any(skb); - ret = -EIO; - goto err; - } - - ATH10K_SKB_CB(skb)->paddr = ce_data; - - pci_dma_sync_single_for_device(ar_pci->pdev, ce_data, - pipe_info->buf_sz, - PCI_DMA_FROMDEVICE); - - ret = ath10k_ce_recv_buf_enqueue(ce_state, (void *)skb, - ce_data); - if (ret) { - ath10k_warn("failed to enqueue to pipe %d: %d\n", - num, ret); - goto err; - } - } - - return ret; - -err: - ath10k_pci_rx_pipe_cleanup(pipe_info); - return ret; -} - -static int ath10k_pci_post_rx(struct ath10k *ar) -{ - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - struct ath10k_pci_pipe *pipe_info; - const struct ce_attr *attr; - int pipe_num, ret = 0; - - for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) { - pipe_info = &ar_pci->pipe_info[pipe_num]; - attr = &host_ce_config_wlan[pipe_num]; - - if (attr->dest_nentries == 0) - continue; - - ret = ath10k_pci_post_rx_pipe(pipe_info, - attr->dest_nentries - 1); - if (ret) { - ath10k_warn("failed to post RX buffer for pipe %d: %d\n", - pipe_num, ret); - - for (; pipe_num >= 0; pipe_num--) { - pipe_info = &ar_pci->pipe_info[pipe_num]; - ath10k_pci_rx_pipe_cleanup(pipe_info); - } - return ret; - } - } - - return 0; -} - static void ath10k_pci_irq_disable(struct ath10k *ar) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); @@ -1117,28 +1116,14 @@ static void ath10k_pci_irq_enable(struct ath10k *ar) static int ath10k_pci_hif_start(struct ath10k *ar) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - int ret; ath10k_dbg(ATH10K_DBG_BOOT, "boot hif start\n"); ath10k_pci_irq_enable(ar); - - /* Post buffers once to start things off. */ - ret = ath10k_pci_post_rx(ar); - if (ret) { - ath10k_warn("failed to post RX buffers for all pipes: %d\n", - ret); - goto err_stop; - } + ath10k_pci_rx_post(ar); ar_pci->started = 1; return 0; - -err_stop: - ath10k_pci_irq_disable(ar); - ath10k_pci_kill_tasklet(ar); - - return ret; } static void ath10k_pci_rx_pipe_cleanup(struct ath10k_pci_pipe *pipe_info) @@ -1240,6 +1225,12 @@ static void ath10k_pci_ce_deinit(struct ath10k *ar) ath10k_ce_deinit_pipe(ar, i); } +static void ath10k_pci_flush(struct ath10k *ar) +{ + ath10k_pci_kill_tasklet(ar); + ath10k_pci_buffer_cleanup(ar); +} + static void ath10k_pci_hif_stop(struct ath10k *ar) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); @@ -1250,8 +1241,7 @@ static void ath10k_pci_hif_stop(struct ath10k *ar) return; ath10k_pci_irq_disable(ar); - ath10k_pci_kill_tasklet(ar); - ath10k_pci_buffer_cleanup(ar); + ath10k_pci_flush(ar); /* Make the sure the device won't access any structures on the host by * resetting it. The device was fed with PCI CE ringbuffer @@ -1311,7 +1301,7 @@ static int ath10k_pci_hif_exchange_bmi_msg(struct ath10k *ar, xfer.wait_for_resp = true; xfer.resp_len = 0; - ath10k_ce_recv_buf_enqueue(ce_rx, &xfer, resp_paddr); + ath10k_ce_rx_post_buf(ce_rx, &xfer, resp_paddr); } ret = ath10k_ce_send(ce_tx, &xfer, req_paddr, req_len, -1, 0); @@ -2513,6 +2503,8 @@ static int ath10k_pci_probe(struct pci_dev *pdev, ar_pci->ar = ar; spin_lock_init(&ar_pci->ce_lock); + setup_timer(&ar_pci->rx_post_retry, ath10k_pci_rx_replenish_retry, + (unsigned long)ar); ret = ath10k_pci_claim(ar); if (ret) { diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h index caed918c7102..b9aa692d22f1 100644 --- a/drivers/net/wireless/ath/ath10k/pci.h +++ b/drivers/net/wireless/ath/ath10k/pci.h @@ -181,6 +181,7 @@ struct ath10k_pci { /* Map CE id to ce_state */ struct ath10k_ce_pipe ce_states[CE_COUNT_MAX]; + struct timer_list rx_post_retry; }; static inline struct ath10k_pci *ath10k_pci_priv(struct ath10k *ar) @@ -188,6 +189,7 @@ static inline struct ath10k_pci *ath10k_pci_priv(struct ath10k *ar) return (struct ath10k_pci *)ar->drv_priv; } +#define ATH10K_PCI_RX_POST_RETRY_MS 50 #define ATH_PCI_RESET_WAIT_MAX 10 /* ms */ #define PCIE_WAKE_TIMEOUT 5000 /* 5ms */ From 10d23db44a6ab4bb454228e9e97ef19455522627 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Fri, 22 Aug 2014 14:33:15 +0200 Subject: [PATCH 084/221] ath10k: update comment regarding warm reset The old comment was a little out of date. HTT Rx ring is a more relevant problem when stopping transport layer. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 21f7dc3fb57e..daa38ce29c5e 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -1243,11 +1243,10 @@ static void ath10k_pci_hif_stop(struct ath10k *ar) ath10k_pci_irq_disable(ar); ath10k_pci_flush(ar); - /* Make the sure the device won't access any structures on the host by - * resetting it. The device was fed with PCI CE ringbuffer - * configuration during init. If ringbuffers are freed and the device - * were to access them this could lead to memory corruption on the - * host. */ + /* Most likely the device has HTT Rx ring configured. The only way to + * prevent the device from accessing (and possible corrupting) host + * memory is to reset the chip now. + */ ath10k_pci_warm_reset(ar); ar_pci->started = 0; From cf5dd36d96d725f798e82038463f7066ddda482a Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Fri, 22 Aug 2014 14:33:16 +0200 Subject: [PATCH 085/221] ath10k: ignore ar_pci->started in pipe cleanup Structures used by these functions are now guaranteed to remain accessible until driver is unregistered. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index daa38ce29c5e..cb4049f8c7b8 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -1143,10 +1143,6 @@ static void ath10k_pci_rx_pipe_cleanup(struct ath10k_pci_pipe *pipe_info) ar = pipe_info->hif_ce_state; ar_pci = ath10k_pci_priv(ar); - - if (!ar_pci->started) - return; - ce_hdl = pipe_info->ce_hdl; while (ath10k_ce_revoke_recv_next(ce_hdl, (void **)&netbuf, @@ -1177,10 +1173,6 @@ static void ath10k_pci_tx_pipe_cleanup(struct ath10k_pci_pipe *pipe_info) ar = pipe_info->hif_ce_state; ar_pci = ath10k_pci_priv(ar); - - if (!ar_pci->started) - return; - ce_hdl = pipe_info->ce_hdl; while (ath10k_ce_cancel_send_next(ce_hdl, (void **)&netbuf, From 53b4e07354d4547b7ebb17b6eb63ce2694ad1479 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Fri, 22 Aug 2014 14:33:17 +0200 Subject: [PATCH 086/221] ath10k: remove ar_pci->started There are basically no more uses for ar_pci->started. It is also perfectly safe to call hif_stop without hif_start now. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 10 ---------- drivers/net/wireless/ath/ath10k/pci.h | 2 -- 2 files changed, 12 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index cb4049f8c7b8..3af462ab27f6 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -1115,14 +1115,11 @@ static void ath10k_pci_irq_enable(struct ath10k *ar) static int ath10k_pci_hif_start(struct ath10k *ar) { - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - ath10k_dbg(ATH10K_DBG_BOOT, "boot hif start\n"); ath10k_pci_irq_enable(ar); ath10k_pci_rx_post(ar); - ar_pci->started = 1; return 0; } @@ -1225,13 +1222,8 @@ static void ath10k_pci_flush(struct ath10k *ar) static void ath10k_pci_hif_stop(struct ath10k *ar) { - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - ath10k_dbg(ATH10K_DBG_BOOT, "boot hif stop\n"); - if (WARN_ON(!ar_pci->started)) - return; - ath10k_pci_irq_disable(ar); ath10k_pci_flush(ar); @@ -1240,8 +1232,6 @@ static void ath10k_pci_hif_stop(struct ath10k *ar) * memory is to reset the chip now. */ ath10k_pci_warm_reset(ar); - - ar_pci->started = 0; } static int ath10k_pci_hif_exchange_bmi_msg(struct ath10k *ar, diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h index b9aa692d22f1..d88928cf60ce 100644 --- a/drivers/net/wireless/ath/ath10k/pci.h +++ b/drivers/net/wireless/ath/ath10k/pci.h @@ -167,8 +167,6 @@ struct ath10k_pci { struct tasklet_struct intr_tq; struct tasklet_struct msi_fw_err; - int started; - struct ath10k_pci_pipe pipe_info[CE_COUNT_MAX]; struct ath10k_hif_cb msg_callbacks_current; From 61e9aab7a1930ae031d1b9d948837b5ffd8e3f5e Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Fri, 22 Aug 2014 14:33:18 +0200 Subject: [PATCH 087/221] ath10k: flush hif buffers before recovery Transport buffers weren't flushed and processed before queueing hw recovery request to mac80211. This could in theory result in an unwanted htt/wmi rx events being processed while mac80211 recovers the device and possibly interfere or even crash the system. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 23ba32175fcc..157dcf906f29 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -665,6 +665,7 @@ static void ath10k_core_restart(struct work_struct *work) switch (ar->state) { case ATH10K_STATE_ON: ar->state = ATH10K_STATE_RESTARTING; + ath10k_hif_stop(ar); ath10k_scan_finish(ar); ieee80211_restart_hw(ar->hw); break; From 6247d2aa5188ac0ace33d8390341075c04107218 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Thu, 31 Jul 2014 21:59:42 +0200 Subject: [PATCH 088/221] b43: update flushing many writes performed in a row MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Flush radio writes as well and add some tiny optimizations (e.g. masksetting PHY reg involves reading it, so reset the counter). Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/bus.h | 14 ++++++++++++++ drivers/net/wireless/b43/phy_common.c | 13 ++++++++++--- drivers/net/wireless/b43/phy_n.c | 1 + 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/b43/bus.h b/drivers/net/wireless/b43/bus.h index f3205c6988bc..460d9d90bdde 100644 --- a/drivers/net/wireless/b43/bus.h +++ b/drivers/net/wireless/b43/bus.h @@ -60,7 +60,21 @@ static inline bool b43_bus_host_is_pcmcia(struct b43_bus_dev *dev) #else return false; #endif +}; + +static inline bool b43_bus_host_is_pci(struct b43_bus_dev *dev) +{ +#ifdef CONFIG_B43_BCMA + if (dev->bus_type == B43_BUS_BCMA) + return (dev->bdev->bus->hosttype == BCMA_HOSTTYPE_PCI); +#endif +#ifdef CONFIG_B43_SSB + if (dev->bus_type == B43_BUS_SSB) + return (dev->sdev->bus->bustype == SSB_BUSTYPE_PCI); +#endif + return false; } + static inline bool b43_bus_host_is_sdio(struct b43_bus_dev *dev) { #ifdef CONFIG_B43_SSB diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c index 3cbef21b4726..c868748b3f9e 100644 --- a/drivers/net/wireless/b43/phy_common.c +++ b/drivers/net/wireless/b43/phy_common.c @@ -222,12 +222,18 @@ static inline void assert_mac_suspended(struct b43_wldev *dev) u16 b43_radio_read(struct b43_wldev *dev, u16 reg) { assert_mac_suspended(dev); + dev->phy.writes_counter = 0; return dev->phy.ops->radio_read(dev, reg); } void b43_radio_write(struct b43_wldev *dev, u16 reg, u16 value) { assert_mac_suspended(dev); + if (b43_bus_host_is_pci(dev->dev) && + ++dev->phy.writes_counter > B43_MAX_WRITES_IN_ROW) { + b43_read32(dev, B43_MMIO_MACCTL); + dev->phy.writes_counter = 1; + } dev->phy.ops->radio_write(dev, reg, value); } @@ -274,11 +280,12 @@ u16 b43_phy_read(struct b43_wldev *dev, u16 reg) void b43_phy_write(struct b43_wldev *dev, u16 reg, u16 value) { assert_mac_suspended(dev); - dev->phy.ops->phy_write(dev, reg, value); - if (++dev->phy.writes_counter == B43_MAX_WRITES_IN_ROW) { + if (b43_bus_host_is_pci(dev->dev) && + ++dev->phy.writes_counter > B43_MAX_WRITES_IN_ROW) { b43_read16(dev, B43_MMIO_PHY_VER); - dev->phy.writes_counter = 0; + dev->phy.writes_counter = 1; } + dev->phy.ops->phy_write(dev, reg, value); } void b43_phy_copy(struct b43_wldev *dev, u16 destreg, u16 srcreg) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index e2a3f0d5bcc2..b04aa34b0277 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -6517,6 +6517,7 @@ static void b43_nphy_op_maskset(struct b43_wldev *dev, u16 reg, u16 mask, check_phyreg(dev, reg); b43_write16(dev, B43_MMIO_PHY_CONTROL, reg); b43_maskset16(dev, B43_MMIO_PHY_DATA, mask, set); + dev->phy.writes_counter = 1; } static u16 b43_nphy_op_radio_read(struct b43_wldev *dev, u16 reg) From d342b95dd735014a590f9051b1ba227eb54ca8f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Thu, 31 Jul 2014 21:59:43 +0200 Subject: [PATCH 089/221] b43: don't duplicate common PHY read/write ops MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Most of the PHYs use the same way of accessing registers, so move that code to the shared place. An exception is G-PHY which sometimes access A-PHY regs and requires special handling. Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_common.c | 14 ++++++++++++-- drivers/net/wireless/b43/phy_ht.c | 14 -------------- drivers/net/wireless/b43/phy_lcn.c | 14 -------------- drivers/net/wireless/b43/phy_lp.c | 14 -------------- drivers/net/wireless/b43/phy_n.c | 16 ---------------- 5 files changed, 12 insertions(+), 60 deletions(-) diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c index c868748b3f9e..08ca524664e6 100644 --- a/drivers/net/wireless/b43/phy_common.c +++ b/drivers/net/wireless/b43/phy_common.c @@ -274,7 +274,12 @@ u16 b43_phy_read(struct b43_wldev *dev, u16 reg) { assert_mac_suspended(dev); dev->phy.writes_counter = 0; - return dev->phy.ops->phy_read(dev, reg); + + if (dev->phy.ops->phy_read) + return dev->phy.ops->phy_read(dev, reg); + + b43_write16(dev, B43_MMIO_PHY_CONTROL, reg); + return b43_read16(dev, B43_MMIO_PHY_DATA); } void b43_phy_write(struct b43_wldev *dev, u16 reg, u16 value) @@ -285,7 +290,12 @@ void b43_phy_write(struct b43_wldev *dev, u16 reg, u16 value) b43_read16(dev, B43_MMIO_PHY_VER); dev->phy.writes_counter = 1; } - dev->phy.ops->phy_write(dev, reg, value); + + if (dev->phy.ops->phy_write) + return dev->phy.ops->phy_write(dev, reg, value); + + b43_write16(dev, B43_MMIO_PHY_CONTROL, reg); + b43_write16(dev, B43_MMIO_PHY_DATA, value); } void b43_phy_copy(struct b43_wldev *dev, u16 destreg, u16 srcreg) diff --git a/drivers/net/wireless/b43/phy_ht.c b/drivers/net/wireless/b43/phy_ht.c index f2974c6b1c01..8b0b4b6852fd 100644 --- a/drivers/net/wireless/b43/phy_ht.c +++ b/drivers/net/wireless/b43/phy_ht.c @@ -1071,18 +1071,6 @@ static unsigned int b43_phy_ht_op_get_default_chan(struct b43_wldev *dev) * R/W ops. **************************************************/ -static u16 b43_phy_ht_op_read(struct b43_wldev *dev, u16 reg) -{ - b43_write16(dev, B43_MMIO_PHY_CONTROL, reg); - return b43_read16(dev, B43_MMIO_PHY_DATA); -} - -static void b43_phy_ht_op_write(struct b43_wldev *dev, u16 reg, u16 value) -{ - b43_write16(dev, B43_MMIO_PHY_CONTROL, reg); - b43_write16(dev, B43_MMIO_PHY_DATA, value); -} - static void b43_phy_ht_op_maskset(struct b43_wldev *dev, u16 reg, u16 mask, u16 set) { @@ -1126,8 +1114,6 @@ const struct b43_phy_operations b43_phyops_ht = { .free = b43_phy_ht_op_free, .prepare_structs = b43_phy_ht_op_prepare_structs, .init = b43_phy_ht_op_init, - .phy_read = b43_phy_ht_op_read, - .phy_write = b43_phy_ht_op_write, .phy_maskset = b43_phy_ht_op_maskset, .radio_read = b43_phy_ht_op_radio_read, .radio_write = b43_phy_ht_op_radio_write, diff --git a/drivers/net/wireless/b43/phy_lcn.c b/drivers/net/wireless/b43/phy_lcn.c index e76bbdf3247e..bf29c3eb0095 100644 --- a/drivers/net/wireless/b43/phy_lcn.c +++ b/drivers/net/wireless/b43/phy_lcn.c @@ -810,18 +810,6 @@ static void b43_phy_lcn_op_adjust_txpower(struct b43_wldev *dev) * R/W ops. **************************************************/ -static u16 b43_phy_lcn_op_read(struct b43_wldev *dev, u16 reg) -{ - b43_write16(dev, B43_MMIO_PHY_CONTROL, reg); - return b43_read16(dev, B43_MMIO_PHY_DATA); -} - -static void b43_phy_lcn_op_write(struct b43_wldev *dev, u16 reg, u16 value) -{ - b43_write16(dev, B43_MMIO_PHY_CONTROL, reg); - b43_write16(dev, B43_MMIO_PHY_DATA, value); -} - static void b43_phy_lcn_op_maskset(struct b43_wldev *dev, u16 reg, u16 mask, u16 set) { @@ -855,8 +843,6 @@ const struct b43_phy_operations b43_phyops_lcn = { .free = b43_phy_lcn_op_free, .prepare_structs = b43_phy_lcn_op_prepare_structs, .init = b43_phy_lcn_op_init, - .phy_read = b43_phy_lcn_op_read, - .phy_write = b43_phy_lcn_op_write, .phy_maskset = b43_phy_lcn_op_maskset, .radio_read = b43_phy_lcn_op_radio_read, .radio_write = b43_phy_lcn_op_radio_write, diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index 92190dacf689..1e9bae68b621 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -1985,18 +1985,6 @@ static void lpphy_calibration(struct b43_wldev *dev) b43_mac_enable(dev); } -static u16 b43_lpphy_op_read(struct b43_wldev *dev, u16 reg) -{ - b43_write16(dev, B43_MMIO_PHY_CONTROL, reg); - return b43_read16(dev, B43_MMIO_PHY_DATA); -} - -static void b43_lpphy_op_write(struct b43_wldev *dev, u16 reg, u16 value) -{ - b43_write16(dev, B43_MMIO_PHY_CONTROL, reg); - b43_write16(dev, B43_MMIO_PHY_DATA, value); -} - static void b43_lpphy_op_maskset(struct b43_wldev *dev, u16 reg, u16 mask, u16 set) { @@ -2713,8 +2701,6 @@ const struct b43_phy_operations b43_phyops_lp = { .free = b43_lpphy_op_free, .prepare_structs = b43_lpphy_op_prepare_structs, .init = b43_lpphy_op_init, - .phy_read = b43_lpphy_op_read, - .phy_write = b43_lpphy_op_write, .phy_maskset = b43_lpphy_op_maskset, .radio_read = b43_lpphy_op_radio_read, .radio_write = b43_lpphy_op_radio_write, diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index b04aa34b0277..55653186b575 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -6497,20 +6497,6 @@ static inline void check_phyreg(struct b43_wldev *dev, u16 offset) #endif /* B43_DEBUG */ } -static u16 b43_nphy_op_read(struct b43_wldev *dev, u16 reg) -{ - check_phyreg(dev, reg); - b43_write16(dev, B43_MMIO_PHY_CONTROL, reg); - return b43_read16(dev, B43_MMIO_PHY_DATA); -} - -static void b43_nphy_op_write(struct b43_wldev *dev, u16 reg, u16 value) -{ - check_phyreg(dev, reg); - b43_write16(dev, B43_MMIO_PHY_CONTROL, reg); - b43_write16(dev, B43_MMIO_PHY_DATA, value); -} - static void b43_nphy_op_maskset(struct b43_wldev *dev, u16 reg, u16 mask, u16 set) { @@ -6653,8 +6639,6 @@ const struct b43_phy_operations b43_phyops_n = { .free = b43_nphy_op_free, .prepare_structs = b43_nphy_op_prepare_structs, .init = b43_nphy_op_init, - .phy_read = b43_nphy_op_read, - .phy_write = b43_nphy_op_write, .phy_maskset = b43_nphy_op_maskset, .radio_read = b43_nphy_op_radio_read, .radio_write = b43_nphy_op_radio_write, From 25c15566635fef86e87f762f73a19f24598e45fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Thu, 7 Aug 2014 07:45:37 +0200 Subject: [PATCH 090/221] b43: flush some writes on Broadcom MIPS SoCs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Access to PHY and radio registers is indirect on Broadcom hardware and it seems that addressing on some MIPS SoCs may require flushing. So far this problem was noticed on 0x4716 SoC only (marketing names: BCM4717, BCM4718). Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/b43.h | 10 ++++++++++ drivers/net/wireless/b43/bus.c | 10 ++++++++++ drivers/net/wireless/b43/bus.h | 1 + drivers/net/wireless/b43/main.c | 17 ++++++++--------- drivers/net/wireless/b43/phy_a.c | 4 ++-- drivers/net/wireless/b43/phy_common.c | 4 ++-- drivers/net/wireless/b43/phy_g.c | 8 ++++---- drivers/net/wireless/b43/phy_ht.c | 6 +++--- drivers/net/wireless/b43/phy_lcn.c | 6 +++--- drivers/net/wireless/b43/phy_lp.c | 6 +++--- drivers/net/wireless/b43/phy_n.c | 6 +++--- 11 files changed, 49 insertions(+), 29 deletions(-) diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index 4113b6934764..9b2d0c9bfb8e 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -1012,6 +1012,16 @@ static inline void b43_write16(struct b43_wldev *dev, u16 offset, u16 value) dev->dev->write16(dev->dev, offset, value); } +/* To optimize this check for flush_writes on BCM47XX_BCMA only. */ +static inline void b43_write16f(struct b43_wldev *dev, u16 offset, u16 value) +{ + b43_write16(dev, offset, value); +#if defined(CONFIG_BCM47XX_BCMA) + if (dev->dev->flush_writes) + b43_read16(dev, offset); +#endif +} + static inline void b43_maskset16(struct b43_wldev *dev, u16 offset, u16 mask, u16 set) { diff --git a/drivers/net/wireless/b43/bus.c b/drivers/net/wireless/b43/bus.c index 565fdbdd6915..17d16a391fe6 100644 --- a/drivers/net/wireless/b43/bus.c +++ b/drivers/net/wireless/b43/bus.c @@ -22,6 +22,10 @@ */ +#ifdef CONFIG_BCM47XX_BCMA +#include +#endif + #include "b43.h" #include "bus.h" @@ -102,6 +106,12 @@ struct b43_bus_dev *b43_bus_dev_bcma_init(struct bcma_device *core) dev->write32 = b43_bus_bcma_write32; dev->block_read = b43_bus_bcma_block_read; dev->block_write = b43_bus_bcma_block_write; +#ifdef CONFIG_BCM47XX_BCMA + if (b43_bus_host_is_pci(dev) && + bcm47xx_bus_type == BCM47XX_BUS_TYPE_BCMA && + bcm47xx_bus.bcma.bus.chipinfo.id == BCMA_CHIP_ID_BCM4716) + dev->flush_writes = true; +#endif dev->dev = &core->dev; dev->dma_dev = core->dma_dev; diff --git a/drivers/net/wireless/b43/bus.h b/drivers/net/wireless/b43/bus.h index 460d9d90bdde..256c2c17939a 100644 --- a/drivers/net/wireless/b43/bus.h +++ b/drivers/net/wireless/b43/bus.h @@ -33,6 +33,7 @@ struct b43_bus_dev { size_t count, u16 offset, u8 reg_width); void (*block_write)(struct b43_bus_dev *dev, const void *buffer, size_t count, u16 offset, u8 reg_width); + bool flush_writes; struct device *dev; struct device *dma_dev; diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 2af1ac396eb4..66ff718cc412 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -4466,10 +4466,10 @@ static int b43_phy_versioning(struct b43_wldev *dev) if (core_rev == 40 || core_rev == 42) { radio_manuf = 0x17F; - b43_write16(dev, B43_MMIO_RADIO24_CONTROL, 0); + b43_write16f(dev, B43_MMIO_RADIO24_CONTROL, 0); radio_rev = b43_read16(dev, B43_MMIO_RADIO24_DATA); - b43_write16(dev, B43_MMIO_RADIO24_CONTROL, 1); + b43_write16f(dev, B43_MMIO_RADIO24_CONTROL, 1); radio_id = b43_read16(dev, B43_MMIO_RADIO24_DATA); radio_ver = 0; /* Is there version somewhere? */ @@ -4477,7 +4477,7 @@ static int b43_phy_versioning(struct b43_wldev *dev) u16 radio24[3]; for (tmp = 0; tmp < 3; tmp++) { - b43_write16(dev, B43_MMIO_RADIO24_CONTROL, tmp); + b43_write16f(dev, B43_MMIO_RADIO24_CONTROL, tmp); radio24[tmp] = b43_read16(dev, B43_MMIO_RADIO24_DATA); } @@ -4494,13 +4494,12 @@ static int b43_phy_versioning(struct b43_wldev *dev) else tmp = 0x5205017F; } else { - b43_write16(dev, B43_MMIO_RADIO_CONTROL, - B43_RADIOCTL_ID); + b43_write16f(dev, B43_MMIO_RADIO_CONTROL, + B43_RADIOCTL_ID); tmp = b43_read16(dev, B43_MMIO_RADIO_DATA_LOW); - b43_write16(dev, B43_MMIO_RADIO_CONTROL, - B43_RADIOCTL_ID); - tmp |= (u32)b43_read16(dev, B43_MMIO_RADIO_DATA_HIGH) - << 16; + b43_write16f(dev, B43_MMIO_RADIO_CONTROL, + B43_RADIOCTL_ID); + tmp |= b43_read16(dev, B43_MMIO_RADIO_DATA_HIGH) << 16; } radio_manuf = (tmp & 0x00000FFF); radio_id = (tmp & 0x0FFFF000) >> 12; diff --git a/drivers/net/wireless/b43/phy_a.c b/drivers/net/wireless/b43/phy_a.c index 25e40432d68b..99c036f5ecb7 100644 --- a/drivers/net/wireless/b43/phy_a.c +++ b/drivers/net/wireless/b43/phy_a.c @@ -444,14 +444,14 @@ static inline u16 adjust_phyreg(struct b43_wldev *dev, u16 offset) static u16 b43_aphy_op_read(struct b43_wldev *dev, u16 reg) { reg = adjust_phyreg(dev, reg); - b43_write16(dev, B43_MMIO_PHY_CONTROL, reg); + b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg); return b43_read16(dev, B43_MMIO_PHY_DATA); } static void b43_aphy_op_write(struct b43_wldev *dev, u16 reg, u16 value) { reg = adjust_phyreg(dev, reg); - b43_write16(dev, B43_MMIO_PHY_CONTROL, reg); + b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg); b43_write16(dev, B43_MMIO_PHY_DATA, value); } diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c index 08ca524664e6..1dfc682a8055 100644 --- a/drivers/net/wireless/b43/phy_common.c +++ b/drivers/net/wireless/b43/phy_common.c @@ -278,7 +278,7 @@ u16 b43_phy_read(struct b43_wldev *dev, u16 reg) if (dev->phy.ops->phy_read) return dev->phy.ops->phy_read(dev, reg); - b43_write16(dev, B43_MMIO_PHY_CONTROL, reg); + b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg); return b43_read16(dev, B43_MMIO_PHY_DATA); } @@ -294,7 +294,7 @@ void b43_phy_write(struct b43_wldev *dev, u16 reg, u16 value) if (dev->phy.ops->phy_write) return dev->phy.ops->phy_write(dev, reg, value); - b43_write16(dev, B43_MMIO_PHY_CONTROL, reg); + b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg); b43_write16(dev, B43_MMIO_PHY_DATA, value); } diff --git a/drivers/net/wireless/b43/phy_g.c b/drivers/net/wireless/b43/phy_g.c index 8f5c14bc10e6..727ce6edb4b3 100644 --- a/drivers/net/wireless/b43/phy_g.c +++ b/drivers/net/wireless/b43/phy_g.c @@ -2555,13 +2555,13 @@ static void b43_gphy_op_exit(struct b43_wldev *dev) static u16 b43_gphy_op_read(struct b43_wldev *dev, u16 reg) { - b43_write16(dev, B43_MMIO_PHY_CONTROL, reg); + b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg); return b43_read16(dev, B43_MMIO_PHY_DATA); } static void b43_gphy_op_write(struct b43_wldev *dev, u16 reg, u16 value) { - b43_write16(dev, B43_MMIO_PHY_CONTROL, reg); + b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg); b43_write16(dev, B43_MMIO_PHY_DATA, value); } @@ -2572,7 +2572,7 @@ static u16 b43_gphy_op_radio_read(struct b43_wldev *dev, u16 reg) /* G-PHY needs 0x80 for read access. */ reg |= 0x80; - b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg); + b43_write16f(dev, B43_MMIO_RADIO_CONTROL, reg); return b43_read16(dev, B43_MMIO_RADIO_DATA_LOW); } @@ -2581,7 +2581,7 @@ static void b43_gphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value) /* Register 1 is a 32-bit register. */ B43_WARN_ON(reg == 1); - b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg); + b43_write16f(dev, B43_MMIO_RADIO_CONTROL, reg); b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, value); } diff --git a/drivers/net/wireless/b43/phy_ht.c b/drivers/net/wireless/b43/phy_ht.c index 8b0b4b6852fd..c4dc8b020f60 100644 --- a/drivers/net/wireless/b43/phy_ht.c +++ b/drivers/net/wireless/b43/phy_ht.c @@ -1074,7 +1074,7 @@ static unsigned int b43_phy_ht_op_get_default_chan(struct b43_wldev *dev) static void b43_phy_ht_op_maskset(struct b43_wldev *dev, u16 reg, u16 mask, u16 set) { - b43_write16(dev, B43_MMIO_PHY_CONTROL, reg); + b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg); b43_write16(dev, B43_MMIO_PHY_DATA, (b43_read16(dev, B43_MMIO_PHY_DATA) & mask) | set); } @@ -1084,14 +1084,14 @@ static u16 b43_phy_ht_op_radio_read(struct b43_wldev *dev, u16 reg) /* HT-PHY needs 0x200 for read access */ reg |= 0x200; - b43_write16(dev, B43_MMIO_RADIO24_CONTROL, reg); + b43_write16f(dev, B43_MMIO_RADIO24_CONTROL, reg); return b43_read16(dev, B43_MMIO_RADIO24_DATA); } static void b43_phy_ht_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value) { - b43_write16(dev, B43_MMIO_RADIO24_CONTROL, reg); + b43_write16f(dev, B43_MMIO_RADIO24_CONTROL, reg); b43_write16(dev, B43_MMIO_RADIO24_DATA, value); } diff --git a/drivers/net/wireless/b43/phy_lcn.c b/drivers/net/wireless/b43/phy_lcn.c index bf29c3eb0095..97461ccf3e1e 100644 --- a/drivers/net/wireless/b43/phy_lcn.c +++ b/drivers/net/wireless/b43/phy_lcn.c @@ -813,7 +813,7 @@ static void b43_phy_lcn_op_adjust_txpower(struct b43_wldev *dev) static void b43_phy_lcn_op_maskset(struct b43_wldev *dev, u16 reg, u16 mask, u16 set) { - b43_write16(dev, B43_MMIO_PHY_CONTROL, reg); + b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg); b43_write16(dev, B43_MMIO_PHY_DATA, (b43_read16(dev, B43_MMIO_PHY_DATA) & mask) | set); } @@ -823,14 +823,14 @@ static u16 b43_phy_lcn_op_radio_read(struct b43_wldev *dev, u16 reg) /* LCN-PHY needs 0x200 for read access */ reg |= 0x200; - b43_write16(dev, B43_MMIO_RADIO24_CONTROL, reg); + b43_write16f(dev, B43_MMIO_RADIO24_CONTROL, reg); return b43_read16(dev, B43_MMIO_RADIO24_DATA); } static void b43_phy_lcn_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value) { - b43_write16(dev, B43_MMIO_RADIO24_CONTROL, reg); + b43_write16f(dev, B43_MMIO_RADIO24_CONTROL, reg); b43_write16(dev, B43_MMIO_RADIO24_DATA, value); } diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index 1e9bae68b621..058a9f232050 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -1988,7 +1988,7 @@ static void lpphy_calibration(struct b43_wldev *dev) static void b43_lpphy_op_maskset(struct b43_wldev *dev, u16 reg, u16 mask, u16 set) { - b43_write16(dev, B43_MMIO_PHY_CONTROL, reg); + b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg); b43_write16(dev, B43_MMIO_PHY_DATA, (b43_read16(dev, B43_MMIO_PHY_DATA) & mask) | set); } @@ -2004,7 +2004,7 @@ static u16 b43_lpphy_op_radio_read(struct b43_wldev *dev, u16 reg) } else reg |= 0x200; - b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg); + b43_write16f(dev, B43_MMIO_RADIO_CONTROL, reg); return b43_read16(dev, B43_MMIO_RADIO_DATA_LOW); } @@ -2013,7 +2013,7 @@ static void b43_lpphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value) /* Register 1 is a 32-bit register. */ B43_WARN_ON(reg == 1); - b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg); + b43_write16f(dev, B43_MMIO_RADIO_CONTROL, reg); b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, value); } diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 55653186b575..df640325aa15 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -6501,7 +6501,7 @@ static void b43_nphy_op_maskset(struct b43_wldev *dev, u16 reg, u16 mask, u16 set) { check_phyreg(dev, reg); - b43_write16(dev, B43_MMIO_PHY_CONTROL, reg); + b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg); b43_maskset16(dev, B43_MMIO_PHY_DATA, mask, set); dev->phy.writes_counter = 1; } @@ -6516,7 +6516,7 @@ static u16 b43_nphy_op_radio_read(struct b43_wldev *dev, u16 reg) else reg |= 0x100; - b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg); + b43_write16f(dev, B43_MMIO_RADIO_CONTROL, reg); return b43_read16(dev, B43_MMIO_RADIO_DATA_LOW); } @@ -6525,7 +6525,7 @@ static void b43_nphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value) /* Register 1 is a 32-bit register. */ B43_WARN_ON(dev->phy.rev < 7 && reg == 1); - b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg); + b43_write16f(dev, B43_MMIO_RADIO_CONTROL, reg); b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, value); } From 33df85f662a0ee03f2b8e0c9d34a51d8dd0406c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Thu, 31 Jul 2014 21:59:45 +0200 Subject: [PATCH 091/221] b43: N-PHY: update rev3+ gain control workarounds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes workarounds on rev 6+ and cleans code slightly. Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/tables_nphy.c | 61 ++++++++++++++++---------- 1 file changed, 37 insertions(+), 24 deletions(-) diff --git a/drivers/net/wireless/b43/tables_nphy.c b/drivers/net/wireless/b43/tables_nphy.c index 4b5885077b01..f449cffc697b 100644 --- a/drivers/net/wireless/b43/tables_nphy.c +++ b/drivers/net/wireless/b43/tables_nphy.c @@ -3197,7 +3197,7 @@ static struct nphy_gain_ctl_workaround_entry nphy_gain_ctl_workaround[2][4] = { { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, 0x527E, /* invalid for external LNA! */ { 0x513F, 0x513F, 0x513F, 0x513F }, /* invalid for external LNA! */ - 0x1076, 0x0066, 0x0000, /* low is invalid (the last one) */ + 0x007E, 0x0066, 0x0000, /* low is invalid (the last one) */ 0x18, 0x18, 0x18, 0x01D0, 0x5, }, @@ -3711,6 +3711,7 @@ const u32 *b43_nphy_get_tx_gain_table(struct b43_wldev *dev) struct nphy_gain_ctl_workaround_entry *b43_nphy_get_gain_ctl_workaround_ent( struct b43_wldev *dev, bool ghz5, bool ext_lna) { + struct b43_phy *phy = &dev->phy; struct nphy_gain_ctl_workaround_entry *e; u8 phy_idx; @@ -3729,37 +3730,49 @@ struct nphy_gain_ctl_workaround_entry *b43_nphy_get_gain_ctl_workaround_ent( e = &nphy_gain_ctl_workaround[ghz5][phy_idx]; /* Some workarounds to the workarounds... */ - if (ghz5 && dev->phy.rev >= 6) { - if (dev->phy.radio_rev == 11 && - !b43_is_40mhz(dev)) - e->cliplo_gain = 0x2d; - } else if (!ghz5 && dev->phy.rev >= 5) { - static const int gain_data[] = {0x0062, 0x0064, 0x006a, 0x106a, - 0x106c, 0x1074, 0x107c, 0x207c}; + if (!ghz5) { u8 tr_iso = dev->dev->bus_sprom->fem.ghz2.tr_iso; - if (ext_lna) { + if (tr_iso > 7) + tr_iso = 3; + + if (phy->rev >= 6) { + static const int gain_data[] = { 0x106a, 0x106c, 0x1074, + 0x107c, 0x007e, 0x107e, + 0x207e, 0x307e, }; + + e->cliplo_gain = gain_data[tr_iso]; + } else if (phy->rev == 5) { + static const int gain_data[] = { 0x0062, 0x0064, 0x006a, + 0x106a, 0x106c, 0x1074, + 0x107c, 0x207c, }; + + e->cliplo_gain = gain_data[tr_iso]; + } + + if (phy->rev >= 5 && ext_lna) { e->rfseq_init[0] &= ~0x4000; e->rfseq_init[1] &= ~0x4000; e->rfseq_init[2] &= ~0x4000; e->rfseq_init[3] &= ~0x4000; e->init_gain &= ~0x4000; } - if (tr_iso > 7) - tr_iso = 3; - e->cliplo_gain = gain_data[tr_iso]; - - } else if (ghz5 && dev->phy.rev == 4 && ext_lna) { - e->rfseq_init[0] &= ~0x4000; - e->rfseq_init[1] &= ~0x4000; - e->rfseq_init[2] &= ~0x4000; - e->rfseq_init[3] &= ~0x4000; - e->init_gain &= ~0x4000; - e->rfseq_init[0] |= 0x1000; - e->rfseq_init[1] |= 0x1000; - e->rfseq_init[2] |= 0x1000; - e->rfseq_init[3] |= 0x1000; - e->init_gain |= 0x1000; + } else { + if (phy->rev >= 6) { + if (phy->radio_rev == 11 && !b43_is_40mhz(dev)) + e->crsminu = 0x2d; + } else if (phy->rev == 4 && ext_lna) { + e->rfseq_init[0] &= ~0x4000; + e->rfseq_init[1] &= ~0x4000; + e->rfseq_init[2] &= ~0x4000; + e->rfseq_init[3] &= ~0x4000; + e->init_gain &= ~0x4000; + e->rfseq_init[0] |= 0x1000; + e->rfseq_init[1] |= 0x1000; + e->rfseq_init[2] |= 0x1000; + e->rfseq_init[3] |= 0x1000; + e->init_gain |= 0x1000; + } } return e; From a68c356bcf1e76ae649e929db5e4cea9e6bdcd65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Thu, 31 Jul 2014 21:59:46 +0200 Subject: [PATCH 092/221] b43: N-PHY: add RF power tables for radio 0x2057 revs 9 & 14 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Don't write them as we don't have gains configured correctly yet. Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 21 ++++++-- drivers/net/wireless/b43/tables_nphy.c | 67 ++++++++++++++++++++++++++ drivers/net/wireless/b43/tables_nphy.h | 2 + 3 files changed, 87 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index df640325aa15..57a3ab2ac4dc 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -4235,8 +4235,9 @@ static void b43_nphy_tx_gain_table_upload(struct b43_wldev *dev) const u32 *table = NULL; u32 rfpwr_offset; - u8 pga_gain; + u8 pga_gain, pad_gain; int i; + const s16 *uninitialized_var(rf_pwr_offset_table); table = b43_nphy_get_tx_gain_table(dev); if (!table) @@ -4252,13 +4253,27 @@ static void b43_nphy_tx_gain_table_upload(struct b43_wldev *dev) nphy->gmval = (table[0] >> 16) & 0x7000; #endif + if (phy->rev >= 19) { + return; + } else if (phy->rev >= 7) { + rf_pwr_offset_table = b43_ntab_get_rf_pwr_offset_table(dev); + if (!rf_pwr_offset_table) + return; + /* TODO: Enable this once we have gains configured */ + return; + } + for (i = 0; i < 128; i++) { if (phy->rev >= 19) { /* TODO */ return; } else if (phy->rev >= 7) { - /* TODO */ - return; + pga_gain = (table[i] >> 24) & 0xf; + pad_gain = (table[i] >> 19) & 0x1f; + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) + rfpwr_offset = rf_pwr_offset_table[pad_gain]; + else + rfpwr_offset = rf_pwr_offset_table[pga_gain]; } else { pga_gain = (table[i] >> 24) & 0xF; if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) diff --git a/drivers/net/wireless/b43/tables_nphy.c b/drivers/net/wireless/b43/tables_nphy.c index f449cffc697b..25d1cbd34306 100644 --- a/drivers/net/wireless/b43/tables_nphy.c +++ b/drivers/net/wireless/b43/tables_nphy.c @@ -2878,6 +2878,40 @@ const s8 b43_ntab_papd_pga_gain_delta_ipa_2g[] = { -54, -46, -39, -31, -23, -15, -8, 0 }; +/* Extracted from MMIO dump of 6.30.223.248 + * Entries: 0, 15, 17, 21, 24, 26, 27, 29, 30 were guessed + */ +static const s16 b43_ntab_rf_pwr_offset_2057_rev9_2g[] = { + -133, -133, -107, -92, -81, + -73, -66, -61, -56, -52, + -48, -44, -41, -37, -34, + -31, -28, -25, -22, -19, + -17, -14, -12, -10, -9, + -7, -5, -4, -3, -2, + -1, 0, +}; + +/* Extracted from MMIO dump of 6.30.223.248 */ +static const s16 b43_ntab_rf_pwr_offset_2057_rev9_5g[] = { + -101, -94, -86, -79, -72, + -65, -57, -50, -42, -35, + -28, -21, -16, -9, -4, + 0, +}; + +/* Extracted from MMIO dump of 6.30.223.248 + * Entries: 0, 26, 28, 29, 30, 31 were guessed + */ +static const s16 b43_ntab_rf_pwr_offset_2057_rev14_2g[] = { + -111, -111, -111, -84, -70, + -59, -52, -45, -40, -36, + -32, -29, -26, -23, -21, + -18, -16, -15, -13, -11, + -10, -8, -7, -6, -5, + -4, -4, -3, -3, -2, + -2, -1, +}; + const u16 tbl_iqcal_gainparams[2][9][8] = { { { 0x000, 0, 0, 2, 0x69, 0x69, 0x69, 0x69 }, @@ -3708,6 +3742,39 @@ const u32 *b43_nphy_get_tx_gain_table(struct b43_wldev *dev) } } +const s16 *b43_ntab_get_rf_pwr_offset_table(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { + switch (phy->rev) { + case 17: + if (phy->radio_rev == 14) + return b43_ntab_rf_pwr_offset_2057_rev14_2g; + break; + case 16: + if (phy->radio_rev == 9) + return b43_ntab_rf_pwr_offset_2057_rev9_2g; + break; + } + + b43err(dev->wl, + "No 2GHz RF power table available for this device\n"); + return NULL; + } else { + switch (phy->rev) { + case 16: + if (phy->radio_rev == 9) + return b43_ntab_rf_pwr_offset_2057_rev9_5g; + break; + } + + b43err(dev->wl, + "No 5GHz RF power table available for this device\n"); + return NULL; + } +} + struct nphy_gain_ctl_workaround_entry *b43_nphy_get_gain_ctl_workaround_ent( struct b43_wldev *dev, bool ghz5, bool ext_lna) { diff --git a/drivers/net/wireless/b43/tables_nphy.h b/drivers/net/wireless/b43/tables_nphy.h index 3ce2e6f3a278..b51f386db02f 100644 --- a/drivers/net/wireless/b43/tables_nphy.h +++ b/drivers/net/wireless/b43/tables_nphy.h @@ -191,6 +191,8 @@ void b43_nphy_tables_init(struct b43_wldev *dev); const u32 *b43_nphy_get_tx_gain_table(struct b43_wldev *dev); +const s16 *b43_ntab_get_rf_pwr_offset_table(struct b43_wldev *dev); + extern const s8 b43_ntab_papd_pga_gain_delta_ipa_2g[]; extern const u16 tbl_iqcal_gainparams[2][9][8]; From ec76643b0057e13c4cc6ed4b55af6389fcbb5e64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Thu, 31 Jul 2014 21:59:47 +0200 Subject: [PATCH 093/221] b43: implement PPR (Power Per Rate) management/API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Broadcom hardware supports auto-adjustment of TX power depending on the currently used rate. So far all calculations were handled without any helpers (API) using big arrays and magic offsets. It seems Broadcom recently decided to clean this up by developing PPR. Their wlc_ppr.h can be found in open parts of the SDK. As we plan to implement support for rate-based TX power it makes sense to also implement our version of PPR as well. Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/Makefile | 1 + drivers/net/wireless/b43/b43.h | 7 ++ drivers/net/wireless/b43/ppr.c | 199 ++++++++++++++++++++++++++++++ drivers/net/wireless/b43/ppr.h | 45 +++++++ 4 files changed, 252 insertions(+) create mode 100644 drivers/net/wireless/b43/ppr.c create mode 100644 drivers/net/wireless/b43/ppr.h diff --git a/drivers/net/wireless/b43/Makefile b/drivers/net/wireless/b43/Makefile index 6e00b8804ada..9f7965aae93d 100644 --- a/drivers/net/wireless/b43/Makefile +++ b/drivers/net/wireless/b43/Makefile @@ -18,6 +18,7 @@ b43-y += xmit.o b43-y += dma.o b43-y += pio.o b43-y += rfkill.o +b43-y += ppr.o b43-$(CONFIG_B43_LEDS) += leds.o b43-$(CONFIG_B43_PCMCIA) += pcmcia.o b43-$(CONFIG_B43_SDIO) += sdio.o diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index 9b2d0c9bfb8e..d17cea05a9c1 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -791,6 +791,13 @@ struct b43_firmware { bool pcm_request_failed; }; +enum b43_band { + B43_BAND_2G = 0, + B43_BAND_5G_LO = 1, + B43_BAND_5G_MI = 2, + B43_BAND_5G_HI = 3, +}; + /* Device (802.11 core) initialization status. */ enum { B43_STAT_UNINIT = 0, /* Uninitialized. */ diff --git a/drivers/net/wireless/b43/ppr.c b/drivers/net/wireless/b43/ppr.c new file mode 100644 index 000000000000..9a770279c415 --- /dev/null +++ b/drivers/net/wireless/b43/ppr.c @@ -0,0 +1,199 @@ +/* + * Broadcom B43 wireless driver + * PPR (Power Per Rate) management + * + * Copyright (c) 2014 Rafał Miłecki + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "ppr.h" +#include "b43.h" + +#define ppr_for_each_entry(ppr, i, entry) \ + for (i = 0, entry = &(ppr)->__all_rates[i]; \ + i < B43_PPR_RATES_NUM; \ + i++, entry++) + +void b43_ppr_clear(struct b43_wldev *dev, struct b43_ppr *ppr) +{ + memset(ppr, 0, sizeof(*ppr)); + + /* Compile-time PPR check */ + BUILD_BUG_ON(sizeof(struct b43_ppr) != B43_PPR_RATES_NUM * sizeof(u8)); +} + +void b43_ppr_add(struct b43_wldev *dev, struct b43_ppr *ppr, int diff) +{ + int i; + u8 *rate; + + ppr_for_each_entry(ppr, i, rate) { + *rate = clamp_val(*rate + diff, 0, 127); + } +} + +void b43_ppr_apply_max(struct b43_wldev *dev, struct b43_ppr *ppr, u8 max) +{ + int i; + u8 *rate; + + ppr_for_each_entry(ppr, i, rate) { + *rate = min(*rate, max); + } +} + +void b43_ppr_apply_min(struct b43_wldev *dev, struct b43_ppr *ppr, u8 min) +{ + int i; + u8 *rate; + + ppr_for_each_entry(ppr, i, rate) { + *rate = max(*rate, min); + } +} + +u8 b43_ppr_get_max(struct b43_wldev *dev, struct b43_ppr *ppr) +{ + u8 res = 0; + int i; + u8 *rate; + + ppr_for_each_entry(ppr, i, rate) { + res = max(*rate, res); + } + + return res; +} + +bool b43_ppr_load_max_from_sprom(struct b43_wldev *dev, struct b43_ppr *ppr, + enum b43_band band) +{ + struct b43_ppr_rates *rates = &ppr->rates; + struct ssb_sprom *sprom = dev->dev->bus_sprom; + struct b43_phy *phy = &dev->phy; + u8 maxpwr, off; + u32 sprom_ofdm_po; + u16 *sprom_mcs_po; + u8 extra_cdd_po, extra_stbc_po; + int i; + + switch (band) { + case B43_BAND_2G: + maxpwr = min(sprom->core_pwr_info[0].maxpwr_2g, + sprom->core_pwr_info[1].maxpwr_2g); + sprom_ofdm_po = sprom->ofdm2gpo; + sprom_mcs_po = sprom->mcs2gpo; + extra_cdd_po = (sprom->cddpo >> 0) & 0xf; + extra_stbc_po = (sprom->stbcpo >> 0) & 0xf; + break; + case B43_BAND_5G_LO: + maxpwr = min(sprom->core_pwr_info[0].maxpwr_5gl, + sprom->core_pwr_info[1].maxpwr_5gl); + sprom_ofdm_po = sprom->ofdm5glpo; + sprom_mcs_po = sprom->mcs5glpo; + extra_cdd_po = (sprom->cddpo >> 8) & 0xf; + extra_stbc_po = (sprom->stbcpo >> 8) & 0xf; + break; + case B43_BAND_5G_MI: + maxpwr = min(sprom->core_pwr_info[0].maxpwr_5g, + sprom->core_pwr_info[1].maxpwr_5g); + sprom_ofdm_po = sprom->ofdm5gpo; + sprom_mcs_po = sprom->mcs5gpo; + extra_cdd_po = (sprom->cddpo >> 4) & 0xf; + extra_stbc_po = (sprom->stbcpo >> 4) & 0xf; + break; + case B43_BAND_5G_HI: + maxpwr = min(sprom->core_pwr_info[0].maxpwr_5gh, + sprom->core_pwr_info[1].maxpwr_5gh); + sprom_ofdm_po = sprom->ofdm5ghpo; + sprom_mcs_po = sprom->mcs5ghpo; + extra_cdd_po = (sprom->cddpo >> 12) & 0xf; + extra_stbc_po = (sprom->stbcpo >> 12) & 0xf; + break; + default: + WARN_ON_ONCE(1); + return false; + } + + if (band == B43_BAND_2G) { + for (i = 0; i < 4; i++) { + off = ((sprom->cck2gpo >> (i * 4)) & 0xf) * 2; + rates->cck[i] = maxpwr - off; + } + } + + /* OFDM */ + for (i = 0; i < 8; i++) { + off = ((sprom_ofdm_po >> (i * 4)) & 0xf) * 2; + rates->ofdm[i] = maxpwr - off; + } + + /* MCS 20 SISO */ + rates->mcs_20[0] = rates->ofdm[0]; + rates->mcs_20[1] = rates->ofdm[2]; + rates->mcs_20[2] = rates->ofdm[3]; + rates->mcs_20[3] = rates->ofdm[4]; + rates->mcs_20[4] = rates->ofdm[5]; + rates->mcs_20[5] = rates->ofdm[6]; + rates->mcs_20[6] = rates->ofdm[7]; + rates->mcs_20[7] = rates->ofdm[7]; + + /* MCS 20 CDD */ + for (i = 0; i < 4; i++) { + off = ((sprom_mcs_po[0] >> (i * 4)) & 0xf) * 2; + rates->mcs_20_cdd[i] = maxpwr - off; + if (phy->type == B43_PHYTYPE_N && phy->rev >= 3) + rates->mcs_20_cdd[i] -= extra_cdd_po; + } + for (i = 0; i < 4; i++) { + off = ((sprom_mcs_po[1] >> (i * 4)) & 0xf) * 2; + rates->mcs_20_cdd[4 + i] = maxpwr - off; + if (phy->type == B43_PHYTYPE_N && phy->rev >= 3) + rates->mcs_20_cdd[4 + i] -= extra_cdd_po; + } + + /* OFDM 20 CDD */ + rates->ofdm_20_cdd[0] = rates->mcs_20_cdd[0]; + rates->ofdm_20_cdd[1] = rates->mcs_20_cdd[0]; + rates->ofdm_20_cdd[2] = rates->mcs_20_cdd[1]; + rates->ofdm_20_cdd[3] = rates->mcs_20_cdd[2]; + rates->ofdm_20_cdd[4] = rates->mcs_20_cdd[3]; + rates->ofdm_20_cdd[5] = rates->mcs_20_cdd[4]; + rates->ofdm_20_cdd[6] = rates->mcs_20_cdd[5]; + rates->ofdm_20_cdd[7] = rates->mcs_20_cdd[6]; + + /* MCS 20 STBC */ + for (i = 0; i < 4; i++) { + off = ((sprom_mcs_po[0] >> (i * 4)) & 0xf) * 2; + rates->mcs_20_stbc[i] = maxpwr - off; + if (phy->type == B43_PHYTYPE_N && phy->rev >= 3) + rates->mcs_20_stbc[i] -= extra_stbc_po; + } + for (i = 0; i < 4; i++) { + off = ((sprom_mcs_po[1] >> (i * 4)) & 0xf) * 2; + rates->mcs_20_stbc[4 + i] = maxpwr - off; + if (phy->type == B43_PHYTYPE_N && phy->rev >= 3) + rates->mcs_20_stbc[4 + i] -= extra_stbc_po; + } + + /* MCS 20 SDM */ + for (i = 0; i < 4; i++) { + off = ((sprom_mcs_po[2] >> (i * 4)) & 0xf) * 2; + rates->mcs_20_sdm[i] = maxpwr - off; + } + for (i = 0; i < 4; i++) { + off = ((sprom_mcs_po[3] >> (i * 4)) & 0xf) * 2; + rates->mcs_20_sdm[4 + i] = maxpwr - off; + } + + return true; +} diff --git a/drivers/net/wireless/b43/ppr.h b/drivers/net/wireless/b43/ppr.h new file mode 100644 index 000000000000..24d7447e9f01 --- /dev/null +++ b/drivers/net/wireless/b43/ppr.h @@ -0,0 +1,45 @@ +#ifndef LINUX_B43_PPR_H_ +#define LINUX_B43_PPR_H_ + +#include + +#define B43_PPR_CCK_RATES_NUM 4 +#define B43_PPR_OFDM_RATES_NUM 8 +#define B43_PPR_MCS_RATES_NUM 8 + +#define B43_PPR_RATES_NUM (B43_PPR_CCK_RATES_NUM + \ + B43_PPR_OFDM_RATES_NUM * 2 + \ + B43_PPR_MCS_RATES_NUM * 4) + +struct b43_ppr_rates { + u8 cck[B43_PPR_CCK_RATES_NUM]; + u8 ofdm[B43_PPR_OFDM_RATES_NUM]; + u8 ofdm_20_cdd[B43_PPR_OFDM_RATES_NUM]; + u8 mcs_20[B43_PPR_MCS_RATES_NUM]; /* SISO */ + u8 mcs_20_cdd[B43_PPR_MCS_RATES_NUM]; + u8 mcs_20_stbc[B43_PPR_MCS_RATES_NUM]; + u8 mcs_20_sdm[B43_PPR_MCS_RATES_NUM]; +}; + +struct b43_ppr { + /* All powers are in qdbm (Q5.2) */ + union { + u8 __all_rates[B43_PPR_RATES_NUM]; + struct b43_ppr_rates rates; + }; +}; + +struct b43_wldev; +enum b43_band; + +void b43_ppr_clear(struct b43_wldev *dev, struct b43_ppr *ppr); + +void b43_ppr_add(struct b43_wldev *dev, struct b43_ppr *ppr, int diff); +void b43_ppr_apply_max(struct b43_wldev *dev, struct b43_ppr *ppr, u8 max); +void b43_ppr_apply_min(struct b43_wldev *dev, struct b43_ppr *ppr, u8 min); +u8 b43_ppr_get_max(struct b43_wldev *dev, struct b43_ppr *ppr); + +bool b43_ppr_load_max_from_sprom(struct b43_wldev *dev, struct b43_ppr *ppr, + enum b43_band band); + +#endif /* LINUX_B43_PPR_H_ */ From 8615eb2870f1a89ad551d80ef821172015af7c28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Thu, 31 Jul 2014 21:59:48 +0200 Subject: [PATCH 094/221] b43: N-PHY: support setting custom TX power MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/b43.h | 1 + drivers/net/wireless/b43/phy_n.c | 84 +++++++++++++++++++++++++++----- drivers/net/wireless/b43/phy_n.h | 4 ++ 3 files changed, 77 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index d17cea05a9c1..95a943326420 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -457,6 +457,7 @@ enum { #define B43_MACCTL_RADIOLOCK 0x00080000 /* Radio lock */ #define B43_MACCTL_BEACPROMISC 0x00100000 /* Beacon Promiscuous */ #define B43_MACCTL_KEEP_BADPLCP 0x00200000 /* Keep frames with bad PLCP */ +#define B43_MACCTL_PHY_LOCK 0x00200000 #define B43_MACCTL_KEEP_CTL 0x00400000 /* Keep control frames */ #define B43_MACCTL_KEEP_BAD 0x00800000 /* Keep bad frames (FCS) */ #define B43_MACCTL_PROMISC 0x01000000 /* Promiscuous mode */ diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 57a3ab2ac4dc..cf625d8732a7 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -34,6 +34,7 @@ #include "radio_2056.h" #include "radio_2057.h" #include "main.h" +#include "ppr.h" struct nphy_txgains { u16 tx_lpf[2]; @@ -3606,16 +3607,6 @@ static void b43_nphy_iq_cal_gain_params(struct b43_wldev *dev, u16 core, * Tx and Rx **************************************************/ -static void b43_nphy_op_adjust_txpower(struct b43_wldev *dev) -{//TODO -} - -static enum b43_txpwr_result b43_nphy_op_recalc_txpower(struct b43_wldev *dev, - bool ignore_tssi) -{//TODO - return B43_TXPWR_RES_DONE; -} - /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxPwrCtrlEnable */ static void b43_nphy_tx_power_ctrl(struct b43_wldev *dev, bool enable) { @@ -4069,6 +4060,7 @@ static void b43_nphy_tx_power_ctl_setup(struct b43_wldev *dev) s16 a1[2], b0[2], b1[2]; u8 idle[2]; + u8 ppr_max; s8 target[2]; s32 num, den, pwr; u32 regval[64]; @@ -4147,7 +4139,12 @@ static void b43_nphy_tx_power_ctl_setup(struct b43_wldev *dev) b1[0] = b1[1] = -1393; } } - /* target[0] = target[1] = nphy->tx_power_max; */ + + ppr_max = b43_ppr_get_max(dev, &nphy->tx_pwr_max_ppr); + if (ppr_max) { + target[0] = ppr_max; + target[1] = ppr_max; + } if (dev->phy.rev >= 3) { if (sprom->fem.ghz2.tssipos) @@ -5889,6 +5886,69 @@ static void b43_nphy_set_rx_core_state(struct b43_wldev *dev, u8 mask) b43_mac_enable(dev); } +static enum b43_txpwr_result b43_nphy_op_recalc_txpower(struct b43_wldev *dev, + bool ignore_tssi) +{ + struct b43_phy *phy = &dev->phy; + struct b43_phy_n *nphy = dev->phy.n; + struct ieee80211_channel *channel = dev->wl->hw->conf.chandef.chan; + struct b43_ppr *ppr = &nphy->tx_pwr_max_ppr; + u8 max; /* qdBm */ + bool tx_pwr_state; + + if (nphy->tx_pwr_last_recalc_freq == channel->center_freq && + nphy->tx_pwr_last_recalc_limit == phy->desired_txpower) + return B43_TXPWR_RES_DONE; + + /* Make sure we have a clean PPR */ + b43_ppr_clear(dev, ppr); + + /* HW limitations */ + b43_ppr_load_max_from_sprom(dev, ppr, B43_BAND_2G); + + /* Regulatory & user settings */ + max = INT_TO_Q52(phy->chandef->chan->max_power); + if (phy->desired_txpower) + max = min_t(u8, max, INT_TO_Q52(phy->desired_txpower)); + b43_ppr_apply_max(dev, ppr, max); + if (b43_debug(dev, B43_DBG_XMITPOWER)) + b43dbg(dev->wl, "Calculated TX power: " Q52_FMT "\n", + Q52_ARG(b43_ppr_get_max(dev, ppr))); + + /* TODO: Enable this once we get gains working */ +#if 0 + /* Some extra gains */ + hw_gain = 6; /* N-PHY specific */ + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) + hw_gain += sprom->antenna_gain.a0; + else + hw_gain += sprom->antenna_gain.a1; + b43_ppr_add(dev, ppr, -hw_gain); +#endif + + /* Make sure we didn't go too low */ + b43_ppr_apply_min(dev, ppr, INT_TO_Q52(8)); + + /* Apply */ + tx_pwr_state = nphy->txpwrctrl; + b43_mac_suspend(dev); + b43_nphy_tx_power_ctl_setup(dev); + if (dev->dev->core_rev == 11 || dev->dev->core_rev == 12) { + b43_maskset32(dev, B43_MMIO_MACCTL, ~0, B43_MACCTL_PHY_LOCK); + b43_read32(dev, B43_MMIO_MACCTL); + udelay(1); + } + b43_nphy_tx_power_ctrl(dev, nphy->txpwrctrl); + if (dev->dev->core_rev == 11 || dev->dev->core_rev == 12) + b43_maskset32(dev, B43_MMIO_MACCTL, ~B43_MACCTL_PHY_LOCK, 0); + b43_mac_enable(dev); + + nphy->tx_pwr_last_recalc_freq = channel->center_freq; + nphy->tx_pwr_last_recalc_limit = phy->desired_txpower; + + return B43_TXPWR_RES_DONE; +} + /************************************************** * N-PHY init **************************************************/ @@ -6422,6 +6482,7 @@ static int b43_nphy_op_allocate(struct b43_wldev *dev) nphy = kzalloc(sizeof(*nphy), GFP_KERNEL); if (!nphy) return -ENOMEM; + dev->phy.n = nphy; return 0; @@ -6662,5 +6723,4 @@ const struct b43_phy_operations b43_phyops_n = { .switch_channel = b43_nphy_op_switch_channel, .get_default_chan = b43_nphy_op_get_default_chan, .recalc_txpower = b43_nphy_op_recalc_txpower, - .adjust_txpower = b43_nphy_op_adjust_txpower, }; diff --git a/drivers/net/wireless/b43/phy_n.h b/drivers/net/wireless/b43/phy_n.h index 30bec815b969..a6da2c31a99c 100644 --- a/drivers/net/wireless/b43/phy_n.h +++ b/drivers/net/wireless/b43/phy_n.h @@ -2,6 +2,7 @@ #define B43_NPHY_H_ #include "phy_common.h" +#include "ppr.h" /* N-PHY registers. */ @@ -967,6 +968,9 @@ struct b43_phy_n { struct b43_phy_n_txpwrindex txpwrindex[2]; struct b43_phy_n_pwr_ctl_info pwr_ctl_info[2]; struct b43_chanspec txiqlocal_chanspec; + struct b43_ppr tx_pwr_max_ppr; + u16 tx_pwr_last_recalc_freq; + int tx_pwr_last_recalc_limit; u8 txrx_chain; u16 tx_rx_cal_phy_saveregs[11]; From 6040aa70c30276e6cd2aacd1f428c3f05462a7f1 Mon Sep 17 00:00:00 2001 From: Himangi Saraogi Date: Sat, 2 Aug 2014 16:51:30 +0530 Subject: [PATCH 095/221] net: wireless: wl1251: Remove unnecessary free_irq This patch does away with free_irq in the remove function as the irq is allocated with a devm_request_irq. Signed-off-by: Himangi Saraogi Signed-off-by: John W. Linville --- drivers/net/wireless/ti/wl1251/spi.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/ti/wl1251/spi.c b/drivers/net/wireless/ti/wl1251/spi.c index a0aa8fa72392..735be5352143 100644 --- a/drivers/net/wireless/ti/wl1251/spi.c +++ b/drivers/net/wireless/ti/wl1251/spi.c @@ -345,7 +345,6 @@ static int wl1251_spi_remove(struct spi_device *spi) { struct wl1251 *wl = spi_get_drvdata(spi); - free_irq(wl->irq, wl); wl1251_free_hw(wl); regulator_disable(wl->vio); From 26c0604628f85d435a664f52fd2ca30aab812266 Mon Sep 17 00:00:00 2001 From: Himangi Saraogi Date: Sat, 2 Aug 2014 20:22:46 +0530 Subject: [PATCH 096/221] cw1200: Introduce the use of devm_kzalloc This patch introduces the use of devm_kzalloc and does away with the kfrees in the probe and remove functions. Signed-off-by: Himangi Saraogi Acked-by: Julia Lawall Signed-off-by: John W. Linville --- drivers/net/wireless/cw1200/cw1200_spi.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/net/wireless/cw1200/cw1200_spi.c b/drivers/net/wireless/cw1200/cw1200_spi.c index 40078f5f932e..964b64ab7fe3 100644 --- a/drivers/net/wireless/cw1200/cw1200_spi.c +++ b/drivers/net/wireless/cw1200/cw1200_spi.c @@ -398,7 +398,7 @@ static int cw1200_spi_probe(struct spi_device *func) return -1; } - self = kzalloc(sizeof(*self), GFP_KERNEL); + self = devm_kzalloc(&func->dev, sizeof(*self), GFP_KERNEL); if (!self) { pr_err("Can't allocate SPI hwbus_priv."); return -ENOMEM; @@ -424,7 +424,6 @@ static int cw1200_spi_probe(struct spi_device *func) if (status) { cw1200_spi_irq_unsubscribe(self); cw1200_spi_off(plat_data); - kfree(self); } return status; @@ -441,7 +440,6 @@ static int cw1200_spi_disconnect(struct spi_device *func) cw1200_core_release(self->core); self->core = NULL; } - kfree(self); } cw1200_spi_off(dev_get_platdata(&func->dev)); From e2261afd4caaf1a6473eddbcbd8a5c5eb593316e Mon Sep 17 00:00:00 2001 From: Hans Wennborg Date: Tue, 5 Aug 2014 21:42:55 -0700 Subject: [PATCH 097/221] mwifiex: fix decimal printf format specifiers prefixed with 0x The prefix suggests the number should be printed in hex, so use the %x specifier to do that. Found by using regex suggested by Joe Perches. Signed-off-by: Hans Wennborg Acked-by: Avinash Patil Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/cfg80211.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index e2e6bf13c2d8..2856f0ecb8fc 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -246,7 +246,7 @@ mwifiex_cfg80211_remain_on_channel(struct wiphy *wiphy, } if (priv->roc_cfg.cookie) { - wiphy_dbg(wiphy, "info: ongoing ROC, cookie = 0x%llu\n", + wiphy_dbg(wiphy, "info: ongoing ROC, cookie = 0x%llx\n", priv->roc_cfg.cookie); return -EBUSY; } From 91b775edf7ad54f849895e021677f7d9c15a9f5d Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Wed, 6 Aug 2014 10:31:49 +0300 Subject: [PATCH 098/221] wil6210: map MAC timer for packet lifetime into debugfs expose reading RGF_MAC_MTRL_COUNTER_0 in debugfs Signed-off-by: Dedy Lansky Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/debugfs.c | 3 +++ drivers/net/wireless/ath/wil6210/wil6210.h | 3 +++ 2 files changed, 6 insertions(+) diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 8f66186adb8c..dee2380a44d3 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -1021,6 +1021,9 @@ int wil6210_debugfs_init(struct wil6210_priv *wil) HOSTADDR(RGF_DMA_EP_MISC_ICR)); wil6210_debugfs_create_pseudo_ISR(wil, dbg); wil6210_debugfs_create_ITR_CNT(wil, dbg); + wil_debugfs_create_iomem_x32("MAC_MTRL_COUNTER_0", S_IRUGO, dbg, + wil->csr + + HOSTADDR(RGF_MAC_MTRL_COUNTER_0)); wil_debugfs_create_iomem_x32("RGF_USER_USAGE_1", S_IRUGO, dbg, wil->csr + diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 67e9624f7111..077e623bfa54 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -133,6 +133,9 @@ struct RGF_ICR { #define RGF_HP_CTRL (0x88265c) #define RGF_PCIE_LOS_COUNTER_CTL (0x882dc4) +/* MAC timer, usec, for packet lifetime */ +#define RGF_MAC_MTRL_COUNTER_0 (0x886aa8) + /* popular locations */ #define HOST_MBOX HOSTADDR(RGF_USER_USER_SCRATCH_PAD) #define HOST_SW_INT (HOSTADDR(RGF_USER_USER_ICR) + \ From cc9e4a2b667c79d531a79c5eede27d11c1394326 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Wed, 6 Aug 2014 10:31:50 +0300 Subject: [PATCH 099/221] wil6210: fix race in reset It is important to halt USER CPU first, then MAC CPU Otherwise, race happens in the firmware Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/main.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 3704d2a434f3..d73428303621 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -327,6 +327,8 @@ static void wil_target_reset(struct wil6210_priv *wil) /* register clear = read, AND with inverted, write */ #define C(a, v) W(a, R(a) & ~v) + wmb(); /* If host reorder writes here -> race in NIC */ + W(RGF_USER_MAC_CPU_0, BIT(1)); /* mac_cpu_man_rst */ wil->hw_version = R(RGF_USER_FW_REV_ID); rev_id = wil->hw_version & 0xff; @@ -343,8 +345,9 @@ static void wil_target_reset(struct wil6210_priv *wil) wmb(); /* order is important here */ } - W(RGF_USER_MAC_CPU_0, BIT(1)); /* mac_cpu_man_rst */ W(RGF_USER_USER_CPU_0, BIT(1)); /* user_cpu_man_rst */ + wmb(); /* If host reorder writes here -> race in NIC */ + W(RGF_USER_MAC_CPU_0, BIT(1)); /* mac_cpu_man_rst */ wmb(); /* order is important here */ W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0xFE000000); From 02525a7925c9a3c55ceef7e9a30218dc47ced1ad Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Wed, 6 Aug 2014 10:31:51 +0300 Subject: [PATCH 100/221] wil6210: update copyright year 2014 Fix Copyright headers in all files changed in 2014, to mention 2014 Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/cfg80211.c | 2 +- drivers/net/wireless/ath/wil6210/debugfs.c | 2 +- drivers/net/wireless/ath/wil6210/interrupt.c | 2 +- drivers/net/wireless/ath/wil6210/main.c | 2 +- drivers/net/wireless/ath/wil6210/netdev.c | 2 +- drivers/net/wireless/ath/wil6210/pcie_bus.c | 2 +- drivers/net/wireless/ath/wil6210/rx_reorder.c | 16 ++++++++++++++++ drivers/net/wireless/ath/wil6210/txrx.c | 2 +- drivers/net/wireless/ath/wil6210/txrx.h | 2 +- drivers/net/wireless/ath/wil6210/wil6210.h | 2 +- drivers/net/wireless/ath/wil6210/wmi.c | 2 +- drivers/net/wireless/ath/wil6210/wmi.h | 2 +- 12 files changed, 27 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 4ac2c208c9ba..ee8a0e588d6e 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012 Qualcomm Atheros, Inc. + * Copyright (c) 2012-2014 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index dee2380a44d3..fb802bdc2c64 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012 Qualcomm Atheros, Inc. + * Copyright (c) 2012-2014 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c index 67f1002a03a1..98bfbb6390b7 100644 --- a/drivers/net/wireless/ath/wil6210/interrupt.c +++ b/drivers/net/wireless/ath/wil6210/interrupt.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012 Qualcomm Atheros, Inc. + * Copyright (c) 2012-2014 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index d73428303621..dc220537de99 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012 Qualcomm Atheros, Inc. + * Copyright (c) 2012-2014 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c index 7afce6e8c507..d42fde903f0f 100644 --- a/drivers/net/wireless/ath/wil6210/netdev.c +++ b/drivers/net/wireless/ath/wil6210/netdev.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012 Qualcomm Atheros, Inc. + * Copyright (c) 2012-2014 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c index d3fbfa28db62..a6af2bb2e9f9 100644 --- a/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012 Qualcomm Atheros, Inc. + * Copyright (c) 2012-2014 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/wil6210/rx_reorder.c b/drivers/net/wireless/ath/wil6210/rx_reorder.c index 180ca4793904..97c6a24716a1 100644 --- a/drivers/net/wireless/ath/wil6210/rx_reorder.c +++ b/drivers/net/wireless/ath/wil6210/rx_reorder.c @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2014 Qualcomm Atheros, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + #include "wil6210.h" #include "txrx.h" diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index d3467943d39d..9fcc2e32180d 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012 Qualcomm Atheros, Inc. + * Copyright (c) 2012-2014 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/wil6210/txrx.h b/drivers/net/wireless/ath/wil6210/txrx.h index bc5706a4f007..a1ac4f87d47b 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.h +++ b/drivers/net/wireless/ath/wil6210/txrx.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012 Qualcomm Atheros, Inc. + * Copyright (c) 2012-2014 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 077e623bfa54..0097300c863c 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012 Qualcomm Atheros, Inc. + * Copyright (c) 2012-2014 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 1d1d0afdd2e1..b25a62da8f22 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012 Qualcomm Atheros, Inc. + * Copyright (c) 2012-2014 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h index 17334c852866..2f51b46f255b 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.h +++ b/drivers/net/wireless/ath/wil6210/wmi.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012 Qualcomm Atheros, Inc. + * Copyright (c) 2012-2014 Qualcomm Atheros, Inc. * Copyright (c) 2006-2012 Wilocity . * * Permission to use, copy, modify, and/or distribute this software for any From bbb2adc7b47cbe841d3cb2fa048f720647f5f4cd Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Wed, 6 Aug 2014 10:31:52 +0300 Subject: [PATCH 101/221] wil6210: check error in wil_target_reset() When resetting target in wil_target_reset(), error may occur. Indicate error via error code. In case of error, don't attempt to further interact with card, specifically don't attempt firmware download or interrupts enabling. Move wil_rx_fini() to be always executed to prevent memory leak. Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/main.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index dc220537de99..5a9934291dab 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -309,7 +309,7 @@ void wil_priv_deinit(struct wil6210_priv *wil) destroy_workqueue(wil->wmi_wq); } -static void wil_target_reset(struct wil6210_priv *wil) +static int wil_target_reset(struct wil6210_priv *wil) { int delay = 0; u32 hw_state; @@ -395,7 +395,7 @@ static void wil_target_reset(struct wil6210_priv *wil) if (delay++ > 100) { wil_err(wil, "Reset not completed, hw_state 0x%08x\n", hw_state); - return; + return -ETIME; } } while (hw_state != HW_MACHINE_BOOT_DONE); @@ -407,6 +407,7 @@ static void wil_target_reset(struct wil6210_priv *wil) wmb(); /* order is important here */ wil_dbg_misc(wil, "Reset completed in %d ms\n", delay); + return 0; #undef R #undef W @@ -471,10 +472,11 @@ int wil_reset(struct wil6210_priv *wil) flush_workqueue(wil->wmi_wq_conn); flush_workqueue(wil->wmi_wq); - /* TODO: put MAC in reset */ - wil_target_reset(wil); - + rc = wil_target_reset(wil); wil_rx_fini(wil); + if (rc) + return rc; + /* init after reset */ wil->pending_connect_cid = -1; From 520d68e7cf6c72687698c4584e8f1f8fab4dfc4e Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Wed, 6 Aug 2014 10:31:53 +0300 Subject: [PATCH 102/221] wil6210: wait longer for hardware reset completion Typical time for hardware reset, as measured, is about 200..250 msec. Adjust sleeping to use more relaxed msleep, increase sleep interval and increase total sleep time to be about 1sec Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/main.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 5a9934291dab..b69d90f0716f 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -25,6 +25,9 @@ static bool no_fw_recovery; module_param(no_fw_recovery, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(no_fw_recovery, " disable FW error recovery"); +#define RST_DELAY (20) /* msec, for loop in @wil_target_reset */ +#define RST_COUNT (1 + 1000/RST_DELAY) /* round up to be above 1 sec total */ + /* * Due to a hardware issue, * one has to read/write to/from NIC in 32-bit chunks; @@ -388,11 +391,11 @@ static int wil_target_reset(struct wil6210_priv *wil) W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0); wmb(); /* order is important here */ - /* wait until device ready */ + /* wait until device ready. typical time is 200..250 msec */ do { - msleep(1); + msleep(RST_DELAY); hw_state = R(RGF_USER_HW_MACHINE_STATE); - if (delay++ > 100) { + if (delay++ > RST_COUNT) { wil_err(wil, "Reset not completed, hw_state 0x%08x\n", hw_state); return -ETIME; @@ -406,7 +409,7 @@ static int wil_target_reset(struct wil6210_priv *wil) C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD); wmb(); /* order is important here */ - wil_dbg_misc(wil, "Reset completed in %d ms\n", delay); + wil_dbg_misc(wil, "Reset completed in %d ms\n", delay * RST_DELAY); return 0; #undef R From 6afd60055d8dd1f28bf6e9556ebc9996cceebaa8 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Wed, 6 Aug 2014 10:31:54 +0300 Subject: [PATCH 103/221] wil6210: Workaround for Sparrow with bad device id If firmware broken on the boot time, Sparrow card enumerates as device 0x302 instead of 0x310. Allow using this ID Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/pcie_bus.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c index a6af2bb2e9f9..cf0b21987d70 100644 --- a/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c @@ -243,6 +243,8 @@ static const struct pci_device_id wil6210_pcie_ids[] = { .driver_data = (kernel_ulong_t)&wil_board_marlon }, { PCI_DEVICE(0x1ae9, 0x0310), .driver_data = (kernel_ulong_t)&wil_board_sparrow }, + { PCI_DEVICE(0x1ae9, 0x0302), /* same as above, firmware broken */ + .driver_data = (kernel_ulong_t)&wil_board_sparrow }, { /* end: all zeroes */ }, }; MODULE_DEVICE_TABLE(pci, wil6210_pcie_ids); From b7cde47009640b88cb3629ee7078a43bc2642459 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Wed, 6 Aug 2014 10:31:55 +0300 Subject: [PATCH 104/221] wil6210: convert debugfs to the table mode Define tables for similar file entries, i.e. - table for debugfs_create_file - table for static parameters - table for parameters that are members of "wil" structure - table for blobs - table for interrupt controllers Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/debugfs.c | 256 +++++++++++++++------ 1 file changed, 181 insertions(+), 75 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index fb802bdc2c64..95269d234ca9 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -29,6 +29,21 @@ static u32 mem_addr; static u32 dbg_txdesc_index; static u32 dbg_vring_index; /* 24+ for Rx, 0..23 for Tx */ +enum dbg_off_type { + doff_u32 = 0, + doff_x32 = 1, + doff_ulong = 2, + doff_io32 = 3, +}; + +/* offset to "wil" */ +struct dbg_off { + const char *name; + umode_t mode; + ulong off; + enum dbg_off_type type; +}; + static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil, const char *name, struct vring *vring, char _s, char _h) @@ -244,9 +259,9 @@ DEFINE_SIMPLE_ATTRIBUTE(fops_iomem_x32, wil_debugfs_iomem_x32_get, static struct dentry *wil_debugfs_create_iomem_x32(const char *name, umode_t mode, struct dentry *parent, - void __iomem *value) + void *value) { - return debugfs_create_file(name, mode, parent, (void * __force)value, + return debugfs_create_file(name, mode, parent, value, &fops_iomem_x32); } @@ -270,6 +285,59 @@ static struct dentry *wil_debugfs_create_ulong(const char *name, umode_t mode, return debugfs_create_file(name, mode, parent, value, &wil_fops_ulong); } +/** + * wil6210_debugfs_init_offset - create set of debugfs files + * @wil - driver's context, used for printing + * @dbg - directory on the debugfs, where files will be created + * @base - base address used in address calculation + * @tbl - table with file descriptions. Should be terminated with empty element. + * + * Creates files accordingly to the @tbl. + */ +static void wil6210_debugfs_init_offset(struct wil6210_priv *wil, + struct dentry *dbg, void *base, + const struct dbg_off * const tbl) +{ + int i; + + for (i = 0; tbl[i].name; i++) { + struct dentry *f = NULL; + + switch (tbl[i].type) { + case doff_u32: + f = debugfs_create_u32(tbl[i].name, tbl[i].mode, dbg, + base + tbl[i].off); + break; + case doff_x32: + f = debugfs_create_x32(tbl[i].name, tbl[i].mode, dbg, + base + tbl[i].off); + break; + case doff_ulong: + f = wil_debugfs_create_ulong(tbl[i].name, tbl[i].mode, + dbg, base + tbl[i].off); + break; + case doff_io32: + f = wil_debugfs_create_iomem_x32(tbl[i].name, + tbl[i].mode, dbg, + base + tbl[i].off); + break; + } + if (IS_ERR_OR_NULL(f)) + wil_err(wil, "Create file \"%s\": err %ld\n", + tbl[i].name, PTR_ERR(f)); + } +} + +static const struct dbg_off isr_off[] = { + {"ICC", S_IRUGO | S_IWUSR, offsetof(struct RGF_ICR, ICC), doff_io32}, + {"ICR", S_IRUGO | S_IWUSR, offsetof(struct RGF_ICR, ICR), doff_io32}, + {"ICM", S_IRUGO | S_IWUSR, offsetof(struct RGF_ICR, ICM), doff_io32}, + {"ICS", S_IWUSR, offsetof(struct RGF_ICR, ICS), doff_io32}, + {"IMV", S_IRUGO | S_IWUSR, offsetof(struct RGF_ICR, IMV), doff_io32}, + {"IMS", S_IWUSR, offsetof(struct RGF_ICR, IMS), doff_io32}, + {"IMC", S_IWUSR, offsetof(struct RGF_ICR, IMC), doff_io32}, + {}, +}; static int wil6210_debugfs_create_ISR(struct wil6210_priv *wil, const char *name, struct dentry *parent, u32 off) @@ -279,24 +347,19 @@ static int wil6210_debugfs_create_ISR(struct wil6210_priv *wil, if (IS_ERR_OR_NULL(d)) return -ENODEV; - wil_debugfs_create_iomem_x32("ICC", S_IRUGO | S_IWUSR, d, - wil->csr + off); - wil_debugfs_create_iomem_x32("ICR", S_IRUGO | S_IWUSR, d, - wil->csr + off + 4); - wil_debugfs_create_iomem_x32("ICM", S_IRUGO | S_IWUSR, d, - wil->csr + off + 8); - wil_debugfs_create_iomem_x32("ICS", S_IWUSR, d, - wil->csr + off + 12); - wil_debugfs_create_iomem_x32("IMV", S_IRUGO | S_IWUSR, d, - wil->csr + off + 16); - wil_debugfs_create_iomem_x32("IMS", S_IWUSR, d, - wil->csr + off + 20); - wil_debugfs_create_iomem_x32("IMC", S_IWUSR, d, - wil->csr + off + 24); + wil6210_debugfs_init_offset(wil, d, (void * __force)wil->csr + off, + isr_off); return 0; } +static const struct dbg_off pseudo_isr_off[] = { + {"CAUSE", S_IRUGO, HOSTADDR(RGF_DMA_PSEUDO_CAUSE), doff_io32}, + {"MASK_SW", S_IRUGO, HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW), doff_io32}, + {"MASK_FW", S_IRUGO, HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_FW), doff_io32}, + {}, +}; + static int wil6210_debugfs_create_pseudo_ISR(struct wil6210_priv *wil, struct dentry *parent) { @@ -305,16 +368,19 @@ static int wil6210_debugfs_create_pseudo_ISR(struct wil6210_priv *wil, if (IS_ERR_OR_NULL(d)) return -ENODEV; - wil_debugfs_create_iomem_x32("CAUSE", S_IRUGO, d, wil->csr + - HOSTADDR(RGF_DMA_PSEUDO_CAUSE)); - wil_debugfs_create_iomem_x32("MASK_SW", S_IRUGO, d, wil->csr + - HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW)); - wil_debugfs_create_iomem_x32("MASK_FW", S_IRUGO, d, wil->csr + - HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_FW)); + wil6210_debugfs_init_offset(wil, d, (void * __force)wil->csr, + pseudo_isr_off); return 0; } +static const struct dbg_off itr_cnt_off[] = { + {"TRSH", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_CNT_TRSH), doff_io32}, + {"DATA", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_CNT_DATA), doff_io32}, + {"CTL", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_CNT_CRL), doff_io32}, + {}, +}; + static int wil6210_debugfs_create_ITR_CNT(struct wil6210_priv *wil, struct dentry *parent) { @@ -323,12 +389,8 @@ static int wil6210_debugfs_create_ITR_CNT(struct wil6210_priv *wil, if (IS_ERR_OR_NULL(d)) return -ENODEV; - wil_debugfs_create_iomem_x32("TRSH", S_IRUGO | S_IWUSR, d, wil->csr + - HOSTADDR(RGF_DMA_ITR_CNT_TRSH)); - wil_debugfs_create_iomem_x32("DATA", S_IRUGO | S_IWUSR, d, wil->csr + - HOSTADDR(RGF_DMA_ITR_CNT_DATA)); - wil_debugfs_create_iomem_x32("CTL", S_IRUGO | S_IWUSR, d, wil->csr + - HOSTADDR(RGF_DMA_ITR_CNT_CRL)); + wil6210_debugfs_init_offset(wil, d, (void * __force)wil->csr, + itr_cnt_off); return 0; } @@ -985,6 +1047,87 @@ static void wil6210_debugfs_init_blobs(struct wil6210_priv *wil, } } +/* misc files */ +static const struct { + const char *name; + umode_t mode; + const struct file_operations *fops; +} dbg_files[] = { + {"mbox", S_IRUGO, &fops_mbox}, + {"vrings", S_IRUGO, &fops_vring}, + {"stations", S_IRUGO, &fops_sta}, + {"desc", S_IRUGO, &fops_txdesc}, + {"bf", S_IRUGO, &fops_bf}, + {"ssid", S_IRUGO | S_IWUSR, &fops_ssid}, + {"mem_val", S_IRUGO, &fops_memread}, + {"reset", S_IWUSR, &fops_reset}, + {"rxon", S_IWUSR, &fops_rxon}, + {"tx_mgmt", S_IWUSR, &fops_txmgmt}, + {"wmi_send", S_IWUSR, &fops_wmi}, + {"temp", S_IRUGO, &fops_temp}, + {"freq", S_IRUGO, &fops_freq}, + {"link", S_IRUGO, &fops_link}, + {"info", S_IRUGO, &fops_info}, +}; + +static void wil6210_debugfs_init_files(struct wil6210_priv *wil, + struct dentry *dbg) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(dbg_files); i++) + debugfs_create_file(dbg_files[i].name, dbg_files[i].mode, dbg, + wil, dbg_files[i].fops); +} + +/* interrupt control blocks */ +static const struct { + const char *name; + u32 icr_off; +} dbg_icr[] = { + {"USER_ICR", HOSTADDR(RGF_USER_USER_ICR)}, + {"DMA_EP_TX_ICR", HOSTADDR(RGF_DMA_EP_TX_ICR)}, + {"DMA_EP_RX_ICR", HOSTADDR(RGF_DMA_EP_RX_ICR)}, + {"DMA_EP_MISC_ICR", HOSTADDR(RGF_DMA_EP_MISC_ICR)}, +}; + +static void wil6210_debugfs_init_isr(struct wil6210_priv *wil, + struct dentry *dbg) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(dbg_icr); i++) + wil6210_debugfs_create_ISR(wil, dbg_icr[i].name, dbg, + dbg_icr[i].icr_off); +} + +#define WIL_FIELD(name, mode, type) { __stringify(name), mode, \ + offsetof(struct wil6210_priv, name), type} + +/* fields in struct wil6210_priv */ +static const struct dbg_off dbg_wil_off[] = { + WIL_FIELD(secure_pcp, S_IRUGO | S_IWUSR, doff_u32), + WIL_FIELD(status, S_IRUGO | S_IWUSR, doff_ulong), + WIL_FIELD(fw_version, S_IRUGO, doff_u32), + WIL_FIELD(hw_version, S_IRUGO, doff_x32), + {}, +}; + +static const struct dbg_off dbg_wil_regs[] = { + {"RGF_MAC_MTRL_COUNTER_0", S_IRUGO, HOSTADDR(RGF_MAC_MTRL_COUNTER_0), + doff_io32}, + {"RGF_USER_USAGE_1", S_IRUGO, HOSTADDR(RGF_USER_USAGE_1), doff_io32}, + {}, +}; + +/* static parameters */ +static const struct dbg_off dbg_statics[] = { + {"desc_index", S_IRUGO | S_IWUSR, (ulong)&dbg_txdesc_index, doff_u32}, + {"vring_index", S_IRUGO | S_IWUSR, (ulong)&dbg_vring_index, doff_u32}, + {"mem_addr", S_IRUGO | S_IWUSR, (ulong)&mem_addr, doff_u32}, + {}, +}; + int wil6210_debugfs_init(struct wil6210_priv *wil) { struct dentry *dbg = wil->debug = debugfs_create_dir(WIL_NAME, @@ -993,54 +1136,17 @@ int wil6210_debugfs_init(struct wil6210_priv *wil) if (IS_ERR_OR_NULL(dbg)) return -ENODEV; - debugfs_create_file("mbox", S_IRUGO, dbg, wil, &fops_mbox); - debugfs_create_file("vrings", S_IRUGO, dbg, wil, &fops_vring); - debugfs_create_file("stations", S_IRUGO, dbg, wil, &fops_sta); - debugfs_create_file("desc", S_IRUGO, dbg, wil, &fops_txdesc); - debugfs_create_u32("desc_index", S_IRUGO | S_IWUSR, dbg, - &dbg_txdesc_index); - debugfs_create_u32("vring_index", S_IRUGO | S_IWUSR, dbg, - &dbg_vring_index); - - debugfs_create_file("bf", S_IRUGO, dbg, wil, &fops_bf); - debugfs_create_file("ssid", S_IRUGO | S_IWUSR, dbg, wil, &fops_ssid); - debugfs_create_u32("secure_pcp", S_IRUGO | S_IWUSR, dbg, - &wil->secure_pcp); - wil_debugfs_create_ulong("status", S_IRUGO | S_IWUSR, dbg, - &wil->status); - debugfs_create_u32("fw_version", S_IRUGO, dbg, &wil->fw_version); - debugfs_create_x32("hw_version", S_IRUGO, dbg, &wil->hw_version); - - wil6210_debugfs_create_ISR(wil, "USER_ICR", dbg, - HOSTADDR(RGF_USER_USER_ICR)); - wil6210_debugfs_create_ISR(wil, "DMA_EP_TX_ICR", dbg, - HOSTADDR(RGF_DMA_EP_TX_ICR)); - wil6210_debugfs_create_ISR(wil, "DMA_EP_RX_ICR", dbg, - HOSTADDR(RGF_DMA_EP_RX_ICR)); - wil6210_debugfs_create_ISR(wil, "DMA_EP_MISC_ICR", dbg, - HOSTADDR(RGF_DMA_EP_MISC_ICR)); - wil6210_debugfs_create_pseudo_ISR(wil, dbg); - wil6210_debugfs_create_ITR_CNT(wil, dbg); - wil_debugfs_create_iomem_x32("MAC_MTRL_COUNTER_0", S_IRUGO, dbg, - wil->csr + - HOSTADDR(RGF_MAC_MTRL_COUNTER_0)); - - wil_debugfs_create_iomem_x32("RGF_USER_USAGE_1", S_IRUGO, dbg, - wil->csr + - HOSTADDR(RGF_USER_USAGE_1)); - debugfs_create_u32("mem_addr", S_IRUGO | S_IWUSR, dbg, &mem_addr); - debugfs_create_file("mem_val", S_IRUGO, dbg, wil, &fops_memread); - - debugfs_create_file("reset", S_IWUSR, dbg, wil, &fops_reset); - debugfs_create_file("rxon", S_IWUSR, dbg, wil, &fops_rxon); - debugfs_create_file("tx_mgmt", S_IWUSR, dbg, wil, &fops_txmgmt); - debugfs_create_file("wmi_send", S_IWUSR, dbg, wil, &fops_wmi); - debugfs_create_file("temp", S_IRUGO, dbg, wil, &fops_temp); - debugfs_create_file("freq", S_IRUGO, dbg, wil, &fops_freq); - debugfs_create_file("link", S_IRUGO, dbg, wil, &fops_link); - debugfs_create_file("info", S_IRUGO, dbg, wil, &fops_info); - + wil6210_debugfs_init_files(wil, dbg); + wil6210_debugfs_init_isr(wil, dbg); wil6210_debugfs_init_blobs(wil, dbg); + wil6210_debugfs_init_offset(wil, dbg, wil, dbg_wil_off); + wil6210_debugfs_init_offset(wil, dbg, (void * __force)wil->csr, + dbg_wil_regs); + wil6210_debugfs_init_offset(wil, dbg, NULL, dbg_statics); + + wil6210_debugfs_create_pseudo_ISR(wil, dbg); + + wil6210_debugfs_create_ITR_CNT(wil, dbg); return 0; } From 36345ac33ca8d381c215091c5535e62335668f01 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Wed, 6 Aug 2014 10:31:56 +0300 Subject: [PATCH 105/221] wil6210: fix beamforming data reporting When reading 'bf' file on debugfs, query beam forming status from firmware. Ignore CID's that return error or return all zeros. Remove obsolete code that used to maintain statistics on per-device basis, as now it is reported be per-CID and current. Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/debugfs.c | 78 ++++++++++++++++++++-- drivers/net/wireless/ath/wil6210/txrx.c | 1 - drivers/net/wireless/ath/wil6210/wil6210.h | 12 ---- drivers/net/wireless/ath/wil6210/wmi.c | 28 -------- drivers/net/wireless/ath/wil6210/wmi.h | 2 +- 5 files changed, 72 insertions(+), 49 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 95269d234ca9..b1c6a7293390 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -22,6 +22,7 @@ #include #include "wil6210.h" +#include "wmi.h" #include "txrx.h" /* Nasty hack. Better have per device instances */ @@ -728,16 +729,79 @@ static const struct file_operations fops_txdesc = { }; /*---------beamforming------------*/ +static char *wil_bfstatus_str(u32 status) +{ + switch (status) { + case 0: + return "Failed"; + case 1: + return "OK"; + case 2: + return "Retrying"; + default: + return "??"; + } +} + +static bool is_all_zeros(void * const x_, size_t sz) +{ + /* if reply is all-0, ignore this CID */ + u32 *x = x_; + int n; + + for (n = 0; n < sz / sizeof(*x); n++) + if (x[n]) + return false; + + return true; +} + static int wil_bf_debugfs_show(struct seq_file *s, void *data) { + int rc; + int i; struct wil6210_priv *wil = s->private; - seq_printf(s, - "TSF : 0x%016llx\n" - "TxMCS : %d\n" - "Sectors(rx:tx) my %2d:%2d peer %2d:%2d\n", - wil->stats.tsf, wil->stats.bf_mcs, - wil->stats.my_rx_sector, wil->stats.my_tx_sector, - wil->stats.peer_rx_sector, wil->stats.peer_tx_sector); + struct wmi_notify_req_cmd cmd = { + .interval_usec = 0, + }; + struct { + struct wil6210_mbox_hdr_wmi wmi; + struct wmi_notify_req_done_event evt; + } __packed reply; + + for (i = 0; i < ARRAY_SIZE(wil->sta); i++) { + u32 status; + + cmd.cid = i; + rc = wmi_call(wil, WMI_NOTIFY_REQ_CMDID, &cmd, sizeof(cmd), + WMI_NOTIFY_REQ_DONE_EVENTID, &reply, + sizeof(reply), 20); + /* if reply is all-0, ignore this CID */ + if (rc || is_all_zeros(&reply.evt, sizeof(reply.evt))) + continue; + + status = le32_to_cpu(reply.evt.status); + seq_printf(s, "CID %d {\n" + " TSF = 0x%016llx\n" + " TxMCS = %2d TxTpt = %4d\n" + " SQI = %4d\n" + " Status = 0x%08x %s\n" + " Sectors(rx:tx) my %2d:%2d peer %2d:%2d\n" + " Goodput(rx:tx) %4d:%4d\n" + "}\n", + i, + le64_to_cpu(reply.evt.tsf), + le16_to_cpu(reply.evt.bf_mcs), + le32_to_cpu(reply.evt.tx_tpt), + reply.evt.sqi, + status, wil_bfstatus_str(status), + le16_to_cpu(reply.evt.my_rx_sector), + le16_to_cpu(reply.evt.my_tx_sector), + le16_to_cpu(reply.evt.other_rx_sector), + le16_to_cpu(reply.evt.other_tx_sector), + le32_to_cpu(reply.evt.rx_goodput), + le32_to_cpu(reply.evt.tx_goodput)); + } return 0; } diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 9fcc2e32180d..9bd920d272bb 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -414,7 +414,6 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, cid = wil_rxdesc_cid(d); stats = &wil->sta[cid].stats; stats->last_mcs_rx = wil_rxdesc_mcs(d); - wil->stats.last_mcs_rx = stats->last_mcs_rx; /* use radiotap header only if required */ if (ndev->type == ARPHRD_IEEE80211_RADIOTAP) diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 0097300c863c..f8718fe547c4 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -330,17 +330,6 @@ struct wil_tid_ampdu_rx { bool first_time; /* is it 1-st time this buffer used? */ }; -struct wil6210_stats { - u64 tsf; - u32 snr; - u16 last_mcs_rx; - u16 bf_mcs; /* last BF, used for Tx */ - u16 my_rx_sector; - u16 my_tx_sector; - u16 peer_rx_sector; - u16 peer_tx_sector; -}; - enum wil_sta_status { wil_sta_unused = 0, wil_sta_conn_pending = 1, @@ -433,7 +422,6 @@ struct wil6210_priv { struct mutex mutex; /* for wil6210_priv access in wil_{up|down} */ /* statistics */ - struct wil6210_stats stats; atomic_t isr_count_rx, isr_count_tx; /* debugfs */ struct dentry *debug; diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index b25a62da8f22..0beb129e9858 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -482,33 +482,6 @@ static void wmi_evt_disconnect(struct wil6210_priv *wil, int id, mutex_unlock(&wil->mutex); } -static void wmi_evt_notify(struct wil6210_priv *wil, int id, void *d, int len) -{ - struct wmi_notify_req_done_event *evt = d; - - if (len < sizeof(*evt)) { - wil_err(wil, "Short NOTIFY event\n"); - return; - } - - wil->stats.tsf = le64_to_cpu(evt->tsf); - wil->stats.snr = le32_to_cpu(evt->snr_val); - wil->stats.bf_mcs = le16_to_cpu(evt->bf_mcs); - wil->stats.my_rx_sector = le16_to_cpu(evt->my_rx_sector); - wil->stats.my_tx_sector = le16_to_cpu(evt->my_tx_sector); - wil->stats.peer_rx_sector = le16_to_cpu(evt->other_rx_sector); - wil->stats.peer_tx_sector = le16_to_cpu(evt->other_tx_sector); - wil_dbg_wmi(wil, "Link status, MCS %d TSF 0x%016llx\n" - "BF status 0x%08x SNR 0x%08x SQI %d%%\n" - "Tx Tpt %d goodput %d Rx goodput %d\n" - "Sectors(rx:tx) my %d:%d peer %d:%d\n", - wil->stats.bf_mcs, wil->stats.tsf, evt->status, - wil->stats.snr, evt->sqi, le32_to_cpu(evt->tx_tpt), - le32_to_cpu(evt->tx_goodput), le32_to_cpu(evt->rx_goodput), - wil->stats.my_rx_sector, wil->stats.my_tx_sector, - wil->stats.peer_rx_sector, wil->stats.peer_tx_sector); -} - /* * Firmware reports EAPOL frame using WME event. * Reconstruct Ethernet frame and deliver it via normal Rx @@ -651,7 +624,6 @@ static const struct { {WMI_SCAN_COMPLETE_EVENTID, wmi_evt_scan_complete}, {WMI_CONNECT_EVENTID, wmi_evt_connect}, {WMI_DISCONNECT_EVENTID, wmi_evt_disconnect}, - {WMI_NOTIFY_REQ_DONE_EVENTID, wmi_evt_notify}, {WMI_EAPOL_RX_EVENTID, wmi_evt_eapol_rx}, {WMI_DATA_PORT_OPEN_EVENTID, wmi_evt_linkup}, {WMI_WBE_LINKDOWN_EVENTID, wmi_evt_linkdown}, diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h index 2f51b46f255b..061618cee9f6 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.h +++ b/drivers/net/wireless/ath/wil6210/wmi.h @@ -980,7 +980,7 @@ struct wmi_ready_event { * WMI_NOTIFY_REQ_DONE_EVENTID */ struct wmi_notify_req_done_event { - __le32 status; + __le32 status; /* beamforming status, 0: fail; 1: OK; 2: retrying */ __le64 tsf; __le32 snr_val; __le32 tx_tpt; From a21420864a28f2cf24afdc555da7b6d7c100e9d8 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Wed, 6 Aug 2014 10:31:57 +0300 Subject: [PATCH 106/221] wil6210: fix false "scan timeout" When sending scan request, if hardware is not ready, scan timer was started and scan timeout mis-reported. Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/cfg80211.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index ee8a0e588d6e..a00f31881df9 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -311,8 +311,10 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, rc = wmi_send(wil, WMI_START_SCAN_CMDID, &cmd, sizeof(cmd.cmd) + cmd.cmd.num_channels * sizeof(cmd.cmd.channel_list[0])); - if (rc) + if (rc) { + del_timer_sync(&wil->scan_timer); wil->scan_request = NULL; + } return rc; } From 1eb9d1e5c659a9f2ae08a3d36d1c64d11368b58a Mon Sep 17 00:00:00 2001 From: Dedy Lansky Date: Wed, 6 Aug 2014 10:31:58 +0300 Subject: [PATCH 107/221] wil6210: Limit max number of associated stations Add a module parameter to support setting the maximum number of stations that can be associated to an AP. Signed-off-by: Dedy Lansky Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/wmi.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 0beb129e9858..596d6c1e8583 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -14,6 +14,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include #include #include @@ -22,6 +23,10 @@ #include "wmi.h" #include "trace.h" +static uint max_assoc_sta = 1; +module_param(max_assoc_sta, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(max_assoc_sta, " Max number of stations associated to the AP"); + /** * WMI event receiving - theory of operations * @@ -794,7 +799,7 @@ int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, u8 chan) .network_type = wmi_nettype, .disable_sec_offload = 1, .channel = chan - 1, - .pcp_max_assoc_sta = WIL6210_MAX_CID, + .pcp_max_assoc_sta = max_assoc_sta, }; struct { struct wil6210_mbox_hdr_wmi wmi; @@ -804,6 +809,14 @@ int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, u8 chan) if (!wil->secure_pcp) cmd.disable_sec = 1; + if ((cmd.pcp_max_assoc_sta > WIL6210_MAX_CID) || + (cmd.pcp_max_assoc_sta <= 0)) { + wil_info(wil, + "Requested connection limit %u, valid values are 1 - %d. Setting to %d\n", + max_assoc_sta, WIL6210_MAX_CID, WIL6210_MAX_CID); + cmd.pcp_max_assoc_sta = WIL6210_MAX_CID; + } + /* * Processing time may be huge, in case of secure AP it takes about * 3500ms for FW to start AP From 8fcfdeac97ee3ee8dd8e0e44b6a3b9d49b951bbd Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Wed, 6 Aug 2014 10:31:59 +0300 Subject: [PATCH 108/221] wil6210: fix free'd memory access in wil_if_free() In the wil_priv_deinit(), wdev->netdev is accessed, so free_netdev() should not be called before mentioned call. Set wdev->netdev to NULL Make sure no more attempts to use it. It is used for debug printk if not NULL. This fix kernel panic on module unload and in case error on probe; if memory allocation debugging enabled. Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/netdev.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c index d42fde903f0f..a44c2b61be08 100644 --- a/drivers/net/wireless/ath/wil6210/netdev.c +++ b/drivers/net/wireless/ath/wil6210/netdev.c @@ -168,11 +168,15 @@ void *wil_if_alloc(struct device *dev, void __iomem *csr) void wil_if_free(struct wil6210_priv *wil) { struct net_device *ndev = wil_to_ndev(wil); + if (!ndev) return; - free_netdev(ndev); wil_priv_deinit(wil); + + wil_to_ndev(wil) = NULL; + free_netdev(ndev); + wil_wdev_free(wil); } From 48e81a15fa40dce4553ae3156e170a2be9562fa9 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Wed, 6 Aug 2014 10:32:00 +0300 Subject: [PATCH 109/221] wil6210: cfg80211_rx_mgmt to use GFP_ATOMIC Internally, cfg80211_rx_mgmt() takes lock: spin_lock_bh(&wdev->mgmt_registrations_lock); and therefore one can't use it with GFP_KERNEL allocation flags. When called with GFP_KERNEL, "sleep while atomic" warning triggered: <3>[242645.446224] BUG: sleeping function called from invalid context at kernel/mm/slub.c:926 <3>[242645.455516] in_atomic(): 1, irqs_disabled(): 0, pid: 18881, name: kworker/u16:0 <6>[242645.462868] CPU: 0 PID: 18881 Comm: kworker/u16:0 Tainted: G O 3.10.40-g619a884-00001-g357fa9c #2 <6>[242645.463044] Workqueue: wil6210_wmi wmi_event_worker [wil6210] <6>[242645.463087] Call trace: <6>[242645.463157] [] dump_backtrace+0x0/0x144 <6>[242645.463205] [] show_stack+0x10/0x1c <6>[242645.463259] [] dump_stack+0x1c/0x28 <6>[242645.463313] [] __might_sleep+0xe0/0xf0 <6>[242645.463365] [] kmem_cache_alloc+0x48/0x1e4 <6>[242645.463414] [] __alloc_skb+0x48/0x164 <6>[242645.463466] [] nl80211_send_mgmt+0x4c/0x1dc <6>[242645.463511] [] cfg80211_rx_mgmt+0x1bc/0x25c <6>[242645.463647] [] wmi_evt_rx_mgmt+0x21c/0x23c [wil6210] <6>[242645.463783] [] wmi_event_worker+0x230/0x2f8 [wil6210] <6>[242645.463838] [] process_one_work+0x258/0x3d0 <6>[242645.463887] [] worker_thread+0x1f0/0x310 <6>[242645.463946] [] kthread+0xac/0xb8 Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/wmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 596d6c1e8583..1b64823544eb 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -355,7 +355,7 @@ static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len) } } else { cfg80211_rx_mgmt(wil->wdev, freq, signal, - (void *)rx_mgmt_frame, d_len, 0, GFP_KERNEL); + (void *)rx_mgmt_frame, d_len, 0, GFP_ATOMIC); } } From 560ce3087292603dafb2603ee12cab0ff6c20aee Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Wed, 6 Aug 2014 10:32:01 +0300 Subject: [PATCH 110/221] wil6210: fix access after free in wil_pcie_remove() 'wil' released in wil_if_free(); save iomapped address aside to properly unmap it. Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/pcie_bus.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c index cf0b21987d70..38dcbea49d44 100644 --- a/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c @@ -218,12 +218,13 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) static void wil_pcie_remove(struct pci_dev *pdev) { struct wil6210_priv *wil = pci_get_drvdata(pdev); + void __iomem *csr = wil->csr; wil6210_debugfs_remove(wil); wil_if_pcie_disable(wil); wil_if_remove(wil); wil_if_free(wil); - pci_iounmap(pdev, wil->csr); + pci_iounmap(pdev, csr); pci_release_region(pdev, 0); pci_disable_device(pdev); } From 372e3a846814656d5e514167484f684f828fff56 Mon Sep 17 00:00:00 2001 From: Himangi Saraogi Date: Thu, 7 Aug 2014 16:32:45 +0530 Subject: [PATCH 111/221] wireless: wlcore: Use devm_kzalloc This patch introduces the use of devm_kzalloc and does away with the kfrees in the probe and remove functions. Also, a couple of labels and the initial assignment of the ret variable in the probe function are removed. Signed-off-by: Himangi Saraogi Acked-by: Julia Lawall Signed-off-by: John W. Linville --- drivers/net/wireless/ti/wlcore/spi.c | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/ti/wlcore/spi.c b/drivers/net/wireless/ti/wlcore/spi.c index 392c882b28f0..69601f6741d9 100644 --- a/drivers/net/wireless/ti/wlcore/spi.c +++ b/drivers/net/wireless/ti/wlcore/spi.c @@ -327,23 +327,22 @@ static int wl1271_probe(struct spi_device *spi) struct wl12xx_spi_glue *glue; struct wlcore_platdev_data pdev_data; struct resource res[1]; - int ret = -ENOMEM; + int ret; memset(&pdev_data, 0x00, sizeof(pdev_data)); pdev_data.pdata = dev_get_platdata(&spi->dev); if (!pdev_data.pdata) { dev_err(&spi->dev, "no platform data\n"); - ret = -ENODEV; - goto out; + return -ENODEV; } pdev_data.if_ops = &spi_ops; - glue = kzalloc(sizeof(*glue), GFP_KERNEL); + glue = devm_kzalloc(&spi->dev, sizeof(*glue), GFP_KERNEL); if (!glue) { dev_err(&spi->dev, "can't allocate glue\n"); - goto out; + return -ENOMEM; } glue->dev = &spi->dev; @@ -357,14 +356,13 @@ static int wl1271_probe(struct spi_device *spi) ret = spi_setup(spi); if (ret < 0) { dev_err(glue->dev, "spi_setup failed\n"); - goto out_free_glue; + return ret; } glue->core = platform_device_alloc("wl12xx", PLATFORM_DEVID_AUTO); if (!glue->core) { dev_err(glue->dev, "can't allocate platform_device\n"); - ret = -ENOMEM; - goto out_free_glue; + return -ENOMEM; } glue->core->dev.parent = &spi->dev; @@ -398,11 +396,6 @@ static int wl1271_probe(struct spi_device *spi) out_dev_put: platform_device_put(glue->core); - -out_free_glue: - kfree(glue); - -out: return ret; } @@ -411,7 +404,6 @@ static int wl1271_remove(struct spi_device *spi) struct wl12xx_spi_glue *glue = spi_get_drvdata(spi); platform_device_unregister(glue->core); - kfree(glue); return 0; } From f0bd88dfd7e5d53bce84a9d077c949774f27a25a Mon Sep 17 00:00:00 2001 From: Rickard Strandqvist Date: Mon, 11 Aug 2014 20:52:56 +0200 Subject: [PATCH 112/221] net: wireless: ipw2x00: ipw2200.c: Cleaning up missing null-terminate in conjunction with strncpy Replacing strncpy with strlcpy to avoid strings that lacks null terminate. Signed-off-by: Rickard Strandqvist Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2x00/ipw2200.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c index a42f9c335090..f0c3c77a48d3 100644 --- a/drivers/net/wireless/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/ipw2x00/ipw2200.c @@ -5552,7 +5552,7 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, min(network->ssid_len, priv->essid_len)))) { char escaped[IW_ESSID_MAX_SIZE * 2 + 1]; - strncpy(escaped, + strlcpy(escaped, print_ssid(ssid, network->ssid, network->ssid_len), sizeof(escaped)); @@ -5765,7 +5765,7 @@ static int ipw_best_network(struct ipw_priv *priv, memcmp(network->ssid, priv->essid, min(network->ssid_len, priv->essid_len)))) { char escaped[IW_ESSID_MAX_SIZE * 2 + 1]; - strncpy(escaped, + strlcpy(escaped, print_ssid(ssid, network->ssid, network->ssid_len), sizeof(escaped)); @@ -5782,7 +5782,7 @@ static int ipw_best_network(struct ipw_priv *priv, * testing everything else. */ if (match->network && match->network->stats.rssi > network->stats.rssi) { char escaped[IW_ESSID_MAX_SIZE * 2 + 1]; - strncpy(escaped, + strlcpy(escaped, print_ssid(ssid, network->ssid, network->ssid_len), sizeof(escaped)); IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded because " From a796dac9a6bedff6db99f57828c85c97071d3d1e Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Wed, 13 Aug 2014 16:04:51 +0300 Subject: [PATCH 113/221] wireless: core: Reorder wiphy_register() notifications relevantly Currently it can send regulatory domain change notification before any NEW_WIPHY notification. Moreover, if rfill_register() fails, calling wiphy_unregister() will send a DEL_WIPHY though no NEW_WIPHY had been sent previously. Thus reordering so it properly notifies NEW_WIPHY before any other. Signed-off-by: Tomasz Bursztyka Signed-off-by: John W. Linville --- net/wireless/core.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/net/wireless/core.c b/net/wireless/core.c index afee5e0455ea..682babde4aa5 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -635,6 +635,9 @@ int wiphy_register(struct wiphy *wiphy) if (IS_ERR(rdev->wiphy.debugfsdir)) rdev->wiphy.debugfsdir = NULL; + cfg80211_debugfs_rdev_add(rdev); + nl80211_notify_wiphy(rdev, NL80211_CMD_NEW_WIPHY); + if (wiphy->regulatory_flags & REGULATORY_CUSTOM_REG) { struct regulatory_request request; @@ -646,8 +649,6 @@ int wiphy_register(struct wiphy *wiphy) nl80211_send_reg_change_event(&request); } - cfg80211_debugfs_rdev_add(rdev); - rdev->wiphy.registered = true; rtnl_unlock(); @@ -659,8 +660,6 @@ int wiphy_register(struct wiphy *wiphy) return res; } - nl80211_notify_wiphy(rdev, NL80211_CMD_NEW_WIPHY); - return 0; } EXPORT_SYMBOL(wiphy_register); From b9395df96ac41cdfcc929f1515828709b2f64b2f Mon Sep 17 00:00:00 2001 From: Himangi Saraogi Date: Wed, 13 Aug 2014 22:40:24 +0530 Subject: [PATCH 114/221] atmel_cs: Remove typedef local_info_t The Linux kernel coding style guidelines suggest not using typedefs for structure types. This patch gets rid of the typedef for local_info_t. Also, the name of the struct is changed to drop the _t, to make the name look less typedef-like. The following Coccinelle semantic patch detects the case: @tn@ identifier i; type td; @@ -typedef struct i { ... } -td ; @@ type tn.td; identifier tn.i; @@ -td + struct i Signed-off-by: Himangi Saraogi Acked-by: Julia Lawall Signed-off-by: John W. Linville --- drivers/net/wireless/atmel_cs.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/atmel_cs.c b/drivers/net/wireless/atmel_cs.c index 4cfb4d99ced0..7afc9c5329fb 100644 --- a/drivers/net/wireless/atmel_cs.c +++ b/drivers/net/wireless/atmel_cs.c @@ -66,18 +66,18 @@ static void atmel_release(struct pcmcia_device *link); static void atmel_detach(struct pcmcia_device *p_dev); -typedef struct local_info_t { +struct local_info { struct net_device *eth_dev; -} local_info_t; +}; static int atmel_probe(struct pcmcia_device *p_dev) { - local_info_t *local; + struct local_info *local; dev_dbg(&p_dev->dev, "atmel_attach()\n"); /* Allocate space for private device-specific data */ - local = kzalloc(sizeof(local_info_t), GFP_KERNEL); + local = kzalloc(sizeof(*local), GFP_KERNEL); if (!local) return -ENOMEM; @@ -117,7 +117,7 @@ static int atmel_config_check(struct pcmcia_device *p_dev, void *priv_data) static int atmel_config(struct pcmcia_device *link) { - local_info_t *dev; + struct local_info *dev; int ret; const struct pcmcia_device_id *did; @@ -141,14 +141,14 @@ static int atmel_config(struct pcmcia_device *link) if (ret) goto failed; - ((local_info_t*)link->priv)->eth_dev = + ((struct local_info *)link->priv)->eth_dev = init_atmel_card(link->irq, link->resource[0]->start, did ? did->driver_info : ATMEL_FW_TYPE_NONE, &link->dev, card_present, link); - if (!((local_info_t*)link->priv)->eth_dev) + if (!((struct local_info *)link->priv)->eth_dev) goto failed; @@ -161,20 +161,20 @@ static int atmel_config(struct pcmcia_device *link) static void atmel_release(struct pcmcia_device *link) { - struct net_device *dev = ((local_info_t*)link->priv)->eth_dev; + struct net_device *dev = ((struct local_info *)link->priv)->eth_dev; dev_dbg(&link->dev, "atmel_release\n"); if (dev) stop_atmel_card(dev); - ((local_info_t*)link->priv)->eth_dev = NULL; + ((struct local_info *)link->priv)->eth_dev = NULL; pcmcia_disable_device(link); } static int atmel_suspend(struct pcmcia_device *link) { - local_info_t *local = link->priv; + struct local_info *local = link->priv; netif_device_detach(local->eth_dev); @@ -183,7 +183,7 @@ static int atmel_suspend(struct pcmcia_device *link) static int atmel_resume(struct pcmcia_device *link) { - local_info_t *local = link->priv; + struct local_info *local = link->priv; atmel_open(local->eth_dev); netif_device_attach(local->eth_dev); From 7bb75da1717296f5850e1a9a36896a52fd07a26a Mon Sep 17 00:00:00 2001 From: Himangi Saraogi Date: Fri, 15 Aug 2014 21:53:24 +0530 Subject: [PATCH 115/221] orinoco_usb: use USB API functions rather than constants This patch introduces the use of the functions usb_endpoint_is_bulk_in(epd) and usb_endpoint_is_bulk_out(epd). The semantic patch that makes these changes is as follows: @@ struct usb_endpoint_descriptor *epd; @@ - ((epd->bmAttributes & \(USB_ENDPOINT_XFERTYPE_MASK\|3\)) == - \(USB_ENDPOINT_XFER_BULK\|2\)) + usb_endpoint_xfer_bulk(epd) @@ struct usb_endpoint_descriptor *epd; @@ - ((epd->bEndpointAddress & \(USB_ENDPOINT_DIR_MASK\|0x80\)) == - \(USB_DIR_IN\|0x80\)) + usb_endpoint_dir_in(epd) @@ struct usb_endpoint_descriptor *epd; @@ - ((epd->bEndpointAddress & \(USB_ENDPOINT_DIR_MASK\|0x80\)) == - \(USB_DIR_OUT\|0\)) + usb_endpoint_dir_out(epd) @@ struct usb_endpoint_descriptor *epd; @@ - (usb_endpoint_xfer_bulk(epd) && usb_endpoint_dir_in(epd)) + usb_endpoint_is_bulk_in(epd) @@ struct usb_endpoint_descriptor *epd; @@ - (usb_endpoint_xfer_bulk(epd) && usb_endpoint_dir_out(epd)) + usb_endpoint_is_bulk_out(epd) Signed-off-by: Himangi Saraogi Acked-by: Julia Lawall Signed-off-by: John W. Linville --- drivers/net/wireless/orinoco/orinoco_usb.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/orinoco/orinoco_usb.c b/drivers/net/wireless/orinoco/orinoco_usb.c index d3cf7c3ebfd6..f4b784fc882b 100644 --- a/drivers/net/wireless/orinoco/orinoco_usb.c +++ b/drivers/net/wireless/orinoco/orinoco_usb.c @@ -1605,10 +1605,7 @@ static int ezusb_probe(struct usb_interface *interface, for (i = 0; i < iface_desc->bNumEndpoints; ++i) { ep = &interface->altsetting[0].endpoint[i].desc; - if (((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) - == USB_DIR_IN) && - ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) - == USB_ENDPOINT_XFER_BULK)) { + if (usb_endpoint_is_bulk_in(ep)) { /* we found a bulk in endpoint */ if (upriv->read_urb != NULL) { pr_warning("Found a second bulk in ep, ignored"); @@ -1636,10 +1633,7 @@ static int ezusb_probe(struct usb_interface *interface, } } - if (((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) - == USB_DIR_OUT) && - ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) - == USB_ENDPOINT_XFER_BULK)) { + if (usb_endpoint_is_bulk_out(ep)) { /* we found a bulk out endpoint */ if (upriv->bap_buf != NULL) { pr_warning("Found a second bulk out ep, ignored"); From f8134fed8346c05007ca23e22e1504097afcd7c9 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Sat, 28 Jun 2014 16:35:26 -0400 Subject: [PATCH 116/221] mac80211: mesh_plink: use get_unaligned_le16 instead of memcpy Use get_unaligned_le16 to access llid/plid. Signed-off-by: Bob Copeland Signed-off-by: Johannes Berg --- net/mac80211/mesh_plink.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 8d67c1ebfbda..8f0887fc7128 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -1001,7 +1001,6 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata, enum ieee80211_self_protected_actioncode ftype; u32 changed = 0; u8 ie_len = elems->peering_len; - __le16 _plid, _llid; u16 plid, llid = 0; if (!elems->peering) { @@ -1036,13 +1035,10 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata, /* Note the lines below are correct, the llid in the frame is the plid * from the point of view of this host. */ - memcpy(&_plid, PLINK_GET_LLID(elems->peering), sizeof(__le16)); - plid = le16_to_cpu(_plid); + plid = get_unaligned_le16(PLINK_GET_LLID(elems->peering)); if (ftype == WLAN_SP_MESH_PEERING_CONFIRM || - (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len == 8)) { - memcpy(&_llid, PLINK_GET_PLID(elems->peering), sizeof(__le16)); - llid = le16_to_cpu(_llid); - } + (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len == 8)) + llid = get_unaligned_le16(PLINK_GET_PLID(elems->peering)); /* WARNING: Only for sta pointer, is dropped & re-acquired */ rcu_read_lock(); From 649b2a4da5d8a39c4d7be2fd228cf797819656f9 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 25 Jul 2014 15:01:59 +0200 Subject: [PATCH 117/221] mac80211: make ieee80211_vif_use_reserved_switch static Reorder some code to make ieee80211_vif_use_reserved_switch() static, no other changes. Signed-off-by: Johannes Berg --- net/mac80211/chan.c | 187 ++++++++++++++++++------------------- net/mac80211/ieee80211_i.h | 1 - 2 files changed, 93 insertions(+), 95 deletions(-) diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index 6d537f03c0ba..792eac6cc7b3 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c @@ -637,41 +637,6 @@ out: return ret; } -static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata) -{ - struct ieee80211_local *local = sdata->local; - struct ieee80211_chanctx_conf *conf; - struct ieee80211_chanctx *ctx; - bool use_reserved_switch = false; - - lockdep_assert_held(&local->chanctx_mtx); - - conf = rcu_dereference_protected(sdata->vif.chanctx_conf, - lockdep_is_held(&local->chanctx_mtx)); - if (!conf) - return; - - ctx = container_of(conf, struct ieee80211_chanctx, conf); - - if (sdata->reserved_chanctx) { - if (sdata->reserved_chanctx->replace_state == - IEEE80211_CHANCTX_REPLACES_OTHER && - ieee80211_chanctx_num_reserved(local, - sdata->reserved_chanctx) > 1) - use_reserved_switch = true; - - ieee80211_vif_unreserve_chanctx(sdata); - } - - ieee80211_assign_vif_chanctx(sdata, NULL); - if (ieee80211_chanctx_refcount(local, ctx) == 0) - ieee80211_free_chanctx(local, ctx); - - /* Unreserving may ready an in-place reservation. */ - if (use_reserved_switch) - ieee80211_vif_use_reserved_switch(local); -} - void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local, struct ieee80211_chanctx *chanctx) { @@ -762,63 +727,6 @@ void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local, drv_change_chanctx(local, chanctx, IEEE80211_CHANCTX_CHANGE_RX_CHAINS); } -int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, - const struct cfg80211_chan_def *chandef, - enum ieee80211_chanctx_mode mode) -{ - struct ieee80211_local *local = sdata->local; - struct ieee80211_chanctx *ctx; - u8 radar_detect_width = 0; - int ret; - - lockdep_assert_held(&local->mtx); - - WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev)); - - mutex_lock(&local->chanctx_mtx); - - ret = cfg80211_chandef_dfs_required(local->hw.wiphy, - chandef, - sdata->wdev.iftype); - if (ret < 0) - goto out; - if (ret > 0) - radar_detect_width = BIT(chandef->width); - - sdata->radar_required = ret; - - ret = ieee80211_check_combinations(sdata, chandef, mode, - radar_detect_width); - if (ret < 0) - goto out; - - __ieee80211_vif_release_channel(sdata); - - ctx = ieee80211_find_chanctx(local, chandef, mode); - if (!ctx) - ctx = ieee80211_new_chanctx(local, chandef, mode); - if (IS_ERR(ctx)) { - ret = PTR_ERR(ctx); - goto out; - } - - sdata->vif.bss_conf.chandef = *chandef; - - ret = ieee80211_assign_vif_chanctx(sdata, ctx); - if (ret) { - /* if assign fails refcount stays the same */ - if (ieee80211_chanctx_refcount(local, ctx) == 0) - ieee80211_free_chanctx(local, ctx); - goto out; - } - - ieee80211_recalc_smps_chanctx(local, ctx); - ieee80211_recalc_radar_chanctx(local, ctx); - out: - mutex_unlock(&local->chanctx_mtx); - return ret; -} - static void __ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata, bool clear) @@ -1267,8 +1175,7 @@ err: return err; } -int -ieee80211_vif_use_reserved_switch(struct ieee80211_local *local) +static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local) { struct ieee80211_sub_if_data *sdata, *sdata_tmp; struct ieee80211_chanctx *ctx, *ctx_tmp, *old_ctx; @@ -1520,6 +1427,98 @@ err: return err; } +static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata) +{ + struct ieee80211_local *local = sdata->local; + struct ieee80211_chanctx_conf *conf; + struct ieee80211_chanctx *ctx; + bool use_reserved_switch = false; + + lockdep_assert_held(&local->chanctx_mtx); + + conf = rcu_dereference_protected(sdata->vif.chanctx_conf, + lockdep_is_held(&local->chanctx_mtx)); + if (!conf) + return; + + ctx = container_of(conf, struct ieee80211_chanctx, conf); + + if (sdata->reserved_chanctx) { + if (sdata->reserved_chanctx->replace_state == + IEEE80211_CHANCTX_REPLACES_OTHER && + ieee80211_chanctx_num_reserved(local, + sdata->reserved_chanctx) > 1) + use_reserved_switch = true; + + ieee80211_vif_unreserve_chanctx(sdata); + } + + ieee80211_assign_vif_chanctx(sdata, NULL); + if (ieee80211_chanctx_refcount(local, ctx) == 0) + ieee80211_free_chanctx(local, ctx); + + /* Unreserving may ready an in-place reservation. */ + if (use_reserved_switch) + ieee80211_vif_use_reserved_switch(local); +} + +int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, + const struct cfg80211_chan_def *chandef, + enum ieee80211_chanctx_mode mode) +{ + struct ieee80211_local *local = sdata->local; + struct ieee80211_chanctx *ctx; + u8 radar_detect_width = 0; + int ret; + + lockdep_assert_held(&local->mtx); + + WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev)); + + mutex_lock(&local->chanctx_mtx); + + ret = cfg80211_chandef_dfs_required(local->hw.wiphy, + chandef, + sdata->wdev.iftype); + if (ret < 0) + goto out; + if (ret > 0) + radar_detect_width = BIT(chandef->width); + + sdata->radar_required = ret; + + ret = ieee80211_check_combinations(sdata, chandef, mode, + radar_detect_width); + if (ret < 0) + goto out; + + __ieee80211_vif_release_channel(sdata); + + ctx = ieee80211_find_chanctx(local, chandef, mode); + if (!ctx) + ctx = ieee80211_new_chanctx(local, chandef, mode); + if (IS_ERR(ctx)) { + ret = PTR_ERR(ctx); + goto out; + } + + sdata->vif.bss_conf.chandef = *chandef; + + ret = ieee80211_assign_vif_chanctx(sdata, ctx); + if (ret) { + /* if assign fails refcount stays the same */ + if (ieee80211_chanctx_refcount(local, ctx) == 0) + ieee80211_free_chanctx(local, ctx); + goto out; + } + + ieee80211_recalc_smps_chanctx(local, ctx); + ieee80211_recalc_radar_chanctx(local, ctx); + out: + mutex_unlock(&local->chanctx_mtx); + return ret; +} + int ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata) { struct ieee80211_local *local = sdata->local; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index ef7a089ac546..ffb20e5e6cf3 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1869,7 +1869,6 @@ ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata, int __must_check ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata); int ieee80211_vif_unreserve_chanctx(struct ieee80211_sub_if_data *sdata); -int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local); int __must_check ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata, From 970fdfa89babb5a6f1a3d345e8cb54d92c1e3a8f Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 11 Aug 2014 03:29:57 -0700 Subject: [PATCH 118/221] cfg80211: remove @gfp parameter from cfg80211_rx_mgmt() In the cfg80211_rx_mgmt(), parameter @gfp was used for the memory allocation. But, memory get allocated under spin_lock_bh(), this implies atomic context. So, one can't use GFP_KERNEL, only variants with no __GFP_WAIT. Actually, in all occurrences GFP_ATOMIC is used (wil6210 use GFP_KERNEL by mistake), and it should be this way or warning triggered in the memory allocation code. Remove @gfp parameter as no actual choice exist, and use hard coded GFP_ATOMIC for memory allocation. Signed-off-by: Vladimir Kondratiev Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath6kl/wmi.c | 5 ++--- drivers/net/wireless/ath/wil6210/wmi.c | 2 +- drivers/net/wireless/brcm80211/brcmfmac/p2p.c | 6 ++---- drivers/net/wireless/mwifiex/util.c | 2 +- drivers/staging/rtl8723au/core/rtw_mlme_ext.c | 2 +- drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c | 4 ++-- include/net/cfg80211.h | 3 +-- net/mac80211/rx.c | 2 +- net/wireless/mlme.c | 4 ++-- 9 files changed, 13 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index 94df345d08c2..77fcca1f5bd6 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -619,8 +619,7 @@ static int ath6kl_wmi_rx_probe_req_event_rx(struct wmi *wmi, u8 *datap, int len, dlen, freq, vif->probe_req_report); if (vif->probe_req_report || vif->nw_type == AP_NETWORK) - cfg80211_rx_mgmt(&vif->wdev, freq, 0, ev->data, dlen, 0, - GFP_ATOMIC); + cfg80211_rx_mgmt(&vif->wdev, freq, 0, ev->data, dlen, 0); return 0; } @@ -659,7 +658,7 @@ static int ath6kl_wmi_rx_action_event_rx(struct wmi *wmi, u8 *datap, int len, return -EINVAL; } ath6kl_dbg(ATH6KL_DBG_WMI, "rx_action: len=%u freq=%u\n", dlen, freq); - cfg80211_rx_mgmt(&vif->wdev, freq, 0, ev->data, dlen, 0, GFP_ATOMIC); + cfg80211_rx_mgmt(&vif->wdev, freq, 0, ev->data, dlen, 0); return 0; } diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 1d1d0afdd2e1..335bc38325db 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -350,7 +350,7 @@ static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len) } } else { cfg80211_rx_mgmt(wil->wdev, freq, signal, - (void *)rx_mgmt_frame, d_len, 0, GFP_KERNEL); + (void *)rx_mgmt_frame, d_len, 0); } } diff --git a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c index 057b982ea8b3..1d78a91db594 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c @@ -1431,8 +1431,7 @@ int brcmf_p2p_notify_action_frame_rx(struct brcmf_if *ifp, IEEE80211_BAND_5GHZ); wdev = &ifp->vif->wdev; - cfg80211_rx_mgmt(wdev, freq, 0, (u8 *)mgmt_frame, mgmt_frame_len, 0, - GFP_ATOMIC); + cfg80211_rx_mgmt(wdev, freq, 0, (u8 *)mgmt_frame, mgmt_frame_len, 0); kfree(mgmt_frame); return 0; @@ -1896,8 +1895,7 @@ s32 brcmf_p2p_notify_rx_mgmt_p2p_probereq(struct brcmf_if *ifp, IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ); - cfg80211_rx_mgmt(&vif->wdev, freq, 0, mgmt_frame, mgmt_frame_len, 0, - GFP_ATOMIC); + cfg80211_rx_mgmt(&vif->wdev, freq, 0, mgmt_frame, mgmt_frame_len, 0); brcmf_dbg(INFO, "mgmt_frame_len (%d) , e->datalen (%d), chanspec (%04x), freq (%d)\n", mgmt_frame_len, e->datalen, chanspec, freq); diff --git a/drivers/net/wireless/mwifiex/util.c b/drivers/net/wireless/mwifiex/util.c index cee028321a9a..ec79c49de097 100644 --- a/drivers/net/wireless/mwifiex/util.c +++ b/drivers/net/wireless/mwifiex/util.c @@ -172,7 +172,7 @@ mwifiex_process_mgmt_packet(struct mwifiex_private *priv, cfg80211_rx_mgmt(priv->wdev, priv->roc_cfg.chan.center_freq, CAL_RSSI(rx_pd->snr, rx_pd->nf), skb->data, pkt_len, - 0, GFP_ATOMIC); + 0); return 0; } diff --git a/drivers/staging/rtl8723au/core/rtw_mlme_ext.c b/drivers/staging/rtl8723au/core/rtw_mlme_ext.c index c5fdcb89dacd..2a1502f351f8 100644 --- a/drivers/staging/rtl8723au/core/rtw_mlme_ext.c +++ b/drivers/staging/rtl8723au/core/rtw_mlme_ext.c @@ -2128,7 +2128,7 @@ static int on_action_public23a(struct rtw_adapter *padapter, IEEE80211_BAND_5GHZ); if (cfg80211_rx_mgmt(padapter->rtw_wdev, freq, 0, pframe, - skb->len, 0, GFP_ATOMIC)) + skb->len, 0)) return _SUCCESS; return _FAIL; diff --git a/drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c b/drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c index 93dc844a10b3..2d6d7d1a5b7d 100644 --- a/drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c +++ b/drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c @@ -2379,7 +2379,7 @@ void rtw_cfg80211_indicate_sta_assoc(struct rtw_adapter *padapter, IEEE80211_BAND_5GHZ); cfg80211_rx_mgmt(padapter->rtw_wdev, freq, 0, pmgmt_frame, frame_len, - 0, GFP_ATOMIC); + 0); #endif /* defined(RTW_USE_CFG80211_STA_EVENT) */ } @@ -2425,7 +2425,7 @@ void rtw_cfg80211_indicate_sta_disassoc(struct rtw_adapter *padapter, frame_len = sizeof(struct ieee80211_hdr_3addr) + 2; cfg80211_rx_mgmt(padapter->rtw_wdev, freq, 0, (u8 *)&mgmt, frame_len, - 0, GFP_ATOMIC); + 0); #endif /* defined(RTW_USE_CFG80211_STA_EVENT) */ } diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 0a080c4de275..7b8dac3efe8f 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -4412,7 +4412,6 @@ void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr, * @buf: Management frame (header + body) * @len: length of the frame data * @flags: flags, as defined in enum nl80211_rxmgmt_flags - * @gfp: context flags * * This function is called whenever an Action frame is received for a station * mode interface, but is not processed in kernel. @@ -4423,7 +4422,7 @@ void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr, * driver is responsible for rejecting the frame. */ bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_dbm, - const u8 *buf, size_t len, u32 flags, gfp_t gfp); + const u8 *buf, size_t len, u32 flags); /** * cfg80211_mgmt_tx_status - notification of TX status for management frame diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index bd2c9b22c945..a8d862f9183c 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2725,7 +2725,7 @@ ieee80211_rx_h_userspace_mgmt(struct ieee80211_rx_data *rx) sig = status->signal; if (cfg80211_rx_mgmt(&rx->sdata->wdev, status->freq, sig, - rx->skb->data, rx->skb->len, 0, GFP_ATOMIC)) { + rx->skb->data, rx->skb->len, 0)) { if (rx->sta) rx->sta->rx_packets++; dev_kfree_skb(rx->skb); diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 266766b8d80b..369fc334fdad 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -605,7 +605,7 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, } bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_mbm, - const u8 *buf, size_t len, u32 flags, gfp_t gfp) + const u8 *buf, size_t len, u32 flags) { struct wiphy *wiphy = wdev->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); @@ -648,7 +648,7 @@ bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_mbm, /* Indicate the received Action frame to user space */ if (nl80211_send_mgmt(rdev, wdev, reg->nlportid, freq, sig_mbm, - buf, len, flags, gfp)) + buf, len, flags, GFP_ATOMIC)) continue; result = true; From 170fd0b1f6108b48df4369afa0ee29a83e922748 Mon Sep 17 00:00:00 2001 From: Andrei Otcheretianski Date: Wed, 30 Jul 2014 14:36:18 +0300 Subject: [PATCH 119/221] ieee80211: Support parsing TPC report element in action frames TPC report element is contained in spectrum management's tpc report action frames and in radio measurement's link measurement report action frames. Add a function which checks whether an action frame contains this element. This may be needed by the drivers in order to set the correct tx power value in these frames. Signed-off-by: Andrei Otcheretianski Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- include/linux/ieee80211.h | 65 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 63ab3873c5ed..8018c915ee63 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -838,6 +838,16 @@ enum ieee80211_vht_opmode_bits { #define WLAN_SA_QUERY_TR_ID_LEN 2 +/** + * struct ieee80211_tpc_report_ie + * + * This structure refers to "TPC Report element" + */ +struct ieee80211_tpc_report_ie { + u8 tx_power; + u8 link_margin; +} __packed; + struct ieee80211_mgmt { __le16 frame_control; __le16 duration; @@ -973,6 +983,13 @@ struct ieee80211_mgmt { u8 action_code; u8 operating_mode; } __packed vht_opmode_notif; + struct { + u8 action_code; + u8 dialog_token; + u8 tpc_elem_id; + u8 tpc_elem_length; + struct ieee80211_tpc_report_ie tpc; + } __packed tpc_report; } u; } __packed action; } u; @@ -1865,6 +1882,7 @@ enum ieee80211_category { WLAN_CATEGORY_DLS = 2, WLAN_CATEGORY_BACK = 3, WLAN_CATEGORY_PUBLIC = 4, + WLAN_CATEGORY_RADIO_MEASUREMENT = 5, WLAN_CATEGORY_HT = 7, WLAN_CATEGORY_SA_QUERY = 8, WLAN_CATEGORY_PROTECTED_DUAL_OF_ACTION = 9, @@ -2378,4 +2396,51 @@ static inline bool ieee80211_check_tim(const struct ieee80211_tim_ie *tim, #define TU_TO_JIFFIES(x) (usecs_to_jiffies((x) * 1024)) #define TU_TO_EXP_TIME(x) (jiffies + TU_TO_JIFFIES(x)) +/** + * ieee80211_action_contains_tpc - checks if the frame contains TPC element + * @skb: the skb containing the frame, length will be checked + * + * This function checks if it's either TPC report action frame or Link + * Measurement report action frame as defined in IEEE Std. 802.11-2012 8.5.2.5 + * and 8.5.7.5 accordingly. + */ +static inline bool ieee80211_action_contains_tpc(struct sk_buff *skb) +{ + struct ieee80211_mgmt *mgmt = (void *)skb->data; + + if (!ieee80211_is_action(mgmt->frame_control)) + return false; + + if (skb->len < IEEE80211_MIN_ACTION_SIZE + + sizeof(mgmt->u.action.u.tpc_report)) + return false; + + /* + * TPC report - check that: + * category = 0 (Spectrum Management) or 5 (Radio Measurement) + * spectrum management action = 3 (TPC/Link Measurement report) + * TPC report EID = 35 + * TPC report element length = 2 + * + * The spectrum management's tpc_report struct is used here both for + * parsing tpc_report and radio measurement's link measurement report + * frame, since the relevant part is identical in both frames. + */ + if (mgmt->u.action.category != WLAN_CATEGORY_SPECTRUM_MGMT && + mgmt->u.action.category != WLAN_CATEGORY_RADIO_MEASUREMENT) + return false; + + /* both spectrum mgmt and link measurement have same action code */ + if (mgmt->u.action.u.tpc_report.action_code != + WLAN_ACTION_SPCT_TPC_RPRT) + return false; + + if (mgmt->u.action.u.tpc_report.tpc_elem_id != WLAN_EID_TPC_REPORT || + mgmt->u.action.u.tpc_report.tpc_elem_length != + sizeof(struct ieee80211_tpc_report_ie)) + return false; + + return true; +} + #endif /* LINUX_IEEE80211_H */ From ca34e3b5c808385b175650605faa29e71e91991b Mon Sep 17 00:00:00 2001 From: Ido Yariv Date: Tue, 29 Jul 2014 15:38:53 +0300 Subject: [PATCH 120/221] mac80211: Fix accounting of the tailroom-needed counter When hw acceleration is enabled, the GENERATE_IV or PUT_IV_SPACE flags will only require headroom space. Consequently, the tailroom-needed counter can safely be decremented. Signed-off-by: Ido Yariv Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- include/net/mac80211.h | 7 +++++-- net/mac80211/key.c | 12 +++--------- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 1cd84444665c..1fbed0a6d556 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1226,7 +1226,8 @@ struct ieee80211_vif *wdev_to_ieee80211_vif(struct wireless_dev *wdev); * * @IEEE80211_KEY_FLAG_GENERATE_IV: This flag should be set by the * driver to indicate that it requires IV generation for this - * particular key. + * particular key. Setting this flag does not necessarily mean that SKBs + * will have sufficient tailroom for ICV or MIC. * @IEEE80211_KEY_FLAG_GENERATE_MMIC: This flag should be set by * the driver for a TKIP key if it requires Michael MIC * generation in software. @@ -1238,7 +1239,9 @@ struct ieee80211_vif *wdev_to_ieee80211_vif(struct wireless_dev *wdev); * @IEEE80211_KEY_FLAG_PUT_IV_SPACE: This flag should be set by the driver * if space should be prepared for the IV, but the IV * itself should not be generated. Do not set together with - * @IEEE80211_KEY_FLAG_GENERATE_IV on the same key. + * @IEEE80211_KEY_FLAG_GENERATE_IV on the same key. Setting this flag does + * not necessarily mean that SKBs will have sufficient tailroom for ICV or + * MIC. * @IEEE80211_KEY_FLAG_RX_MGMT: This key will be used to decrypt received * management frames. The flag can help drivers that have a hardware * crypto implementation that doesn't deal with management frames diff --git a/net/mac80211/key.c b/net/mac80211/key.c index d808cff80153..6429d0e1d4a1 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -130,9 +130,7 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key) if (!ret) { key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE; - if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) || - (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) || - (key->conf.flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE))) + if (!(key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC)) sdata->crypto_tx_tailroom_needed_cnt--; WARN_ON((key->conf.flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE) && @@ -180,9 +178,7 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) sta = key->sta; sdata = key->sdata; - if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) || - (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) || - (key->conf.flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE))) + if (!(key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC)) increment_tailroom_need_count(sdata); ret = drv_set_key(key->local, DISABLE_KEY, sdata, @@ -878,9 +874,7 @@ void ieee80211_remove_key(struct ieee80211_key_conf *keyconf) if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) { key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; - if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) || - (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) || - (key->conf.flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE))) + if (!(key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC)) increment_tailroom_need_count(key->sdata); } From c70f59a2a007c57843195a93c3b7308204e0a5ab Mon Sep 17 00:00:00 2001 From: Ido Yariv Date: Tue, 29 Jul 2014 15:39:14 +0300 Subject: [PATCH 121/221] mac80211: don't resize skbs needlessly Header-less cloned skbs with sufficient headroom need not be cloned unless the tailroom is going to be modified. Fix ieee80211_skb_resize so it would only resize cloned skbs if either the header isn't released or the tailroom is going to be modified. Some drivers might have assumed that skbs are never cloned, so add a HW flag that explicitly permits cloned TX skbs. Drivers which do not modify TX skbs should set this flag to avoid copying skbs. Signed-off-by: Ido Yariv Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- include/net/mac80211.h | 5 ++++- net/mac80211/tx.c | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 1fbed0a6d556..c9b2bec8db47 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1609,6 +1609,9 @@ struct ieee80211_tx_control { * is not enabled the default action is to disconnect when getting the * CSA frame. * + * @IEEE80211_HW_SUPPORTS_CLONED_SKBS: The driver will never modify the payload + * or tailroom of TX skbs without copying them first. + * * @IEEE80211_SINGLE_HW_SCAN_ON_ALL_BANDS: The HW supports scanning on all bands * in one command, mac80211 doesn't have to run separate scans per band. */ @@ -1642,7 +1645,7 @@ enum ieee80211_hw_flags { IEEE80211_HW_TIMING_BEACON_ONLY = 1<<26, IEEE80211_HW_SUPPORTS_HT_CCK_RATES = 1<<27, IEEE80211_HW_CHANCTX_STA_CSA = 1<<28, - /* bit 29 unused */ + IEEE80211_HW_SUPPORTS_CLONED_SKBS = 1<<29, IEEE80211_SINGLE_HW_SCAN_ON_ALL_BANDS = 1<<30, }; diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 2051cc60f8ce..925c39f4099e 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1478,7 +1478,10 @@ static int ieee80211_skb_resize(struct ieee80211_sub_if_data *sdata, tail_need = max_t(int, tail_need, 0); } - if (skb_cloned(skb)) + if (skb_cloned(skb) && + (!(local->hw.flags & IEEE80211_HW_SUPPORTS_CLONED_SKBS) || + !skb_clone_writable(skb, ETH_HLEN) || + sdata->crypto_tx_tailroom_needed_cnt)) I802_DEBUG_INC(local->tx_expand_skb_head_cloned); else if (head_need || tail_need) I802_DEBUG_INC(local->tx_expand_skb_head); From f41ef64853fb1e02728e56b2d0d55aef8ed12b26 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Mon, 28 Jul 2014 15:21:05 +0200 Subject: [PATCH 122/221] cfg80211: re-enable CSA for drivers that support it This reverts commit dda444d52496aa8ddc501561bca580f1374a96a9. Channel switching code has been reworked and improved significantly since the time original locking issues were found. Signed-off-by: Michal Kazior Signed-off-by: Johannes Berg --- net/wireless/core.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/net/wireless/core.c b/net/wireless/core.c index afee5e0455ea..a207eb116829 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -492,12 +492,6 @@ int wiphy_register(struct wiphy *wiphy) int i; u16 ifmodes = wiphy->interface_modes; - /* - * There are major locking problems in nl80211/mac80211 for CSA, - * disable for all drivers until this has been reworked. - */ - wiphy->flags &= ~WIPHY_FLAG_HAS_CHANNEL_SWITCH; - #ifdef CONFIG_PM if (WARN_ON(wiphy->wowlan && (wiphy->wowlan->flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) && From 0e227084aee36b3ba27b4fc9cd9e425be6ce2ab8 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 12 Aug 2014 20:34:30 +0200 Subject: [PATCH 123/221] cfg80211: clarify BSS probe response vs. beacon data There are a few possible cases of where BSS data came from: 1) only a beacon has been received 2) only a probe response has been received 3) the driver didn't report what it received (this happens when using cfg80211_inform_bss[_width]()) 4) both probe response and beacon data has been received Unfortunately, in the userspace API, a few things weren't there: a) there was no way to differentiate cases 1) and 4) above without comparing the data of the IEs b) the TSF was always from the last frame, instead of being exposed for beacon/probe response separately like IEs Fix this by i) exporting a new flag attribute that indicates whether or not probe response data has been received - this addresses (a) ii) exporting a BEACON_TSF attribute that holds the beacon's TSF if a beacon has been received iii) not exporting the beacon attributes in case (3) above as that would just lead userspace into thinking the data actually came from a beacon when that isn't clear To implement this, track inside the IEs struct whether or not it (definitely) came from a beacon. Reported-by: William Seto Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 2 ++ include/uapi/linux/nl80211.h | 16 ++++++++++++++-- net/wireless/nl80211.c | 16 ++++++++++++---- net/wireless/scan.c | 6 ++++-- 4 files changed, 32 insertions(+), 8 deletions(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 7b8dac3efe8f..77b85a89abca 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1503,12 +1503,14 @@ enum cfg80211_signal_type { * @tsf: TSF contained in the frame that carried these IEs * @rcu_head: internal use, for freeing * @len: length of the IEs + * @from_beacon: these IEs are known to come from a beacon * @data: IE data */ struct cfg80211_bss_ies { u64 tsf; struct rcu_head rcu_head; int len; + bool from_beacon; u8 data[]; }; diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index f1db15b9c041..d097568da690 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -3055,14 +3055,20 @@ enum nl80211_bss_scan_width { * @NL80211_BSS_BSSID: BSSID of the BSS (6 octets) * @NL80211_BSS_FREQUENCY: frequency in MHz (u32) * @NL80211_BSS_TSF: TSF of the received probe response/beacon (u64) + * (if @NL80211_BSS_PRESP_DATA is present then this is known to be + * from a probe response, otherwise it may be from the same beacon + * that the NL80211_BSS_BEACON_TSF will be from) * @NL80211_BSS_BEACON_INTERVAL: beacon interval of the (I)BSS (u16) * @NL80211_BSS_CAPABILITY: capability field (CPU order, u16) * @NL80211_BSS_INFORMATION_ELEMENTS: binary attribute containing the * raw information elements from the probe response/beacon (bin); - * if the %NL80211_BSS_BEACON_IES attribute is present, the IEs here are - * from a Probe Response frame; otherwise they are from a Beacon frame. + * if the %NL80211_BSS_BEACON_IES attribute is present and the data is + * different then the IEs here are from a Probe Response frame; otherwise + * they are from a Beacon frame. * However, if the driver does not indicate the source of the IEs, these * IEs may be from either frame subtype. + * If present, the @NL80211_BSS_PRESP_DATA attribute indicates that the + * data here is known to be from a probe response, without any heuristics. * @NL80211_BSS_SIGNAL_MBM: signal strength of probe response/beacon * in mBm (100 * dBm) (s32) * @NL80211_BSS_SIGNAL_UNSPEC: signal strength of the probe response/beacon @@ -3074,6 +3080,10 @@ enum nl80211_bss_scan_width { * yet been received * @NL80211_BSS_CHAN_WIDTH: channel width of the control channel * (u32, enum nl80211_bss_scan_width) + * @NL80211_BSS_BEACON_TSF: TSF of the last received beacon (u64) + * (not present if no beacon frame has been received yet) + * @NL80211_BSS_PRESP_DATA: the data in @NL80211_BSS_INFORMATION_ELEMENTS and + * @NL80211_BSS_TSF is known to be from a probe response (flag attribute) * @__NL80211_BSS_AFTER_LAST: internal * @NL80211_BSS_MAX: highest BSS attribute */ @@ -3091,6 +3101,8 @@ enum nl80211_bss { NL80211_BSS_SEEN_MS_AGO, NL80211_BSS_BEACON_IES, NL80211_BSS_CHAN_WIDTH, + NL80211_BSS_BEACON_TSF, + NL80211_BSS_PRESP_DATA, /* keep last */ __NL80211_BSS_AFTER_LAST, diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index df7b1332a1ec..3011401f52c0 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -6033,7 +6033,6 @@ static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb, const struct cfg80211_bss_ies *ies; void *hdr; struct nlattr *bss; - bool tsf = false; ASSERT_WDEV_LOCK(wdev); @@ -6060,18 +6059,27 @@ static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb, goto nla_put_failure; rcu_read_lock(); + /* indicate whether we have probe response data or not */ + if (rcu_access_pointer(res->proberesp_ies) && + nla_put_flag(msg, NL80211_BSS_PRESP_DATA)) + goto fail_unlock_rcu; + + /* this pointer prefers to be pointed to probe response data + * but is always valid + */ ies = rcu_dereference(res->ies); if (ies) { if (nla_put_u64(msg, NL80211_BSS_TSF, ies->tsf)) goto fail_unlock_rcu; - tsf = true; if (ies->len && nla_put(msg, NL80211_BSS_INFORMATION_ELEMENTS, ies->len, ies->data)) goto fail_unlock_rcu; } + + /* and this pointer is always (unless driver didn't know) beacon data */ ies = rcu_dereference(res->beacon_ies); - if (ies) { - if (!tsf && nla_put_u64(msg, NL80211_BSS_TSF, ies->tsf)) + if (ies && ies->from_beacon) { + if (nla_put_u64(msg, NL80211_BSS_BEACON_TSF, ies->tsf)) goto fail_unlock_rcu; if (ies->len && nla_put(msg, NL80211_BSS_BEACON_IES, ies->len, ies->data)) diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 0798c62e6085..ad1a1a2808d3 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -918,11 +918,12 @@ cfg80211_inform_bss_width(struct wiphy *wiphy, * override the IEs pointer should we have received an earlier * indication of Probe Response data. */ - ies = kmalloc(sizeof(*ies) + ielen, gfp); + ies = kzalloc(sizeof(*ies) + ielen, gfp); if (!ies) return NULL; ies->len = ielen; ies->tsf = tsf; + ies->from_beacon = false; memcpy(ies->data, ie, ielen); rcu_assign_pointer(tmp.pub.beacon_ies, ies); @@ -982,11 +983,12 @@ cfg80211_inform_bss_width_frame(struct wiphy *wiphy, if (!channel) return NULL; - ies = kmalloc(sizeof(*ies) + ielen, gfp); + ies = kzalloc(sizeof(*ies) + ielen, gfp); if (!ies) return NULL; ies->len = ielen; ies->tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp); + ies->from_beacon = ieee80211_is_beacon(mgmt->frame_control); memcpy(ies->data, mgmt->u.probe_resp.variable, ielen); if (ieee80211_is_probe_resp(mgmt->frame_control)) From 5bc8c1f2b070bab82ed738f98ecfac725e33c57f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 12 Aug 2014 21:01:28 +0200 Subject: [PATCH 124/221] cfg80211: allow passing frame type to cfg80211_inform_bss() When using the cfg80211_inform_bss[_width]() functions drivers cannot currently indicate whether the data was received in a beacon or probe response. Fix that by passing a new enum that indicates such (or unknown). For good measure, use it in ath6kl. Acked-by: Kalle Valo [ath6kl] Acked-by: Arend van Spriel [brcmfmac] Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 1 + drivers/net/wireless/ath/ath6kl/wmi.c | 43 ++++--------------- drivers/net/wireless/ath/wil6210/wmi.c | 2 +- .../wireless/brcm80211/brcmfmac/wl_cfg80211.c | 18 +++++--- drivers/net/wireless/libertas/cfg.c | 2 + drivers/net/wireless/mwifiex/cfg80211.c | 1 + drivers/net/wireless/mwifiex/scan.c | 3 +- drivers/net/wireless/orinoco/scan.c | 14 +++--- drivers/net/wireless/rndis_wlan.c | 14 +++--- .../staging/rtl8723au/os_dep/ioctl_cfg80211.c | 1 + drivers/staging/wlan-ng/cfg80211.c | 1 + include/net/cfg80211.h | 20 ++++++++- net/wireless/scan.c | 15 ++++++- 13 files changed, 77 insertions(+), 58 deletions(-) diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index e535807c3d89..ba60e37213eb 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -717,6 +717,7 @@ ath6kl_add_bss_if_needed(struct ath6kl_vif *vif, memcpy(ie + 2, vif->ssid, vif->ssid_len); memcpy(ie + 2 + vif->ssid_len, beacon_ie, beacon_ie_len); bss = cfg80211_inform_bss(ar->wiphy, chan, + CFG80211_BSS_FTYPE_UNKNOWN, bssid, 0, cap_val, 100, ie, 2 + vif->ssid_len + beacon_ie_len, 0, GFP_KERNEL); diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index 77fcca1f5bd6..b921005ad7ee 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -1092,7 +1092,6 @@ static int ath6kl_wmi_bssinfo_event_rx(struct wmi *wmi, u8 *datap, int len, u8 *buf; struct ieee80211_channel *channel; struct ath6kl *ar = wmi->parent_dev; - struct ieee80211_mgmt *mgmt; struct cfg80211_bss *bss; if (len <= sizeof(struct wmi_bss_info_hdr2)) @@ -1138,39 +1137,15 @@ static int ath6kl_wmi_bssinfo_event_rx(struct wmi *wmi, u8 *datap, int len, } } - /* - * In theory, use of cfg80211_inform_bss() would be more natural here - * since we do not have the full frame. However, at least for now, - * cfg80211 can only distinguish Beacon and Probe Response frames from - * each other when using cfg80211_inform_bss_frame(), so let's build a - * fake IEEE 802.11 header to be able to take benefit of this. - */ - mgmt = kmalloc(24 + len, GFP_ATOMIC); - if (mgmt == NULL) - return -EINVAL; - - if (bih->frame_type == BEACON_FTYPE) { - mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | - IEEE80211_STYPE_BEACON); - memset(mgmt->da, 0xff, ETH_ALEN); - } else { - struct net_device *dev = vif->ndev; - - mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | - IEEE80211_STYPE_PROBE_RESP); - memcpy(mgmt->da, dev->dev_addr, ETH_ALEN); - } - mgmt->duration = cpu_to_le16(0); - memcpy(mgmt->sa, bih->bssid, ETH_ALEN); - memcpy(mgmt->bssid, bih->bssid, ETH_ALEN); - mgmt->seq_ctrl = cpu_to_le16(0); - - memcpy(&mgmt->u.beacon, buf, len); - - bss = cfg80211_inform_bss_frame(ar->wiphy, channel, mgmt, - 24 + len, (bih->snr - 95) * 100, - GFP_ATOMIC); - kfree(mgmt); + bss = cfg80211_inform_bss(ar->wiphy, channel, + bih->frame_type == BEACON_FTYPE ? + CFG80211_BSS_FTYPE_BEACON : + CFG80211_BSS_FTYPE_PRESP, + bih->bssid, get_unaligned_le64((__le64 *)buf), + get_unaligned_le16(((__le16 *)buf) + 5), + get_unaligned_le16(((__le16 *)buf) + 4), + buf + 8 + 2 + 2, len - 8 - 2 - 2, + (bih->snr - 95) * 100, GFP_ATOMIC); if (bss == NULL) return -ENOMEM; cfg80211_put_bss(ar->wiphy, bss); diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 335bc38325db..960b66fc1430 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -346,7 +346,7 @@ static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len) rx_mgmt_frame->bssid); cfg80211_put_bss(wiphy, bss); } else { - wil_err(wil, "cfg80211_inform_bss() failed\n"); + wil_err(wil, "cfg80211_inform_bss_frame() failed\n"); } } else { cfg80211_rx_mgmt(wil->wdev, freq, signal, diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index 02fe706fc9ec..12a60ca1462a 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c @@ -2394,9 +2394,13 @@ static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg, brcmf_dbg(CONN, "Beacon interval: %d\n", notify_interval); brcmf_dbg(CONN, "Signal: %d\n", notify_signal); - bss = cfg80211_inform_bss(wiphy, notify_channel, (const u8 *)bi->BSSID, - 0, notify_capability, notify_interval, notify_ie, - notify_ielen, notify_signal, GFP_KERNEL); + bss = cfg80211_inform_bss(wiphy, notify_channel, + CFG80211_BSS_FTYPE_UNKNOWN, + (const u8 *)bi->BSSID, + 0, notify_capability, + notify_interval, notify_ie, + notify_ielen, notify_signal, + GFP_KERNEL); if (!bss) return -ENOMEM; @@ -2498,9 +2502,11 @@ static s32 wl_inform_ibss(struct brcmf_cfg80211_info *cfg, brcmf_dbg(CONN, "beacon interval: %d\n", notify_interval); brcmf_dbg(CONN, "signal: %d\n", notify_signal); - bss = cfg80211_inform_bss(wiphy, notify_channel, bssid, - 0, notify_capability, notify_interval, - notify_ie, notify_ielen, notify_signal, GFP_KERNEL); + bss = cfg80211_inform_bss(wiphy, notify_channel, + CFG80211_BSS_FTYPE_UNKNOWN, bssid, 0, + notify_capability, notify_interval, + notify_ie, notify_ielen, notify_signal, + GFP_KERNEL); if (!bss) { err = -ENOMEM; diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c index 47a998d8f99e..22884ba7d6cc 100644 --- a/drivers/net/wireless/libertas/cfg.c +++ b/drivers/net/wireless/libertas/cfg.c @@ -653,6 +653,7 @@ static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy, if (channel && !(channel->flags & IEEE80211_CHAN_DISABLED)) { bss = cfg80211_inform_bss(wiphy, channel, + CFG80211_BSS_FTYPE_UNKNOWN, bssid, get_unaligned_le64(tsfdesc), capa, intvl, ie, ielen, LBS_SCAN_RSSI_TO_MBM(rssi), @@ -1754,6 +1755,7 @@ static void lbs_join_post(struct lbs_private *priv, bss = cfg80211_inform_bss(priv->wdev->wiphy, params->chandef.chan, + CFG80211_BSS_FTYPE_UNKNOWN, bssid, 0, capability, diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index e2e6bf13c2d8..15f994f3b4ce 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -1557,6 +1557,7 @@ static int mwifiex_cfg80211_inform_ibss_bss(struct mwifiex_private *priv) band)); bss = cfg80211_inform_bss(priv->wdev->wiphy, chan, + CFG80211_BSS_FTYPE_UNKNOWN, bss_info.bssid, 0, WLAN_CAPABILITY_IBSS, 0, ie_buf, ie_len, 0, GFP_KERNEL); cfg80211_put_bss(priv->wdev->wiphy, bss); diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c index dee717a19ddb..195ef0ca343f 100644 --- a/drivers/net/wireless/mwifiex/scan.c +++ b/drivers/net/wireless/mwifiex/scan.c @@ -1719,7 +1719,8 @@ mwifiex_parse_single_response_buf(struct mwifiex_private *priv, u8 **bss_info, if (chan && !(chan->flags & IEEE80211_CHAN_DISABLED)) { bss = cfg80211_inform_bss(priv->wdev->wiphy, - chan, bssid, timestamp, + chan, CFG80211_BSS_FTYPE_UNKNOWN, + bssid, timestamp, cap_info_bitmap, beacon_period, ie_buf, ie_len, rssi, GFP_KERNEL); bss_priv = (struct mwifiex_bss_priv *)bss->priv; diff --git a/drivers/net/wireless/orinoco/scan.c b/drivers/net/wireless/orinoco/scan.c index e175b9b8561b..2c66166add70 100644 --- a/drivers/net/wireless/orinoco/scan.c +++ b/drivers/net/wireless/orinoco/scan.c @@ -123,9 +123,10 @@ static void orinoco_add_hostscan_result(struct orinoco_private *priv, beacon_interval = le16_to_cpu(bss->a.beacon_interv); signal = SIGNAL_TO_MBM(le16_to_cpu(bss->a.level)); - cbss = cfg80211_inform_bss(wiphy, channel, bss->a.bssid, timestamp, - capability, beacon_interval, ie_buf, ie_len, - signal, GFP_KERNEL); + cbss = cfg80211_inform_bss(wiphy, channel, CFG80211_BSS_FTYPE_UNKNOWN, + bss->a.bssid, timestamp, capability, + beacon_interval, ie_buf, ie_len, signal, + GFP_KERNEL); cfg80211_put_bss(wiphy, cbss); } @@ -156,9 +157,10 @@ void orinoco_add_extscan_result(struct orinoco_private *priv, ie = bss->data; signal = SIGNAL_TO_MBM(bss->level); - cbss = cfg80211_inform_bss(wiphy, channel, bss->bssid, timestamp, - capability, beacon_interval, ie, ie_len, - signal, GFP_KERNEL); + cbss = cfg80211_inform_bss(wiphy, channel, CFG80211_BSS_FTYPE_UNKNOWN, + bss->bssid, timestamp, capability, + beacon_interval, ie, ie_len, signal, + GFP_KERNEL); cfg80211_put_bss(wiphy, cbss); } diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index d2a9a08210be..1a4facd1fbf3 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -2022,9 +2022,10 @@ static bool rndis_bss_info_update(struct usbnet *usbdev, capability = le16_to_cpu(fixed->capabilities); beacon_interval = le16_to_cpu(fixed->beacon_interval); - bss = cfg80211_inform_bss(priv->wdev.wiphy, channel, bssid->mac, - timestamp, capability, beacon_interval, ie, ie_len, signal, - GFP_KERNEL); + bss = cfg80211_inform_bss(priv->wdev.wiphy, channel, + CFG80211_BSS_FTYPE_UNKNOWN, bssid->mac, + timestamp, capability, beacon_interval, + ie, ie_len, signal, GFP_KERNEL); cfg80211_put_bss(priv->wdev.wiphy, bss); return (bss != NULL); @@ -2711,9 +2712,10 @@ static void rndis_wlan_craft_connected_bss(struct usbnet *usbdev, u8 *bssid, bssid, (u32)timestamp, capability, beacon_period, ie_len, ssid.essid, signal); - bss = cfg80211_inform_bss(priv->wdev.wiphy, channel, bssid, - timestamp, capability, beacon_period, ie_buf, ie_len, - signal, GFP_KERNEL); + bss = cfg80211_inform_bss(priv->wdev.wiphy, channel, + CFG80211_BSS_FTYPE_UNKNOWN, bssid, + timestamp, capability, beacon_period, + ie_buf, ie_len, signal, GFP_KERNEL); cfg80211_put_bss(priv->wdev.wiphy, bss); } diff --git a/drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c b/drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c index 2d6d7d1a5b7d..8b0ccb5c5fc4 100644 --- a/drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c +++ b/drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c @@ -279,6 +279,7 @@ static int rtw_cfg80211_inform_bss(struct rtw_adapter *padapter, } bss = cfg80211_inform_bss(wiphy, notify_channel, + CFG80211_BSS_FTYPE_UNKNOWN, pnetwork->network.MacAddress, pnetwork->network.tsf, pnetwork->network.capability, diff --git a/drivers/staging/wlan-ng/cfg80211.c b/drivers/staging/wlan-ng/cfg80211.c index 3727f6d25cf1..8942dcb44180 100644 --- a/drivers/staging/wlan-ng/cfg80211.c +++ b/drivers/staging/wlan-ng/cfg80211.c @@ -422,6 +422,7 @@ static int prism2_scan(struct wiphy *wiphy, IEEE80211_BAND_2GHZ); bss = cfg80211_inform_bss(wiphy, ieee80211_get_channel(wiphy, freq), + CFG80211_BSS_FTYPE_UNKNOWN, (const u8 *) &(msg2.bssid.data.data), msg2.timestamp.data, msg2.capinfo.data, msg2.beaconperiod.data, diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 77b85a89abca..ab21299c8f4d 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -3767,11 +3767,25 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy, } /** - * cfg80211_inform_bss - inform cfg80211 of a new BSS + * enum cfg80211_bss_frame_type - frame type that the BSS data came from + * @CFG80211_BSS_FTYPE_UNKNOWN: driver doesn't know whether the data is + * from a beacon or probe response + * @CFG80211_BSS_FTYPE_BEACON: data comes from a beacon + * @CFG80211_BSS_FTYPE_PRESP: data comes from a probe response + */ +enum cfg80211_bss_frame_type { + CFG80211_BSS_FTYPE_UNKNOWN, + CFG80211_BSS_FTYPE_BEACON, + CFG80211_BSS_FTYPE_PRESP, +}; + +/** + * cfg80211_inform_bss_width - inform cfg80211 of a new BSS * * @wiphy: the wiphy reporting the BSS * @rx_channel: The channel the frame was received on * @scan_width: width of the control channel + * @ftype: frame type (if known) * @bssid: the BSSID of the BSS * @tsf: the TSF sent by the peer in the beacon/probe response (or 0) * @capability: the capability field sent by the peer @@ -3791,6 +3805,7 @@ struct cfg80211_bss * __must_check cfg80211_inform_bss_width(struct wiphy *wiphy, struct ieee80211_channel *rx_channel, enum nl80211_bss_scan_width scan_width, + enum cfg80211_bss_frame_type ftype, const u8 *bssid, u64 tsf, u16 capability, u16 beacon_interval, const u8 *ie, size_t ielen, s32 signal, gfp_t gfp); @@ -3798,12 +3813,13 @@ cfg80211_inform_bss_width(struct wiphy *wiphy, static inline struct cfg80211_bss * __must_check cfg80211_inform_bss(struct wiphy *wiphy, struct ieee80211_channel *rx_channel, + enum cfg80211_bss_frame_type ftype, const u8 *bssid, u64 tsf, u16 capability, u16 beacon_interval, const u8 *ie, size_t ielen, s32 signal, gfp_t gfp) { return cfg80211_inform_bss_width(wiphy, rx_channel, - NL80211_BSS_CHAN_WIDTH_20, + NL80211_BSS_CHAN_WIDTH_20, ftype, bssid, tsf, capability, beacon_interval, ie, ielen, signal, gfp); diff --git a/net/wireless/scan.c b/net/wireless/scan.c index ad1a1a2808d3..620a4b40d466 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -884,6 +884,7 @@ struct cfg80211_bss* cfg80211_inform_bss_width(struct wiphy *wiphy, struct ieee80211_channel *rx_channel, enum nl80211_bss_scan_width scan_width, + enum cfg80211_bss_frame_type ftype, const u8 *bssid, u64 tsf, u16 capability, u16 beacon_interval, const u8 *ie, size_t ielen, s32 signal, gfp_t gfp) @@ -911,7 +912,7 @@ cfg80211_inform_bss_width(struct wiphy *wiphy, tmp.pub.beacon_interval = beacon_interval; tmp.pub.capability = capability; /* - * Since we do not know here whether the IEs are from a Beacon or Probe + * If we do not know here whether the IEs are from a Beacon or Probe * Response frame, we need to pick one of the options and only use it * with the driver that does not provide the full Beacon/Probe Response * frame. Use Beacon frame pointer to avoid indicating that this should @@ -926,7 +927,17 @@ cfg80211_inform_bss_width(struct wiphy *wiphy, ies->from_beacon = false; memcpy(ies->data, ie, ielen); - rcu_assign_pointer(tmp.pub.beacon_ies, ies); + switch (ftype) { + case CFG80211_BSS_FTYPE_BEACON: + ies->from_beacon = true; + /* fall through to assign */ + case CFG80211_BSS_FTYPE_UNKNOWN: + rcu_assign_pointer(tmp.pub.beacon_ies, ies); + break; + case CFG80211_BSS_FTYPE_PRESP: + rcu_assign_pointer(tmp.pub.proberesp_ies, ies); + break; + } rcu_assign_pointer(tmp.pub.ies, ies); signal_valid = abs(rx_channel->center_freq - channel->center_freq) <= From ad053a962f1e83597ec8388716619c7633a00ef1 Mon Sep 17 00:00:00 2001 From: Andreea-Cristina Bernat Date: Fri, 22 Aug 2014 16:14:49 +0300 Subject: [PATCH 125/221] mac80211: scan: Replace rcu_assign_pointer() with RCU_INIT_POINTER() The use of "rcu_assign_pointer()" is NULLing out the pointer. According to RCU_INIT_POINTER()'s block comment: "1. This use of RCU_INIT_POINTER() is NULLing out the pointer" it is better to use it instead of rcu_assign_pointer() because it has a smaller overhead. The following Coccinelle semantic patch was used: @@ @@ - rcu_assign_pointer + RCU_INIT_POINTER (..., NULL) Signed-off-by: Andreea-Cristina Bernat Signed-off-by: Johannes Berg --- net/mac80211/scan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index a0a938145dcc..a9bb6eb8c3e0 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -1094,7 +1094,7 @@ int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata) if (rcu_access_pointer(local->sched_scan_sdata)) { ret = drv_sched_scan_stop(local, sdata); if (!ret) - rcu_assign_pointer(local->sched_scan_sdata, NULL); + RCU_INIT_POINTER(local->sched_scan_sdata, NULL); } out: mutex_unlock(&local->mtx); From 7aa7a72a23679abf1cea9b3b65a8921244e769a7 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Mon, 25 Aug 2014 12:09:38 +0200 Subject: [PATCH 126/221] ath10k: improve logging to include dev id This makes it a lot easier to log and debug messages if there's more than 1 ath10k device on a system. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/bmi.c | 52 +-- drivers/net/wireless/ath/ath10k/ce.c | 14 +- drivers/net/wireless/ath/ath10k/core.c | 181 ++++----- drivers/net/wireless/ath/ath10k/debug.c | 67 ++-- drivers/net/wireless/ath/ath10k/debug.h | 18 +- drivers/net/wireless/ath/ath10k/htc.c | 99 ++--- drivers/net/wireless/ath/ath10k/htc.h | 2 +- drivers/net/wireless/ath/ath10k/htt.c | 9 +- drivers/net/wireless/ath/ath10k/htt_rx.c | 116 +++--- drivers/net/wireless/ath/ath10k/htt_tx.c | 46 ++- drivers/net/wireless/ath/ath10k/mac.c | 427 +++++++++++---------- drivers/net/wireless/ath/ath10k/pci.c | 203 +++++----- drivers/net/wireless/ath/ath10k/spectral.c | 8 +- drivers/net/wireless/ath/ath10k/txrx.c | 17 +- drivers/net/wireless/ath/ath10k/wmi.c | 355 ++++++++--------- 15 files changed, 833 insertions(+), 781 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/bmi.c b/drivers/net/wireless/ath/ath10k/bmi.c index 17d221abd58c..3d29b0875b3e 100644 --- a/drivers/net/wireless/ath/ath10k/bmi.c +++ b/drivers/net/wireless/ath/ath10k/bmi.c @@ -22,7 +22,7 @@ void ath10k_bmi_start(struct ath10k *ar) { - ath10k_dbg(ATH10K_DBG_BMI, "bmi start\n"); + ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi start\n"); ar->bmi.done_sent = false; } @@ -33,10 +33,10 @@ int ath10k_bmi_done(struct ath10k *ar) u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.done); int ret; - ath10k_dbg(ATH10K_DBG_BMI, "bmi done\n"); + ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi done\n"); if (ar->bmi.done_sent) { - ath10k_dbg(ATH10K_DBG_BMI, "bmi skipped\n"); + ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi skipped\n"); return 0; } @@ -45,7 +45,7 @@ int ath10k_bmi_done(struct ath10k *ar) ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, NULL, NULL); if (ret) { - ath10k_warn("unable to write to the device: %d\n", ret); + ath10k_warn(ar, "unable to write to the device: %d\n", ret); return ret; } @@ -61,10 +61,10 @@ int ath10k_bmi_get_target_info(struct ath10k *ar, u32 resplen = sizeof(resp.get_target_info); int ret; - ath10k_dbg(ATH10K_DBG_BMI, "bmi get target info\n"); + ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi get target info\n"); if (ar->bmi.done_sent) { - ath10k_warn("BMI Get Target Info Command disallowed\n"); + ath10k_warn(ar, "BMI Get Target Info Command disallowed\n"); return -EBUSY; } @@ -72,12 +72,12 @@ int ath10k_bmi_get_target_info(struct ath10k *ar, ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, &resp, &resplen); if (ret) { - ath10k_warn("unable to get target info from device\n"); + ath10k_warn(ar, "unable to get target info from device\n"); return ret; } if (resplen < sizeof(resp.get_target_info)) { - ath10k_warn("invalid get_target_info response length (%d)\n", + ath10k_warn(ar, "invalid get_target_info response length (%d)\n", resplen); return -EIO; } @@ -97,11 +97,11 @@ int ath10k_bmi_read_memory(struct ath10k *ar, u32 rxlen; int ret; - ath10k_dbg(ATH10K_DBG_BMI, "bmi read address 0x%x length %d\n", + ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi read address 0x%x length %d\n", address, length); if (ar->bmi.done_sent) { - ath10k_warn("command disallowed\n"); + ath10k_warn(ar, "command disallowed\n"); return -EBUSY; } @@ -115,7 +115,7 @@ int ath10k_bmi_read_memory(struct ath10k *ar, ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, &resp, &rxlen); if (ret) { - ath10k_warn("unable to read from the device (%d)\n", + ath10k_warn(ar, "unable to read from the device (%d)\n", ret); return ret; } @@ -137,11 +137,11 @@ int ath10k_bmi_write_memory(struct ath10k *ar, u32 txlen; int ret; - ath10k_dbg(ATH10K_DBG_BMI, "bmi write address 0x%x length %d\n", + ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi write address 0x%x length %d\n", address, length); if (ar->bmi.done_sent) { - ath10k_warn("command disallowed\n"); + ath10k_warn(ar, "command disallowed\n"); return -EBUSY; } @@ -159,7 +159,7 @@ int ath10k_bmi_write_memory(struct ath10k *ar, ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, hdrlen + txlen, NULL, NULL); if (ret) { - ath10k_warn("unable to write to the device (%d)\n", + ath10k_warn(ar, "unable to write to the device (%d)\n", ret); return ret; } @@ -183,11 +183,11 @@ int ath10k_bmi_execute(struct ath10k *ar, u32 address, u32 param, u32 *result) u32 resplen = sizeof(resp.execute); int ret; - ath10k_dbg(ATH10K_DBG_BMI, "bmi execute address 0x%x param 0x%x\n", + ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi execute address 0x%x param 0x%x\n", address, param); if (ar->bmi.done_sent) { - ath10k_warn("command disallowed\n"); + ath10k_warn(ar, "command disallowed\n"); return -EBUSY; } @@ -197,19 +197,19 @@ int ath10k_bmi_execute(struct ath10k *ar, u32 address, u32 param, u32 *result) ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, &resp, &resplen); if (ret) { - ath10k_warn("unable to read from the device\n"); + ath10k_warn(ar, "unable to read from the device\n"); return ret; } if (resplen < sizeof(resp.execute)) { - ath10k_warn("invalid execute response length (%d)\n", + ath10k_warn(ar, "invalid execute response length (%d)\n", resplen); return -EIO; } *result = __le32_to_cpu(resp.execute.result); - ath10k_dbg(ATH10K_DBG_BMI, "bmi execute result 0x%x\n", *result); + ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi execute result 0x%x\n", *result); return 0; } @@ -221,11 +221,11 @@ int ath10k_bmi_lz_data(struct ath10k *ar, const void *buffer, u32 length) u32 txlen; int ret; - ath10k_dbg(ATH10K_DBG_BMI, "bmi lz data buffer 0x%p length %d\n", + ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi lz data buffer 0x%p length %d\n", buffer, length); if (ar->bmi.done_sent) { - ath10k_warn("command disallowed\n"); + ath10k_warn(ar, "command disallowed\n"); return -EBUSY; } @@ -241,7 +241,7 @@ int ath10k_bmi_lz_data(struct ath10k *ar, const void *buffer, u32 length) ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, hdrlen + txlen, NULL, NULL); if (ret) { - ath10k_warn("unable to write to the device\n"); + ath10k_warn(ar, "unable to write to the device\n"); return ret; } @@ -258,11 +258,11 @@ int ath10k_bmi_lz_stream_start(struct ath10k *ar, u32 address) u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.lz_start); int ret; - ath10k_dbg(ATH10K_DBG_BMI, "bmi lz stream start address 0x%x\n", + ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi lz stream start address 0x%x\n", address); if (ar->bmi.done_sent) { - ath10k_warn("command disallowed\n"); + ath10k_warn(ar, "command disallowed\n"); return -EBUSY; } @@ -271,7 +271,7 @@ int ath10k_bmi_lz_stream_start(struct ath10k *ar, u32 address) ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, NULL, NULL); if (ret) { - ath10k_warn("unable to Start LZ Stream to the device\n"); + ath10k_warn(ar, "unable to Start LZ Stream to the device\n"); return ret; } @@ -286,7 +286,7 @@ int ath10k_bmi_fast_download(struct ath10k *ar, u32 trailer_len = length - head_len; int ret; - ath10k_dbg(ATH10K_DBG_BMI, + ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi fast download address 0x%x buffer 0x%p length %d\n", address, buffer, length); diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index f6668162a0a8..71eef233bd01 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c @@ -284,7 +284,7 @@ int ath10k_ce_send_nolock(struct ath10k_ce_pipe *ce_state, int ret = 0; if (nbytes > ce_state->src_sz_max) - ath10k_warn("%s: send more we can (nbytes: %d, max: %d)\n", + ath10k_warn(ar, "%s: send more we can (nbytes: %d, max: %d)\n", __func__, nbytes, ce_state->src_sz_max); if (unlikely(CE_RING_DELTA(nentries_mask, @@ -853,7 +853,7 @@ static int ath10k_ce_init_src_ring(struct ath10k *ar, ath10k_ce_src_ring_lowmark_set(ar, ctrl_addr, 0); ath10k_ce_src_ring_highmark_set(ar, ctrl_addr, nentries); - ath10k_dbg(ATH10K_DBG_BOOT, + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot init ce src ring id %d entries %d base_addr %p\n", ce_id, nentries, src_ring->base_addr_owner_space); @@ -887,7 +887,7 @@ static int ath10k_ce_init_dest_ring(struct ath10k *ar, ath10k_ce_dest_ring_lowmark_set(ar, ctrl_addr, 0); ath10k_ce_dest_ring_highmark_set(ar, ctrl_addr, nentries); - ath10k_dbg(ATH10K_DBG_BOOT, + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot ce dest ring id %d entries %d base_addr %p\n", ce_id, nentries, dest_ring->base_addr_owner_space); @@ -1056,7 +1056,7 @@ int ath10k_ce_init_pipe(struct ath10k *ar, unsigned int ce_id, if (attr->src_nentries) { ret = ath10k_ce_init_src_ring(ar, ce_id, attr); if (ret) { - ath10k_err("Failed to initialize CE src ring for ID: %d (%d)\n", + ath10k_err(ar, "Failed to initialize CE src ring for ID: %d (%d)\n", ce_id, ret); return ret; } @@ -1065,7 +1065,7 @@ int ath10k_ce_init_pipe(struct ath10k *ar, unsigned int ce_id, if (attr->dest_nentries) { ret = ath10k_ce_init_dest_ring(ar, ce_id, attr); if (ret) { - ath10k_err("Failed to initialize CE dest ring for ID: %d (%d)\n", + ath10k_err(ar, "Failed to initialize CE dest ring for ID: %d (%d)\n", ce_id, ret); return ret; } @@ -1110,7 +1110,7 @@ int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id, ce_state->src_ring = ath10k_ce_alloc_src_ring(ar, ce_id, attr); if (IS_ERR(ce_state->src_ring)) { ret = PTR_ERR(ce_state->src_ring); - ath10k_err("failed to allocate copy engine source ring %d: %d\n", + ath10k_err(ar, "failed to allocate copy engine source ring %d: %d\n", ce_id, ret); ce_state->src_ring = NULL; return ret; @@ -1122,7 +1122,7 @@ int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id, attr); if (IS_ERR(ce_state->dest_ring)) { ret = PTR_ERR(ce_state->dest_ring); - ath10k_err("failed to allocate copy engine destination ring %d: %d\n", + ath10k_err(ar, "failed to allocate copy engine destination ring %d: %d\n", ce_id, ret); ce_state->dest_ring = NULL; return ret; diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 157dcf906f29..651a6da8adf5 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -53,7 +53,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { static void ath10k_send_suspend_complete(struct ath10k *ar) { - ath10k_dbg(ATH10K_DBG_BOOT, "boot suspend complete\n"); + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot suspend complete\n"); complete(&ar->target_suspend); } @@ -67,14 +67,14 @@ static int ath10k_init_configure_target(struct ath10k *ar) ret = ath10k_bmi_write32(ar, hi_app_host_interest, HTC_PROTOCOL_VERSION); if (ret) { - ath10k_err("settings HTC version failed\n"); + ath10k_err(ar, "settings HTC version failed\n"); return ret; } /* set the firmware mode to STA/IBSS/AP */ ret = ath10k_bmi_read32(ar, hi_option_flag, ¶m_host); if (ret) { - ath10k_err("setting firmware mode (1/2) failed\n"); + ath10k_err(ar, "setting firmware mode (1/2) failed\n"); return ret; } @@ -93,14 +93,14 @@ static int ath10k_init_configure_target(struct ath10k *ar) ret = ath10k_bmi_write32(ar, hi_option_flag, param_host); if (ret) { - ath10k_err("setting firmware mode (2/2) failed\n"); + ath10k_err(ar, "setting firmware mode (2/2) failed\n"); return ret; } /* We do all byte-swapping on the host */ ret = ath10k_bmi_write32(ar, hi_be, 0); if (ret) { - ath10k_err("setting host CPU BE mode failed\n"); + ath10k_err(ar, "setting host CPU BE mode failed\n"); return ret; } @@ -108,7 +108,7 @@ static int ath10k_init_configure_target(struct ath10k *ar) ret = ath10k_bmi_write32(ar, hi_fw_swap, 0); if (ret) { - ath10k_err("setting FW data/desc swap flags failed\n"); + ath10k_err(ar, "setting FW data/desc swap flags failed\n"); return ret; } @@ -146,11 +146,12 @@ static int ath10k_push_board_ext_data(struct ath10k *ar) ret = ath10k_bmi_read32(ar, hi_board_ext_data, &board_ext_data_addr); if (ret) { - ath10k_err("could not read board ext data addr (%d)\n", ret); + ath10k_err(ar, "could not read board ext data addr (%d)\n", + ret); return ret; } - ath10k_dbg(ATH10K_DBG_BOOT, + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot push board extended data addr 0x%x\n", board_ext_data_addr); @@ -158,7 +159,7 @@ static int ath10k_push_board_ext_data(struct ath10k *ar) return 0; if (ar->board_len != (board_data_size + board_ext_data_size)) { - ath10k_err("invalid board (ext) data sizes %zu != %d+%d\n", + ath10k_err(ar, "invalid board (ext) data sizes %zu != %d+%d\n", ar->board_len, board_data_size, board_ext_data_size); return -EINVAL; } @@ -167,14 +168,15 @@ static int ath10k_push_board_ext_data(struct ath10k *ar) ar->board_data + board_data_size, board_ext_data_size); if (ret) { - ath10k_err("could not write board ext data (%d)\n", ret); + ath10k_err(ar, "could not write board ext data (%d)\n", ret); return ret; } ret = ath10k_bmi_write32(ar, hi_board_ext_data_config, (board_ext_data_size << 16) | 1); if (ret) { - ath10k_err("could not write board ext data bit (%d)\n", ret); + ath10k_err(ar, "could not write board ext data bit (%d)\n", + ret); return ret; } @@ -189,13 +191,13 @@ static int ath10k_download_board_data(struct ath10k *ar) ret = ath10k_push_board_ext_data(ar); if (ret) { - ath10k_err("could not push board ext data (%d)\n", ret); + ath10k_err(ar, "could not push board ext data (%d)\n", ret); goto exit; } ret = ath10k_bmi_read32(ar, hi_board_data, &address); if (ret) { - ath10k_err("could not read board data addr (%d)\n", ret); + ath10k_err(ar, "could not read board data addr (%d)\n", ret); goto exit; } @@ -203,13 +205,13 @@ static int ath10k_download_board_data(struct ath10k *ar) min_t(u32, board_data_size, ar->board_len)); if (ret) { - ath10k_err("could not write board data (%d)\n", ret); + ath10k_err(ar, "could not write board data (%d)\n", ret); goto exit; } ret = ath10k_bmi_write32(ar, hi_board_data_initialized, 1); if (ret) { - ath10k_err("could not write board data bit (%d)\n", ret); + ath10k_err(ar, "could not write board data bit (%d)\n", ret); goto exit; } @@ -225,30 +227,30 @@ static int ath10k_download_and_run_otp(struct ath10k *ar) /* OTP is optional */ if (!ar->otp_data || !ar->otp_len) { - ath10k_warn("Not running otp, calibration will be incorrect (otp-data %p otp_len %zd)!\n", + ath10k_warn(ar, "Not running otp, calibration will be incorrect (otp-data %p otp_len %zd)!\n", ar->otp_data, ar->otp_len); return 0; } - ath10k_dbg(ATH10K_DBG_BOOT, "boot upload otp to 0x%x len %zd\n", + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot upload otp to 0x%x len %zd\n", address, ar->otp_len); ret = ath10k_bmi_fast_download(ar, address, ar->otp_data, ar->otp_len); if (ret) { - ath10k_err("could not write otp (%d)\n", ret); + ath10k_err(ar, "could not write otp (%d)\n", ret); return ret; } ret = ath10k_bmi_execute(ar, address, 0, &result); if (ret) { - ath10k_err("could not execute otp (%d)\n", ret); + ath10k_err(ar, "could not execute otp (%d)\n", ret); return ret; } - ath10k_dbg(ATH10K_DBG_BOOT, "boot otp execute result %d\n", result); + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot otp execute result %d\n", result); if (result != 0) { - ath10k_err("otp calibration failed: %d", result); + ath10k_err(ar, "otp calibration failed: %d", result); return -EINVAL; } @@ -265,7 +267,7 @@ static int ath10k_download_fw(struct ath10k *ar) ret = ath10k_bmi_fast_download(ar, address, ar->firmware_data, ar->firmware_len); if (ret) { - ath10k_err("could not write fw (%d)\n", ret); + ath10k_err(ar, "could not write fw (%d)\n", ret); goto exit; } @@ -302,12 +304,12 @@ static int ath10k_core_fetch_firmware_api_1(struct ath10k *ar) int ret = 0; if (ar->hw_params.fw.fw == NULL) { - ath10k_err("firmware file not defined\n"); + ath10k_err(ar, "firmware file not defined\n"); return -EINVAL; } if (ar->hw_params.fw.board == NULL) { - ath10k_err("board data file not defined"); + ath10k_err(ar, "board data file not defined"); return -EINVAL; } @@ -316,7 +318,7 @@ static int ath10k_core_fetch_firmware_api_1(struct ath10k *ar) ar->hw_params.fw.board); if (IS_ERR(ar->board)) { ret = PTR_ERR(ar->board); - ath10k_err("could not fetch board data (%d)\n", ret); + ath10k_err(ar, "could not fetch board data (%d)\n", ret); goto err; } @@ -328,7 +330,7 @@ static int ath10k_core_fetch_firmware_api_1(struct ath10k *ar) ar->hw_params.fw.fw); if (IS_ERR(ar->firmware)) { ret = PTR_ERR(ar->firmware); - ath10k_err("could not fetch firmware (%d)\n", ret); + ath10k_err(ar, "could not fetch firmware (%d)\n", ret); goto err; } @@ -344,7 +346,7 @@ static int ath10k_core_fetch_firmware_api_1(struct ath10k *ar) ar->hw_params.fw.otp); if (IS_ERR(ar->otp)) { ret = PTR_ERR(ar->otp); - ath10k_err("could not fetch otp (%d)\n", ret); + ath10k_err(ar, "could not fetch otp (%d)\n", ret); goto err; } @@ -369,7 +371,7 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name) /* first fetch the firmware file (firmware-*.bin) */ ar->firmware = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir, name); if (IS_ERR(ar->firmware)) { - ath10k_err("could not fetch firmware file '%s/%s': %ld\n", + ath10k_err(ar, "could not fetch firmware file '%s/%s': %ld\n", ar->hw_params.fw.dir, name, PTR_ERR(ar->firmware)); return PTR_ERR(ar->firmware); } @@ -381,14 +383,14 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name) magic_len = strlen(ATH10K_FIRMWARE_MAGIC) + 1; if (len < magic_len) { - ath10k_err("firmware file '%s/%s' too small to contain magic: %zu\n", + ath10k_err(ar, "firmware file '%s/%s' too small to contain magic: %zu\n", ar->hw_params.fw.dir, name, len); ret = -EINVAL; goto err; } if (memcmp(data, ATH10K_FIRMWARE_MAGIC, magic_len) != 0) { - ath10k_err("invalid firmware magic\n"); + ath10k_err(ar, "invalid firmware magic\n"); ret = -EINVAL; goto err; } @@ -410,7 +412,7 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name) data += sizeof(*hdr); if (len < ie_len) { - ath10k_err("invalid length for FW IE %d (%zu < %zu)\n", + ath10k_err(ar, "invalid length for FW IE %d (%zu < %zu)\n", ie_id, len, ie_len); ret = -EINVAL; goto err; @@ -424,7 +426,7 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name) memcpy(ar->hw->wiphy->fw_version, data, ie_len); ar->hw->wiphy->fw_version[ie_len] = '\0'; - ath10k_dbg(ATH10K_DBG_BOOT, + ath10k_dbg(ar, ATH10K_DBG_BOOT, "found fw version %s\n", ar->hw->wiphy->fw_version); break; @@ -434,11 +436,11 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name) timestamp = (__le32 *)data; - ath10k_dbg(ATH10K_DBG_BOOT, "found fw timestamp %d\n", + ath10k_dbg(ar, ATH10K_DBG_BOOT, "found fw timestamp %d\n", le32_to_cpup(timestamp)); break; case ATH10K_FW_IE_FEATURES: - ath10k_dbg(ATH10K_DBG_BOOT, + ath10k_dbg(ar, ATH10K_DBG_BOOT, "found firmware features ie (%zd B)\n", ie_len); @@ -450,19 +452,19 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name) break; if (data[index] & (1 << bit)) { - ath10k_dbg(ATH10K_DBG_BOOT, + ath10k_dbg(ar, ATH10K_DBG_BOOT, "Enabling feature bit: %i\n", i); __set_bit(i, ar->fw_features); } } - ath10k_dbg_dump(ATH10K_DBG_BOOT, "features", "", + ath10k_dbg_dump(ar, ATH10K_DBG_BOOT, "features", "", ar->fw_features, sizeof(ar->fw_features)); break; case ATH10K_FW_IE_FW_IMAGE: - ath10k_dbg(ATH10K_DBG_BOOT, + ath10k_dbg(ar, ATH10K_DBG_BOOT, "found fw image ie (%zd B)\n", ie_len); @@ -471,7 +473,7 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name) break; case ATH10K_FW_IE_OTP_IMAGE: - ath10k_dbg(ATH10K_DBG_BOOT, + ath10k_dbg(ar, ATH10K_DBG_BOOT, "found otp image ie (%zd B)\n", ie_len); @@ -480,7 +482,7 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name) break; default: - ath10k_warn("Unknown FW IE: %u\n", + ath10k_warn(ar, "Unknown FW IE: %u\n", le32_to_cpu(hdr->id)); break; } @@ -493,7 +495,7 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name) } if (!ar->firmware_data || !ar->firmware_len) { - ath10k_warn("No ATH10K_FW_IE_FW_IMAGE found from '%s/%s', skipping\n", + ath10k_warn(ar, "No ATH10K_FW_IE_FW_IMAGE found from '%s/%s', skipping\n", ar->hw_params.fw.dir, name); ret = -ENOMEDIUM; goto err; @@ -501,14 +503,14 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name) if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features) && !test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) { - ath10k_err("feature bits corrupted: 10.2 feature requires 10.x feature to be set as well"); + ath10k_err(ar, "feature bits corrupted: 10.2 feature requires 10.x feature to be set as well"); ret = -EINVAL; goto err; } /* now fetch the board file */ if (ar->hw_params.fw.board == NULL) { - ath10k_err("board data file not defined"); + ath10k_err(ar, "board data file not defined"); ret = -EINVAL; goto err; } @@ -518,7 +520,7 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name) ar->hw_params.fw.board); if (IS_ERR(ar->board)) { ret = PTR_ERR(ar->board); - ath10k_err("could not fetch board data '%s/%s' (%d)\n", + ath10k_err(ar, "could not fetch board data '%s/%s' (%d)\n", ar->hw_params.fw.dir, ar->hw_params.fw.board, ret); goto err; @@ -539,28 +541,28 @@ static int ath10k_core_fetch_firmware_files(struct ath10k *ar) int ret; ar->fw_api = 3; - ath10k_dbg(ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api); + ath10k_dbg(ar, ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api); ret = ath10k_core_fetch_firmware_api_n(ar, ATH10K_FW_API3_FILE); if (ret == 0) goto success; ar->fw_api = 2; - ath10k_dbg(ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api); + ath10k_dbg(ar, ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api); ret = ath10k_core_fetch_firmware_api_n(ar, ATH10K_FW_API2_FILE); if (ret == 0) goto success; ar->fw_api = 1; - ath10k_dbg(ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api); + ath10k_dbg(ar, ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api); ret = ath10k_core_fetch_firmware_api_1(ar); if (ret) return ret; success: - ath10k_dbg(ATH10K_DBG_BOOT, "using fw api %d\n", ar->fw_api); + ath10k_dbg(ar, ATH10K_DBG_BOOT, "using fw api %d\n", ar->fw_api); return 0; } @@ -571,19 +573,19 @@ static int ath10k_init_download_firmware(struct ath10k *ar) ret = ath10k_download_board_data(ar); if (ret) { - ath10k_err("failed to download board data: %d\n", ret); + ath10k_err(ar, "failed to download board data: %d\n", ret); return ret; } ret = ath10k_download_and_run_otp(ar); if (ret) { - ath10k_err("failed to run otp: %d\n", ret); + ath10k_err(ar, "failed to run otp: %d\n", ret); return ret; } ret = ath10k_download_fw(ar); if (ret) { - ath10k_err("failed to download firmware: %d\n", ret); + ath10k_err(ar, "failed to download firmware: %d\n", ret); return ret; } @@ -600,7 +602,7 @@ static int ath10k_init_uart(struct ath10k *ar) */ ret = ath10k_bmi_write32(ar, hi_serial_enable, 0); if (ret) { - ath10k_warn("could not disable UART prints (%d)\n", ret); + ath10k_warn(ar, "could not disable UART prints (%d)\n", ret); return ret; } @@ -609,24 +611,24 @@ static int ath10k_init_uart(struct ath10k *ar) ret = ath10k_bmi_write32(ar, hi_dbg_uart_txpin, 7); if (ret) { - ath10k_warn("could not enable UART prints (%d)\n", ret); + ath10k_warn(ar, "could not enable UART prints (%d)\n", ret); return ret; } ret = ath10k_bmi_write32(ar, hi_serial_enable, 1); if (ret) { - ath10k_warn("could not enable UART prints (%d)\n", ret); + ath10k_warn(ar, "could not enable UART prints (%d)\n", ret); return ret; } /* Set the UART baud rate to 19200. */ ret = ath10k_bmi_write32(ar, hi_desired_baud_rate, 19200); if (ret) { - ath10k_warn("could not set the baud rate (%d)\n", ret); + ath10k_warn(ar, "could not set the baud rate (%d)\n", ret); return ret; } - ath10k_info("UART prints enabled\n"); + ath10k_info(ar, "UART prints enabled\n"); return 0; } @@ -643,14 +645,14 @@ static int ath10k_init_hw_params(struct ath10k *ar) } if (i == ARRAY_SIZE(ath10k_hw_params_list)) { - ath10k_err("Unsupported hardware version: 0x%x\n", + ath10k_err(ar, "Unsupported hardware version: 0x%x\n", ar->target_version); return -EINVAL; } ar->hw_params = *hw_params; - ath10k_dbg(ATH10K_DBG_BOOT, "Hardware name %s version 0x%x\n", + ath10k_dbg(ar, ATH10K_DBG_BOOT, "Hardware name %s version 0x%x\n", ar->hw_params.name, ar->target_version); return 0; @@ -672,7 +674,7 @@ static void ath10k_core_restart(struct work_struct *work) case ATH10K_STATE_OFF: /* this can happen if driver is being unloaded * or if the crash happens during FW probing */ - ath10k_warn("cannot restart a device that hasn't been started\n"); + ath10k_warn(ar, "cannot restart a device that hasn't been started\n"); break; case ATH10K_STATE_RESTARTING: /* hw restart might be requested from multiple places */ @@ -681,7 +683,7 @@ static void ath10k_core_restart(struct work_struct *work) ar->state = ATH10K_STATE_WEDGED; /* fall through */ case ATH10K_STATE_WEDGED: - ath10k_warn("device is wedged, will not restart\n"); + ath10k_warn(ar, "device is wedged, will not restart\n"); break; } @@ -714,7 +716,7 @@ int ath10k_core_start(struct ath10k *ar) status = ath10k_htc_init(ar); if (status) { - ath10k_err("could not init HTC (%d)\n", status); + ath10k_err(ar, "could not init HTC (%d)\n", status); goto err; } @@ -724,84 +726,85 @@ int ath10k_core_start(struct ath10k *ar) status = ath10k_wmi_attach(ar); if (status) { - ath10k_err("WMI attach failed: %d\n", status); + ath10k_err(ar, "WMI attach failed: %d\n", status); goto err; } status = ath10k_htt_init(ar); if (status) { - ath10k_err("failed to init htt: %d\n", status); + ath10k_err(ar, "failed to init htt: %d\n", status); goto err_wmi_detach; } status = ath10k_htt_tx_alloc(&ar->htt); if (status) { - ath10k_err("failed to alloc htt tx: %d\n", status); + ath10k_err(ar, "failed to alloc htt tx: %d\n", status); goto err_wmi_detach; } status = ath10k_htt_rx_alloc(&ar->htt); if (status) { - ath10k_err("failed to alloc htt rx: %d\n", status); + ath10k_err(ar, "failed to alloc htt rx: %d\n", status); goto err_htt_tx_detach; } status = ath10k_hif_start(ar); if (status) { - ath10k_err("could not start HIF: %d\n", status); + ath10k_err(ar, "could not start HIF: %d\n", status); goto err_htt_rx_detach; } status = ath10k_htc_wait_target(&ar->htc); if (status) { - ath10k_err("failed to connect to HTC: %d\n", status); + ath10k_err(ar, "failed to connect to HTC: %d\n", status); goto err_hif_stop; } status = ath10k_htt_connect(&ar->htt); if (status) { - ath10k_err("failed to connect htt (%d)\n", status); + ath10k_err(ar, "failed to connect htt (%d)\n", status); goto err_hif_stop; } status = ath10k_wmi_connect(ar); if (status) { - ath10k_err("could not connect wmi: %d\n", status); + ath10k_err(ar, "could not connect wmi: %d\n", status); goto err_hif_stop; } status = ath10k_htc_start(&ar->htc); if (status) { - ath10k_err("failed to start htc: %d\n", status); + ath10k_err(ar, "failed to start htc: %d\n", status); goto err_hif_stop; } status = ath10k_wmi_wait_for_service_ready(ar); if (status <= 0) { - ath10k_warn("wmi service ready event not received"); + ath10k_warn(ar, "wmi service ready event not received"); status = -ETIMEDOUT; goto err_hif_stop; } - ath10k_dbg(ATH10K_DBG_BOOT, "firmware %s booted\n", + ath10k_dbg(ar, ATH10K_DBG_BOOT, "firmware %s booted\n", ar->hw->wiphy->fw_version); status = ath10k_wmi_cmd_init(ar); if (status) { - ath10k_err("could not send WMI init command (%d)\n", status); + ath10k_err(ar, "could not send WMI init command (%d)\n", + status); goto err_hif_stop; } status = ath10k_wmi_wait_for_unified_ready(ar); if (status <= 0) { - ath10k_err("wmi unified ready event not received\n"); + ath10k_err(ar, "wmi unified ready event not received\n"); status = -ETIMEDOUT; goto err_hif_stop; } status = ath10k_htt_setup(&ar->htt); if (status) { - ath10k_err("failed to setup htt: %d\n", status); + ath10k_err(ar, "failed to setup htt: %d\n", status); goto err_hif_stop; } @@ -839,14 +842,14 @@ int ath10k_wait_for_suspend(struct ath10k *ar, u32 suspend_opt) ret = ath10k_wmi_pdev_suspend_target(ar, suspend_opt); if (ret) { - ath10k_warn("could not suspend target (%d)\n", ret); + ath10k_warn(ar, "could not suspend target (%d)\n", ret); return ret; } ret = wait_for_completion_timeout(&ar->target_suspend, 1 * HZ); if (ret == 0) { - ath10k_warn("suspend timed out - target pause event never came\n"); + ath10k_warn(ar, "suspend timed out - target pause event never came\n"); return -ETIMEDOUT; } @@ -880,14 +883,14 @@ static int ath10k_core_probe_fw(struct ath10k *ar) ret = ath10k_hif_power_up(ar); if (ret) { - ath10k_err("could not start pci hif (%d)\n", ret); + ath10k_err(ar, "could not start pci hif (%d)\n", ret); return ret; } memset(&target_info, 0, sizeof(target_info)); ret = ath10k_bmi_get_target_info(ar, &target_info); if (ret) { - ath10k_err("could not get target info (%d)\n", ret); + ath10k_err(ar, "could not get target info (%d)\n", ret); ath10k_hif_power_down(ar); return ret; } @@ -897,14 +900,14 @@ static int ath10k_core_probe_fw(struct ath10k *ar) ret = ath10k_init_hw_params(ar); if (ret) { - ath10k_err("could not get hw params (%d)\n", ret); + ath10k_err(ar, "could not get hw params (%d)\n", ret); ath10k_hif_power_down(ar); return ret; } ret = ath10k_core_fetch_firmware_files(ar); if (ret) { - ath10k_err("could not fetch firmware files (%d)\n", ret); + ath10k_err(ar, "could not fetch firmware files (%d)\n", ret); ath10k_hif_power_down(ar); return ret; } @@ -913,7 +916,7 @@ static int ath10k_core_probe_fw(struct ath10k *ar) ret = ath10k_core_start(ar); if (ret) { - ath10k_err("could not init core (%d)\n", ret); + ath10k_err(ar, "could not init core (%d)\n", ret); ath10k_core_free_firmware_files(ar); ath10k_hif_power_down(ar); mutex_unlock(&ar->conf_mutex); @@ -933,7 +936,7 @@ static int ath10k_core_check_chip_id(struct ath10k *ar) { u32 hw_revision = MS(ar->chip_id, SOC_CHIP_ID_REV); - ath10k_dbg(ATH10K_DBG_BOOT, "boot chip_id 0x%08x hw_revision 0x%x\n", + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot chip_id 0x%08x hw_revision 0x%x\n", ar->chip_id, hw_revision); /* Check that we are not using hw1.0 (some of them have same pci id @@ -941,7 +944,7 @@ static int ath10k_core_check_chip_id(struct ath10k *ar) * due to missing hw1.0 workarounds. */ switch (hw_revision) { case QCA988X_HW_1_0_CHIP_ID_REV: - ath10k_err("ERROR: qca988x hw1.0 is not supported\n"); + ath10k_err(ar, "ERROR: qca988x hw1.0 is not supported\n"); return -EOPNOTSUPP; case QCA988X_HW_2_0_CHIP_ID_REV: @@ -949,7 +952,7 @@ static int ath10k_core_check_chip_id(struct ath10k *ar) return 0; default: - ath10k_warn("Warning: hardware revision unknown (0x%x), expect problems\n", + ath10k_warn(ar, "Warning: hardware revision unknown (0x%x), expect problems\n", ar->chip_id); return 0; } @@ -964,25 +967,25 @@ static void ath10k_core_register_work(struct work_struct *work) status = ath10k_core_probe_fw(ar); if (status) { - ath10k_err("could not probe fw (%d)\n", status); + ath10k_err(ar, "could not probe fw (%d)\n", status); goto err; } status = ath10k_mac_register(ar); if (status) { - ath10k_err("could not register to mac80211 (%d)\n", status); + ath10k_err(ar, "could not register to mac80211 (%d)\n", status); goto err_release_fw; } status = ath10k_debug_create(ar); if (status) { - ath10k_err("unable to initialize debugfs\n"); + ath10k_err(ar, "unable to initialize debugfs\n"); goto err_unregister_mac; } status = ath10k_spectral_create(ar); if (status) { - ath10k_err("failed to initialize spectral\n"); + ath10k_err(ar, "failed to initialize spectral\n"); goto err_debug_destroy; } @@ -1010,7 +1013,7 @@ int ath10k_core_register(struct ath10k *ar, u32 chip_id) status = ath10k_core_check_chip_id(ar); if (status) { - ath10k_err("Unsupported chip id 0x%08x\n", ar->chip_id); + ath10k_err(ar, "Unsupported chip id 0x%08x\n", ar->chip_id); return status; } diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index 442fe93d18be..f3f0a80f8bab 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -106,25 +106,7 @@ struct ath10k_dump_file_data { u8 data[0]; } __packed; -static int ath10k_printk(const char *level, const char *fmt, ...) -{ - struct va_format vaf; - va_list args; - int rtn; - - va_start(args, fmt); - - vaf.fmt = fmt; - vaf.va = &args; - - rtn = printk("%sath10k: %pV", level, &vaf); - - va_end(args); - - return rtn; -} - -int ath10k_info(const char *fmt, ...) +int ath10k_info(struct ath10k *ar, const char *fmt, ...) { struct va_format vaf = { .fmt = fmt, @@ -134,7 +116,7 @@ int ath10k_info(const char *fmt, ...) va_start(args, fmt); vaf.va = &args; - ret = ath10k_printk(KERN_INFO, "%pV", &vaf); + ret = dev_info(ar->dev, "%pV", &vaf); trace_ath10k_log_info(&vaf); va_end(args); @@ -144,7 +126,7 @@ EXPORT_SYMBOL(ath10k_info); void ath10k_print_driver_info(struct ath10k *ar) { - ath10k_info("%s (0x%08x, 0x%08x) fw %s api %d htt %d.%d\n", + ath10k_info(ar, "%s (0x%08x, 0x%08x) fw %s api %d htt %d.%d\n", ar->hw_params.name, ar->target_version, ar->chip_id, @@ -152,7 +134,7 @@ void ath10k_print_driver_info(struct ath10k *ar) ar->fw_api, ar->htt.target_version_major, ar->htt.target_version_minor); - ath10k_info("debug %d debugfs %d tracing %d dfs %d\n", + ath10k_info(ar, "debug %d debugfs %d tracing %d dfs %d\n", config_enabled(CONFIG_ATH10K_DEBUG), config_enabled(CONFIG_ATH10K_DEBUGFS), config_enabled(CONFIG_ATH10K_TRACING), @@ -160,7 +142,7 @@ void ath10k_print_driver_info(struct ath10k *ar) } EXPORT_SYMBOL(ath10k_print_driver_info); -int ath10k_err(const char *fmt, ...) +int ath10k_err(struct ath10k *ar, const char *fmt, ...) { struct va_format vaf = { .fmt = fmt, @@ -170,7 +152,7 @@ int ath10k_err(const char *fmt, ...) va_start(args, fmt); vaf.va = &args; - ret = ath10k_printk(KERN_ERR, "%pV", &vaf); + ret = dev_err(ar->dev, "%pV", &vaf); trace_ath10k_log_err(&vaf); va_end(args); @@ -178,25 +160,21 @@ int ath10k_err(const char *fmt, ...) } EXPORT_SYMBOL(ath10k_err); -int ath10k_warn(const char *fmt, ...) +int ath10k_warn(struct ath10k *ar, const char *fmt, ...) { struct va_format vaf = { .fmt = fmt, }; va_list args; - int ret = 0; va_start(args, fmt); vaf.va = &args; - - if (net_ratelimit()) - ret = ath10k_printk(KERN_WARNING, "%pV", &vaf); - + dev_warn_ratelimited(ar->dev, "%pV", &vaf); trace_ath10k_log_warn(&vaf); va_end(args); - return ret; + return 0; } EXPORT_SYMBOL(ath10k_warn); @@ -417,7 +395,7 @@ static ssize_t ath10k_read_fw_stats(struct file *file, char __user *user_buf, ret = ath10k_wmi_request_stats(ar, WMI_REQUEST_PEER_STAT); if (ret) { - ath10k_warn("could not request stats (%d)\n", ret); + ath10k_warn(ar, "could not request stats (%d)\n", ret); goto exit; } @@ -635,10 +613,10 @@ static ssize_t ath10k_write_simulate_fw_crash(struct file *file, } if (!strcmp(buf, "soft")) { - ath10k_info("simulating soft firmware crash\n"); + ath10k_info(ar, "simulating soft firmware crash\n"); ret = ath10k_wmi_force_fw_hang(ar, WMI_FORCE_FW_HANG_ASSERT, 0); } else if (!strcmp(buf, "hard")) { - ath10k_info("simulating hard firmware crash\n"); + ath10k_info(ar, "simulating hard firmware crash\n"); /* 0x7fff is vdev id, and it is always out of range for all * firmware variants in order to force a firmware crash. */ @@ -650,7 +628,7 @@ static ssize_t ath10k_write_simulate_fw_crash(struct file *file, } if (ret) { - ath10k_warn("failed to simulate firmware crash: %d\n", ret); + ath10k_warn(ar, "failed to simulate firmware crash: %d\n", ret); goto exit; } @@ -839,7 +817,7 @@ static int ath10k_debug_htt_stats_req(struct ath10k *ar) ret = ath10k_htt_h2t_stats_req(&ar->htt, ar->debug.htt_stats_mask, cookie); if (ret) { - ath10k_warn("failed to send htt stats request: %d\n", ret); + ath10k_warn(ar, "failed to send htt stats request: %d\n", ret); return ret; } @@ -1013,7 +991,7 @@ static ssize_t ath10k_write_fw_dbglog(struct file *file, if (ar->state == ATH10K_STATE_ON) { ret = ath10k_wmi_dbglog_cfg(ar, ar->debug.fw_dbglog_mask); if (ret) { - ath10k_warn("dbglog cfg failed from debugfs: %d\n", + ath10k_warn(ar, "dbglog cfg failed from debugfs: %d\n", ret); goto exit; } @@ -1044,13 +1022,14 @@ int ath10k_debug_start(struct ath10k *ar) ret = ath10k_debug_htt_stats_req(ar); if (ret) /* continue normally anyway, this isn't serious */ - ath10k_warn("failed to start htt stats workqueue: %d\n", ret); + ath10k_warn(ar, "failed to start htt stats workqueue: %d\n", + ret); if (ar->debug.fw_dbglog_mask) { ret = ath10k_wmi_dbglog_cfg(ar, ar->debug.fw_dbglog_mask); if (ret) /* not serious */ - ath10k_warn("failed to enable dbglog during start: %d", + ath10k_warn(ar, "failed to enable dbglog during start: %d", ret); } @@ -1230,7 +1209,8 @@ void ath10k_debug_destroy(struct ath10k *ar) #endif /* CONFIG_ATH10K_DEBUGFS */ #ifdef CONFIG_ATH10K_DEBUG -void ath10k_dbg(enum ath10k_debug_mask mask, const char *fmt, ...) +void ath10k_dbg(struct ath10k *ar, enum ath10k_debug_mask mask, + const char *fmt, ...) { struct va_format vaf; va_list args; @@ -1241,7 +1221,7 @@ void ath10k_dbg(enum ath10k_debug_mask mask, const char *fmt, ...) vaf.va = &args; if (ath10k_debug_mask & mask) - ath10k_printk(KERN_DEBUG, "%pV", &vaf); + dev_printk(KERN_DEBUG, ar->dev, "%pV", &vaf); trace_ath10k_log_dbg(mask, &vaf); @@ -1249,13 +1229,14 @@ void ath10k_dbg(enum ath10k_debug_mask mask, const char *fmt, ...) } EXPORT_SYMBOL(ath10k_dbg); -void ath10k_dbg_dump(enum ath10k_debug_mask mask, +void ath10k_dbg_dump(struct ath10k *ar, + enum ath10k_debug_mask mask, const char *msg, const char *prefix, const void *buf, size_t len) { if (ath10k_debug_mask & mask) { if (msg) - ath10k_dbg(mask, "%s\n", msg); + ath10k_dbg(ar, mask, "%s\n", msg); print_hex_dump_bytes(prefix, DUMP_PREFIX_OFFSET, buf, len); } diff --git a/drivers/net/wireless/ath/ath10k/debug.h b/drivers/net/wireless/ath/ath10k/debug.h index 47ee4a623af6..56746539bea2 100644 --- a/drivers/net/wireless/ath/ath10k/debug.h +++ b/drivers/net/wireless/ath/ath10k/debug.h @@ -39,9 +39,9 @@ enum ath10k_debug_mask { extern unsigned int ath10k_debug_mask; -__printf(1, 2) int ath10k_info(const char *fmt, ...); -__printf(1, 2) int ath10k_err(const char *fmt, ...); -__printf(1, 2) int ath10k_warn(const char *fmt, ...); +__printf(2, 3) int ath10k_info(struct ath10k *ar, const char *fmt, ...); +__printf(2, 3) int ath10k_err(struct ath10k *ar, const char *fmt, ...); +__printf(2, 3) int ath10k_warn(struct ath10k *ar, const char *fmt, ...); void ath10k_print_driver_info(struct ath10k *ar); #ifdef CONFIG_ATH10K_DEBUGFS @@ -107,20 +107,24 @@ ath10k_debug_get_new_fw_crash_data(struct ath10k *ar) #endif /* CONFIG_ATH10K_DEBUGFS */ #ifdef CONFIG_ATH10K_DEBUG -__printf(2, 3) void ath10k_dbg(enum ath10k_debug_mask mask, +__printf(3, 4) void ath10k_dbg(struct ath10k *ar, + enum ath10k_debug_mask mask, const char *fmt, ...); -void ath10k_dbg_dump(enum ath10k_debug_mask mask, +void ath10k_dbg_dump(struct ath10k *ar, + enum ath10k_debug_mask mask, const char *msg, const char *prefix, const void *buf, size_t len); #else /* CONFIG_ATH10K_DEBUG */ -static inline int ath10k_dbg(enum ath10k_debug_mask dbg_mask, +static inline int ath10k_dbg(struct ath10k *ar, + enum ath10k_debug_mask dbg_mask, const char *fmt, ...) { return 0; } -static inline void ath10k_dbg_dump(enum ath10k_debug_mask mask, +static inline void ath10k_dbg_dump(struct ath10k *ar, + enum ath10k_debug_mask mask, const char *msg, const char *prefix, const void *buf, size_t len) { diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c index 7e08bb328847..fd9a251f0659 100644 --- a/drivers/net/wireless/ath/ath10k/htc.c +++ b/drivers/net/wireless/ath/ath10k/htc.c @@ -46,7 +46,7 @@ static struct sk_buff *ath10k_htc_build_tx_ctrl_skb(void *ar) skb = dev_alloc_skb(ATH10K_HTC_CONTROL_BUFFER_SIZE); if (!skb) { - ath10k_warn("Unable to allocate ctrl skb\n"); + ath10k_warn(ar, "Unable to allocate ctrl skb\n"); return NULL; } @@ -56,7 +56,7 @@ static struct sk_buff *ath10k_htc_build_tx_ctrl_skb(void *ar) skb_cb = ATH10K_SKB_CB(skb); memset(skb_cb, 0, sizeof(*skb_cb)); - ath10k_dbg(ATH10K_DBG_HTC, "%s: skb %p\n", __func__, skb); + ath10k_dbg(ar, ATH10K_DBG_HTC, "%s: skb %p\n", __func__, skb); return skb; } @@ -72,13 +72,15 @@ static inline void ath10k_htc_restore_tx_skb(struct ath10k_htc *htc, static void ath10k_htc_notify_tx_completion(struct ath10k_htc_ep *ep, struct sk_buff *skb) { - ath10k_dbg(ATH10K_DBG_HTC, "%s: ep %d skb %p\n", __func__, + struct ath10k *ar = ep->htc->ar; + + ath10k_dbg(ar, ATH10K_DBG_HTC, "%s: ep %d skb %p\n", __func__, ep->eid, skb); ath10k_htc_restore_tx_skb(ep->htc, skb); if (!ep->ep_ops.ep_tx_complete) { - ath10k_warn("no tx handler for eid %d\n", ep->eid); + ath10k_warn(ar, "no tx handler for eid %d\n", ep->eid); dev_kfree_skb_any(skb); return; } @@ -89,12 +91,14 @@ static void ath10k_htc_notify_tx_completion(struct ath10k_htc_ep *ep, /* assumes tx_lock is held */ static bool ath10k_htc_ep_need_credit_update(struct ath10k_htc_ep *ep) { + struct ath10k *ar = ep->htc->ar; + if (!ep->tx_credit_flow_enabled) return false; if (ep->tx_credits >= ep->tx_credits_per_max_message) return false; - ath10k_dbg(ATH10K_DBG_HTC, "HTC: endpoint %d needs credit update\n", + ath10k_dbg(ar, ATH10K_DBG_HTC, "HTC: endpoint %d needs credit update\n", ep->eid); return true; } @@ -123,6 +127,7 @@ int ath10k_htc_send(struct ath10k_htc *htc, enum ath10k_htc_ep_id eid, struct sk_buff *skb) { + struct ath10k *ar = htc->ar; struct ath10k_htc_ep *ep = &htc->endpoint[eid]; struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(skb); struct ath10k_hif_sg_item sg_item; @@ -134,7 +139,7 @@ int ath10k_htc_send(struct ath10k_htc *htc, return -ECOMM; if (eid >= ATH10K_HTC_EP_COUNT) { - ath10k_warn("Invalid endpoint id: %d\n", eid); + ath10k_warn(ar, "Invalid endpoint id: %d\n", eid); return -ENOENT; } @@ -149,7 +154,7 @@ int ath10k_htc_send(struct ath10k_htc *htc, goto err_pull; } ep->tx_credits -= credits; - ath10k_dbg(ATH10K_DBG_HTC, + ath10k_dbg(ar, ATH10K_DBG_HTC, "htc ep %d consumed %d credits (total %d)\n", eid, credits, ep->tx_credits); spin_unlock_bh(&htc->tx_lock); @@ -180,7 +185,7 @@ err_credits: if (ep->tx_credit_flow_enabled) { spin_lock_bh(&htc->tx_lock); ep->tx_credits += credits; - ath10k_dbg(ATH10K_DBG_HTC, + ath10k_dbg(ar, ATH10K_DBG_HTC, "htc ep %d reverted %d credits back (total %d)\n", eid, credits, ep->tx_credits); spin_unlock_bh(&htc->tx_lock); @@ -219,11 +224,12 @@ ath10k_htc_process_credit_report(struct ath10k_htc *htc, int len, enum ath10k_htc_ep_id eid) { + struct ath10k *ar = htc->ar; struct ath10k_htc_ep *ep; int i, n_reports; if (len % sizeof(*report)) - ath10k_warn("Uneven credit report len %d", len); + ath10k_warn(ar, "Uneven credit report len %d", len); n_reports = len / sizeof(*report); @@ -235,7 +241,7 @@ ath10k_htc_process_credit_report(struct ath10k_htc *htc, ep = &htc->endpoint[report->eid]; ep->tx_credits += report->credits; - ath10k_dbg(ATH10K_DBG_HTC, "htc ep %d got %d credits (total %d)\n", + ath10k_dbg(ar, ATH10K_DBG_HTC, "htc ep %d got %d credits (total %d)\n", report->eid, report->credits, ep->tx_credits); if (ep->ep_ops.ep_tx_credits) { @@ -252,6 +258,7 @@ static int ath10k_htc_process_trailer(struct ath10k_htc *htc, int length, enum ath10k_htc_ep_id src_eid) { + struct ath10k *ar = htc->ar; int status = 0; struct ath10k_htc_record *record; u8 *orig_buffer; @@ -271,7 +278,7 @@ static int ath10k_htc_process_trailer(struct ath10k_htc *htc, if (record->hdr.len > length) { /* no room left in buffer for record */ - ath10k_warn("Invalid record length: %d\n", + ath10k_warn(ar, "Invalid record length: %d\n", record->hdr.len); status = -EINVAL; break; @@ -281,7 +288,7 @@ static int ath10k_htc_process_trailer(struct ath10k_htc *htc, case ATH10K_HTC_RECORD_CREDITS: len = sizeof(struct ath10k_htc_credit_report); if (record->hdr.len < len) { - ath10k_warn("Credit report too long\n"); + ath10k_warn(ar, "Credit report too long\n"); status = -EINVAL; break; } @@ -291,7 +298,7 @@ static int ath10k_htc_process_trailer(struct ath10k_htc *htc, src_eid); break; default: - ath10k_warn("Unhandled record: id:%d length:%d\n", + ath10k_warn(ar, "Unhandled record: id:%d length:%d\n", record->hdr.id, record->hdr.len); break; } @@ -305,7 +312,7 @@ static int ath10k_htc_process_trailer(struct ath10k_htc *htc, } if (status) - ath10k_dbg_dump(ATH10K_DBG_HTC, "htc rx bad trailer", "", + ath10k_dbg_dump(ar, ATH10K_DBG_HTC, "htc rx bad trailer", "", orig_buffer, orig_length); return status; @@ -331,8 +338,8 @@ static int ath10k_htc_rx_completion_handler(struct ath10k *ar, eid = hdr->eid; if (eid >= ATH10K_HTC_EP_COUNT) { - ath10k_warn("HTC Rx: invalid eid %d\n", eid); - ath10k_dbg_dump(ATH10K_DBG_HTC, "htc bad header", "", + ath10k_warn(ar, "HTC Rx: invalid eid %d\n", eid); + ath10k_dbg_dump(ar, ATH10K_DBG_HTC, "htc bad header", "", hdr, sizeof(*hdr)); status = -EINVAL; goto out; @@ -352,19 +359,19 @@ static int ath10k_htc_rx_completion_handler(struct ath10k *ar, payload_len = __le16_to_cpu(hdr->len); if (payload_len + sizeof(*hdr) > ATH10K_HTC_MAX_LEN) { - ath10k_warn("HTC rx frame too long, len: %zu\n", + ath10k_warn(ar, "HTC rx frame too long, len: %zu\n", payload_len + sizeof(*hdr)); - ath10k_dbg_dump(ATH10K_DBG_HTC, "htc bad rx pkt len", "", + ath10k_dbg_dump(ar, ATH10K_DBG_HTC, "htc bad rx pkt len", "", hdr, sizeof(*hdr)); status = -EINVAL; goto out; } if (skb->len < payload_len) { - ath10k_dbg(ATH10K_DBG_HTC, + ath10k_dbg(ar, ATH10K_DBG_HTC, "HTC Rx: insufficient length, got %d, expected %d\n", skb->len, payload_len); - ath10k_dbg_dump(ATH10K_DBG_HTC, "htc bad rx pkt len", + ath10k_dbg_dump(ar, ATH10K_DBG_HTC, "htc bad rx pkt len", "", hdr, sizeof(*hdr)); status = -EINVAL; goto out; @@ -380,7 +387,7 @@ static int ath10k_htc_rx_completion_handler(struct ath10k *ar, if ((trailer_len < min_len) || (trailer_len > payload_len)) { - ath10k_warn("Invalid trailer length: %d\n", + ath10k_warn(ar, "Invalid trailer length: %d\n", trailer_len); status = -EPROTO; goto out; @@ -413,7 +420,7 @@ static int ath10k_htc_rx_completion_handler(struct ath10k *ar, * this is a fatal error, target should not be * sending unsolicited messages on the ep 0 */ - ath10k_warn("HTC rx ctrl still processing\n"); + ath10k_warn(ar, "HTC rx ctrl still processing\n"); status = -EINVAL; complete(&htc->ctl_resp); goto out; @@ -434,7 +441,7 @@ static int ath10k_htc_rx_completion_handler(struct ath10k *ar, goto out; } - ath10k_dbg(ATH10K_DBG_HTC, "htc rx completion ep %d skb %p\n", + ath10k_dbg(ar, ATH10K_DBG_HTC, "htc rx completion ep %d skb %p\n", eid, skb); ep->ep_ops.ep_rx_complete(ar, skb); @@ -451,7 +458,7 @@ static void ath10k_htc_control_rx_complete(struct ath10k *ar, { /* This is unexpected. FW is not supposed to send regular rx on this * endpoint. */ - ath10k_warn("unexpected htc rx\n"); + ath10k_warn(ar, "unexpected htc rx\n"); kfree_skb(skb); } @@ -538,6 +545,7 @@ static u8 ath10k_htc_get_credit_allocation(struct ath10k_htc *htc, int ath10k_htc_wait_target(struct ath10k_htc *htc) { + struct ath10k *ar = htc->ar; int i, status = 0; struct ath10k_htc_svc_conn_req conn_req; struct ath10k_htc_svc_conn_resp conn_resp; @@ -555,7 +563,7 @@ int ath10k_htc_wait_target(struct ath10k_htc *htc) * iomap writes unmasking PCI CE irqs aren't propagated * properly in KVM PCI-passthrough sometimes. */ - ath10k_warn("failed to receive control response completion, polling..\n"); + ath10k_warn(ar, "failed to receive control response completion, polling..\n"); for (i = 0; i < CE_COUNT; i++) ath10k_hif_send_complete_check(htc->ar, i, 1); @@ -568,12 +576,12 @@ int ath10k_htc_wait_target(struct ath10k_htc *htc) } if (status < 0) { - ath10k_err("ctl_resp never came in (%d)\n", status); + ath10k_err(ar, "ctl_resp never came in (%d)\n", status); return status; } if (htc->control_resp_len < sizeof(msg->hdr) + sizeof(msg->ready)) { - ath10k_err("Invalid HTC ready msg len:%d\n", + ath10k_err(ar, "Invalid HTC ready msg len:%d\n", htc->control_resp_len); return -ECOMM; } @@ -584,21 +592,21 @@ int ath10k_htc_wait_target(struct ath10k_htc *htc) credit_size = __le16_to_cpu(msg->ready.credit_size); if (message_id != ATH10K_HTC_MSG_READY_ID) { - ath10k_err("Invalid HTC ready msg: 0x%x\n", message_id); + ath10k_err(ar, "Invalid HTC ready msg: 0x%x\n", message_id); return -ECOMM; } htc->total_transmit_credits = credit_count; htc->target_credit_size = credit_size; - ath10k_dbg(ATH10K_DBG_HTC, + ath10k_dbg(ar, ATH10K_DBG_HTC, "Target ready! transmit resources: %d size:%d\n", htc->total_transmit_credits, htc->target_credit_size); if ((htc->total_transmit_credits == 0) || (htc->target_credit_size == 0)) { - ath10k_err("Invalid credit size received\n"); + ath10k_err(ar, "Invalid credit size received\n"); return -ECOMM; } @@ -615,7 +623,8 @@ int ath10k_htc_wait_target(struct ath10k_htc *htc) /* connect fake service */ status = ath10k_htc_connect_service(htc, &conn_req, &conn_resp); if (status) { - ath10k_err("could not connect to htc service (%d)\n", status); + ath10k_err(ar, "could not connect to htc service (%d)\n", + status); return status; } @@ -626,6 +635,7 @@ int ath10k_htc_connect_service(struct ath10k_htc *htc, struct ath10k_htc_svc_conn_req *conn_req, struct ath10k_htc_svc_conn_resp *conn_resp) { + struct ath10k *ar = htc->ar; struct ath10k_htc_msg *msg; struct ath10k_htc_conn_svc *req_msg; struct ath10k_htc_conn_svc_response resp_msg_dummy; @@ -651,13 +661,13 @@ int ath10k_htc_connect_service(struct ath10k_htc *htc, tx_alloc = ath10k_htc_get_credit_allocation(htc, conn_req->service_id); if (!tx_alloc) - ath10k_dbg(ATH10K_DBG_BOOT, + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot htc service %s does not allocate target credits\n", htc_service_name(conn_req->service_id)); skb = ath10k_htc_build_tx_ctrl_skb(htc->ar); if (!skb) { - ath10k_err("Failed to allocate HTC packet\n"); + ath10k_err(ar, "Failed to allocate HTC packet\n"); return -ENOMEM; } @@ -695,7 +705,7 @@ int ath10k_htc_connect_service(struct ath10k_htc *htc, if (status <= 0) { if (status == 0) status = -ETIMEDOUT; - ath10k_err("Service connect timeout: %d\n", status); + ath10k_err(ar, "Service connect timeout: %d\n", status); return status; } @@ -708,11 +718,11 @@ int ath10k_htc_connect_service(struct ath10k_htc *htc, if ((message_id != ATH10K_HTC_MSG_CONNECT_SERVICE_RESP_ID) || (htc->control_resp_len < sizeof(msg->hdr) + sizeof(msg->connect_service_response))) { - ath10k_err("Invalid resp message ID 0x%x", message_id); + ath10k_err(ar, "Invalid resp message ID 0x%x", message_id); return -EPROTO; } - ath10k_dbg(ATH10K_DBG_HTC, + ath10k_dbg(ar, ATH10K_DBG_HTC, "HTC Service %s connect response: status: 0x%x, assigned ep: 0x%x\n", htc_service_name(service_id), resp_msg->status, resp_msg->eid); @@ -721,7 +731,7 @@ int ath10k_htc_connect_service(struct ath10k_htc *htc, /* check response status */ if (resp_msg->status != ATH10K_HTC_CONN_SVC_STATUS_SUCCESS) { - ath10k_err("HTC Service %s connect request failed: 0x%x)\n", + ath10k_err(ar, "HTC Service %s connect request failed: 0x%x)\n", htc_service_name(service_id), resp_msg->status); return -EPROTO; @@ -772,18 +782,18 @@ setup: if (status) return status; - ath10k_dbg(ATH10K_DBG_BOOT, + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot htc service '%s' ul pipe %d dl pipe %d eid %d ready\n", htc_service_name(ep->service_id), ep->ul_pipe_id, ep->dl_pipe_id, ep->eid); - ath10k_dbg(ATH10K_DBG_BOOT, + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot htc ep %d ul polled %d dl polled %d\n", ep->eid, ep->ul_is_polled, ep->dl_is_polled); if (disable_credit_flow_ctrl && ep->tx_credit_flow_enabled) { ep->tx_credit_flow_enabled = false; - ath10k_dbg(ATH10K_DBG_BOOT, + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot htc service '%s' eid %d TX flow control disabled\n", htc_service_name(ep->service_id), assigned_eid); } @@ -791,13 +801,13 @@ setup: return status; } -struct sk_buff *ath10k_htc_alloc_skb(int size) +struct sk_buff *ath10k_htc_alloc_skb(struct ath10k *ar, int size) { struct sk_buff *skb; skb = dev_alloc_skb(size + sizeof(struct ath10k_htc_hdr)); if (!skb) { - ath10k_warn("could not allocate HTC tx skb\n"); + ath10k_warn(ar, "could not allocate HTC tx skb\n"); return NULL; } @@ -805,13 +815,14 @@ struct sk_buff *ath10k_htc_alloc_skb(int size) /* FW/HTC requires 4-byte aligned streams */ if (!IS_ALIGNED((unsigned long)skb->data, 4)) - ath10k_warn("Unaligned HTC tx skb\n"); + ath10k_warn(ar, "Unaligned HTC tx skb\n"); return skb; } int ath10k_htc_start(struct ath10k_htc *htc) { + struct ath10k *ar = htc->ar; struct sk_buff *skb; int status = 0; struct ath10k_htc_msg *msg; @@ -827,7 +838,7 @@ int ath10k_htc_start(struct ath10k_htc *htc) msg->hdr.message_id = __cpu_to_le16(ATH10K_HTC_MSG_SETUP_COMPLETE_EX_ID); - ath10k_dbg(ATH10K_DBG_HTC, "HTC is using TX credit flow control\n"); + ath10k_dbg(ar, ATH10K_DBG_HTC, "HTC is using TX credit flow control\n"); status = ath10k_htc_send(htc, ATH10K_HTC_EP_0, skb); if (status) { diff --git a/drivers/net/wireless/ath/ath10k/htc.h b/drivers/net/wireless/ath/ath10k/htc.h index b5a9daacc2c2..bf532f671189 100644 --- a/drivers/net/wireless/ath/ath10k/htc.h +++ b/drivers/net/wireless/ath/ath10k/htc.h @@ -355,6 +355,6 @@ int ath10k_htc_connect_service(struct ath10k_htc *htc, struct ath10k_htc_svc_conn_resp *conn_resp); int ath10k_htc_send(struct ath10k_htc *htc, enum ath10k_htc_ep_id eid, struct sk_buff *packet); -struct sk_buff *ath10k_htc_alloc_skb(int size); +struct sk_buff *ath10k_htc_alloc_skb(struct ath10k *ar, int size); #endif diff --git a/drivers/net/wireless/ath/ath10k/htt.c b/drivers/net/wireless/ath/ath10k/htt.c index 19c12cc8d663..87daae11f116 100644 --- a/drivers/net/wireless/ath/ath10k/htt.c +++ b/drivers/net/wireless/ath/ath10k/htt.c @@ -74,12 +74,14 @@ int ath10k_htt_init(struct ath10k *ar) static int ath10k_htt_verify_version(struct ath10k_htt *htt) { - ath10k_dbg(ATH10K_DBG_BOOT, "htt target version %d.%d\n", + struct ath10k *ar = htt->ar; + + ath10k_dbg(ar, ATH10K_DBG_BOOT, "htt target version %d.%d\n", htt->target_version_major, htt->target_version_minor); if (htt->target_version_major != 2 && htt->target_version_major != 3) { - ath10k_err("unsupported htt major version %d. supported versions are 2 and 3\n", + ath10k_err(ar, "unsupported htt major version %d. supported versions are 2 and 3\n", htt->target_version_major); return -ENOTSUPP; } @@ -89,6 +91,7 @@ static int ath10k_htt_verify_version(struct ath10k_htt *htt) int ath10k_htt_setup(struct ath10k_htt *htt) { + struct ath10k *ar = htt->ar; int status; init_completion(&htt->target_version_received); @@ -100,7 +103,7 @@ int ath10k_htt_setup(struct ath10k_htt *htt) status = wait_for_completion_timeout(&htt->target_version_received, HTT_TARGET_VERSION_TIMEOUT_HZ); if (status <= 0) { - ath10k_warn("htt version request timed out\n"); + ath10k_warn(ar, "htt version request timed out\n"); return -ETIMEDOUT; } diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 763d6a228a13..30927b1d7109 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -271,13 +271,14 @@ void ath10k_htt_rx_free(struct ath10k_htt *htt) static inline struct sk_buff *ath10k_htt_rx_netbuf_pop(struct ath10k_htt *htt) { + struct ath10k *ar = htt->ar; int idx; struct sk_buff *msdu; lockdep_assert_held(&htt->rx_ring.lock); if (htt->rx_ring.fill_cnt == 0) { - ath10k_warn("tried to pop sk_buff from an empty rx ring\n"); + ath10k_warn(ar, "tried to pop sk_buff from an empty rx ring\n"); return NULL; } @@ -311,6 +312,7 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt, struct sk_buff **tail_msdu, u32 *attention) { + struct ath10k *ar = htt->ar; int msdu_len, msdu_chaining = 0; struct sk_buff *msdu; struct htt_rx_desc *rx_desc; @@ -318,7 +320,7 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt, lockdep_assert_held(&htt->rx_ring.lock); if (htt->rx_confused) { - ath10k_warn("htt is confused. refusing rx\n"); + ath10k_warn(ar, "htt is confused. refusing rx\n"); return -1; } @@ -331,7 +333,7 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt, msdu->len + skb_tailroom(msdu), DMA_FROM_DEVICE); - ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt rx pop: ", + ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt rx pop: ", msdu->data, msdu->len + skb_tailroom(msdu)); rx_desc = (struct htt_rx_desc *)msdu->data; @@ -354,7 +356,7 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt, ath10k_htt_rx_free_msdu_chain(*head_msdu); *head_msdu = NULL; msdu = NULL; - ath10k_err("htt rx stopped. cannot recover\n"); + ath10k_err(ar, "htt rx stopped. cannot recover\n"); htt->rx_confused = true; break; } @@ -429,7 +431,7 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt, next->len + skb_tailroom(next), DMA_FROM_DEVICE); - ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, + ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt rx chained: ", next->data, next->len + skb_tailroom(next)); @@ -483,13 +485,14 @@ static void ath10k_htt_rx_replenish_task(unsigned long ptr) int ath10k_htt_rx_alloc(struct ath10k_htt *htt) { + struct ath10k *ar = htt->ar; dma_addr_t paddr; void *vaddr; struct timer_list *timer = &htt->rx_ring.refill_retry_timer; htt->rx_ring.size = ath10k_htt_rx_ring_size(htt); if (!is_power_of_2(htt->rx_ring.size)) { - ath10k_warn("htt rx ring size is not power of 2\n"); + ath10k_warn(ar, "htt rx ring size is not power of 2\n"); return -EINVAL; } @@ -550,7 +553,7 @@ int ath10k_htt_rx_alloc(struct ath10k_htt *htt) tasklet_init(&htt->txrx_compl_task, ath10k_htt_txrx_compl_task, (unsigned long)htt); - ath10k_dbg(ATH10K_DBG_BOOT, "htt rx ring size %d fill_level %d\n", + ath10k_dbg(ar, ATH10K_DBG_BOOT, "htt rx ring size %d fill_level %d\n", htt->rx_ring.size, htt->rx_ring.fill_level); return 0; @@ -572,7 +575,8 @@ err_netbuf: return -ENOMEM; } -static int ath10k_htt_rx_crypto_param_len(enum htt_rx_mpdu_encrypt_type type) +static int ath10k_htt_rx_crypto_param_len(struct ath10k *ar, + enum htt_rx_mpdu_encrypt_type type) { switch (type) { case HTT_RX_MPDU_ENCRYPT_WEP40: @@ -588,11 +592,12 @@ static int ath10k_htt_rx_crypto_param_len(enum htt_rx_mpdu_encrypt_type type) return 0; } - ath10k_warn("unknown encryption type %d\n", type); + ath10k_warn(ar, "unknown encryption type %d\n", type); return 0; } -static int ath10k_htt_rx_crypto_tail_len(enum htt_rx_mpdu_encrypt_type type) +static int ath10k_htt_rx_crypto_tail_len(struct ath10k *ar, + enum htt_rx_mpdu_encrypt_type type) { switch (type) { case HTT_RX_MPDU_ENCRYPT_NONE: @@ -608,7 +613,7 @@ static int ath10k_htt_rx_crypto_tail_len(enum htt_rx_mpdu_encrypt_type type) return 8; } - ath10k_warn("unknown encryption type %d\n", type); + ath10k_warn(ar, "unknown encryption type %d\n", type); return 0; } @@ -859,7 +864,7 @@ static void ath10k_process_rx(struct ath10k *ar, status = IEEE80211_SKB_RXCB(skb); *status = *rx_status; - ath10k_dbg(ATH10K_DBG_DATA, + ath10k_dbg(ar, ATH10K_DBG_DATA, "rx skb %p len %u peer %pM %s %s sn %u %s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i mic-err %i amsdu-more %i\n", skb, skb->len, @@ -881,7 +886,7 @@ static void ath10k_process_rx(struct ath10k *ar, !!(status->flag & RX_FLAG_FAILED_FCS_CRC), !!(status->flag & RX_FLAG_MMIC_ERROR), !!(status->flag & RX_FLAG_AMSDU_MORE)); - ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "rx skb: ", + ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "rx skb: ", skb->data, skb->len); ieee80211_rx(ar->hw, skb); @@ -897,6 +902,7 @@ static void ath10k_htt_rx_amsdu(struct ath10k_htt *htt, struct ieee80211_rx_status *rx_status, struct sk_buff *skb_in) { + struct ath10k *ar = htt->ar; struct htt_rx_desc *rxd; struct sk_buff *skb = skb_in; struct sk_buff *first; @@ -930,8 +936,8 @@ static void ath10k_htt_rx_amsdu(struct ath10k_htt *htt, /* First frame in an A-MSDU chain has more decapped data. */ if (skb == first) { len = round_up(ieee80211_hdrlen(hdr->frame_control), 4); - len += round_up(ath10k_htt_rx_crypto_param_len(enctype), - 4); + len += round_up(ath10k_htt_rx_crypto_param_len(ar, + enctype), 4); decap_hdr += len; } @@ -1006,6 +1012,7 @@ static void ath10k_htt_rx_msdu(struct ath10k_htt *htt, struct ieee80211_rx_status *rx_status, struct sk_buff *skb) { + struct ath10k *ar = htt->ar; struct htt_rx_desc *rxd; struct ieee80211_hdr *hdr; enum rx_msdu_decap_format fmt; @@ -1015,7 +1022,7 @@ static void ath10k_htt_rx_msdu(struct ath10k_htt *htt, /* This shouldn't happen. If it does than it may be a FW bug. */ if (skb->next) { - ath10k_warn("htt rx received chained non A-MSDU frame\n"); + ath10k_warn(ar, "htt rx received chained non A-MSDU frame\n"); ath10k_htt_rx_free_msdu_chain(skb->next); skb->next = NULL; } @@ -1052,7 +1059,8 @@ static void ath10k_htt_rx_msdu(struct ath10k_htt *htt, rfc1042 = hdr; rfc1042 += roundup(hdr_len, 4); - rfc1042 += roundup(ath10k_htt_rx_crypto_param_len(enctype), 4); + rfc1042 += roundup(ath10k_htt_rx_crypto_param_len(ar, + enctype), 4); skb_pull(skb, sizeof(struct ethhdr)); memcpy(skb_push(skb, sizeof(struct rfc1042_hdr)), @@ -1161,27 +1169,29 @@ static bool ath10k_htt_rx_amsdu_allowed(struct ath10k_htt *htt, bool channel_set, u32 attention) { + struct ath10k *ar = htt->ar; + if (head->len == 0) { - ath10k_dbg(ATH10K_DBG_HTT, + ath10k_dbg(ar, ATH10K_DBG_HTT, "htt rx dropping due to zero-len\n"); return false; } if (attention & RX_ATTENTION_FLAGS_DECRYPT_ERR) { - ath10k_dbg(ATH10K_DBG_HTT, + ath10k_dbg(ar, ATH10K_DBG_HTT, "htt rx dropping due to decrypt-err\n"); return false; } if (!channel_set) { - ath10k_warn("no channel configured; ignoring frame!\n"); + ath10k_warn(ar, "no channel configured; ignoring frame!\n"); return false; } /* Skip mgmt frames while we handle this in WMI */ if (status == HTT_RX_IND_MPDU_STATUS_MGMT_CTRL || attention & RX_ATTENTION_FLAGS_MGMT_TYPE) { - ath10k_dbg(ATH10K_DBG_HTT, "htt rx mgmt ctrl\n"); + ath10k_dbg(ar, ATH10K_DBG_HTT, "htt rx mgmt ctrl\n"); return false; } @@ -1189,14 +1199,14 @@ static bool ath10k_htt_rx_amsdu_allowed(struct ath10k_htt *htt, status != HTT_RX_IND_MPDU_STATUS_TKIP_MIC_ERR && status != HTT_RX_IND_MPDU_STATUS_ERR_INV_PEER && !htt->ar->monitor_started) { - ath10k_dbg(ATH10K_DBG_HTT, + ath10k_dbg(ar, ATH10K_DBG_HTT, "htt rx ignoring frame w/ status %d\n", status); return false; } if (test_bit(ATH10K_CAC_RUNNING, &htt->ar->dev_flags)) { - ath10k_dbg(ATH10K_DBG_HTT, + ath10k_dbg(ar, ATH10K_DBG_HTT, "htt rx CAC running\n"); return false; } @@ -1207,6 +1217,7 @@ static bool ath10k_htt_rx_amsdu_allowed(struct ath10k_htt *htt, static void ath10k_htt_rx_handler(struct ath10k_htt *htt, struct htt_rx_indication *rx) { + struct ath10k *ar = htt->ar; struct ieee80211_rx_status *rx_status = &htt->rx_status; struct htt_rx_indication_mpdu_range *mpdu_ranges; struct htt_rx_desc *rxd; @@ -1252,7 +1263,7 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt, rx_status); } - ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt rx ind: ", + ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt rx ind: ", rx, sizeof(*rx) + (sizeof(struct htt_rx_indication_mpdu_range) * num_mpdu_ranges)); @@ -1274,7 +1285,7 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt, &attention); if (ret < 0) { - ath10k_warn("failed to pop amsdu from htt rx ring %d\n", + ath10k_warn(ar, "failed to pop amsdu from htt rx ring %d\n", ret); ath10k_htt_rx_free_msdu_chain(msdu_head); continue; @@ -1323,6 +1334,7 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt, static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt, struct htt_rx_fragment_indication *frag) { + struct ath10k *ar = htt->ar; struct sk_buff *msdu_head, *msdu_tail; enum htt_rx_mpdu_encrypt_type enctype; struct htt_rx_desc *rxd; @@ -1349,10 +1361,10 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt, &attention); spin_unlock_bh(&htt->rx_ring.lock); - ath10k_dbg(ATH10K_DBG_HTT_DUMP, "htt rx frag ahead\n"); + ath10k_dbg(ar, ATH10K_DBG_HTT_DUMP, "htt rx frag ahead\n"); if (ret) { - ath10k_warn("failed to pop amsdu from httr rx ring for fragmented rx %d\n", + ath10k_warn(ar, "failed to pop amsdu from httr rx ring for fragmented rx %d\n", ret); ath10k_htt_rx_free_msdu_chain(msdu_head); return; @@ -1369,7 +1381,7 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt, RX_MSDU_START_INFO1_DECAP_FORMAT); if (fmt != RX_MSDU_DECAP_RAW) { - ath10k_warn("we dont support non-raw fragmented rx yet\n"); + ath10k_warn(ar, "we dont support non-raw fragmented rx yet\n"); dev_kfree_skb_any(msdu_head); goto end; } @@ -1381,17 +1393,17 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt, msdu_head->ip_summed = ath10k_htt_rx_get_csum_state(msdu_head); if (tkip_mic_err) - ath10k_warn("tkip mic error\n"); + ath10k_warn(ar, "tkip mic error\n"); if (decrypt_err) { - ath10k_warn("decryption err in fragmented rx\n"); + ath10k_warn(ar, "decryption err in fragmented rx\n"); dev_kfree_skb_any(msdu_head); goto end; } if (enctype != HTT_RX_MPDU_ENCRYPT_NONE) { hdrlen = ieee80211_hdrlen(hdr->frame_control); - paramlen = ath10k_htt_rx_crypto_param_len(enctype); + paramlen = ath10k_htt_rx_crypto_param_len(ar, enctype); /* It is more efficient to move the header than the payload */ memmove((void *)msdu_head->data + paramlen, @@ -1405,7 +1417,7 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt, trim = 4; /* remove crypto trailer */ - trim += ath10k_htt_rx_crypto_tail_len(enctype); + trim += ath10k_htt_rx_crypto_tail_len(ar, enctype); /* last fragment of TKIP frags has MIC */ if (!ieee80211_has_morefrags(hdr->frame_control) && @@ -1413,20 +1425,20 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt, trim += 8; if (trim > msdu_head->len) { - ath10k_warn("htt rx fragment: trailer longer than the frame itself? drop\n"); + ath10k_warn(ar, "htt rx fragment: trailer longer than the frame itself? drop\n"); dev_kfree_skb_any(msdu_head); goto end; } skb_trim(msdu_head, msdu_head->len - trim); - ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt rx frag mpdu: ", + ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt rx frag mpdu: ", msdu_head->data, msdu_head->len); ath10k_process_rx(htt->ar, rx_status, msdu_head); end: if (fw_desc_len > 0) { - ath10k_dbg(ATH10K_DBG_HTT, + ath10k_dbg(ar, ATH10K_DBG_HTT, "expecting more fragmented rx in one indication %d\n", fw_desc_len); } @@ -1456,12 +1468,12 @@ static void ath10k_htt_rx_frm_tx_compl(struct ath10k *ar, tx_done.discard = true; break; default: - ath10k_warn("unhandled tx completion status %d\n", status); + ath10k_warn(ar, "unhandled tx completion status %d\n", status); tx_done.discard = true; break; } - ath10k_dbg(ATH10K_DBG_HTT, "htt tx completion num_msdus %d\n", + ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx completion num_msdus %d\n", resp->data_tx_completion.num_msdus); for (i = 0; i < resp->data_tx_completion.num_msdus; i++) { @@ -1482,14 +1494,14 @@ static void ath10k_htt_rx_addba(struct ath10k *ar, struct htt_resp *resp) tid = MS(info0, HTT_RX_BA_INFO0_TID); peer_id = MS(info0, HTT_RX_BA_INFO0_PEER_ID); - ath10k_dbg(ATH10K_DBG_HTT, + ath10k_dbg(ar, ATH10K_DBG_HTT, "htt rx addba tid %hu peer_id %hu size %hhu\n", tid, peer_id, ev->window_size); spin_lock_bh(&ar->data_lock); peer = ath10k_peer_find_by_id(ar, peer_id); if (!peer) { - ath10k_warn("received addba event for invalid peer_id: %hu\n", + ath10k_warn(ar, "received addba event for invalid peer_id: %hu\n", peer_id); spin_unlock_bh(&ar->data_lock); return; @@ -1497,13 +1509,13 @@ static void ath10k_htt_rx_addba(struct ath10k *ar, struct htt_resp *resp) arvif = ath10k_get_arvif(ar, peer->vdev_id); if (!arvif) { - ath10k_warn("received addba event for invalid vdev_id: %u\n", + ath10k_warn(ar, "received addba event for invalid vdev_id: %u\n", peer->vdev_id); spin_unlock_bh(&ar->data_lock); return; } - ath10k_dbg(ATH10K_DBG_HTT, + ath10k_dbg(ar, ATH10K_DBG_HTT, "htt rx start rx ba session sta %pM tid %hu size %hhu\n", peer->addr, tid, ev->window_size); @@ -1522,14 +1534,14 @@ static void ath10k_htt_rx_delba(struct ath10k *ar, struct htt_resp *resp) tid = MS(info0, HTT_RX_BA_INFO0_TID); peer_id = MS(info0, HTT_RX_BA_INFO0_PEER_ID); - ath10k_dbg(ATH10K_DBG_HTT, + ath10k_dbg(ar, ATH10K_DBG_HTT, "htt rx delba tid %hu peer_id %hu\n", tid, peer_id); spin_lock_bh(&ar->data_lock); peer = ath10k_peer_find_by_id(ar, peer_id); if (!peer) { - ath10k_warn("received addba event for invalid peer_id: %hu\n", + ath10k_warn(ar, "received addba event for invalid peer_id: %hu\n", peer_id); spin_unlock_bh(&ar->data_lock); return; @@ -1537,13 +1549,13 @@ static void ath10k_htt_rx_delba(struct ath10k *ar, struct htt_resp *resp) arvif = ath10k_get_arvif(ar, peer->vdev_id); if (!arvif) { - ath10k_warn("received addba event for invalid vdev_id: %u\n", + ath10k_warn(ar, "received addba event for invalid vdev_id: %u\n", peer->vdev_id); spin_unlock_bh(&ar->data_lock); return; } - ath10k_dbg(ATH10K_DBG_HTT, + ath10k_dbg(ar, ATH10K_DBG_HTT, "htt rx stop rx ba session sta %pM tid %hu\n", peer->addr, tid); @@ -1558,9 +1570,9 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) /* confirm alignment */ if (!IS_ALIGNED((unsigned long)skb->data, 4)) - ath10k_warn("unaligned htt message, expect trouble\n"); + ath10k_warn(ar, "unaligned htt message, expect trouble\n"); - ath10k_dbg(ATH10K_DBG_HTT, "htt rx, msg_type: 0x%0X\n", + ath10k_dbg(ar, ATH10K_DBG_HTT, "htt rx, msg_type: 0x%0X\n", resp->hdr.msg_type); switch (resp->hdr.msg_type) { case HTT_T2H_MSG_TYPE_VERSION_CONF: { @@ -1624,7 +1636,7 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) struct ath10k *ar = htt->ar; struct htt_security_indication *ev = &resp->security_indication; - ath10k_dbg(ATH10K_DBG_HTT, + ath10k_dbg(ar, ATH10K_DBG_HTT, "sec ind peer_id %d unicast %d type %d\n", __le16_to_cpu(ev->peer_id), !!(ev->flags & HTT_SECURITY_IS_UNICAST), @@ -1633,7 +1645,7 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) break; } case HTT_T2H_MSG_TYPE_RX_FRAG_IND: { - ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt event: ", + ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt event: ", skb->data, skb->len); ath10k_htt_rx_frag_handler(htt, &resp->rx_frag_ind); break; @@ -1650,7 +1662,7 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) * sends all tx frames as already inspected so this shouldn't * happen unless fw has a bug. */ - ath10k_warn("received an unexpected htt tx inspect event\n"); + ath10k_warn(ar, "received an unexpected htt tx inspect event\n"); break; case HTT_T2H_MSG_TYPE_RX_ADDBA: ath10k_htt_rx_addba(ar, resp); @@ -1665,9 +1677,9 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) break; } default: - ath10k_dbg(ATH10K_DBG_HTT, "htt event (%d) not handled\n", + ath10k_dbg(ar, ATH10K_DBG_HTT, "htt event (%d) not handled\n", resp->hdr.msg_type); - ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt event: ", + ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt event: ", skb->data, skb->len); break; }; diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index 8b27bfcc1de3..eaa73aa99c20 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -58,6 +58,7 @@ exit: int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt) { + struct ath10k *ar = htt->ar; int msdu_id; lockdep_assert_held(&htt->tx_lock); @@ -67,24 +68,29 @@ int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt) if (msdu_id == htt->max_num_pending_tx) return -ENOBUFS; - ath10k_dbg(ATH10K_DBG_HTT, "htt tx alloc msdu_id %d\n", msdu_id); + ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx alloc msdu_id %d\n", msdu_id); __set_bit(msdu_id, htt->used_msdu_ids); return msdu_id; } void ath10k_htt_tx_free_msdu_id(struct ath10k_htt *htt, u16 msdu_id) { + struct ath10k *ar = htt->ar; + lockdep_assert_held(&htt->tx_lock); if (!test_bit(msdu_id, htt->used_msdu_ids)) - ath10k_warn("trying to free unallocated msdu_id %d\n", msdu_id); + ath10k_warn(ar, "trying to free unallocated msdu_id %d\n", + msdu_id); - ath10k_dbg(ATH10K_DBG_HTT, "htt tx free msdu_id %hu\n", msdu_id); + ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx free msdu_id %hu\n", msdu_id); __clear_bit(msdu_id, htt->used_msdu_ids); } int ath10k_htt_tx_alloc(struct ath10k_htt *htt) { + struct ath10k *ar = htt->ar; + spin_lock_init(&htt->tx_lock); init_waitqueue_head(&htt->empty_tx_wq); @@ -93,7 +99,7 @@ int ath10k_htt_tx_alloc(struct ath10k_htt *htt) else htt->max_num_pending_tx = TARGET_NUM_MSDU_DESC; - ath10k_dbg(ATH10K_DBG_BOOT, "htt tx max num pending tx %d\n", + ath10k_dbg(ar, ATH10K_DBG_BOOT, "htt tx max num pending tx %d\n", htt->max_num_pending_tx); htt->pending_tx = kzalloc(sizeof(*htt->pending_tx) * @@ -122,6 +128,7 @@ int ath10k_htt_tx_alloc(struct ath10k_htt *htt) static void ath10k_htt_tx_free_pending(struct ath10k_htt *htt) { + struct ath10k *ar = htt->ar; struct htt_tx_done tx_done = {0}; int msdu_id; @@ -130,7 +137,7 @@ static void ath10k_htt_tx_free_pending(struct ath10k_htt *htt) if (!test_bit(msdu_id, htt->used_msdu_ids)) continue; - ath10k_dbg(ATH10K_DBG_HTT, "force cleanup msdu_id %hu\n", + ath10k_dbg(ar, ATH10K_DBG_HTT, "force cleanup msdu_id %hu\n", msdu_id); tx_done.discard = 1; @@ -157,6 +164,7 @@ void ath10k_htt_htc_tx_complete(struct ath10k *ar, struct sk_buff *skb) int ath10k_htt_h2t_ver_req_msg(struct ath10k_htt *htt) { + struct ath10k *ar = htt->ar; struct sk_buff *skb; struct htt_cmd *cmd; int len = 0; @@ -165,7 +173,7 @@ int ath10k_htt_h2t_ver_req_msg(struct ath10k_htt *htt) len += sizeof(cmd->hdr); len += sizeof(cmd->ver_req); - skb = ath10k_htc_alloc_skb(len); + skb = ath10k_htc_alloc_skb(ar, len); if (!skb) return -ENOMEM; @@ -184,6 +192,7 @@ int ath10k_htt_h2t_ver_req_msg(struct ath10k_htt *htt) int ath10k_htt_h2t_stats_req(struct ath10k_htt *htt, u8 mask, u64 cookie) { + struct ath10k *ar = htt->ar; struct htt_stats_req *req; struct sk_buff *skb; struct htt_cmd *cmd; @@ -192,7 +201,7 @@ int ath10k_htt_h2t_stats_req(struct ath10k_htt *htt, u8 mask, u64 cookie) len += sizeof(cmd->hdr); len += sizeof(cmd->stats_req); - skb = ath10k_htc_alloc_skb(len); + skb = ath10k_htc_alloc_skb(ar, len); if (!skb) return -ENOMEM; @@ -214,7 +223,8 @@ int ath10k_htt_h2t_stats_req(struct ath10k_htt *htt, u8 mask, u64 cookie) ret = ath10k_htc_send(&htt->ar->htc, htt->eid, skb); if (ret) { - ath10k_warn("failed to send htt type stats request: %d", ret); + ath10k_warn(ar, "failed to send htt type stats request: %d", + ret); dev_kfree_skb_any(skb); return ret; } @@ -224,6 +234,7 @@ int ath10k_htt_h2t_stats_req(struct ath10k_htt *htt, u8 mask, u64 cookie) int ath10k_htt_send_rx_ring_cfg_ll(struct ath10k_htt *htt) { + struct ath10k *ar = htt->ar; struct sk_buff *skb; struct htt_cmd *cmd; struct htt_rx_ring_setup_ring *ring; @@ -242,7 +253,7 @@ int ath10k_htt_send_rx_ring_cfg_ll(struct ath10k_htt *htt) len = sizeof(cmd->hdr) + sizeof(cmd->rx_setup.hdr) + (sizeof(*ring) * num_rx_ring); - skb = ath10k_htc_alloc_skb(len); + skb = ath10k_htc_alloc_skb(ar, len); if (!skb) return -ENOMEM; @@ -311,6 +322,7 @@ int ath10k_htt_h2t_aggr_cfg_msg(struct ath10k_htt *htt, u8 max_subfrms_ampdu, u8 max_subfrms_amsdu) { + struct ath10k *ar = htt->ar; struct htt_aggr_conf *aggr_conf; struct sk_buff *skb; struct htt_cmd *cmd; @@ -328,7 +340,7 @@ int ath10k_htt_h2t_aggr_cfg_msg(struct ath10k_htt *htt, len = sizeof(cmd->hdr); len += sizeof(cmd->aggr_conf); - skb = ath10k_htc_alloc_skb(len); + skb = ath10k_htc_alloc_skb(ar, len); if (!skb) return -ENOMEM; @@ -340,7 +352,7 @@ int ath10k_htt_h2t_aggr_cfg_msg(struct ath10k_htt *htt, aggr_conf->max_num_ampdu_subframes = max_subfrms_ampdu; aggr_conf->max_num_amsdu_subframes = max_subfrms_amsdu; - ath10k_dbg(ATH10K_DBG_HTT, "htt h2t aggr cfg msg amsdu %d ampdu %d", + ath10k_dbg(ar, ATH10K_DBG_HTT, "htt h2t aggr cfg msg amsdu %d ampdu %d", aggr_conf->max_num_amsdu_subframes, aggr_conf->max_num_ampdu_subframes); @@ -355,7 +367,8 @@ int ath10k_htt_h2t_aggr_cfg_msg(struct ath10k_htt *htt, int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) { - struct device *dev = htt->ar->dev; + struct ath10k *ar = htt->ar; + struct device *dev = ar->dev; struct sk_buff *txdesc = NULL; struct htt_cmd *cmd; struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(msdu); @@ -382,7 +395,7 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) htt->pending_tx[msdu_id] = msdu; spin_unlock_bh(&htt->tx_lock); - txdesc = ath10k_htc_alloc_skb(len); + txdesc = ath10k_htc_alloc_skb(ar, len); if (!txdesc) { res = -ENOMEM; goto err_free_msdu_id; @@ -429,7 +442,8 @@ err: int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) { - struct device *dev = htt->ar->dev; + struct ath10k *ar = htt->ar; + struct device *dev = ar->dev; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)msdu->data; struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(msdu); struct ath10k_hif_sg_item sg_items[2]; @@ -545,11 +559,11 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) skb_cb->htt.txbuf->cmd_tx.frags_paddr = __cpu_to_le32(frags_paddr); skb_cb->htt.txbuf->cmd_tx.peerid = __cpu_to_le32(HTT_INVALID_PEERID); - ath10k_dbg(ATH10K_DBG_HTT, + ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx flags0 %hhu flags1 %hu len %d id %hu frags_paddr %08x, msdu_paddr %08x vdev %hhu tid %hhu\n", flags0, flags1, msdu->len, msdu_id, frags_paddr, (u32)skb_cb->paddr, vdev_id, tid); - ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt tx msdu: ", + ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt tx msdu: ", msdu->data, msdu->len); sg_items[0].transfer_id = 0; diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index e568882a17de..b858c8288196 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -36,6 +36,7 @@ static int ath10k_send_key(struct ath10k_vif *arvif, enum set_key_cmd cmd, const u8 *macaddr) { + struct ath10k *ar = arvif->ar; struct wmi_vdev_install_key_arg arg = { .vdev_id = arvif->vdev_id, .key_idx = key->keyidx, @@ -73,7 +74,7 @@ static int ath10k_send_key(struct ath10k_vif *arvif, arg.key_flags = WMI_KEY_PAIRWISE; break; default: - ath10k_warn("cipher %d is not supported\n", key->cipher); + ath10k_warn(ar, "cipher %d is not supported\n", key->cipher); return -EOPNOTSUPP; } @@ -168,7 +169,7 @@ static int ath10k_clear_peer_keys(struct ath10k_vif *arvif, first_errno = ret; if (ret) - ath10k_warn("failed to remove peer wep key %d: %d\n", + ath10k_warn(ar, "failed to remove peer wep key %d: %d\n", i, ret); peer->keys[i] = NULL; @@ -216,7 +217,7 @@ static int ath10k_clear_vdev_key(struct ath10k_vif *arvif, first_errno = ret; if (ret) - ath10k_warn("failed to remove key for %pM: %d\n", + ath10k_warn(ar, "failed to remove key for %pM: %d\n", addr, ret); } @@ -327,14 +328,14 @@ static int ath10k_peer_create(struct ath10k *ar, u32 vdev_id, const u8 *addr) ret = ath10k_wmi_peer_create(ar, vdev_id, addr); if (ret) { - ath10k_warn("failed to create wmi peer %pM on vdev %i: %i\n", + ath10k_warn(ar, "failed to create wmi peer %pM on vdev %i: %i\n", addr, vdev_id, ret); return ret; } ret = ath10k_wait_for_peer_created(ar, vdev_id, addr); if (ret) { - ath10k_warn("failed to wait for created wmi peer %pM on vdev %i: %i\n", + ath10k_warn(ar, "failed to wait for created wmi peer %pM on vdev %i: %i\n", addr, vdev_id, ret); return ret; } @@ -355,7 +356,7 @@ static int ath10k_mac_set_kickout(struct ath10k_vif *arvif) ret = ath10k_wmi_pdev_set_param(ar, param, ATH10K_KICKOUT_THRESHOLD); if (ret) { - ath10k_warn("failed to set kickout threshold on vdev %i: %d\n", + ath10k_warn(ar, "failed to set kickout threshold on vdev %i: %d\n", arvif->vdev_id, ret); return ret; } @@ -364,7 +365,7 @@ static int ath10k_mac_set_kickout(struct ath10k_vif *arvif) ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, param, ATH10K_KEEPALIVE_MIN_IDLE); if (ret) { - ath10k_warn("failed to set keepalive minimum idle time on vdev %i: %d\n", + ath10k_warn(ar, "failed to set keepalive minimum idle time on vdev %i: %d\n", arvif->vdev_id, ret); return ret; } @@ -373,7 +374,7 @@ static int ath10k_mac_set_kickout(struct ath10k_vif *arvif) ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, param, ATH10K_KEEPALIVE_MAX_IDLE); if (ret) { - ath10k_warn("failed to set keepalive maximum idle time on vdev %i: %d\n", + ath10k_warn(ar, "failed to set keepalive maximum idle time on vdev %i: %d\n", arvif->vdev_id, ret); return ret; } @@ -382,7 +383,7 @@ static int ath10k_mac_set_kickout(struct ath10k_vif *arvif) ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, param, ATH10K_KEEPALIVE_MAX_UNRESPONSIVE); if (ret) { - ath10k_warn("failed to set keepalive maximum unresponsive time on vdev %i: %d\n", + ath10k_warn(ar, "failed to set keepalive maximum unresponsive time on vdev %i: %d\n", arvif->vdev_id, ret); return ret; } @@ -449,7 +450,7 @@ static void ath10k_peer_cleanup(struct ath10k *ar, u32 vdev_id) if (peer->vdev_id != vdev_id) continue; - ath10k_warn("removing stale peer %pM from vdev_id %d\n", + ath10k_warn(ar, "removing stale peer %pM from vdev_id %d\n", peer->addr, vdev_id); list_del(&peer->list); @@ -496,7 +497,7 @@ static bool ath10k_monitor_is_enabled(struct ath10k *ar) { lockdep_assert_held(&ar->conf_mutex); - ath10k_dbg(ATH10K_DBG_MAC, + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor refs: promisc %d monitor %d cac %d\n", ar->promisc, ar->monitor, test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags)); @@ -531,35 +532,35 @@ static int ath10k_monitor_vdev_start(struct ath10k *ar, int vdev_id) ret = ath10k_wmi_vdev_start(ar, &arg); if (ret) { - ath10k_warn("failed to request monitor vdev %i start: %d\n", + ath10k_warn(ar, "failed to request monitor vdev %i start: %d\n", vdev_id, ret); return ret; } ret = ath10k_vdev_setup_sync(ar); if (ret) { - ath10k_warn("failed to synchronize setup for monitor vdev %i: %d\n", + ath10k_warn(ar, "failed to synchronize setup for monitor vdev %i: %d\n", vdev_id, ret); return ret; } ret = ath10k_wmi_vdev_up(ar, vdev_id, 0, ar->mac_addr); if (ret) { - ath10k_warn("failed to put up monitor vdev %i: %d\n", + ath10k_warn(ar, "failed to put up monitor vdev %i: %d\n", vdev_id, ret); goto vdev_stop; } ar->monitor_vdev_id = vdev_id; - ath10k_dbg(ATH10K_DBG_MAC, "mac monitor vdev %i started\n", + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor vdev %i started\n", ar->monitor_vdev_id); return 0; vdev_stop: ret = ath10k_wmi_vdev_stop(ar, ar->monitor_vdev_id); if (ret) - ath10k_warn("failed to stop monitor vdev %i after start failure: %d\n", + ath10k_warn(ar, "failed to stop monitor vdev %i after start failure: %d\n", ar->monitor_vdev_id, ret); return ret; @@ -573,20 +574,20 @@ static int ath10k_monitor_vdev_stop(struct ath10k *ar) ret = ath10k_wmi_vdev_down(ar, ar->monitor_vdev_id); if (ret) - ath10k_warn("failed to put down monitor vdev %i: %d\n", + ath10k_warn(ar, "failed to put down monitor vdev %i: %d\n", ar->monitor_vdev_id, ret); ret = ath10k_wmi_vdev_stop(ar, ar->monitor_vdev_id); if (ret) - ath10k_warn("failed to to request monitor vdev %i stop: %d\n", + ath10k_warn(ar, "failed to to request monitor vdev %i stop: %d\n", ar->monitor_vdev_id, ret); ret = ath10k_vdev_setup_sync(ar); if (ret) - ath10k_warn("failed to synchronise monitor vdev %i: %d\n", + ath10k_warn(ar, "failed to synchronise monitor vdev %i: %d\n", ar->monitor_vdev_id, ret); - ath10k_dbg(ATH10K_DBG_MAC, "mac monitor vdev %i stopped\n", + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor vdev %i stopped\n", ar->monitor_vdev_id); return ret; } @@ -598,7 +599,7 @@ static int ath10k_monitor_vdev_create(struct ath10k *ar) lockdep_assert_held(&ar->conf_mutex); if (ar->free_vdev_map == 0) { - ath10k_warn("failed to find free vdev id for monitor vdev\n"); + ath10k_warn(ar, "failed to find free vdev id for monitor vdev\n"); return -ENOMEM; } @@ -610,13 +611,13 @@ static int ath10k_monitor_vdev_create(struct ath10k *ar) WMI_VDEV_TYPE_MONITOR, 0, ar->mac_addr); if (ret) { - ath10k_warn("failed to request monitor vdev %i creation: %d\n", + ath10k_warn(ar, "failed to request monitor vdev %i creation: %d\n", ar->monitor_vdev_id, ret); return ret; } ar->free_vdev_map &= ~(1 << ar->monitor_vdev_id); - ath10k_dbg(ATH10K_DBG_MAC, "mac monitor vdev %d created\n", + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor vdev %d created\n", ar->monitor_vdev_id); return 0; @@ -630,14 +631,14 @@ static int ath10k_monitor_vdev_delete(struct ath10k *ar) ret = ath10k_wmi_vdev_delete(ar, ar->monitor_vdev_id); if (ret) { - ath10k_warn("failed to request wmi monitor vdev %i removal: %d\n", + ath10k_warn(ar, "failed to request wmi monitor vdev %i removal: %d\n", ar->monitor_vdev_id, ret); return ret; } ar->free_vdev_map |= 1 << ar->monitor_vdev_id; - ath10k_dbg(ATH10K_DBG_MAC, "mac monitor vdev %d deleted\n", + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor vdev %d deleted\n", ar->monitor_vdev_id); return ret; } @@ -649,30 +650,30 @@ static int ath10k_monitor_start(struct ath10k *ar) lockdep_assert_held(&ar->conf_mutex); if (!ath10k_monitor_is_enabled(ar)) { - ath10k_warn("trying to start monitor with no references\n"); + ath10k_warn(ar, "trying to start monitor with no references\n"); return 0; } if (ar->monitor_started) { - ath10k_dbg(ATH10K_DBG_MAC, "mac monitor already started\n"); + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor already started\n"); return 0; } ret = ath10k_monitor_vdev_create(ar); if (ret) { - ath10k_warn("failed to create monitor vdev: %d\n", ret); + ath10k_warn(ar, "failed to create monitor vdev: %d\n", ret); return ret; } ret = ath10k_monitor_vdev_start(ar, ar->monitor_vdev_id); if (ret) { - ath10k_warn("failed to start monitor vdev: %d\n", ret); + ath10k_warn(ar, "failed to start monitor vdev: %d\n", ret); ath10k_monitor_vdev_delete(ar); return ret; } ar->monitor_started = true; - ath10k_dbg(ATH10K_DBG_MAC, "mac monitor started\n"); + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor started\n"); return 0; } @@ -684,27 +685,27 @@ static void ath10k_monitor_stop(struct ath10k *ar) lockdep_assert_held(&ar->conf_mutex); if (ath10k_monitor_is_enabled(ar)) { - ath10k_dbg(ATH10K_DBG_MAC, + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor will be stopped later\n"); return; } if (!ar->monitor_started) { - ath10k_dbg(ATH10K_DBG_MAC, + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor probably failed to start earlier\n"); return; } ret = ath10k_monitor_vdev_stop(ar); if (ret) - ath10k_warn("failed to stop monitor vdev: %d\n", ret); + ath10k_warn(ar, "failed to stop monitor vdev: %d\n", ret); ret = ath10k_monitor_vdev_delete(ar); if (ret) - ath10k_warn("failed to delete monitor vdev: %d\n", ret); + ath10k_warn(ar, "failed to delete monitor vdev: %d\n", ret); ar->monitor_started = false; - ath10k_dbg(ATH10K_DBG_MAC, "mac monitor stopped\n"); + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor stopped\n"); } static int ath10k_recalc_rtscts_prot(struct ath10k_vif *arvif) @@ -737,12 +738,12 @@ static int ath10k_start_cac(struct ath10k *ar) ret = ath10k_monitor_start(ar); if (ret) { - ath10k_warn("failed to start monitor (cac): %d\n", ret); + ath10k_warn(ar, "failed to start monitor (cac): %d\n", ret); clear_bit(ATH10K_CAC_RUNNING, &ar->dev_flags); return ret; } - ath10k_dbg(ATH10K_DBG_MAC, "mac cac start monitor vdev %d\n", + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac cac start monitor vdev %d\n", ar->monitor_vdev_id); return 0; @@ -759,7 +760,7 @@ static int ath10k_stop_cac(struct ath10k *ar) clear_bit(ATH10K_CAC_RUNNING, &ar->dev_flags); ath10k_monitor_stop(ar); - ath10k_dbg(ATH10K_DBG_MAC, "mac cac finished\n"); + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac cac finished\n"); return 0; } @@ -785,7 +786,7 @@ static void ath10k_recalc_radar_detection(struct ath10k *ar) * radiation is not allowed, make this channel DFS_UNAVAILABLE * by indicating that radar was detected. */ - ath10k_warn("failed to start CAC: %d\n", ret); + ath10k_warn(ar, "failed to start CAC: %d\n", ret); ieee80211_radar_detected(ar->hw); } } @@ -827,7 +828,7 @@ static int ath10k_vdev_start_restart(struct ath10k_vif *arvif, bool restart) arg.ssid_len = arvif->vif->bss_conf.ssid_len; } - ath10k_dbg(ATH10K_DBG_MAC, + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d start center_freq %d phymode %s\n", arg.vdev_id, arg.channel.freq, ath10k_wmi_phymode_str(arg.channel.mode)); @@ -838,14 +839,14 @@ static int ath10k_vdev_start_restart(struct ath10k_vif *arvif, bool restart) ret = ath10k_wmi_vdev_start(ar, &arg); if (ret) { - ath10k_warn("failed to start WMI vdev %i: %d\n", + ath10k_warn(ar, "failed to start WMI vdev %i: %d\n", arg.vdev_id, ret); return ret; } ret = ath10k_vdev_setup_sync(ar); if (ret) { - ath10k_warn("failed to synchronise setup for vdev %i: %d\n", + ath10k_warn(ar, "failed to synchronise setup for vdev %i: %d\n", arg.vdev_id, ret); return ret; } @@ -877,14 +878,14 @@ static int ath10k_vdev_stop(struct ath10k_vif *arvif) ret = ath10k_wmi_vdev_stop(ar, arvif->vdev_id); if (ret) { - ath10k_warn("failed to stop WMI vdev %i: %d\n", + ath10k_warn(ar, "failed to stop WMI vdev %i: %d\n", arvif->vdev_id, ret); return ret; } ret = ath10k_vdev_setup_sync(ar); if (ret) { - ath10k_warn("failed to syncronise setup for vdev %i: %d\n", + ath10k_warn(ar, "failed to syncronise setup for vdev %i: %d\n", arvif->vdev_id, ret); return ret; } @@ -902,6 +903,7 @@ static int ath10k_vdev_stop(struct ath10k_vif *arvif) static void ath10k_control_beaconing(struct ath10k_vif *arvif, struct ieee80211_bss_conf *info) { + struct ath10k *ar = arvif->ar; int ret = 0; lockdep_assert_held(&arvif->ar->conf_mutex); @@ -939,7 +941,7 @@ static void ath10k_control_beaconing(struct ath10k_vif *arvif, ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid, arvif->bssid); if (ret) { - ath10k_warn("failed to bring up vdev %d: %i\n", + ath10k_warn(ar, "failed to bring up vdev %d: %i\n", arvif->vdev_id, ret); ath10k_vdev_stop(arvif); return; @@ -948,13 +950,14 @@ static void ath10k_control_beaconing(struct ath10k_vif *arvif, arvif->is_started = true; arvif->is_up = true; - ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d up\n", arvif->vdev_id); + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d up\n", arvif->vdev_id); } static void ath10k_control_ibss(struct ath10k_vif *arvif, struct ieee80211_bss_conf *info, const u8 self_peer[ETH_ALEN]) { + struct ath10k *ar = arvif->ar; u32 vdev_param; int ret = 0; @@ -963,7 +966,7 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif, if (!info->ibss_joined) { ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id, self_peer); if (ret) - ath10k_warn("failed to delete IBSS self peer %pM for vdev %d: %d\n", + ath10k_warn(ar, "failed to delete IBSS self peer %pM for vdev %d: %d\n", self_peer, arvif->vdev_id, ret); if (is_zero_ether_addr(arvif->bssid)) @@ -972,7 +975,7 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif, ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id, arvif->bssid); if (ret) { - ath10k_warn("failed to delete IBSS BSSID peer %pM for vdev %d: %d\n", + ath10k_warn(ar, "failed to delete IBSS BSSID peer %pM for vdev %d: %d\n", arvif->bssid, arvif->vdev_id, ret); return; } @@ -984,7 +987,7 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif, ret = ath10k_peer_create(arvif->ar, arvif->vdev_id, self_peer); if (ret) { - ath10k_warn("failed to create IBSS self peer %pM for vdev %d: %d\n", + ath10k_warn(ar, "failed to create IBSS self peer %pM for vdev %d: %d\n", self_peer, arvif->vdev_id, ret); return; } @@ -993,7 +996,7 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif, ret = ath10k_wmi_vdev_set_param(arvif->ar, arvif->vdev_id, vdev_param, ATH10K_DEFAULT_ATIM); if (ret) - ath10k_warn("failed to set IBSS ATIM for vdev %d: %d\n", + ath10k_warn(ar, "failed to set IBSS ATIM for vdev %d: %d\n", arvif->vdev_id, ret); } @@ -1020,7 +1023,7 @@ static int ath10k_mac_vif_setup_ps(struct ath10k_vif *arvif) ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id, param, conf->dynamic_ps_timeout); if (ret) { - ath10k_warn("failed to set inactivity time for vdev %d: %i\n", + ath10k_warn(ar, "failed to set inactivity time for vdev %d: %i\n", arvif->vdev_id, ret); return ret; } @@ -1028,12 +1031,12 @@ static int ath10k_mac_vif_setup_ps(struct ath10k_vif *arvif) psmode = WMI_STA_PS_MODE_DISABLED; } - ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d psmode %s\n", + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d psmode %s\n", arvif->vdev_id, psmode ? "enable" : "disable"); ret = ath10k_wmi_set_psmode(ar, arvif->vdev_id, psmode); if (ret) { - ath10k_warn("failed to set PS Mode %d for vdev %d: %d\n", + ath10k_warn(ar, "failed to set PS Mode %d for vdev %d: %d\n", psmode, arvif->vdev_id, ret); return ret; } @@ -1117,12 +1120,12 @@ static void ath10k_peer_assoc_h_crypto(struct ath10k *ar, /* FIXME: base on RSN IE/WPA IE is a correct idea? */ if (rsnie || wpaie) { - ath10k_dbg(ATH10K_DBG_WMI, "%s: rsn ie found\n", __func__); + ath10k_dbg(ar, ATH10K_DBG_WMI, "%s: rsn ie found\n", __func__); arg->peer_flags |= WMI_PEER_NEED_PTK_4_WAY; } if (wpaie) { - ath10k_dbg(ATH10K_DBG_WMI, "%s: wpa ie found\n", __func__); + ath10k_dbg(ar, ATH10K_DBG_WMI, "%s: wpa ie found\n", __func__); arg->peer_flags |= WMI_PEER_NEED_GTK_2_WAY; } } @@ -1231,7 +1234,7 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar, arg->peer_num_spatial_streams = sta->rx_nss; } - ath10k_dbg(ATH10K_DBG_MAC, "mac ht peer %pM mcs cnt %d nss %d\n", + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac ht peer %pM mcs cnt %d nss %d\n", arg->addr, arg->peer_ht_rates.num_rates, arg->peer_num_spatial_streams); @@ -1248,7 +1251,7 @@ static int ath10k_peer_assoc_qos_ap(struct ath10k *ar, lockdep_assert_held(&ar->conf_mutex); if (sta->wme && sta->uapsd_queues) { - ath10k_dbg(ATH10K_DBG_MAC, "mac uapsd_queues 0x%x max_sp %d\n", + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac uapsd_queues 0x%x max_sp %d\n", sta->uapsd_queues, sta->max_sp); if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO) @@ -1273,7 +1276,7 @@ static int ath10k_peer_assoc_qos_ap(struct ath10k *ar, WMI_AP_PS_PEER_PARAM_UAPSD, uapsd); if (ret) { - ath10k_warn("failed to set ap ps peer param uapsd for vdev %i: %d\n", + ath10k_warn(ar, "failed to set ap ps peer param uapsd for vdev %i: %d\n", arvif->vdev_id, ret); return ret; } @@ -1283,7 +1286,7 @@ static int ath10k_peer_assoc_qos_ap(struct ath10k *ar, WMI_AP_PS_PEER_PARAM_MAX_SP, max_sp); if (ret) { - ath10k_warn("failed to set ap ps peer param max sp for vdev %i: %d\n", + ath10k_warn(ar, "failed to set ap ps peer param max sp for vdev %i: %d\n", arvif->vdev_id, ret); return ret; } @@ -1295,7 +1298,7 @@ static int ath10k_peer_assoc_qos_ap(struct ath10k *ar, ret = ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id, sta->addr, WMI_AP_PS_PEER_PARAM_AGEOUT_TIME, 10); if (ret) { - ath10k_warn("failed to set ap ps peer param ageout time for vdev %i: %d\n", + ath10k_warn(ar, "failed to set ap ps peer param ageout time for vdev %i: %d\n", arvif->vdev_id, ret); return ret; } @@ -1342,7 +1345,7 @@ static void ath10k_peer_assoc_h_vht(struct ath10k *ar, arg->peer_vht_rates.tx_mcs_set = __le16_to_cpu(vht_cap->vht_mcs.tx_mcs_map); - ath10k_dbg(ATH10K_DBG_MAC, "mac vht peer %pM max_mpdu %d flags 0x%x\n", + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vht peer %pM max_mpdu %d flags 0x%x\n", sta->addr, arg->peer_max_mpdu, arg->peer_flags); } @@ -1415,7 +1418,7 @@ static void ath10k_peer_assoc_h_phymode(struct ath10k *ar, break; } - ath10k_dbg(ATH10K_DBG_MAC, "mac peer %pM phymode %s\n", + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac peer %pM phymode %s\n", sta->addr, ath10k_wmi_phymode_str(phymode)); arg->peer_phymode = phymode; @@ -1488,7 +1491,7 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw, ap_sta = ieee80211_find_sta(vif, bss_conf->bssid); if (!ap_sta) { - ath10k_warn("failed to find station entry for bss %pM vdev %i\n", + ath10k_warn(ar, "failed to find station entry for bss %pM vdev %i\n", bss_conf->bssid, arvif->vdev_id); rcu_read_unlock(); return; @@ -1501,7 +1504,7 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw, ret = ath10k_peer_assoc_prepare(ar, arvif, ap_sta, bss_conf, &peer_arg); if (ret) { - ath10k_warn("failed to prepare peer assoc for %pM vdev %i: %d\n", + ath10k_warn(ar, "failed to prepare peer assoc for %pM vdev %i: %d\n", bss_conf->bssid, arvif->vdev_id, ret); rcu_read_unlock(); return; @@ -1511,19 +1514,19 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw, ret = ath10k_wmi_peer_assoc(ar, &peer_arg); if (ret) { - ath10k_warn("failed to run peer assoc for %pM vdev %i: %d\n", + ath10k_warn(ar, "failed to run peer assoc for %pM vdev %i: %d\n", bss_conf->bssid, arvif->vdev_id, ret); return; } ret = ath10k_setup_peer_smps(ar, arvif, bss_conf->bssid, &ht_cap); if (ret) { - ath10k_warn("failed to setup peer SMPS for vdev %i: %d\n", + ath10k_warn(ar, "failed to setup peer SMPS for vdev %i: %d\n", arvif->vdev_id, ret); return; } - ath10k_dbg(ATH10K_DBG_MAC, + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d up (associated) bssid %pM aid %d\n", arvif->vdev_id, bss_conf->bssid, bss_conf->aid); @@ -1532,7 +1535,7 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw, ret = ath10k_wmi_vdev_up(ar, arvif->vdev_id, arvif->aid, arvif->bssid); if (ret) { - ath10k_warn("failed to set vdev %d up: %d\n", + ath10k_warn(ar, "failed to set vdev %d up: %d\n", arvif->vdev_id, ret); return; } @@ -1558,7 +1561,7 @@ static void ath10k_bss_disassoc(struct ieee80211_hw *hw, * No idea why this happens, even though VDEV-DOWN is supposed * to be analogous to link down, so just stop the VDEV. */ - ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d stop (disassociated\n", + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d stop (disassociated\n", arvif->vdev_id); /* FIXME: check return value */ @@ -1571,7 +1574,7 @@ static void ath10k_bss_disassoc(struct ieee80211_hw *hw, * interfaces as it expects there is no rx when no interface is * running. */ - ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d down\n", arvif->vdev_id); + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d down\n", arvif->vdev_id); /* FIXME: why don't we print error if wmi call fails? */ ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id); @@ -1592,7 +1595,7 @@ static int ath10k_station_assoc(struct ath10k *ar, struct ath10k_vif *arvif, ret = ath10k_peer_assoc_prepare(ar, arvif, sta, NULL, &peer_arg); if (ret) { - ath10k_warn("failed to prepare WMI peer assoc for %pM vdev %i: %i\n", + ath10k_warn(ar, "failed to prepare WMI peer assoc for %pM vdev %i: %i\n", sta->addr, arvif->vdev_id, ret); return ret; } @@ -1600,14 +1603,14 @@ static int ath10k_station_assoc(struct ath10k *ar, struct ath10k_vif *arvif, peer_arg.peer_reassoc = reassoc; ret = ath10k_wmi_peer_assoc(ar, &peer_arg); if (ret) { - ath10k_warn("failed to run peer assoc for STA %pM vdev %i: %d\n", + ath10k_warn(ar, "failed to run peer assoc for STA %pM vdev %i: %d\n", sta->addr, arvif->vdev_id, ret); return ret; } ret = ath10k_setup_peer_smps(ar, arvif, sta->addr, &sta->ht_cap); if (ret) { - ath10k_warn("failed to setup peer SMPS for vdev %d: %d\n", + ath10k_warn(ar, "failed to setup peer SMPS for vdev %d: %d\n", arvif->vdev_id, ret); return ret; } @@ -1616,7 +1619,7 @@ static int ath10k_station_assoc(struct ath10k *ar, struct ath10k_vif *arvif, arvif->num_legacy_stations++; ret = ath10k_recalc_rtscts_prot(arvif); if (ret) { - ath10k_warn("failed to recalculate rts/cts prot for vdev %d: %d\n", + ath10k_warn(ar, "failed to recalculate rts/cts prot for vdev %d: %d\n", arvif->vdev_id, ret); return ret; } @@ -1624,14 +1627,14 @@ static int ath10k_station_assoc(struct ath10k *ar, struct ath10k_vif *arvif, ret = ath10k_install_peer_wep_keys(arvif, sta->addr); if (ret) { - ath10k_warn("failed to install peer wep keys for vdev %i: %d\n", + ath10k_warn(ar, "failed to install peer wep keys for vdev %i: %d\n", arvif->vdev_id, ret); return ret; } ret = ath10k_peer_assoc_qos_ap(ar, arvif, sta); if (ret) { - ath10k_warn("failed to set qos params for STA %pM for vdev %i: %d\n", + ath10k_warn(ar, "failed to set qos params for STA %pM for vdev %i: %d\n", sta->addr, arvif->vdev_id, ret); return ret; } @@ -1650,7 +1653,7 @@ static int ath10k_station_disassoc(struct ath10k *ar, struct ath10k_vif *arvif, arvif->num_legacy_stations--; ret = ath10k_recalc_rtscts_prot(arvif); if (ret) { - ath10k_warn("failed to recalculate rts/cts prot for vdev %d: %d\n", + ath10k_warn(ar, "failed to recalculate rts/cts prot for vdev %d: %d\n", arvif->vdev_id, ret); return ret; } @@ -1658,7 +1661,7 @@ static int ath10k_station_disassoc(struct ath10k *ar, struct ath10k_vif *arvif, ret = ath10k_clear_peer_keys(arvif, sta->addr); if (ret) { - ath10k_warn("failed to clear all peer wep keys for vdev %i: %d\n", + ath10k_warn(ar, "failed to clear all peer wep keys for vdev %i: %d\n", arvif->vdev_id, ret); return ret; } @@ -1750,7 +1753,7 @@ static int ath10k_update_channel_list(struct ath10k *ar) if (WARN_ON_ONCE(ch->mode == MODE_UNKNOWN)) continue; - ath10k_dbg(ATH10K_DBG_WMI, + ath10k_dbg(ar, ATH10K_DBG_WMI, "mac channel [%zd/%d] freq %d maxpower %d regpower %d antenna %d mode %d\n", ch - arg.channels, arg.n_channels, ch->freq, ch->max_power, ch->max_reg_power, @@ -1793,7 +1796,7 @@ static void ath10k_regd_update(struct ath10k *ar) ret = ath10k_update_channel_list(ar); if (ret) - ath10k_warn("failed to update channel list: %d\n", ret); + ath10k_warn(ar, "failed to update channel list: %d\n", ret); regpair = ar->ath_common.regulatory.regpair; @@ -1814,7 +1817,7 @@ static void ath10k_regd_update(struct ath10k *ar) regpair->reg_5ghz_ctl, wmi_dfs_reg); if (ret) - ath10k_warn("failed to set pdev regdomain: %d\n", ret); + ath10k_warn(ar, "failed to set pdev regdomain: %d\n", ret); } static void ath10k_reg_notifier(struct wiphy *wiphy, @@ -1827,12 +1830,12 @@ static void ath10k_reg_notifier(struct wiphy *wiphy, ath_reg_notifier_apply(wiphy, request, &ar->ath_common.regulatory); if (config_enabled(CONFIG_ATH10K_DFS_CERTIFIED) && ar->dfs_detector) { - ath10k_dbg(ATH10K_DBG_REGULATORY, "dfs region 0x%x\n", + ath10k_dbg(ar, ATH10K_DBG_REGULATORY, "dfs region 0x%x\n", request->dfs_region); result = ar->dfs_detector->set_dfs_domain(ar->dfs_detector, request->dfs_region); if (!result) - ath10k_warn("DFS region 0x%X not supported, will trigger radar for every pulse\n", + ath10k_warn(ar, "DFS region 0x%X not supported, will trigger radar for every pulse\n", request->dfs_region); } @@ -1869,7 +1872,7 @@ static u8 ath10k_tx_h_get_vdev_id(struct ath10k *ar, if (ar->monitor_started) return ar->monitor_vdev_id; - ath10k_warn("failed to resolve vdev id\n"); + ath10k_warn(ar, "failed to resolve vdev id\n"); return 0; } @@ -1905,6 +1908,7 @@ static void ath10k_tx_wep_key_work(struct work_struct *work) { struct ath10k_vif *arvif = container_of(work, struct ath10k_vif, wep_key_work); + struct ath10k *ar = arvif->ar; int ret, keyidx = arvif->def_wep_key_newidx; mutex_lock(&arvif->ar->conf_mutex); @@ -1915,7 +1919,7 @@ static void ath10k_tx_wep_key_work(struct work_struct *work) if (arvif->def_wep_key_idx == keyidx) goto unlock; - ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d set keyidx %d\n", + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d set keyidx %d\n", arvif->vdev_id, keyidx); ret = ath10k_wmi_vdev_set_param(arvif->ar, @@ -1923,7 +1927,7 @@ static void ath10k_tx_wep_key_work(struct work_struct *work) arvif->ar->wmi.vdev_param->def_keyid, keyidx); if (ret) { - ath10k_warn("failed to update wep key index for vdev %d: %d\n", + ath10k_warn(ar, "failed to update wep key index for vdev %d: %d\n", arvif->vdev_id, ret); goto unlock; @@ -2003,7 +2007,7 @@ static void ath10k_tx_htt(struct ath10k *ar, struct sk_buff *skb) ar->fw_features)) { if (skb_queue_len(&ar->wmi_mgmt_tx_queue) >= ATH10K_MAX_NUM_MGMT_PENDING) { - ath10k_warn("reached WMI management transmit queue limit\n"); + ath10k_warn(ar, "reached WMI management transmit queue limit\n"); ret = -EBUSY; goto exit; } @@ -2027,7 +2031,8 @@ static void ath10k_tx_htt(struct ath10k *ar, struct sk_buff *skb) exit: if (ret) { - ath10k_warn("failed to transmit packet, dropping: %d\n", ret); + ath10k_warn(ar, "failed to transmit packet, dropping: %d\n", + ret); ieee80211_free_txskb(ar->hw, skb); } } @@ -2069,7 +2074,7 @@ void ath10k_offchan_tx_work(struct work_struct *work) mutex_lock(&ar->conf_mutex); - ath10k_dbg(ATH10K_DBG_MAC, "mac offchannel skb %p\n", + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac offchannel skb %p\n", skb); hdr = (struct ieee80211_hdr *)skb->data; @@ -2082,13 +2087,13 @@ void ath10k_offchan_tx_work(struct work_struct *work) if (peer) /* FIXME: should this use ath10k_warn()? */ - ath10k_dbg(ATH10K_DBG_MAC, "peer %pM on vdev %d already present\n", + ath10k_dbg(ar, ATH10K_DBG_MAC, "peer %pM on vdev %d already present\n", peer_addr, vdev_id); if (!peer) { ret = ath10k_peer_create(ar, vdev_id, peer_addr); if (ret) - ath10k_warn("failed to create peer %pM on vdev %d: %d\n", + ath10k_warn(ar, "failed to create peer %pM on vdev %d: %d\n", peer_addr, vdev_id, ret); } @@ -2102,13 +2107,13 @@ void ath10k_offchan_tx_work(struct work_struct *work) ret = wait_for_completion_timeout(&ar->offchan_tx_completed, 3 * HZ); if (ret <= 0) - ath10k_warn("timed out waiting for offchannel skb %p\n", + ath10k_warn(ar, "timed out waiting for offchannel skb %p\n", skb); if (!peer) { ret = ath10k_peer_delete(ar, vdev_id, peer_addr); if (ret) - ath10k_warn("failed to delete peer %pM on vdev %d: %d\n", + ath10k_warn(ar, "failed to delete peer %pM on vdev %d: %d\n", peer_addr, vdev_id, ret); } @@ -2142,7 +2147,7 @@ void ath10k_mgmt_over_wmi_tx_work(struct work_struct *work) ret = ath10k_wmi_mgmt_tx(ar, skb); if (ret) { - ath10k_warn("failed to transmit management frame via WMI: %d\n", + ath10k_warn(ar, "failed to transmit management frame via WMI: %d\n", ret); ieee80211_free_txskb(ar->hw, skb); } @@ -2199,13 +2204,13 @@ static int ath10k_scan_stop(struct ath10k *ar) ret = ath10k_wmi_stop_scan(ar, &arg); if (ret) { - ath10k_warn("failed to stop wmi scan: %d\n", ret); + ath10k_warn(ar, "failed to stop wmi scan: %d\n", ret); goto out; } ret = wait_for_completion_timeout(&ar->scan.completed, 3*HZ); if (ret == 0) { - ath10k_warn("failed to receive scan abortion completion: timed out\n"); + ath10k_warn(ar, "failed to receive scan abortion completion: timed out\n"); ret = -ETIMEDOUT; } else if (ret > 0) { ret = 0; @@ -2243,7 +2248,7 @@ static void ath10k_scan_abort(struct ath10k *ar) break; case ATH10K_SCAN_STARTING: case ATH10K_SCAN_ABORTING: - ath10k_warn("refusing scan abortion due to invalid scan state: %s (%d)\n", + ath10k_warn(ar, "refusing scan abortion due to invalid scan state: %s (%d)\n", ath10k_scan_state_str(ar->scan.state), ar->scan.state); break; @@ -2253,7 +2258,7 @@ static void ath10k_scan_abort(struct ath10k *ar) ret = ath10k_scan_stop(ar); if (ret) - ath10k_warn("failed to abort scan: %d\n", ret); + ath10k_warn(ar, "failed to abort scan: %d\n", ret); spin_lock_bh(&ar->data_lock); break; @@ -2287,7 +2292,7 @@ static int ath10k_start_scan(struct ath10k *ar, if (ret == 0) { ret = ath10k_scan_stop(ar); if (ret) - ath10k_warn("failed to stop scan: %d\n", ret); + ath10k_warn(ar, "failed to stop scan: %d\n", ret); return -ETIMEDOUT; } @@ -2314,7 +2319,7 @@ static void ath10k_tx(struct ieee80211_hw *hw, /* We should disable CCK RATE due to P2P */ if (info->flags & IEEE80211_TX_CTL_NO_CCK_RATE) - ath10k_dbg(ATH10K_DBG_MAC, "IEEE80211_TX_CTL_NO_CCK_RATE\n"); + ath10k_dbg(ar, ATH10K_DBG_MAC, "IEEE80211_TX_CTL_NO_CCK_RATE\n"); ATH10K_SKB_CB(skb)->htt.is_offchan = false; ATH10K_SKB_CB(skb)->htt.tid = ath10k_tx_h_get_tid(hdr); @@ -2334,7 +2339,8 @@ static void ath10k_tx(struct ieee80211_hw *hw, ATH10K_SKB_CB(skb)->vdev_id = ar->scan.vdev_id; spin_unlock_bh(&ar->data_lock); - ath10k_dbg(ATH10K_DBG_MAC, "queued offchannel skb %p\n", skb); + ath10k_dbg(ar, ATH10K_DBG_MAC, "queued offchannel skb %p\n", + skb); skb_queue_tail(&ar->offchan_tx_queue, skb); ieee80211_queue_work(hw, &ar->offchan_tx_work); @@ -2424,7 +2430,7 @@ static int __ath10k_set_antenna(struct ath10k *ar, u32 tx_ant, u32 rx_ant) ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->tx_chain_mask, tx_ant); if (ret) { - ath10k_warn("failed to set tx-chainmask: %d, req 0x%x\n", + ath10k_warn(ar, "failed to set tx-chainmask: %d, req 0x%x\n", ret, tx_ant); return ret; } @@ -2432,7 +2438,7 @@ static int __ath10k_set_antenna(struct ath10k *ar, u32 tx_ant, u32 rx_ant) ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->rx_chain_mask, rx_ant); if (ret) { - ath10k_warn("failed to set rx-chainmask: %d, req 0x%x\n", + ath10k_warn(ar, "failed to set rx-chainmask: %d, req 0x%x\n", ret, rx_ant); return ret; } @@ -2483,25 +2489,25 @@ static int ath10k_start(struct ieee80211_hw *hw) ret = ath10k_hif_power_up(ar); if (ret) { - ath10k_err("Could not init hif: %d\n", ret); + ath10k_err(ar, "Could not init hif: %d\n", ret); goto err_off; } ret = ath10k_core_start(ar); if (ret) { - ath10k_err("Could not init core: %d\n", ret); + ath10k_err(ar, "Could not init core: %d\n", ret); goto err_power_down; } ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->pmf_qos, 1); if (ret) { - ath10k_warn("failed to enable PMF QOS: %d\n", ret); + ath10k_warn(ar, "failed to enable PMF QOS: %d\n", ret); goto err_core_stop; } ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->dynamic_bw, 1); if (ret) { - ath10k_warn("failed to enable dynamic BW: %d\n", ret); + ath10k_warn(ar, "failed to enable dynamic BW: %d\n", ret); goto err_core_stop; } @@ -2521,7 +2527,7 @@ static int ath10k_start(struct ieee80211_hw *hw) ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->arp_ac_override, 0); if (ret) { - ath10k_warn("failed to set arp ac override parameter: %d\n", + ath10k_warn(ar, "failed to set arp ac override parameter: %d\n", ret); goto err_core_stop; } @@ -2575,7 +2581,7 @@ static int ath10k_config_ps(struct ath10k *ar) list_for_each_entry(arvif, &ar->arvifs, list) { ret = ath10k_mac_vif_setup_ps(arvif); if (ret) { - ath10k_warn("failed to setup powersave: %d\n", ret); + ath10k_warn(ar, "failed to setup powersave: %d\n", ret); break; } } @@ -2613,7 +2619,7 @@ static void ath10k_config_chan(struct ath10k *ar) lockdep_assert_held(&ar->conf_mutex); - ath10k_dbg(ATH10K_DBG_MAC, + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac config channel to %dMHz (cf1 %dMHz cf2 %dMHz width %s)\n", ar->chandef.chan->center_freq, ar->chandef.center_freq1, @@ -2637,7 +2643,7 @@ static void ath10k_config_chan(struct ath10k *ar) ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id); if (ret) { - ath10k_warn("failed to down vdev %d: %d\n", + ath10k_warn(ar, "failed to down vdev %d: %d\n", arvif->vdev_id, ret); continue; } @@ -2654,7 +2660,7 @@ static void ath10k_config_chan(struct ath10k *ar) ret = ath10k_vdev_restart(arvif); if (ret) { - ath10k_warn("failed to restart vdev %d: %d\n", + ath10k_warn(ar, "failed to restart vdev %d: %d\n", arvif->vdev_id, ret); continue; } @@ -2665,7 +2671,7 @@ static void ath10k_config_chan(struct ath10k *ar) ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid, arvif->bssid); if (ret) { - ath10k_warn("failed to bring vdev up %d: %d\n", + ath10k_warn(ar, "failed to bring vdev up %d: %d\n", arvif->vdev_id, ret); continue; } @@ -2685,7 +2691,7 @@ static int ath10k_config(struct ieee80211_hw *hw, u32 changed) mutex_lock(&ar->conf_mutex); if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { - ath10k_dbg(ATH10K_DBG_MAC, + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac config channel %dMHz flags 0x%x radar %d\n", conf->chandef.chan->center_freq, conf->chandef.chan->flags, @@ -2705,21 +2711,21 @@ static int ath10k_config(struct ieee80211_hw *hw, u32 changed) } if (changed & IEEE80211_CONF_CHANGE_POWER) { - ath10k_dbg(ATH10K_DBG_MAC, "mac config power %d\n", + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac config power %d\n", hw->conf.power_level); param = ar->wmi.pdev_param->txpower_limit2g; ret = ath10k_wmi_pdev_set_param(ar, param, hw->conf.power_level * 2); if (ret) - ath10k_warn("failed to set 2g txpower %d: %d\n", + ath10k_warn(ar, "failed to set 2g txpower %d: %d\n", hw->conf.power_level, ret); param = ar->wmi.pdev_param->txpower_limit5g; ret = ath10k_wmi_pdev_set_param(ar, param, hw->conf.power_level * 2); if (ret) - ath10k_warn("failed to set 5g txpower %d: %d\n", + ath10k_warn(ar, "failed to set 5g txpower %d: %d\n", hw->conf.power_level, ret); } @@ -2731,7 +2737,7 @@ static int ath10k_config(struct ieee80211_hw *hw, u32 changed) ar->monitor = true; ret = ath10k_monitor_start(ar); if (ret) { - ath10k_warn("failed to start monitor (config): %d\n", + ath10k_warn(ar, "failed to start monitor (config): %d\n", ret); ar->monitor = false; } @@ -2775,7 +2781,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, INIT_LIST_HEAD(&arvif->list); if (ar->free_vdev_map == 0) { - ath10k_warn("Free vdev map is empty, no more interfaces allowed.\n"); + ath10k_warn(ar, "Free vdev map is empty, no more interfaces allowed.\n"); ret = -EBUSY; goto err; } @@ -2811,13 +2817,13 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, break; } - ath10k_dbg(ATH10K_DBG_MAC, "mac vdev create %d (add interface) type %d subtype %d\n", + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev create %d (add interface) type %d subtype %d\n", arvif->vdev_id, arvif->vdev_type, arvif->vdev_subtype); ret = ath10k_wmi_vdev_create(ar, arvif->vdev_id, arvif->vdev_type, arvif->vdev_subtype, vif->addr); if (ret) { - ath10k_warn("failed to create WMI vdev %i: %d\n", + ath10k_warn(ar, "failed to create WMI vdev %i: %d\n", arvif->vdev_id, ret); goto err; } @@ -2829,7 +2835,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, ret = ath10k_wmi_vdev_set_param(ar, 0, vdev_param, arvif->def_wep_key_idx); if (ret) { - ath10k_warn("failed to set vdev %i default key id: %d\n", + ath10k_warn(ar, "failed to set vdev %i default key id: %d\n", arvif->vdev_id, ret); goto err_vdev_delete; } @@ -2839,7 +2845,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, ATH10K_HW_TXRX_NATIVE_WIFI); /* 10.X firmware does not support this VDEV parameter. Do not warn */ if (ret && ret != -EOPNOTSUPP) { - ath10k_warn("failed to set vdev %i TX encapsulation: %d\n", + ath10k_warn(ar, "failed to set vdev %i TX encapsulation: %d\n", arvif->vdev_id, ret); goto err_vdev_delete; } @@ -2847,14 +2853,14 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, if (arvif->vdev_type == WMI_VDEV_TYPE_AP) { ret = ath10k_peer_create(ar, arvif->vdev_id, vif->addr); if (ret) { - ath10k_warn("failed to create vdev %i peer for AP: %d\n", + ath10k_warn(ar, "failed to create vdev %i peer for AP: %d\n", arvif->vdev_id, ret); goto err_vdev_delete; } ret = ath10k_mac_set_kickout(arvif); if (ret) { - ath10k_warn("failed to set vdev %i kickout parameters: %d\n", + ath10k_warn(ar, "failed to set vdev %i kickout parameters: %d\n", arvif->vdev_id, ret); goto err_peer_delete; } @@ -2866,7 +2872,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id, param, value); if (ret) { - ath10k_warn("failed to set vdev %i RX wake policy: %d\n", + ath10k_warn(ar, "failed to set vdev %i RX wake policy: %d\n", arvif->vdev_id, ret); goto err_peer_delete; } @@ -2876,7 +2882,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id, param, value); if (ret) { - ath10k_warn("failed to set vdev %i TX wake thresh: %d\n", + ath10k_warn(ar, "failed to set vdev %i TX wake thresh: %d\n", arvif->vdev_id, ret); goto err_peer_delete; } @@ -2886,7 +2892,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id, param, value); if (ret) { - ath10k_warn("failed to set vdev %i PSPOLL count: %d\n", + ath10k_warn(ar, "failed to set vdev %i PSPOLL count: %d\n", arvif->vdev_id, ret); goto err_peer_delete; } @@ -2894,14 +2900,14 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, ret = ath10k_mac_set_rts(arvif, ar->hw->wiphy->rts_threshold); if (ret) { - ath10k_warn("failed to set rts threshold for vdev %d: %d\n", + ath10k_warn(ar, "failed to set rts threshold for vdev %d: %d\n", arvif->vdev_id, ret); goto err_peer_delete; } ret = ath10k_mac_set_frag(arvif, ar->hw->wiphy->frag_threshold); if (ret) { - ath10k_warn("failed to set frag threshold for vdev %d: %d\n", + ath10k_warn(ar, "failed to set frag threshold for vdev %d: %d\n", arvif->vdev_id, ret); goto err_peer_delete; } @@ -2948,7 +2954,7 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw, ret = ath10k_spectral_vif_stop(arvif); if (ret) - ath10k_warn("failed to stop spectral for vdev %i: %d\n", + ath10k_warn(ar, "failed to stop spectral for vdev %i: %d\n", arvif->vdev_id, ret); ar->free_vdev_map |= 1 << arvif->vdev_id; @@ -2957,18 +2963,18 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw, if (arvif->vdev_type == WMI_VDEV_TYPE_AP) { ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id, vif->addr); if (ret) - ath10k_warn("failed to remove peer for AP vdev %i: %d\n", + ath10k_warn(ar, "failed to remove peer for AP vdev %i: %d\n", arvif->vdev_id, ret); kfree(arvif->u.ap.noa_data); } - ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %i delete (remove interface)\n", + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %i delete (remove interface)\n", arvif->vdev_id); ret = ath10k_wmi_vdev_delete(ar, arvif->vdev_id); if (ret) - ath10k_warn("failed to delete WMI vdev %i: %d\n", + ath10k_warn(ar, "failed to delete WMI vdev %i: %d\n", arvif->vdev_id, ret); ath10k_peer_cleanup(ar, arvif->vdev_id); @@ -3007,7 +3013,7 @@ static void ath10k_configure_filter(struct ieee80211_hw *hw, ar->promisc = true; ret = ath10k_monitor_start(ar); if (ret) { - ath10k_warn("failed to start monitor (promisc): %d\n", + ath10k_warn(ar, "failed to start monitor (promisc): %d\n", ret); ar->promisc = false; } @@ -3039,17 +3045,17 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, vdev_param = ar->wmi.vdev_param->beacon_interval; ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, arvif->beacon_interval); - ath10k_dbg(ATH10K_DBG_MAC, + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d beacon_interval %d\n", arvif->vdev_id, arvif->beacon_interval); if (ret) - ath10k_warn("failed to set beacon interval for vdev %d: %i\n", + ath10k_warn(ar, "failed to set beacon interval for vdev %d: %i\n", arvif->vdev_id, ret); } if (changed & BSS_CHANGED_BEACON) { - ath10k_dbg(ATH10K_DBG_MAC, + ath10k_dbg(ar, ATH10K_DBG_MAC, "vdev %d set beacon tx mode to staggered\n", arvif->vdev_id); @@ -3057,14 +3063,14 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, ret = ath10k_wmi_pdev_set_param(ar, pdev_param, WMI_BEACON_STAGGERED_MODE); if (ret) - ath10k_warn("failed to set beacon mode for vdev %d: %i\n", + ath10k_warn(ar, "failed to set beacon mode for vdev %d: %i\n", arvif->vdev_id, ret); } if (changed & BSS_CHANGED_BEACON_INFO) { arvif->dtim_period = info->dtim_period; - ath10k_dbg(ATH10K_DBG_MAC, + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d dtim_period %d\n", arvif->vdev_id, arvif->dtim_period); @@ -3072,7 +3078,7 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, arvif->dtim_period); if (ret) - ath10k_warn("failed to set dtim period for vdev %d: %i\n", + ath10k_warn(ar, "failed to set dtim period for vdev %d: %i\n", arvif->vdev_id, ret); } @@ -3091,14 +3097,14 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_BSSID && vif->type != NL80211_IFTYPE_AP) { if (!is_zero_ether_addr(info->bssid)) { - ath10k_dbg(ATH10K_DBG_MAC, + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d create peer %pM\n", arvif->vdev_id, info->bssid); ret = ath10k_peer_create(ar, arvif->vdev_id, info->bssid); if (ret) - ath10k_warn("failed to add peer %pM for vdev %d when changing bssid: %i\n", + ath10k_warn(ar, "failed to add peer %pM for vdev %d when changing bssid: %i\n", info->bssid, arvif->vdev_id, ret); if (vif->type == NL80211_IFTYPE_STATION) { @@ -3108,13 +3114,13 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, */ memcpy(arvif->bssid, info->bssid, ETH_ALEN); - ath10k_dbg(ATH10K_DBG_MAC, + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d start %pM\n", arvif->vdev_id, info->bssid); ret = ath10k_vdev_start(arvif); if (ret) { - ath10k_warn("failed to start vdev %i: %d\n", + ath10k_warn(ar, "failed to start vdev %i: %d\n", arvif->vdev_id, ret); goto exit; } @@ -3138,12 +3144,12 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_ERP_CTS_PROT) { arvif->use_cts_prot = info->use_cts_prot; - ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d cts_prot %d\n", + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d cts_prot %d\n", arvif->vdev_id, info->use_cts_prot); ret = ath10k_recalc_rtscts_prot(arvif); if (ret) - ath10k_warn("failed to recalculate rts/cts prot for vdev %d: %d\n", + ath10k_warn(ar, "failed to recalculate rts/cts prot for vdev %d: %d\n", arvif->vdev_id, ret); } @@ -3155,14 +3161,14 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, else slottime = WMI_VDEV_SLOT_TIME_LONG; /* 20us */ - ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d slot_time %d\n", + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d slot_time %d\n", arvif->vdev_id, slottime); vdev_param = ar->wmi.vdev_param->slot_time; ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, slottime); if (ret) - ath10k_warn("failed to set erp slot for vdev %d: %i\n", + ath10k_warn(ar, "failed to set erp slot for vdev %d: %i\n", arvif->vdev_id, ret); } @@ -3173,7 +3179,7 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, else preamble = WMI_VDEV_PREAMBLE_LONG; - ath10k_dbg(ATH10K_DBG_MAC, + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d preamble %dn", arvif->vdev_id, preamble); @@ -3181,7 +3187,7 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, preamble); if (ret) - ath10k_warn("failed to set preamble for vdev %d: %i\n", + ath10k_warn(ar, "failed to set preamble for vdev %d: %i\n", arvif->vdev_id, ret); } @@ -3259,7 +3265,7 @@ static int ath10k_hw_scan(struct ieee80211_hw *hw, ret = ath10k_start_scan(ar, &arg); if (ret) { - ath10k_warn("failed to start hw scan: %d\n", ret); + ath10k_warn(ar, "failed to start hw scan: %d\n", ret); spin_lock_bh(&ar->data_lock); ar->scan.state = ATH10K_SCAN_IDLE; spin_unlock_bh(&ar->data_lock); @@ -3315,7 +3321,7 @@ static void ath10k_set_key_h_def_keyidx(struct ath10k *ar, ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, key->keyidx); if (ret) - ath10k_warn("failed to set vdev %i group key as default key: %d\n", + ath10k_warn(ar, "failed to set vdev %i group key as default key: %d\n", arvif->vdev_id, ret); } @@ -3353,7 +3359,7 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, if (!peer) { if (cmd == SET_KEY) { - ath10k_warn("failed to install key for non-existent peer %pM\n", + ath10k_warn(ar, "failed to install key for non-existent peer %pM\n", peer_addr); ret = -EOPNOTSUPP; goto exit; @@ -3376,7 +3382,7 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, ret = ath10k_install_key(arvif, key, cmd, peer_addr); if (ret) { - ath10k_warn("failed to install key for vdev %i peer %pM: %d\n", + ath10k_warn(ar, "failed to install key for vdev %i peer %pM: %d\n", arvif->vdev_id, peer_addr, ret); goto exit; } @@ -3391,7 +3397,7 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, peer->keys[key->keyidx] = NULL; else if (peer == NULL) /* impossible unless FW goes crazy */ - ath10k_warn("Peer %pM disappeared!\n", peer_addr); + ath10k_warn(ar, "Peer %pM disappeared!\n", peer_addr); spin_unlock_bh(&ar->data_lock); exit: @@ -3427,45 +3433,45 @@ static void ath10k_sta_rc_update_wk(struct work_struct *wk) mutex_lock(&ar->conf_mutex); if (changed & IEEE80211_RC_BW_CHANGED) { - ath10k_dbg(ATH10K_DBG_MAC, "mac update sta %pM peer bw %d\n", + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM peer bw %d\n", sta->addr, bw); err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr, WMI_PEER_CHAN_WIDTH, bw); if (err) - ath10k_warn("failed to update STA %pM peer bw %d: %d\n", + ath10k_warn(ar, "failed to update STA %pM peer bw %d: %d\n", sta->addr, bw, err); } if (changed & IEEE80211_RC_NSS_CHANGED) { - ath10k_dbg(ATH10K_DBG_MAC, "mac update sta %pM nss %d\n", + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM nss %d\n", sta->addr, nss); err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr, WMI_PEER_NSS, nss); if (err) - ath10k_warn("failed to update STA %pM nss %d: %d\n", + ath10k_warn(ar, "failed to update STA %pM nss %d: %d\n", sta->addr, nss, err); } if (changed & IEEE80211_RC_SMPS_CHANGED) { - ath10k_dbg(ATH10K_DBG_MAC, "mac update sta %pM smps %d\n", + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM smps %d\n", sta->addr, smps); err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr, WMI_PEER_SMPS_STATE, smps); if (err) - ath10k_warn("failed to update STA %pM smps %d: %d\n", + ath10k_warn(ar, "failed to update STA %pM smps %d: %d\n", sta->addr, smps, err); } if (changed & IEEE80211_RC_SUPP_RATES_CHANGED) { - ath10k_dbg(ATH10K_DBG_MAC, "mac update sta %pM supp rates\n", + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM supp rates\n", sta->addr); err = ath10k_station_assoc(ar, arvif, sta, true); if (err) - ath10k_warn("failed to reassociate station: %pM\n", + ath10k_warn(ar, "failed to reassociate station: %pM\n", sta->addr); } @@ -3510,31 +3516,31 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, max_num_peers = TARGET_NUM_PEERS; if (ar->num_peers >= max_num_peers) { - ath10k_warn("number of peers exceeded: peers number %d (max peers %d)\n", + ath10k_warn(ar, "number of peers exceeded: peers number %d (max peers %d)\n", ar->num_peers, max_num_peers); ret = -ENOBUFS; goto exit; } - ath10k_dbg(ATH10K_DBG_MAC, + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d peer create %pM (new sta) num_peers %d\n", arvif->vdev_id, sta->addr, ar->num_peers); ret = ath10k_peer_create(ar, arvif->vdev_id, sta->addr); if (ret) - ath10k_warn("failed to add peer %pM for vdev %d when adding a new sta: %i\n", + ath10k_warn(ar, "failed to add peer %pM for vdev %d when adding a new sta: %i\n", sta->addr, arvif->vdev_id, ret); } else if ((old_state == IEEE80211_STA_NONE && new_state == IEEE80211_STA_NOTEXIST)) { /* * Existing station deletion. */ - ath10k_dbg(ATH10K_DBG_MAC, + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d peer delete %pM (sta gone)\n", arvif->vdev_id, sta->addr); ret = ath10k_peer_delete(ar, arvif->vdev_id, sta->addr); if (ret) - ath10k_warn("failed to delete peer %pM for vdev %d: %i\n", + ath10k_warn(ar, "failed to delete peer %pM for vdev %d: %i\n", sta->addr, arvif->vdev_id, ret); if (vif->type == NL80211_IFTYPE_STATION) @@ -3546,12 +3552,12 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, /* * New association. */ - ath10k_dbg(ATH10K_DBG_MAC, "mac sta %pM associated\n", + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac sta %pM associated\n", sta->addr); ret = ath10k_station_assoc(ar, arvif, sta, false); if (ret) - ath10k_warn("failed to associate station %pM for vdev %i: %i\n", + ath10k_warn(ar, "failed to associate station %pM for vdev %i: %i\n", sta->addr, arvif->vdev_id, ret); } else if (old_state == IEEE80211_STA_ASSOC && new_state == IEEE80211_STA_AUTH && @@ -3560,12 +3566,12 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, /* * Disassociation. */ - ath10k_dbg(ATH10K_DBG_MAC, "mac sta %pM disassociated\n", + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac sta %pM disassociated\n", sta->addr); ret = ath10k_station_disassoc(ar, arvif, sta); if (ret) - ath10k_warn("failed to disassociate station: %pM vdev %i: %i\n", + ath10k_warn(ar, "failed to disassociate station: %pM vdev %i: %i\n", sta->addr, arvif->vdev_id, ret); } exit: @@ -3613,7 +3619,7 @@ static int ath10k_conf_tx_uapsd(struct ath10k *ar, struct ieee80211_vif *vif, WMI_STA_PS_PARAM_UAPSD, arvif->u.sta.uapsd); if (ret) { - ath10k_warn("failed to set uapsd params: %d\n", ret); + ath10k_warn(ar, "failed to set uapsd params: %d\n", ret); goto exit; } @@ -3626,7 +3632,7 @@ static int ath10k_conf_tx_uapsd(struct ath10k *ar, struct ieee80211_vif *vif, WMI_STA_PS_PARAM_RX_WAKE_POLICY, value); if (ret) - ath10k_warn("failed to set rx wake param: %d\n", ret); + ath10k_warn(ar, "failed to set rx wake param: %d\n", ret); exit: return ret; @@ -3676,13 +3682,13 @@ static int ath10k_conf_tx(struct ieee80211_hw *hw, /* FIXME: FW accepts wmm params per hw, not per vif */ ret = ath10k_wmi_pdev_set_wmm_params(ar, &ar->wmm_params); if (ret) { - ath10k_warn("failed to set wmm params: %d\n", ret); + ath10k_warn(ar, "failed to set wmm params: %d\n", ret); goto exit; } ret = ath10k_conf_tx_uapsd(ar, vif, ac, params->uapsd); if (ret) - ath10k_warn("failed to set sta uapsd: %d\n", ret); + ath10k_warn(ar, "failed to set sta uapsd: %d\n", ret); exit: mutex_unlock(&ar->conf_mutex); @@ -3741,7 +3747,7 @@ static int ath10k_remain_on_channel(struct ieee80211_hw *hw, ret = ath10k_start_scan(ar, &arg); if (ret) { - ath10k_warn("failed to start roc scan: %d\n", ret); + ath10k_warn(ar, "failed to start roc scan: %d\n", ret); spin_lock_bh(&ar->data_lock); ar->scan.state = ATH10K_SCAN_IDLE; spin_unlock_bh(&ar->data_lock); @@ -3750,11 +3756,11 @@ static int ath10k_remain_on_channel(struct ieee80211_hw *hw, ret = wait_for_completion_timeout(&ar->scan.on_channel, 3*HZ); if (ret == 0) { - ath10k_warn("failed to switch to channel for roc scan\n"); + ath10k_warn(ar, "failed to switch to channel for roc scan\n"); ret = ath10k_scan_stop(ar); if (ret) - ath10k_warn("failed to stop scan: %d\n", ret); + ath10k_warn(ar, "failed to stop scan: %d\n", ret); ret = -ETIMEDOUT; goto exit; @@ -3791,12 +3797,12 @@ static int ath10k_set_rts_threshold(struct ieee80211_hw *hw, u32 value) mutex_lock(&ar->conf_mutex); list_for_each_entry(arvif, &ar->arvifs, list) { - ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d rts threshold %d\n", + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d rts threshold %d\n", arvif->vdev_id, value); ret = ath10k_mac_set_rts(arvif, value); if (ret) { - ath10k_warn("failed to set rts threshold for vdev %d: %d\n", + ath10k_warn(ar, "failed to set rts threshold for vdev %d: %d\n", arvif->vdev_id, ret); break; } @@ -3814,12 +3820,12 @@ static int ath10k_set_frag_threshold(struct ieee80211_hw *hw, u32 value) mutex_lock(&ar->conf_mutex); list_for_each_entry(arvif, &ar->arvifs, list) { - ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d fragmentation threshold %d\n", + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d fragmentation threshold %d\n", arvif->vdev_id, value); ret = ath10k_mac_set_rts(arvif, value); if (ret) { - ath10k_warn("failed to set fragmentation threshold for vdev %d: %d\n", + ath10k_warn(ar, "failed to set fragmentation threshold for vdev %d: %d\n", arvif->vdev_id, ret); break; } @@ -3859,7 +3865,7 @@ static void ath10k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, }), ATH10K_FLUSH_TIMEOUT_HZ); if (ret <= 0 || skip) - ath10k_warn("failed to flush transmit queue (skip %i ar-state %i): %i\n", + ath10k_warn(ar, "failed to flush transmit queue (skip %i ar-state %i): %i\n", skip, ar->state, ret); skip: @@ -3894,7 +3900,7 @@ static int ath10k_suspend(struct ieee80211_hw *hw, ret = ath10k_hif_suspend(ar); if (ret) { - ath10k_warn("failed to suspend hif: %d\n", ret); + ath10k_warn(ar, "failed to suspend hif: %d\n", ret); goto resume; } @@ -3903,7 +3909,7 @@ static int ath10k_suspend(struct ieee80211_hw *hw, resume: ret = ath10k_wmi_pdev_resume_target(ar); if (ret) - ath10k_warn("failed to resume target: %d\n", ret); + ath10k_warn(ar, "failed to resume target: %d\n", ret); ret = 1; exit: @@ -3920,14 +3926,14 @@ static int ath10k_resume(struct ieee80211_hw *hw) ret = ath10k_hif_resume(ar); if (ret) { - ath10k_warn("failed to resume hif: %d\n", ret); + ath10k_warn(ar, "failed to resume hif: %d\n", ret); ret = 1; goto exit; } ret = ath10k_wmi_pdev_resume_target(ar); if (ret) { - ath10k_warn("failed to resume target: %d\n", ret); + ath10k_warn(ar, "failed to resume target: %d\n", ret); ret = 1; goto exit; } @@ -3948,7 +3954,7 @@ static void ath10k_restart_complete(struct ieee80211_hw *hw) /* If device failed to restart it will be in a different state, e.g. * ATH10K_STATE_WEDGED */ if (ar->state == ATH10K_STATE_RESTARTED) { - ath10k_info("device successfully recovered\n"); + ath10k_info(ar, "device successfully recovered\n"); ar->state = ATH10K_STATE_ON; } @@ -4145,7 +4151,8 @@ ath10k_bitrate_mask_correct(const struct cfg80211_bitrate_mask *mask, } static bool -ath10k_bitrate_mask_rate(const struct cfg80211_bitrate_mask *mask, +ath10k_bitrate_mask_rate(struct ath10k *ar, + const struct cfg80211_bitrate_mask *mask, enum ieee80211_band band, u8 *fixed_rate, u8 *fixed_nss) @@ -4203,7 +4210,7 @@ ath10k_bitrate_mask_rate(const struct cfg80211_bitrate_mask *mask, nss <<= 4; pream <<= 6; - ath10k_dbg(ATH10K_DBG_MAC, "mac fixed rate pream 0x%02x nss 0x%02x rate 0x%02x\n", + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac fixed rate pream 0x%02x nss 0x%02x rate 0x%02x\n", pream, nss, rate); *fixed_rate = pream | nss | rate; @@ -4211,7 +4218,8 @@ ath10k_bitrate_mask_rate(const struct cfg80211_bitrate_mask *mask, return true; } -static bool ath10k_get_fixed_rate_nss(const struct cfg80211_bitrate_mask *mask, +static bool ath10k_get_fixed_rate_nss(struct ath10k *ar, + const struct cfg80211_bitrate_mask *mask, enum ieee80211_band band, u8 *fixed_rate, u8 *fixed_nss) @@ -4221,7 +4229,7 @@ static bool ath10k_get_fixed_rate_nss(const struct cfg80211_bitrate_mask *mask, return true; /* Next Check single rate is set */ - return ath10k_bitrate_mask_rate(mask, band, fixed_rate, fixed_nss); + return ath10k_bitrate_mask_rate(ar, mask, band, fixed_rate, fixed_nss); } static int ath10k_set_fixed_rate_param(struct ath10k_vif *arvif, @@ -4241,16 +4249,16 @@ static int ath10k_set_fixed_rate_param(struct ath10k_vif *arvif, goto exit; if (fixed_rate == WMI_FIXED_RATE_NONE) - ath10k_dbg(ATH10K_DBG_MAC, "mac disable fixed bitrate mask\n"); + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac disable fixed bitrate mask\n"); if (force_sgi) - ath10k_dbg(ATH10K_DBG_MAC, "mac force sgi\n"); + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac force sgi\n"); vdev_param = ar->wmi.vdev_param->fixed_rate; ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, fixed_rate); if (ret) { - ath10k_warn("failed to set fixed rate param 0x%02x: %d\n", + ath10k_warn(ar, "failed to set fixed rate param 0x%02x: %d\n", fixed_rate, ret); ret = -EINVAL; goto exit; @@ -4263,7 +4271,7 @@ static int ath10k_set_fixed_rate_param(struct ath10k_vif *arvif, vdev_param, fixed_nss); if (ret) { - ath10k_warn("failed to set fixed nss param %d: %d\n", + ath10k_warn(ar, "failed to set fixed nss param %d: %d\n", fixed_nss, ret); ret = -EINVAL; goto exit; @@ -4276,7 +4284,7 @@ static int ath10k_set_fixed_rate_param(struct ath10k_vif *arvif, force_sgi); if (ret) { - ath10k_warn("failed to set sgi param %d: %d\n", + ath10k_warn(ar, "failed to set sgi param %d: %d\n", force_sgi, ret); ret = -EINVAL; goto exit; @@ -4305,14 +4313,14 @@ static int ath10k_set_bitrate_mask(struct ieee80211_hw *hw, return -EINVAL; if (!ath10k_default_bitrate_mask(ar, band, mask)) { - if (!ath10k_get_fixed_rate_nss(mask, band, + if (!ath10k_get_fixed_rate_nss(ar, mask, band, &fixed_rate, &fixed_nss)) return -EINVAL; } if (fixed_rate == WMI_FIXED_RATE_NONE && force_sgi) { - ath10k_warn("failed to force SGI usage for default rate settings\n"); + ath10k_warn(ar, "failed to force SGI usage for default rate settings\n"); return -EINVAL; } @@ -4331,7 +4339,7 @@ static void ath10k_sta_rc_update(struct ieee80211_hw *hw, spin_lock_bh(&ar->data_lock); - ath10k_dbg(ATH10K_DBG_MAC, + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac sta rc update for %pM changed %08x bw %d nss %d smps %d\n", sta->addr, changed, sta->bandwidth, sta->rx_nss, sta->smps_mode); @@ -4350,7 +4358,7 @@ static void ath10k_sta_rc_update(struct ieee80211_hw *hw, bw = WMI_PEER_CHWIDTH_80MHZ; break; case IEEE80211_STA_RX_BW_160: - ath10k_warn("Invalid bandwith %d in rc update for %pM\n", + ath10k_warn(ar, "Invalid bandwith %d in rc update for %pM\n", sta->bandwidth, sta->addr); bw = WMI_PEER_CHWIDTH_20MHZ; break; @@ -4377,7 +4385,7 @@ static void ath10k_sta_rc_update(struct ieee80211_hw *hw, smps = WMI_PEER_SMPS_DYNAMIC; break; case IEEE80211_SMPS_NUM_MODES: - ath10k_warn("Invalid smps %d in sta rc update for %pM\n", + ath10k_warn(ar, "Invalid smps %d in sta rc update for %pM\n", sta->smps_mode, sta->addr); smps = WMI_PEER_SMPS_PS_NONE; break; @@ -4409,9 +4417,10 @@ static int ath10k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_sta *sta, u16 tid, u16 *ssn, u8 buf_size) { + struct ath10k *ar = hw->priv; struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); - ath10k_dbg(ATH10K_DBG_MAC, "mac ampdu vdev_id %i sta %pM tid %hu action %d\n", + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac ampdu vdev_id %i sta %pM tid %hu action %d\n", arvif->vdev_id, sta->addr, tid, action); switch (action) { @@ -4739,7 +4748,7 @@ struct ath10k_vif *ath10k_get_arvif(struct ath10k *ar, u32 vdev_id) ath10k_get_arvif_iter, &arvif_iter); if (!arvif_iter.arvif) { - ath10k_warn("No VIF found for vdev %d\n", vdev_id); + ath10k_warn(ar, "No VIF found for vdev %d\n", vdev_id); return NULL; } @@ -4885,19 +4894,19 @@ int ath10k_mac_register(struct ath10k *ar) NL80211_DFS_UNSET); if (!ar->dfs_detector) - ath10k_warn("failed to initialise DFS pattern detector\n"); + ath10k_warn(ar, "failed to initialise DFS pattern detector\n"); } ret = ath_regd_init(&ar->ath_common.regulatory, ar->hw->wiphy, ath10k_reg_notifier); if (ret) { - ath10k_err("failed to initialise regulatory: %i\n", ret); + ath10k_err(ar, "failed to initialise regulatory: %i\n", ret); goto err_free; } ret = ieee80211_register_hw(ar->hw); if (ret) { - ath10k_err("failed to register ieee80211: %d\n", ret); + ath10k_err(ar, "failed to register ieee80211: %d\n", ret); goto err_free; } diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 3af462ab27f6..83ef6ef622fa 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -296,7 +296,7 @@ static int __ath10k_pci_rx_post_buf(struct ath10k_pci_pipe *pipe) skb->len + skb_tailroom(skb), DMA_FROM_DEVICE); if (unlikely(dma_mapping_error(ar->dev, paddr))) { - ath10k_warn("failed to dma map pci rx buf\n"); + ath10k_warn(ar, "failed to dma map pci rx buf\n"); dev_kfree_skb_any(skb); return -EIO; } @@ -305,7 +305,7 @@ static int __ath10k_pci_rx_post_buf(struct ath10k_pci_pipe *pipe) ret = __ath10k_ce_rx_post_buf(ce_pipe, skb, paddr); if (ret) { - ath10k_warn("failed to post pci rx buf: %d\n", ret); + ath10k_warn(ar, "failed to post pci rx buf: %d\n", ret); dma_unmap_single(ar->dev, paddr, skb->len + skb_tailroom(skb), DMA_FROM_DEVICE); dev_kfree_skb_any(skb); @@ -334,7 +334,7 @@ static void __ath10k_pci_rx_post_pipe(struct ath10k_pci_pipe *pipe) while (num--) { ret = __ath10k_pci_rx_post_buf(pipe); if (ret) { - ath10k_warn("failed to post pci rx buf: %d\n", ret); + ath10k_warn(ar, "failed to post pci rx buf: %d\n", ret); mod_timer(&ar_pci->rx_post_retry, jiffies + ATH10K_PCI_RX_POST_RETRY_MS); break; @@ -514,7 +514,7 @@ done: __le32_to_cpu(((__le32 *)data_buf)[i]); } } else - ath10k_warn("failed to read diag value at 0x%x: %d\n", + ath10k_warn(ar, "failed to read diag value at 0x%x: %d\n", address, ret); if (data_buf) @@ -539,14 +539,14 @@ static int __ath10k_pci_diag_read_hi(struct ath10k *ar, void *dest, ret = ath10k_pci_diag_read32(ar, host_addr, &addr); if (ret != 0) { - ath10k_warn("failed to get memcpy hi address for firmware address %d: %d\n", + ath10k_warn(ar, "failed to get memcpy hi address for firmware address %d: %d\n", src, ret); return ret; } ret = ath10k_pci_diag_read_mem(ar, addr, dest, len); if (ret != 0) { - ath10k_warn("failed to memcpy firmware memory from %d (%d B): %d\n", + ath10k_warn(ar, "failed to memcpy firmware memory from %d (%d B): %d\n", addr, len, ret); return ret; } @@ -695,7 +695,7 @@ done: } if (ret != 0) - ath10k_warn("failed to write diag value at 0x%x: %d\n", + ath10k_warn(ar, "failed to write diag value at 0x%x: %d\n", address, ret); return ret; @@ -798,7 +798,7 @@ static void ath10k_pci_ce_recv_data(struct ath10k_ce_pipe *ce_state) max_nbytes, DMA_FROM_DEVICE); if (unlikely(max_nbytes < nbytes)) { - ath10k_warn("rxed more than expected (nbytes %d, max %d)", + ath10k_warn(ar, "rxed more than expected (nbytes %d, max %d)", nbytes, max_nbytes); dev_kfree_skb_any(skb); continue; @@ -836,10 +836,10 @@ static int ath10k_pci_hif_tx_sg(struct ath10k *ar, u8 pipe_id, } for (i = 0; i < n_items - 1; i++) { - ath10k_dbg(ATH10K_DBG_PCI, + ath10k_dbg(ar, ATH10K_DBG_PCI, "pci tx item %d paddr 0x%08x len %d n_items %d\n", i, items[i].paddr, items[i].len, n_items); - ath10k_dbg_dump(ATH10K_DBG_PCI_DUMP, NULL, "item data: ", + ath10k_dbg_dump(ar, ATH10K_DBG_PCI_DUMP, NULL, "pci tx data: ", items[i].vaddr, items[i].len); err = ath10k_ce_send_nolock(ce_pipe, @@ -854,10 +854,10 @@ static int ath10k_pci_hif_tx_sg(struct ath10k *ar, u8 pipe_id, /* `i` is equal to `n_items -1` after for() */ - ath10k_dbg(ATH10K_DBG_PCI, + ath10k_dbg(ar, ATH10K_DBG_PCI, "pci tx item %d paddr 0x%08x len %d n_items %d\n", i, items[i].paddr, items[i].len, n_items); - ath10k_dbg_dump(ATH10K_DBG_PCI_DUMP, NULL, "item data: ", + ath10k_dbg_dump(ar, ATH10K_DBG_PCI_DUMP, NULL, "pci tx data: ", items[i].vaddr, items[i].len); err = ath10k_ce_send_nolock(ce_pipe, @@ -884,7 +884,7 @@ static u16 ath10k_pci_hif_get_free_queue_number(struct ath10k *ar, u8 pipe) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - ath10k_dbg(ATH10K_DBG_PCI, "pci hif get free queue number\n"); + ath10k_dbg(ar, ATH10K_DBG_PCI, "pci hif get free queue number\n"); return ath10k_ce_num_free_src_entries(ar_pci->pipe_info[pipe].ce_hdl); } @@ -901,15 +901,15 @@ static void ath10k_pci_dump_registers(struct ath10k *ar, hi_failure_state, REG_DUMP_COUNT_QCA988X * sizeof(u32)); if (ret) { - ath10k_err("failed to read firmware dump area: %d\n", ret); + ath10k_err(ar, "failed to read firmware dump area: %d\n", ret); return; } BUILD_BUG_ON(REG_DUMP_COUNT_QCA988X % 4); - ath10k_err("firmware register dump:\n"); + ath10k_err(ar, "firmware register dump:\n"); for (i = 0; i < REG_DUMP_COUNT_QCA988X; i += 4) - ath10k_err("[%02d]: 0x%08X 0x%08X 0x%08X 0x%08X\n", + ath10k_err(ar, "[%02d]: 0x%08X 0x%08X 0x%08X 0x%08X\n", i, reg_dump_values[i], reg_dump_values[i + 1], @@ -935,7 +935,7 @@ static void ath10k_pci_fw_crashed_dump(struct ath10k *ar) else scnprintf(uuid, sizeof(uuid), "n/a"); - ath10k_err("firmware crashed! (uuid %s)\n", uuid); + ath10k_err(ar, "firmware crashed! (uuid %s)\n", uuid); ath10k_print_driver_info(ar); if (!crash_data) @@ -952,7 +952,7 @@ exit: static void ath10k_pci_hif_send_complete_check(struct ath10k *ar, u8 pipe, int force) { - ath10k_dbg(ATH10K_DBG_PCI, "pci hif send complete check\n"); + ath10k_dbg(ar, ATH10K_DBG_PCI, "pci hif send complete check\n"); if (!force) { int resources; @@ -980,7 +980,7 @@ static void ath10k_pci_hif_set_callbacks(struct ath10k *ar, { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - ath10k_dbg(ATH10K_DBG_PCI, "pci hif set callbacks\n"); + ath10k_dbg(ar, ATH10K_DBG_PCI, "pci hif set callbacks\n"); memcpy(&ar_pci->msg_callbacks_current, callbacks, sizeof(ar_pci->msg_callbacks_current)); @@ -1008,7 +1008,7 @@ static int ath10k_pci_hif_map_service_to_pipe(struct ath10k *ar, { int ret = 0; - ath10k_dbg(ATH10K_DBG_PCI, "pci hif map service\n"); + ath10k_dbg(ar, ATH10K_DBG_PCI, "pci hif map service\n"); /* polling for received messages not supported */ *dl_is_polled = 0; @@ -1069,7 +1069,7 @@ static void ath10k_pci_hif_get_default_pipe(struct ath10k *ar, { int ul_is_polled, dl_is_polled; - ath10k_dbg(ATH10K_DBG_PCI, "pci hif get default pipe\n"); + ath10k_dbg(ar, ATH10K_DBG_PCI, "pci hif get default pipe\n"); (void)ath10k_pci_hif_map_service_to_pipe(ar, ATH10K_HTC_SVC_ID_RSVD_CTRL, @@ -1115,7 +1115,7 @@ static void ath10k_pci_irq_enable(struct ath10k *ar) static int ath10k_pci_hif_start(struct ath10k *ar) { - ath10k_dbg(ATH10K_DBG_BOOT, "boot hif start\n"); + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif start\n"); ath10k_pci_irq_enable(ar); ath10k_pci_rx_post(ar); @@ -1222,7 +1222,7 @@ static void ath10k_pci_flush(struct ath10k *ar) static void ath10k_pci_hif_stop(struct ath10k *ar) { - ath10k_dbg(ATH10K_DBG_BOOT, "boot hif stop\n"); + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif stop\n"); ath10k_pci_irq_disable(ar); ath10k_pci_flush(ar); @@ -1340,6 +1340,7 @@ static void ath10k_pci_bmi_send_done(struct ath10k_ce_pipe *ce_state) static void ath10k_pci_bmi_recv_data(struct ath10k_ce_pipe *ce_state) { + struct ath10k *ar = ce_state->ar; struct bmi_xfer *xfer; u32 ce_data; unsigned int nbytes; @@ -1351,7 +1352,7 @@ static void ath10k_pci_bmi_recv_data(struct ath10k_ce_pipe *ce_state) return; if (!xfer->wait_for_resp) { - ath10k_warn("unexpected: BMI data received; ignoring\n"); + ath10k_warn(ar, "unexpected: BMI data received; ignoring\n"); return; } @@ -1487,7 +1488,7 @@ static int ath10k_pci_wake_target_cpu(struct ath10k *ar) CORE_CTRL_ADDRESS, &core_ctrl); if (ret) { - ath10k_warn("failed to read core_ctrl: %d\n", ret); + ath10k_warn(ar, "failed to read core_ctrl: %d\n", ret); return ret; } @@ -1498,7 +1499,7 @@ static int ath10k_pci_wake_target_cpu(struct ath10k *ar) CORE_CTRL_ADDRESS, core_ctrl); if (ret) { - ath10k_warn("failed to set target CPU interrupt mask: %d\n", + ath10k_warn(ar, "failed to set target CPU interrupt mask: %d\n", ret); return ret; } @@ -1527,13 +1528,13 @@ static int ath10k_pci_init_config(struct ath10k *ar) ret = ath10k_pci_diag_read_access(ar, interconnect_targ_addr, &pcie_state_targ_addr); if (ret != 0) { - ath10k_err("Failed to get pcie state addr: %d\n", ret); + ath10k_err(ar, "Failed to get pcie state addr: %d\n", ret); return ret; } if (pcie_state_targ_addr == 0) { ret = -EIO; - ath10k_err("Invalid pcie state addr\n"); + ath10k_err(ar, "Invalid pcie state addr\n"); return ret; } @@ -1542,13 +1543,13 @@ static int ath10k_pci_init_config(struct ath10k *ar) pipe_cfg_addr), &pipe_cfg_targ_addr); if (ret != 0) { - ath10k_err("Failed to get pipe cfg addr: %d\n", ret); + ath10k_err(ar, "Failed to get pipe cfg addr: %d\n", ret); return ret; } if (pipe_cfg_targ_addr == 0) { ret = -EIO; - ath10k_err("Invalid pipe cfg addr\n"); + ath10k_err(ar, "Invalid pipe cfg addr\n"); return ret; } @@ -1557,7 +1558,7 @@ static int ath10k_pci_init_config(struct ath10k *ar) sizeof(target_ce_config_wlan)); if (ret != 0) { - ath10k_err("Failed to write pipe cfg: %d\n", ret); + ath10k_err(ar, "Failed to write pipe cfg: %d\n", ret); return ret; } @@ -1566,13 +1567,13 @@ static int ath10k_pci_init_config(struct ath10k *ar) svc_to_pipe_map), &svc_to_pipe_map); if (ret != 0) { - ath10k_err("Failed to get svc/pipe map: %d\n", ret); + ath10k_err(ar, "Failed to get svc/pipe map: %d\n", ret); return ret; } if (svc_to_pipe_map == 0) { ret = -EIO; - ath10k_err("Invalid svc_to_pipe map\n"); + ath10k_err(ar, "Invalid svc_to_pipe map\n"); return ret; } @@ -1580,7 +1581,7 @@ static int ath10k_pci_init_config(struct ath10k *ar) target_service_to_ce_map_wlan, sizeof(target_service_to_ce_map_wlan)); if (ret != 0) { - ath10k_err("Failed to write svc/pipe map: %d\n", ret); + ath10k_err(ar, "Failed to write svc/pipe map: %d\n", ret); return ret; } @@ -1589,7 +1590,7 @@ static int ath10k_pci_init_config(struct ath10k *ar) config_flags), &pcie_config_flags); if (ret != 0) { - ath10k_err("Failed to get pcie config_flags: %d\n", ret); + ath10k_err(ar, "Failed to get pcie config_flags: %d\n", ret); return ret; } @@ -1600,7 +1601,7 @@ static int ath10k_pci_init_config(struct ath10k *ar) &pcie_config_flags, sizeof(pcie_config_flags)); if (ret != 0) { - ath10k_err("Failed to write pcie config_flags: %d\n", ret); + ath10k_err(ar, "Failed to write pcie config_flags: %d\n", ret); return ret; } @@ -1609,7 +1610,7 @@ static int ath10k_pci_init_config(struct ath10k *ar) ret = ath10k_pci_diag_read_access(ar, ealloc_targ_addr, &ealloc_value); if (ret != 0) { - ath10k_err("Faile to get early alloc val: %d\n", ret); + ath10k_err(ar, "Faile to get early alloc val: %d\n", ret); return ret; } @@ -1621,7 +1622,7 @@ static int ath10k_pci_init_config(struct ath10k *ar) ret = ath10k_pci_diag_write_access(ar, ealloc_targ_addr, ealloc_value); if (ret != 0) { - ath10k_err("Failed to set early alloc val: %d\n", ret); + ath10k_err(ar, "Failed to set early alloc val: %d\n", ret); return ret; } @@ -1630,7 +1631,7 @@ static int ath10k_pci_init_config(struct ath10k *ar) ret = ath10k_pci_diag_read_access(ar, flag2_targ_addr, &flag2_value); if (ret != 0) { - ath10k_err("Failed to get option val: %d\n", ret); + ath10k_err(ar, "Failed to get option val: %d\n", ret); return ret; } @@ -1638,7 +1639,7 @@ static int ath10k_pci_init_config(struct ath10k *ar) ret = ath10k_pci_diag_write_access(ar, flag2_targ_addr, flag2_value); if (ret != 0) { - ath10k_err("Failed to set option val: %d\n", ret); + ath10k_err(ar, "Failed to set option val: %d\n", ret); return ret; } @@ -1652,7 +1653,7 @@ static int ath10k_pci_alloc_ce(struct ath10k *ar) for (i = 0; i < CE_COUNT; i++) { ret = ath10k_ce_alloc_pipe(ar, i, &host_ce_config_wlan[i]); if (ret) { - ath10k_err("failed to allocate copy engine pipe %d: %d\n", + ath10k_err(ar, "failed to allocate copy engine pipe %d: %d\n", i, ret); return ret; } @@ -1687,7 +1688,7 @@ static int ath10k_pci_ce_init(struct ath10k *ar) ath10k_pci_ce_send_done, ath10k_pci_ce_recv_data); if (ret) { - ath10k_err("failed to initialize copy engine pipe %d: %d\n", + ath10k_err(ar, "failed to initialize copy engine pipe %d: %d\n", pipe_num, ret); return ret; } @@ -1746,16 +1747,17 @@ static int ath10k_pci_warm_reset(struct ath10k *ar) { u32 val; - ath10k_dbg(ATH10K_DBG_BOOT, "boot warm reset\n"); + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot warm reset\n"); /* debug */ val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + PCIE_INTR_CAUSE_ADDRESS); - ath10k_dbg(ATH10K_DBG_BOOT, "boot host cpu intr cause: 0x%08x\n", val); + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot host cpu intr cause: 0x%08x\n", + val); val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + CPU_INTR_ADDRESS); - ath10k_dbg(ATH10K_DBG_BOOT, "boot target cpu intr cause: 0x%08x\n", + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot target cpu intr cause: 0x%08x\n", val); /* disable pending irqs */ @@ -1798,11 +1800,12 @@ static int ath10k_pci_warm_reset(struct ath10k *ar) /* debug */ val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + PCIE_INTR_CAUSE_ADDRESS); - ath10k_dbg(ATH10K_DBG_BOOT, "boot host cpu intr cause: 0x%08x\n", val); + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot host cpu intr cause: 0x%08x\n", + val); val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + CPU_INTR_ADDRESS); - ath10k_dbg(ATH10K_DBG_BOOT, "boot target cpu intr cause: 0x%08x\n", + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot target cpu intr cause: 0x%08x\n", val); /* CPU warm reset */ @@ -1813,11 +1816,12 @@ static int ath10k_pci_warm_reset(struct ath10k *ar) val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS + SOC_RESET_CONTROL_ADDRESS); - ath10k_dbg(ATH10K_DBG_BOOT, "boot target reset state: 0x%08x\n", val); + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot target reset state: 0x%08x\n", + val); msleep(100); - ath10k_dbg(ATH10K_DBG_BOOT, "boot warm reset complete\n"); + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot warm reset complete\n"); return 0; } @@ -1842,31 +1846,31 @@ static int __ath10k_pci_hif_power_up(struct ath10k *ar, bool cold_reset) ret = ath10k_pci_warm_reset(ar); if (ret) { - ath10k_err("failed to reset target: %d\n", ret); + ath10k_err(ar, "failed to reset target: %d\n", ret); goto err; } ret = ath10k_pci_ce_init(ar); if (ret) { - ath10k_err("failed to initialize CE: %d\n", ret); + ath10k_err(ar, "failed to initialize CE: %d\n", ret); goto err; } ret = ath10k_pci_wait_for_target_init(ar); if (ret) { - ath10k_err("failed to wait for target to init: %d\n", ret); + ath10k_err(ar, "failed to wait for target to init: %d\n", ret); goto err_ce; } ret = ath10k_pci_init_config(ar); if (ret) { - ath10k_err("failed to setup init config: %d\n", ret); + ath10k_err(ar, "failed to setup init config: %d\n", ret); goto err_ce; } ret = ath10k_pci_wake_target_cpu(ar); if (ret) { - ath10k_err("could not wake up target CPU: %d\n", ret); + ath10k_err(ar, "could not wake up target CPU: %d\n", ret); goto err_ce; } @@ -1894,7 +1898,7 @@ static int ath10k_pci_hif_power_up_warm(struct ath10k *ar) if (ret == 0) break; - ath10k_warn("failed to warm reset (attempt %d out of %d): %d\n", + ath10k_warn(ar, "failed to warm reset (attempt %d out of %d): %d\n", i + 1, ATH10K_PCI_NUM_WARM_RESET_ATTEMPTS, ret); } @@ -1905,7 +1909,7 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar) { int ret; - ath10k_dbg(ATH10K_DBG_BOOT, "boot hif power up\n"); + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif power up\n"); /* * Hardware CUS232 version 2 has some issues with cold reset and the @@ -1917,17 +1921,17 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar) */ ret = ath10k_pci_hif_power_up_warm(ar); if (ret) { - ath10k_warn("failed to power up target using warm reset: %d\n", + ath10k_warn(ar, "failed to power up target using warm reset: %d\n", ret); if (ath10k_pci_reset_mode == ATH10K_PCI_RESET_WARM_ONLY) return ret; - ath10k_warn("trying cold reset\n"); + ath10k_warn(ar, "trying cold reset\n"); ret = __ath10k_pci_hif_power_up(ar, true); if (ret) { - ath10k_err("failed to power up target using cold reset too (%d)\n", + ath10k_err(ar, "failed to power up target using cold reset too (%d)\n", ret); return ret; } @@ -1938,7 +1942,7 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar) static void ath10k_pci_hif_power_down(struct ath10k *ar) { - ath10k_dbg(ATH10K_DBG_BOOT, "boot hif power down\n"); + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif power down\n"); ath10k_pci_warm_reset(ar); } @@ -2023,7 +2027,7 @@ static void ath10k_msi_err_tasklet(unsigned long data) struct ath10k *ar = (struct ath10k *)data; if (!ath10k_pci_has_fw_crashed(ar)) { - ath10k_warn("received unsolicited fw crash interrupt\n"); + ath10k_warn(ar, "received unsolicited fw crash interrupt\n"); return; } @@ -2042,7 +2046,8 @@ static irqreturn_t ath10k_pci_per_engine_handler(int irq, void *arg) int ce_id = irq - ar_pci->pdev->irq - MSI_ASSIGN_CE_INITIAL; if (ce_id < 0 || ce_id >= ARRAY_SIZE(ar_pci->pipe_info)) { - ath10k_warn("unexpected/invalid irq %d ce_id %d\n", irq, ce_id); + ath10k_warn(ar, "unexpected/invalid irq %d ce_id %d\n", irq, + ce_id); return IRQ_HANDLED; } @@ -2116,7 +2121,7 @@ static int ath10k_pci_request_irq_msix(struct ath10k *ar) ath10k_pci_msi_fw_handler, IRQF_SHARED, "ath10k_pci", ar); if (ret) { - ath10k_warn("failed to request MSI-X fw irq %d: %d\n", + ath10k_warn(ar, "failed to request MSI-X fw irq %d: %d\n", ar_pci->pdev->irq + MSI_ASSIGN_FW, ret); return ret; } @@ -2126,7 +2131,7 @@ static int ath10k_pci_request_irq_msix(struct ath10k *ar) ath10k_pci_per_engine_handler, IRQF_SHARED, "ath10k_pci", ar); if (ret) { - ath10k_warn("failed to request MSI-X ce irq %d: %d\n", + ath10k_warn(ar, "failed to request MSI-X ce irq %d: %d\n", ar_pci->pdev->irq + i, ret); for (i--; i >= MSI_ASSIGN_CE_INITIAL; i--) @@ -2149,7 +2154,7 @@ static int ath10k_pci_request_irq_msi(struct ath10k *ar) ath10k_pci_interrupt_handler, IRQF_SHARED, "ath10k_pci", ar); if (ret) { - ath10k_warn("failed to request MSI irq %d: %d\n", + ath10k_warn(ar, "failed to request MSI irq %d: %d\n", ar_pci->pdev->irq, ret); return ret; } @@ -2166,7 +2171,7 @@ static int ath10k_pci_request_irq_legacy(struct ath10k *ar) ath10k_pci_interrupt_handler, IRQF_SHARED, "ath10k_pci", ar); if (ret) { - ath10k_warn("failed to request legacy irq %d: %d\n", + ath10k_warn(ar, "failed to request legacy irq %d: %d\n", ar_pci->pdev->irq, ret); return ret; } @@ -2187,7 +2192,7 @@ static int ath10k_pci_request_irq(struct ath10k *ar) return ath10k_pci_request_irq_msix(ar); } - ath10k_warn("unknown irq configuration upon request\n"); + ath10k_warn(ar, "unknown irq configuration upon request\n"); return -EINVAL; } @@ -2226,7 +2231,8 @@ static int ath10k_pci_init_irq(struct ath10k *ar) ath10k_pci_init_irq_tasklets(ar); if (ath10k_pci_irq_mode != ATH10K_PCI_IRQ_AUTO) - ath10k_info("limiting irq mode to: %d\n", ath10k_pci_irq_mode); + ath10k_info(ar, "limiting irq mode to: %d\n", + ath10k_pci_irq_mode); /* Try MSI-X */ if (ath10k_pci_irq_mode == ATH10K_PCI_IRQ_AUTO) { @@ -2288,7 +2294,7 @@ static int ath10k_pci_deinit_irq(struct ath10k *ar) pci_disable_msi(ar_pci->pdev); } - ath10k_warn("unknown irq configuration upon deinit\n"); + ath10k_warn(ar, "unknown irq configuration upon deinit\n"); return -EINVAL; } @@ -2298,14 +2304,15 @@ static int ath10k_pci_wait_for_target_init(struct ath10k *ar) unsigned long timeout; u32 val; - ath10k_dbg(ATH10K_DBG_BOOT, "boot waiting target to initialise\n"); + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot waiting target to initialise\n"); timeout = jiffies + msecs_to_jiffies(ATH10K_PCI_TARGET_WAIT); do { val = ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS); - ath10k_dbg(ATH10K_DBG_BOOT, "boot target indicator %x\n", val); + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot target indicator %x\n", + val); /* target should never return this */ if (val == 0xffffffff) @@ -2329,24 +2336,24 @@ static int ath10k_pci_wait_for_target_init(struct ath10k *ar) } while (time_before(jiffies, timeout)); if (val == 0xffffffff) { - ath10k_err("failed to read device register, device is gone\n"); + ath10k_err(ar, "failed to read device register, device is gone\n"); return -EIO; } if (val & FW_IND_EVENT_PENDING) { - ath10k_warn("device has crashed during init\n"); + ath10k_warn(ar, "device has crashed during init\n"); ath10k_pci_fw_crashed_clear(ar); ath10k_pci_fw_crashed_dump(ar); return -ECOMM; } if (!(val & FW_IND_INITIALIZED)) { - ath10k_err("failed to receive initialized event from target: %08x\n", + ath10k_err(ar, "failed to receive initialized event from target: %08x\n", val); return -ETIMEDOUT; } - ath10k_dbg(ATH10K_DBG_BOOT, "boot target initialised\n"); + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot target initialised\n"); return 0; } @@ -2355,7 +2362,7 @@ static int ath10k_pci_cold_reset(struct ath10k *ar) int i; u32 val; - ath10k_dbg(ATH10K_DBG_BOOT, "boot cold reset\n"); + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot cold reset\n"); /* Put Target, including PCIe, into RESET. */ val = ath10k_pci_reg_read32(ar, SOC_GLOBAL_RESET_ADDRESS); @@ -2380,7 +2387,7 @@ static int ath10k_pci_cold_reset(struct ath10k *ar) msleep(1); } - ath10k_dbg(ATH10K_DBG_BOOT, "boot cold reset complete\n"); + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot cold reset complete\n"); return 0; } @@ -2396,13 +2403,13 @@ static int ath10k_pci_claim(struct ath10k *ar) ret = pci_enable_device(pdev); if (ret) { - ath10k_err("failed to enable pci device: %d\n", ret); + ath10k_err(ar, "failed to enable pci device: %d\n", ret); return ret; } ret = pci_request_region(pdev, BAR_NUM, "ath"); if (ret) { - ath10k_err("failed to request region BAR%d: %d\n", BAR_NUM, + ath10k_err(ar, "failed to request region BAR%d: %d\n", BAR_NUM, ret); goto err_device; } @@ -2410,13 +2417,13 @@ static int ath10k_pci_claim(struct ath10k *ar) /* Target expects 32 bit DMA. Enforce it. */ ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); if (ret) { - ath10k_err("failed to set dma mask to 32-bit: %d\n", ret); + ath10k_err(ar, "failed to set dma mask to 32-bit: %d\n", ret); goto err_region; } ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); if (ret) { - ath10k_err("failed to set consistent dma mask to 32-bit: %d\n", + ath10k_err(ar, "failed to set consistent dma mask to 32-bit: %d\n", ret); goto err_region; } @@ -2430,12 +2437,12 @@ static int ath10k_pci_claim(struct ath10k *ar) /* Arrange for access to Target SoC registers. */ ar_pci->mem = pci_iomap(pdev, BAR_NUM, 0); if (!ar_pci->mem) { - ath10k_err("failed to iomap BAR%d\n", BAR_NUM); + ath10k_err(ar, "failed to iomap BAR%d\n", BAR_NUM); ret = -EIO; goto err_master; } - ath10k_dbg(ATH10K_DBG_BOOT, "boot pci_mem 0x%p\n", ar_pci->mem); + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot pci_mem 0x%p\n", ar_pci->mem); return 0; err_master: @@ -2469,15 +2476,15 @@ static int ath10k_pci_probe(struct pci_dev *pdev, struct ath10k_pci *ar_pci; u32 chip_id; - ath10k_dbg(ATH10K_DBG_PCI, "pci probe\n"); - ar = ath10k_core_create(sizeof(*ar_pci), &pdev->dev, &ath10k_pci_hif_ops); if (!ar) { - ath10k_err("failed to allocate core\n"); + dev_err(&pdev->dev, "failed to allocate core\n"); return -ENOMEM; } + ath10k_dbg(ar, ATH10K_DBG_PCI, "pci probe\n"); + ar_pci = ath10k_pci_priv(ar); ar_pci->pdev = pdev; ar_pci->dev = &pdev->dev; @@ -2489,25 +2496,26 @@ static int ath10k_pci_probe(struct pci_dev *pdev, ret = ath10k_pci_claim(ar); if (ret) { - ath10k_err("failed to claim device: %d\n", ret); + ath10k_err(ar, "failed to claim device: %d\n", ret); goto err_core_destroy; } ret = ath10k_pci_wake(ar); if (ret) { - ath10k_err("failed to wake up: %d\n", ret); + ath10k_err(ar, "failed to wake up: %d\n", ret); goto err_release; } chip_id = ath10k_pci_soc_read32(ar, SOC_CHIP_ID_ADDRESS); if (chip_id == 0xffffffff) { - ath10k_err("failed to get chip id\n"); + ath10k_err(ar, "failed to get chip id\n"); goto err_sleep; } ret = ath10k_pci_alloc_ce(ar); if (ret) { - ath10k_err("failed to allocate copy engine pipes: %d\n", ret); + ath10k_err(ar, "failed to allocate copy engine pipes: %d\n", + ret); goto err_sleep; } @@ -2515,7 +2523,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev, ret = ath10k_ce_disable_interrupts(ar); if (ret) { - ath10k_err("failed to disable copy engine interrupts: %d\n", + ath10k_err(ar, "failed to disable copy engine interrupts: %d\n", ret); goto err_free_ce; } @@ -2529,17 +2537,17 @@ static int ath10k_pci_probe(struct pci_dev *pdev, ret = ath10k_pci_init_irq(ar); if (ret) { - ath10k_err("failed to init irqs: %d\n", ret); + ath10k_err(ar, "failed to init irqs: %d\n", ret); goto err_free_ce; } - ath10k_info("pci irq %s interrupts %d irq_mode %d reset_mode %d\n", + ath10k_info(ar, "pci irq %s interrupts %d irq_mode %d reset_mode %d\n", ath10k_pci_get_irq_method(ar), ar_pci->num_msi_intrs, ath10k_pci_irq_mode, ath10k_pci_reset_mode); ret = ath10k_pci_request_irq(ar); if (ret) { - ath10k_warn("failed to request irqs: %d\n", ret); + ath10k_warn(ar, "failed to request irqs: %d\n", ret); goto err_deinit_irq; } @@ -2548,7 +2556,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev, ret = ath10k_core_register(ar, chip_id); if (ret) { - ath10k_err("failed to register driver core: %d\n", ret); + ath10k_err(ar, "failed to register driver core: %d\n", ret); goto err_free_irq; } @@ -2580,7 +2588,7 @@ static void ath10k_pci_remove(struct pci_dev *pdev) struct ath10k *ar = pci_get_drvdata(pdev); struct ath10k_pci *ar_pci; - ath10k_dbg(ATH10K_DBG_PCI, "pci remove\n"); + ath10k_dbg(ar, ATH10K_DBG_PCI, "pci remove\n"); if (!ar) return; @@ -2615,7 +2623,8 @@ static int __init ath10k_pci_init(void) ret = pci_register_driver(&ath10k_pci_driver); if (ret) - ath10k_err("failed to register PCI driver: %d\n", ret); + printk(KERN_ERR "failed to register ath10k pci driver: %d\n", + ret); return ret; } diff --git a/drivers/net/wireless/ath/ath10k/spectral.c b/drivers/net/wireless/ath/ath10k/spectral.c index a53afc23864f..3e1454b74e00 100644 --- a/drivers/net/wireless/ath/ath10k/spectral.c +++ b/drivers/net/wireless/ath/ath10k/spectral.c @@ -237,7 +237,7 @@ static int ath10k_spectral_scan_config(struct ath10k *ar, WMI_SPECTRAL_TRIGGER_CMD_CLEAR, WMI_SPECTRAL_ENABLE_CMD_DISABLE); if (res < 0) { - ath10k_warn("failed to enable spectral scan: %d\n", res); + ath10k_warn(ar, "failed to enable spectral scan: %d\n", res); return res; } @@ -271,7 +271,7 @@ static int ath10k_spectral_scan_config(struct ath10k *ar, res = ath10k_wmi_vdev_spectral_conf(ar, &arg); if (res < 0) { - ath10k_warn("failed to configure spectral scan: %d\n", res); + ath10k_warn(ar, "failed to configure spectral scan: %d\n", res); return res; } @@ -332,12 +332,12 @@ static ssize_t write_file_spec_scan_ctl(struct file *file, res = ath10k_spectral_scan_config(ar, ar->spectral.mode); if (res < 0) { - ath10k_warn("failed to reconfigure spectral scan: %d\n", + ath10k_warn(ar, "failed to reconfigure spectral scan: %d\n", res); } res = ath10k_spectral_scan_trigger(ar); if (res < 0) { - ath10k_warn("failed to trigger spectral scan: %d\n", + ath10k_warn(ar, "failed to trigger spectral scan: %d\n", res); } } else { diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c index f4fa22d1d591..2eeec8a63d5c 100644 --- a/drivers/net/wireless/ath/ath10k/txrx.c +++ b/drivers/net/wireless/ath/ath10k/txrx.c @@ -32,14 +32,14 @@ static void ath10k_report_offchan_tx(struct ath10k *ar, struct sk_buff *skb) * offchan_tx_skb. */ spin_lock_bh(&ar->data_lock); if (ar->offchan_tx_skb != skb) { - ath10k_warn("completed old offchannel frame\n"); + ath10k_warn(ar, "completed old offchannel frame\n"); goto out; } complete(&ar->offchan_tx_completed); ar->offchan_tx_skb = NULL; /* just for sanity */ - ath10k_dbg(ATH10K_DBG_HTT, "completed offchannel skb %p\n", skb); + ath10k_dbg(ar, ATH10K_DBG_HTT, "completed offchannel skb %p\n", skb); out: spin_unlock_bh(&ar->data_lock); } @@ -47,18 +47,19 @@ out: void ath10k_txrx_tx_unref(struct ath10k_htt *htt, const struct htt_tx_done *tx_done) { - struct device *dev = htt->ar->dev; + struct ath10k *ar = htt->ar; + struct device *dev = ar->dev; struct ieee80211_tx_info *info; struct ath10k_skb_cb *skb_cb; struct sk_buff *msdu; lockdep_assert_held(&htt->tx_lock); - ath10k_dbg(ATH10K_DBG_HTT, "htt tx completion msdu_id %u discard %d no_ack %d\n", + ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx completion msdu_id %u discard %d no_ack %d\n", tx_done->msdu_id, !!tx_done->discard, !!tx_done->no_ack); if (tx_done->msdu_id >= htt->max_num_pending_tx) { - ath10k_warn("warning: msdu_id %d too big, ignoring\n", + ath10k_warn(ar, "warning: msdu_id %d too big, ignoring\n", tx_done->msdu_id); return; } @@ -182,7 +183,7 @@ void ath10k_peer_map_event(struct ath10k_htt *htt, wake_up(&ar->peer_mapping_wq); } - ath10k_dbg(ATH10K_DBG_HTT, "htt peer map vdev %d peer %pM id %d\n", + ath10k_dbg(ar, ATH10K_DBG_HTT, "htt peer map vdev %d peer %pM id %d\n", ev->vdev_id, ev->addr, ev->peer_id); set_bit(ev->peer_id, peer->peer_ids); @@ -199,12 +200,12 @@ void ath10k_peer_unmap_event(struct ath10k_htt *htt, spin_lock_bh(&ar->data_lock); peer = ath10k_peer_find_by_id(ar, ev->peer_id); if (!peer) { - ath10k_warn("peer-unmap-event: unknown peer id %d\n", + ath10k_warn(ar, "peer-unmap-event: unknown peer id %d\n", ev->peer_id); goto exit; } - ath10k_dbg(ATH10K_DBG_HTT, "htt peer unmap vdev %d peer %pM id %d\n", + ath10k_dbg(ar, ATH10K_DBG_HTT, "htt peer unmap vdev %d peer %pM id %d\n", peer->vdev_id, peer->addr, ev->peer_id); clear_bit(ev->peer_id, peer->peer_ids); diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index ec3bf4e00b4d..e500a3cc905e 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -624,18 +624,18 @@ int ath10k_wmi_wait_for_unified_ready(struct ath10k *ar) return ret; } -static struct sk_buff *ath10k_wmi_alloc_skb(u32 len) +static struct sk_buff *ath10k_wmi_alloc_skb(struct ath10k *ar, u32 len) { struct sk_buff *skb; u32 round_len = roundup(len, 4); - skb = ath10k_htc_alloc_skb(WMI_SKB_HEADROOM + round_len); + skb = ath10k_htc_alloc_skb(ar, WMI_SKB_HEADROOM + round_len); if (!skb) return NULL; skb_reserve(skb, WMI_SKB_HEADROOM); if (!IS_ALIGNED((unsigned long)skb->data, 4)) - ath10k_warn("Unaligned WMI skb\n"); + ath10k_warn(ar, "Unaligned WMI skb\n"); skb_put(skb, round_len); memset(skb->data, 0, round_len); @@ -733,7 +733,7 @@ static int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, might_sleep(); if (cmd_id == WMI_CMD_UNSUPPORTED) { - ath10k_warn("wmi command %d is not supported by firmware\n", + ath10k_warn(ar, "wmi command %d is not supported by firmware\n", cmd_id); return ret; } @@ -781,7 +781,7 @@ int ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *skb) len = round_up(len, 4); - wmi_skb = ath10k_wmi_alloc_skb(len); + wmi_skb = ath10k_wmi_alloc_skb(ar, len); if (!wmi_skb) return -ENOMEM; @@ -795,7 +795,7 @@ int ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *skb) memcpy(cmd->hdr.peer_macaddr.addr, ieee80211_get_DA(hdr), ETH_ALEN); memcpy(cmd->buf, skb->data, skb->len); - ath10k_dbg(ATH10K_DBG_WMI, "wmi mgmt tx skb %p len %d ftype %02x stype %02x\n", + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi mgmt tx skb %p len %d ftype %02x stype %02x\n", wmi_skb, wmi_skb->len, fc & IEEE80211_FCTL_FTYPE, fc & IEEE80211_FCTL_STYPE); @@ -819,7 +819,7 @@ static void ath10k_wmi_event_scan_started(struct ath10k *ar) case ATH10K_SCAN_IDLE: case ATH10K_SCAN_RUNNING: case ATH10K_SCAN_ABORTING: - ath10k_warn("received scan started event in an invalid scan state: %s (%d)\n", + ath10k_warn(ar, "received scan started event in an invalid scan state: %s (%d)\n", ath10k_scan_state_str(ar->scan.state), ar->scan.state); break; @@ -849,7 +849,7 @@ static void ath10k_wmi_event_scan_completed(struct ath10k *ar) * is) ignored by the host as it may be just firmware's scan * state machine recovering. */ - ath10k_warn("received scan completed event in an invalid scan state: %s (%d)\n", + ath10k_warn(ar, "received scan completed event in an invalid scan state: %s (%d)\n", ath10k_scan_state_str(ar->scan.state), ar->scan.state); break; @@ -867,7 +867,7 @@ static void ath10k_wmi_event_scan_bss_chan(struct ath10k *ar) switch (ar->scan.state) { case ATH10K_SCAN_IDLE: case ATH10K_SCAN_STARTING: - ath10k_warn("received scan bss chan event in an invalid scan state: %s (%d)\n", + ath10k_warn(ar, "received scan bss chan event in an invalid scan state: %s (%d)\n", ath10k_scan_state_str(ar->scan.state), ar->scan.state); break; @@ -885,7 +885,7 @@ static void ath10k_wmi_event_scan_foreign_chan(struct ath10k *ar, u32 freq) switch (ar->scan.state) { case ATH10K_SCAN_IDLE: case ATH10K_SCAN_STARTING: - ath10k_warn("received scan foreign chan event in an invalid scan state: %s (%d)\n", + ath10k_warn(ar, "received scan foreign chan event in an invalid scan state: %s (%d)\n", ath10k_scan_state_str(ar->scan.state), ar->scan.state); break; @@ -954,7 +954,7 @@ static int ath10k_wmi_event_scan(struct ath10k *ar, struct sk_buff *skb) spin_lock_bh(&ar->data_lock); - ath10k_dbg(ATH10K_DBG_WMI, + ath10k_dbg(ar, ATH10K_DBG_WMI, "scan event %s type %d reason %d freq %d req_id %d scan_id %d vdev_id %d state %s (%d)\n", ath10k_wmi_event_scan_type_str(event_type, reason), event_type, reason, freq, req_id, scan_id, vdev_id, @@ -974,7 +974,7 @@ static int ath10k_wmi_event_scan(struct ath10k *ar, struct sk_buff *skb) ath10k_wmi_event_scan_foreign_chan(ar, freq); break; case WMI_SCAN_EVENT_START_FAILED: - ath10k_warn("received scan start failure event\n"); + ath10k_warn(ar, "received scan start failure event\n"); break; case WMI_SCAN_EVENT_DEQUEUED: case WMI_SCAN_EVENT_PREEMPTED: @@ -1107,7 +1107,7 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb) memset(status, 0, sizeof(*status)); - ath10k_dbg(ATH10K_DBG_MGMT, + ath10k_dbg(ar, ATH10K_DBG_MGMT, "event mgmt rx status %08x\n", rx_status); if (test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags)) { @@ -1143,9 +1143,9 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb) if (phy_mode == MODE_11B && status->band == IEEE80211_BAND_5GHZ) - ath10k_dbg(ATH10K_DBG_MGMT, "wmi mgmt rx 11b (CCK) on 5GHz\n"); + ath10k_dbg(ar, ATH10K_DBG_MGMT, "wmi mgmt rx 11b (CCK) on 5GHz\n"); } else { - ath10k_warn("using (unreliable) phy_mode to extract band for mgmt rx\n"); + ath10k_warn(ar, "using (unreliable) phy_mode to extract band for mgmt rx\n"); status->band = phy_mode_to_band(phy_mode); } @@ -1175,12 +1175,12 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb) } } - ath10k_dbg(ATH10K_DBG_MGMT, + ath10k_dbg(ar, ATH10K_DBG_MGMT, "event mgmt rx skb %p len %d ftype %02x stype %02x\n", skb, skb->len, fc & IEEE80211_FCTL_FTYPE, fc & IEEE80211_FCTL_STYPE); - ath10k_dbg(ATH10K_DBG_MGMT, + ath10k_dbg(ar, ATH10K_DBG_MGMT, "event mgmt rx freq %d band %d snr %d, rate_idx %d\n", status->freq, status->band, status->signal, status->rate_idx); @@ -1230,7 +1230,7 @@ static void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb) rx_clear_count = __le32_to_cpu(ev->rx_clear_count); cycle_count = __le32_to_cpu(ev->cycle_count); - ath10k_dbg(ATH10K_DBG_WMI, + ath10k_dbg(ar, ATH10K_DBG_WMI, "chan info err_code %d freq %d cmd_flags %d noise_floor %d rx_clear_count %d cycle_count %d\n", err_code, freq, cmd_flags, noise_floor, rx_clear_count, cycle_count); @@ -1240,7 +1240,7 @@ static void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb) switch (ar->scan.state) { case ATH10K_SCAN_IDLE: case ATH10K_SCAN_STARTING: - ath10k_warn("received chan info event without a scan request, ignoring\n"); + ath10k_warn(ar, "received chan info event without a scan request, ignoring\n"); goto exit; case ATH10K_SCAN_RUNNING: case ATH10K_SCAN_ABORTING: @@ -1249,7 +1249,7 @@ static void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb) idx = freq_to_idx(ar, freq); if (idx >= ARRAY_SIZE(ar->survey)) { - ath10k_warn("chan info: invalid frequency %d (idx %d out of bounds)\n", + ath10k_warn(ar, "chan info: invalid frequency %d (idx %d out of bounds)\n", freq, idx); goto exit; } @@ -1280,12 +1280,12 @@ exit: static void ath10k_wmi_event_echo(struct ath10k *ar, struct sk_buff *skb) { - ath10k_dbg(ATH10K_DBG_WMI, "WMI_ECHO_EVENTID\n"); + ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_ECHO_EVENTID\n"); } static int ath10k_wmi_event_debug_mesg(struct ath10k *ar, struct sk_buff *skb) { - ath10k_dbg(ATH10K_DBG_WMI, "wmi event debug mesg len %d\n", + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi event debug mesg len %d\n", skb->len); trace_ath10k_wmi_dbglog(skb->data, skb->len); @@ -1298,7 +1298,7 @@ static void ath10k_wmi_event_update_stats(struct ath10k *ar, { struct wmi_stats_event *ev = (struct wmi_stats_event *)skb->data; - ath10k_dbg(ATH10K_DBG_WMI, "WMI_UPDATE_STATS_EVENTID\n"); + ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_UPDATE_STATS_EVENTID\n"); ath10k_debug_read_target_stats(ar, ev); } @@ -1308,7 +1308,7 @@ static void ath10k_wmi_event_vdev_start_resp(struct ath10k *ar, { struct wmi_vdev_start_response_event *ev; - ath10k_dbg(ATH10K_DBG_WMI, "WMI_VDEV_START_RESP_EVENTID\n"); + ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_START_RESP_EVENTID\n"); ev = (struct wmi_vdev_start_response_event *)skb->data; @@ -1321,7 +1321,7 @@ static void ath10k_wmi_event_vdev_start_resp(struct ath10k *ar, static void ath10k_wmi_event_vdev_stopped(struct ath10k *ar, struct sk_buff *skb) { - ath10k_dbg(ATH10K_DBG_WMI, "WMI_VDEV_STOPPED_EVENTID\n"); + ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_STOPPED_EVENTID\n"); complete(&ar->vdev_setup_done); } @@ -1333,14 +1333,14 @@ static void ath10k_wmi_event_peer_sta_kickout(struct ath10k *ar, ev = (struct wmi_peer_sta_kickout_event *)skb->data; - ath10k_dbg(ATH10K_DBG_WMI, "wmi event peer sta kickout %pM\n", + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi event peer sta kickout %pM\n", ev->peer_macaddr.addr); rcu_read_lock(); sta = ieee80211_find_sta_by_ifaddr(ar->hw, ev->peer_macaddr.addr, NULL); if (!sta) { - ath10k_warn("Spurious quick kickout for STA %pM\n", + ath10k_warn(ar, "Spurious quick kickout for STA %pM\n", ev->peer_macaddr.addr); goto exit; } @@ -1417,7 +1417,7 @@ static void ath10k_wmi_update_tim(struct ath10k *ar, (u8 *)skb_tail_pointer(bcn) - ies); if (!ie) { if (arvif->vdev_type != WMI_VDEV_TYPE_IBSS) - ath10k_warn("no tim ie found;\n"); + ath10k_warn(ar, "no tim ie found;\n"); return; } @@ -1437,12 +1437,12 @@ static void ath10k_wmi_update_tim(struct ath10k *ar, ie_len += expand_size; pvm_len += expand_size; } else { - ath10k_warn("tim expansion failed\n"); + ath10k_warn(ar, "tim expansion failed\n"); } } if (pvm_len > sizeof(arvif->u.ap.tim_bitmap)) { - ath10k_warn("tim pvm length is too great (%d)\n", pvm_len); + ath10k_warn(ar, "tim pvm length is too great (%d)\n", pvm_len); return; } @@ -1456,7 +1456,7 @@ static void ath10k_wmi_update_tim(struct ath10k *ar, ATH10K_SKB_CB(bcn)->bcn.deliver_cab = true; } - ath10k_dbg(ATH10K_DBG_MGMT, "dtim %d/%d mcast %d pvmlen %d\n", + ath10k_dbg(ar, ATH10K_DBG_MGMT, "dtim %d/%d mcast %d pvmlen %d\n", tim->dtim_count, tim->dtim_period, tim->bitmap_ctrl, pvm_len); } @@ -1534,7 +1534,7 @@ static void ath10k_wmi_update_noa(struct ath10k *ar, struct ath10k_vif *arvif, if (arvif->vdev_subtype != WMI_VDEV_SUBTYPE_P2P_GO) return; - ath10k_dbg(ATH10K_DBG_MGMT, "noa changed: %d\n", noa->changed); + ath10k_dbg(ar, ATH10K_DBG_MGMT, "noa changed: %d\n", noa->changed); if (noa->changed & WMI_P2P_NOA_CHANGED_BIT) { new_len = ath10k_p2p_calc_noa_ie_len(noa); if (!new_len) @@ -1582,7 +1582,7 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) ev = (struct wmi_host_swba_event *)skb->data; map = __le32_to_cpu(ev->vdev_map); - ath10k_dbg(ATH10K_DBG_MGMT, "mgmt swba vdev_map 0x%x\n", + ath10k_dbg(ar, ATH10K_DBG_MGMT, "mgmt swba vdev_map 0x%x\n", ev->vdev_map); for (; map; map >>= 1, vdev_id++) { @@ -1592,13 +1592,13 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) i++; if (i >= WMI_MAX_AP_VDEV) { - ath10k_warn("swba has corrupted vdev map\n"); + ath10k_warn(ar, "swba has corrupted vdev map\n"); break; } bcn_info = &ev->bcn_info[i]; - ath10k_dbg(ATH10K_DBG_MGMT, + ath10k_dbg(ar, ATH10K_DBG_MGMT, "mgmt event bcn_info %d tim_len %d mcast %d changed %d num_ps_pending %d bitmap 0x%08x%08x%08x%08x\n", i, __le32_to_cpu(bcn_info->tim_info.tim_len), @@ -1612,7 +1612,8 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) arvif = ath10k_get_arvif(ar, vdev_id); if (arvif == NULL) { - ath10k_warn("no vif for vdev_id %d found\n", vdev_id); + ath10k_warn(ar, "no vif for vdev_id %d found\n", + vdev_id); continue; } @@ -1629,7 +1630,7 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) bcn = ieee80211_beacon_get(ar->hw, arvif->vif); if (!bcn) { - ath10k_warn("could not get mac80211 beacon\n"); + ath10k_warn(ar, "could not get mac80211 beacon\n"); continue; } @@ -1641,7 +1642,7 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) if (arvif->beacon) { if (!arvif->beacon_sent) - ath10k_warn("SWBA overrun on vdev %d\n", + ath10k_warn(ar, "SWBA overrun on vdev %d\n", arvif->vdev_id); dma_unmap_single(arvif->ar->dev, @@ -1657,7 +1658,7 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) ret = dma_mapping_error(arvif->ar->dev, ATH10K_SKB_CB(bcn)->paddr); if (ret) { - ath10k_warn("failed to map beacon: %d\n", ret); + ath10k_warn(ar, "failed to map beacon: %d\n", ret); dev_kfree_skb_any(bcn); goto skip; } @@ -1674,7 +1675,7 @@ skip: static void ath10k_wmi_event_tbttoffset_update(struct ath10k *ar, struct sk_buff *skb) { - ath10k_dbg(ATH10K_DBG_WMI, "WMI_TBTTOFFSET_UPDATE_EVENTID\n"); + ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_TBTTOFFSET_UPDATE_EVENTID\n"); } static void ath10k_dfs_radar_report(struct ath10k *ar, @@ -1690,20 +1691,20 @@ static void ath10k_dfs_radar_report(struct ath10k *ar, reg0 = __le32_to_cpu(rr->reg0); reg1 = __le32_to_cpu(rr->reg1); - ath10k_dbg(ATH10K_DBG_REGULATORY, + ath10k_dbg(ar, ATH10K_DBG_REGULATORY, "wmi phyerr radar report chirp %d max_width %d agc_total_gain %d pulse_delta_diff %d\n", MS(reg0, RADAR_REPORT_REG0_PULSE_IS_CHIRP), MS(reg0, RADAR_REPORT_REG0_PULSE_IS_MAX_WIDTH), MS(reg0, RADAR_REPORT_REG0_AGC_TOTAL_GAIN), MS(reg0, RADAR_REPORT_REG0_PULSE_DELTA_DIFF)); - ath10k_dbg(ATH10K_DBG_REGULATORY, + ath10k_dbg(ar, ATH10K_DBG_REGULATORY, "wmi phyerr radar report pulse_delta_pean %d pulse_sidx %d fft_valid %d agc_mb_gain %d subchan_mask %d\n", MS(reg0, RADAR_REPORT_REG0_PULSE_DELTA_PEAK), MS(reg0, RADAR_REPORT_REG0_PULSE_SIDX), MS(reg1, RADAR_REPORT_REG1_PULSE_SRCH_FFT_VALID), MS(reg1, RADAR_REPORT_REG1_PULSE_AGC_MB_GAIN), MS(reg1, RADAR_REPORT_REG1_PULSE_SUBCHAN_MASK)); - ath10k_dbg(ATH10K_DBG_REGULATORY, + ath10k_dbg(ar, ATH10K_DBG_REGULATORY, "wmi phyerr radar report pulse_tsf_offset 0x%X pulse_dur: %d\n", MS(reg1, RADAR_REPORT_REG1_PULSE_TSF_OFFSET), MS(reg1, RADAR_REPORT_REG1_PULSE_DUR)); @@ -1730,25 +1731,25 @@ static void ath10k_dfs_radar_report(struct ath10k *ar, pe.width = width; pe.rssi = rssi; - ath10k_dbg(ATH10K_DBG_REGULATORY, + ath10k_dbg(ar, ATH10K_DBG_REGULATORY, "dfs add pulse freq: %d, width: %d, rssi %d, tsf: %llX\n", pe.freq, pe.width, pe.rssi, pe.ts); ATH10K_DFS_STAT_INC(ar, pulses_detected); if (!ar->dfs_detector->add_pulse(ar->dfs_detector, &pe)) { - ath10k_dbg(ATH10K_DBG_REGULATORY, + ath10k_dbg(ar, ATH10K_DBG_REGULATORY, "dfs no pulse pattern detected, yet\n"); return; } - ath10k_dbg(ATH10K_DBG_REGULATORY, "dfs radar detected\n"); + ath10k_dbg(ar, ATH10K_DBG_REGULATORY, "dfs radar detected\n"); ATH10K_DFS_STAT_INC(ar, radar_detected); /* Control radar events reporting in debugfs file dfs_block_radar_events */ if (ar->dfs_block_radar_events) { - ath10k_info("DFS Radar detected, but ignored as requested\n"); + ath10k_info(ar, "DFS Radar detected, but ignored as requested\n"); return; } @@ -1767,13 +1768,13 @@ static int ath10k_dfs_fft_report(struct ath10k *ar, reg1 = __le32_to_cpu(fftr->reg1); rssi = event->hdr.rssi_combined; - ath10k_dbg(ATH10K_DBG_REGULATORY, + ath10k_dbg(ar, ATH10K_DBG_REGULATORY, "wmi phyerr fft report total_gain_db %d base_pwr_db %d fft_chn_idx %d peak_sidx %d\n", MS(reg0, SEARCH_FFT_REPORT_REG0_TOTAL_GAIN_DB), MS(reg0, SEARCH_FFT_REPORT_REG0_BASE_PWR_DB), MS(reg0, SEARCH_FFT_REPORT_REG0_FFT_CHN_IDX), MS(reg0, SEARCH_FFT_REPORT_REG0_PEAK_SIDX)); - ath10k_dbg(ATH10K_DBG_REGULATORY, + ath10k_dbg(ar, ATH10K_DBG_REGULATORY, "wmi phyerr fft report rel_pwr_db %d avgpwr_db %d peak_mag %d num_store_bin %d\n", MS(reg1, SEARCH_FFT_REPORT_REG1_RELPWR_DB), MS(reg1, SEARCH_FFT_REPORT_REG1_AVGPWR_DB), @@ -1785,7 +1786,7 @@ static int ath10k_dfs_fft_report(struct ath10k *ar, /* false event detection */ if (rssi == DFS_RSSI_POSSIBLY_FALSE && peak_mag < 2 * DFS_PEAK_MAG_THOLD_POSSIBLY_FALSE) { - ath10k_dbg(ATH10K_DBG_REGULATORY, "dfs false pulse detected\n"); + ath10k_dbg(ar, ATH10K_DBG_REGULATORY, "dfs false pulse detected\n"); ATH10K_DFS_STAT_INC(ar, pulses_discarded); return -EINVAL; } @@ -1804,7 +1805,7 @@ static void ath10k_wmi_event_dfs(struct ath10k *ar, u8 *tlv_buf; buf_len = __le32_to_cpu(event->hdr.buf_len); - ath10k_dbg(ATH10K_DBG_REGULATORY, + ath10k_dbg(ar, ATH10K_DBG_REGULATORY, "wmi event dfs err_code %d rssi %d tsfl 0x%X tsf64 0x%llX len %d\n", event->hdr.phy_err_code, event->hdr.rssi_combined, __le32_to_cpu(event->hdr.tsf_timestamp), tsf, buf_len); @@ -1817,21 +1818,22 @@ static void ath10k_wmi_event_dfs(struct ath10k *ar, while (i < buf_len) { if (i + sizeof(*tlv) > buf_len) { - ath10k_warn("too short buf for tlv header (%d)\n", i); + ath10k_warn(ar, "too short buf for tlv header (%d)\n", + i); return; } tlv = (struct phyerr_tlv *)&event->bufp[i]; tlv_len = __le16_to_cpu(tlv->len); tlv_buf = &event->bufp[i + sizeof(*tlv)]; - ath10k_dbg(ATH10K_DBG_REGULATORY, + ath10k_dbg(ar, ATH10K_DBG_REGULATORY, "wmi event dfs tlv_len %d tlv_tag 0x%02X tlv_sig 0x%02X\n", tlv_len, tlv->tag, tlv->sig); switch (tlv->tag) { case PHYERR_TLV_TAG_RADAR_PULSE_SUMMARY: if (i + sizeof(*tlv) + sizeof(*rr) > buf_len) { - ath10k_warn("too short radar pulse summary (%d)\n", + ath10k_warn(ar, "too short radar pulse summary (%d)\n", i); return; } @@ -1841,7 +1843,8 @@ static void ath10k_wmi_event_dfs(struct ath10k *ar, break; case PHYERR_TLV_TAG_SEARCH_FFT_REPORT: if (i + sizeof(*tlv) + sizeof(*fftr) > buf_len) { - ath10k_warn("too short fft report (%d)\n", i); + ath10k_warn(ar, "too short fft report (%d)\n", + i); return; } @@ -1870,7 +1873,7 @@ static void ath10k_wmi_event_spectral_scan(struct ath10k *ar, while (i < buf_len) { if (i + sizeof(*tlv) > buf_len) { - ath10k_warn("failed to parse phyerr tlv header at byte %d\n", + ath10k_warn(ar, "failed to parse phyerr tlv header at byte %d\n", i); return; } @@ -1880,7 +1883,7 @@ static void ath10k_wmi_event_spectral_scan(struct ath10k *ar, tlv_buf = &event->bufp[i + sizeof(*tlv)]; if (i + sizeof(*tlv) + tlv_len > buf_len) { - ath10k_warn("failed to parse phyerr tlv payload at byte %d\n", + ath10k_warn(ar, "failed to parse phyerr tlv payload at byte %d\n", i); return; } @@ -1888,7 +1891,7 @@ static void ath10k_wmi_event_spectral_scan(struct ath10k *ar, switch (tlv->tag) { case PHYERR_TLV_TAG_SEARCH_FFT_REPORT: if (sizeof(*fftr) > tlv_len) { - ath10k_warn("failed to parse fft report at byte %d\n", + ath10k_warn(ar, "failed to parse fft report at byte %d\n", i); return; } @@ -1899,7 +1902,7 @@ static void ath10k_wmi_event_spectral_scan(struct ath10k *ar, fftr, fftr_len, tsf); if (res < 0) { - ath10k_warn("failed to process fft report: %d\n", + ath10k_warn(ar, "failed to process fft report: %d\n", res); return; } @@ -1922,7 +1925,7 @@ static void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb) /* Check if combined event available */ if (left_len < sizeof(*comb_event)) { - ath10k_warn("wmi phyerr combined event wrong len\n"); + ath10k_warn(ar, "wmi phyerr combined event wrong len\n"); return; } @@ -1936,7 +1939,7 @@ static void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb) tsf <<= 32; tsf |= __le32_to_cpu(comb_event->hdr.tsf_l32); - ath10k_dbg(ATH10K_DBG_WMI, + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi event phyerr count %d tsf64 0x%llX\n", count, tsf); @@ -1944,7 +1947,8 @@ static void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb) for (i = 0; i < count; i++) { /* Check if we can read event header */ if (left_len < sizeof(*event)) { - ath10k_warn("single event (%d) wrong head len\n", i); + ath10k_warn(ar, "single event (%d) wrong head len\n", + i); return; } @@ -1954,7 +1958,7 @@ static void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb) phy_err_code = event->hdr.phy_err_code; if (left_len < buf_len) { - ath10k_warn("single event (%d) wrong buf len\n", i); + ath10k_warn(ar, "single event (%d) wrong buf len\n", i); return; } @@ -1981,13 +1985,13 @@ static void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb) static void ath10k_wmi_event_roam(struct ath10k *ar, struct sk_buff *skb) { - ath10k_dbg(ATH10K_DBG_WMI, "WMI_ROAM_EVENTID\n"); + ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_ROAM_EVENTID\n"); } static void ath10k_wmi_event_profile_match(struct ath10k *ar, struct sk_buff *skb) { - ath10k_dbg(ATH10K_DBG_WMI, "WMI_PROFILE_MATCH\n"); + ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_PROFILE_MATCH\n"); } static void ath10k_wmi_event_debug_print(struct ath10k *ar, @@ -2012,7 +2016,7 @@ static void ath10k_wmi_event_debug_print(struct ath10k *ar, } if (i == sizeof(buf) - 1) - ath10k_warn("wmi debug print truncated: %d\n", skb->len); + ath10k_warn(ar, "wmi debug print truncated: %d\n", skb->len); /* for some reason the debug prints end with \n, remove that */ if (skb->data[i - 1] == '\n') @@ -2021,108 +2025,108 @@ static void ath10k_wmi_event_debug_print(struct ath10k *ar, /* the last byte is always reserved for the null character */ buf[i] = '\0'; - ath10k_dbg(ATH10K_DBG_WMI, "wmi event debug print '%s'\n", buf); + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi event debug print '%s'\n", buf); } static void ath10k_wmi_event_pdev_qvit(struct ath10k *ar, struct sk_buff *skb) { - ath10k_dbg(ATH10K_DBG_WMI, "WMI_PDEV_QVIT_EVENTID\n"); + ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_PDEV_QVIT_EVENTID\n"); } static void ath10k_wmi_event_wlan_profile_data(struct ath10k *ar, struct sk_buff *skb) { - ath10k_dbg(ATH10K_DBG_WMI, "WMI_WLAN_PROFILE_DATA_EVENTID\n"); + ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_WLAN_PROFILE_DATA_EVENTID\n"); } static void ath10k_wmi_event_rtt_measurement_report(struct ath10k *ar, struct sk_buff *skb) { - ath10k_dbg(ATH10K_DBG_WMI, "WMI_RTT_MEASUREMENT_REPORT_EVENTID\n"); + ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_RTT_MEASUREMENT_REPORT_EVENTID\n"); } static void ath10k_wmi_event_tsf_measurement_report(struct ath10k *ar, struct sk_buff *skb) { - ath10k_dbg(ATH10K_DBG_WMI, "WMI_TSF_MEASUREMENT_REPORT_EVENTID\n"); + ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_TSF_MEASUREMENT_REPORT_EVENTID\n"); } static void ath10k_wmi_event_rtt_error_report(struct ath10k *ar, struct sk_buff *skb) { - ath10k_dbg(ATH10K_DBG_WMI, "WMI_RTT_ERROR_REPORT_EVENTID\n"); + ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_RTT_ERROR_REPORT_EVENTID\n"); } static void ath10k_wmi_event_wow_wakeup_host(struct ath10k *ar, struct sk_buff *skb) { - ath10k_dbg(ATH10K_DBG_WMI, "WMI_WOW_WAKEUP_HOST_EVENTID\n"); + ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_WOW_WAKEUP_HOST_EVENTID\n"); } static void ath10k_wmi_event_dcs_interference(struct ath10k *ar, struct sk_buff *skb) { - ath10k_dbg(ATH10K_DBG_WMI, "WMI_DCS_INTERFERENCE_EVENTID\n"); + ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_DCS_INTERFERENCE_EVENTID\n"); } static void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, struct sk_buff *skb) { - ath10k_dbg(ATH10K_DBG_WMI, "WMI_PDEV_TPC_CONFIG_EVENTID\n"); + ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_PDEV_TPC_CONFIG_EVENTID\n"); } static void ath10k_wmi_event_pdev_ftm_intg(struct ath10k *ar, struct sk_buff *skb) { - ath10k_dbg(ATH10K_DBG_WMI, "WMI_PDEV_FTM_INTG_EVENTID\n"); + ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_PDEV_FTM_INTG_EVENTID\n"); } static void ath10k_wmi_event_gtk_offload_status(struct ath10k *ar, struct sk_buff *skb) { - ath10k_dbg(ATH10K_DBG_WMI, "WMI_GTK_OFFLOAD_STATUS_EVENTID\n"); + ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_GTK_OFFLOAD_STATUS_EVENTID\n"); } static void ath10k_wmi_event_gtk_rekey_fail(struct ath10k *ar, struct sk_buff *skb) { - ath10k_dbg(ATH10K_DBG_WMI, "WMI_GTK_REKEY_FAIL_EVENTID\n"); + ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_GTK_REKEY_FAIL_EVENTID\n"); } static void ath10k_wmi_event_delba_complete(struct ath10k *ar, struct sk_buff *skb) { - ath10k_dbg(ATH10K_DBG_WMI, "WMI_TX_DELBA_COMPLETE_EVENTID\n"); + ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_TX_DELBA_COMPLETE_EVENTID\n"); } static void ath10k_wmi_event_addba_complete(struct ath10k *ar, struct sk_buff *skb) { - ath10k_dbg(ATH10K_DBG_WMI, "WMI_TX_ADDBA_COMPLETE_EVENTID\n"); + ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_TX_ADDBA_COMPLETE_EVENTID\n"); } static void ath10k_wmi_event_vdev_install_key_complete(struct ath10k *ar, struct sk_buff *skb) { - ath10k_dbg(ATH10K_DBG_WMI, "WMI_VDEV_INSTALL_KEY_COMPLETE_EVENTID\n"); + ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_INSTALL_KEY_COMPLETE_EVENTID\n"); } static void ath10k_wmi_event_inst_rssi_stats(struct ath10k *ar, struct sk_buff *skb) { - ath10k_dbg(ATH10K_DBG_WMI, "WMI_INST_RSSI_STATS_EVENTID\n"); + ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_INST_RSSI_STATS_EVENTID\n"); } static void ath10k_wmi_event_vdev_standby_req(struct ath10k *ar, struct sk_buff *skb) { - ath10k_dbg(ATH10K_DBG_WMI, "WMI_VDEV_STANDBY_REQ_EVENTID\n"); + ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_STANDBY_REQ_EVENTID\n"); } static void ath10k_wmi_event_vdev_resume_req(struct ath10k *ar, struct sk_buff *skb) { - ath10k_dbg(ATH10K_DBG_WMI, "WMI_VDEV_RESUME_REQ_EVENTID\n"); + ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_RESUME_REQ_EVENTID\n"); } static int ath10k_wmi_alloc_host_mem(struct ath10k *ar, u32 req_id, @@ -2142,7 +2146,7 @@ static int ath10k_wmi_alloc_host_mem(struct ath10k *ar, u32 req_id, &paddr, GFP_ATOMIC); if (!ar->wmi.mem_chunks[idx].vaddr) { - ath10k_warn("failed to allocate memory chunk\n"); + ath10k_warn(ar, "failed to allocate memory chunk\n"); return -ENOMEM; } @@ -2163,7 +2167,7 @@ static void ath10k_wmi_service_ready_event_rx(struct ath10k *ar, DECLARE_BITMAP(svc_bmap, WMI_SERVICE_BM_SIZE) = {}; if (skb->len < sizeof(*ev)) { - ath10k_warn("Service ready event was %d B but expected %zu B. Wrong firmware version?\n", + ath10k_warn(ar, "Service ready event was %d B but expected %zu B. Wrong firmware version?\n", skb->len, sizeof(*ev)); return; } @@ -2186,7 +2190,7 @@ static void ath10k_wmi_service_ready_event_rx(struct ath10k *ar, set_bit(ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX, ar->fw_features); if (ar->num_rf_chains > WMI_MAX_SPATIAL_STREAM) { - ath10k_warn("hardware advertises support for more spatial streams than it should (%d > %d)\n", + ath10k_warn(ar, "hardware advertises support for more spatial streams than it should (%d > %d)\n", ar->num_rf_chains, WMI_MAX_SPATIAL_STREAM); ar->num_rf_chains = WMI_MAX_SPATIAL_STREAM; } @@ -2196,7 +2200,7 @@ static void ath10k_wmi_service_ready_event_rx(struct ath10k *ar, wmi_main_svc_map(ev->wmi_service_bitmap, svc_bmap); ath10k_debug_read_service_map(ar, svc_bmap, sizeof(svc_bmap)); - ath10k_dbg_dump(ATH10K_DBG_WMI, NULL, "ath10k: wmi svc: ", + ath10k_dbg_dump(ar, ATH10K_DBG_WMI, NULL, "wmi svc: ", ev->wmi_service_bitmap, sizeof(ev->wmi_service_bitmap)); if (strlen(ar->hw->wiphy->fw_version) == 0) { @@ -2211,11 +2215,11 @@ static void ath10k_wmi_service_ready_event_rx(struct ath10k *ar, /* FIXME: it probably should be better to support this */ if (__le32_to_cpu(ev->num_mem_reqs) > 0) { - ath10k_warn("target requested %d memory chunks; ignoring\n", + ath10k_warn(ar, "target requested %d memory chunks; ignoring\n", __le32_to_cpu(ev->num_mem_reqs)); } - ath10k_dbg(ATH10K_DBG_WMI, + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi event service ready sw_ver 0x%08x sw_ver1 0x%08x abi_ver %u phy_cap 0x%08x ht_cap 0x%08x vht_cap 0x%08x vht_supp_msc 0x%08x sys_cap_info 0x%08x mem_reqs %u num_rf_chains %u\n", __le32_to_cpu(ev->sw_version), __le32_to_cpu(ev->sw_version_1), @@ -2240,7 +2244,7 @@ static void ath10k_wmi_10x_service_ready_event_rx(struct ath10k *ar, DECLARE_BITMAP(svc_bmap, WMI_SERVICE_BM_SIZE) = {}; if (skb->len < sizeof(*ev)) { - ath10k_warn("Service ready event was %d B but expected %zu B. Wrong firmware version?\n", + ath10k_warn(ar, "Service ready event was %d B but expected %zu B. Wrong firmware version?\n", skb->len, sizeof(*ev)); return; } @@ -2256,7 +2260,7 @@ static void ath10k_wmi_10x_service_ready_event_rx(struct ath10k *ar, ar->num_rf_chains = __le32_to_cpu(ev->num_rf_chains); if (ar->num_rf_chains > WMI_MAX_SPATIAL_STREAM) { - ath10k_warn("hardware advertises support for more spatial streams than it should (%d > %d)\n", + ath10k_warn(ar, "hardware advertises support for more spatial streams than it should (%d > %d)\n", ar->num_rf_chains, WMI_MAX_SPATIAL_STREAM); ar->num_rf_chains = WMI_MAX_SPATIAL_STREAM; } @@ -2266,7 +2270,7 @@ static void ath10k_wmi_10x_service_ready_event_rx(struct ath10k *ar, wmi_10x_svc_map(ev->wmi_service_bitmap, svc_bmap); ath10k_debug_read_service_map(ar, svc_bmap, sizeof(svc_bmap)); - ath10k_dbg_dump(ATH10K_DBG_WMI, NULL, "ath10k: wmi svc: ", + ath10k_dbg_dump(ar, ATH10K_DBG_WMI, NULL, "wmi svc: ", ev->wmi_service_bitmap, sizeof(ev->wmi_service_bitmap)); if (strlen(ar->hw->wiphy->fw_version) == 0) { @@ -2280,7 +2284,7 @@ static void ath10k_wmi_10x_service_ready_event_rx(struct ath10k *ar, num_mem_reqs = __le32_to_cpu(ev->num_mem_reqs); if (num_mem_reqs > ATH10K_MAX_MEM_REQS) { - ath10k_warn("requested memory chunks number (%d) exceeds the limit\n", + ath10k_warn(ar, "requested memory chunks number (%d) exceeds the limit\n", num_mem_reqs); return; } @@ -2288,7 +2292,7 @@ static void ath10k_wmi_10x_service_ready_event_rx(struct ath10k *ar, if (!num_mem_reqs) goto exit; - ath10k_dbg(ATH10K_DBG_WMI, "firmware has requested %d memory chunks\n", + ath10k_dbg(ar, ATH10K_DBG_WMI, "firmware has requested %d memory chunks\n", num_mem_reqs); for (i = 0; i < num_mem_reqs; ++i) { @@ -2306,7 +2310,7 @@ static void ath10k_wmi_10x_service_ready_event_rx(struct ath10k *ar, else if (num_unit_info & NUM_UNITS_IS_NUM_VDEVS) num_units = TARGET_10X_NUM_VDEVS + 1; - ath10k_dbg(ATH10K_DBG_WMI, + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi mem_req_id %d num_units %d num_unit_info %d unit size %d actual units %d\n", req_id, __le32_to_cpu(ev->mem_reqs[i].num_units), @@ -2321,7 +2325,7 @@ static void ath10k_wmi_10x_service_ready_event_rx(struct ath10k *ar, } exit: - ath10k_dbg(ATH10K_DBG_WMI, + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi event service ready sw_ver 0x%08x abi_ver %u phy_cap 0x%08x ht_cap 0x%08x vht_cap 0x%08x vht_supp_msc 0x%08x sys_cap_info 0x%08x mem_reqs %u num_rf_chains %u\n", __le32_to_cpu(ev->sw_version), __le32_to_cpu(ev->abi_version), @@ -2345,7 +2349,7 @@ static int ath10k_wmi_ready_event_rx(struct ath10k *ar, struct sk_buff *skb) memcpy(ar->mac_addr, ev->mac_addr.addr, ETH_ALEN); - ath10k_dbg(ATH10K_DBG_WMI, + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi event ready sw_version %u abi_version %u mac_addr %pM status %d skb->len %i ev-sz %zu\n", __le32_to_cpu(ev->sw_version), __le32_to_cpu(ev->abi_version), @@ -2465,7 +2469,7 @@ static void ath10k_wmi_main_process_rx(struct ath10k *ar, struct sk_buff *skb) ath10k_wmi_ready_event_rx(ar, skb); break; default: - ath10k_warn("Unknown eventid: %d\n", id); + ath10k_warn(ar, "Unknown eventid: %d\n", id); break; } @@ -2572,7 +2576,7 @@ static void ath10k_wmi_10x_process_rx(struct ath10k *ar, struct sk_buff *skb) ath10k_wmi_ready_event_rx(ar, skb); break; default: - ath10k_warn("Unknown eventid: %d\n", id); + ath10k_warn(ar, "Unknown eventid: %d\n", id); break; } @@ -2685,11 +2689,11 @@ static void ath10k_wmi_10_2_process_rx(struct ath10k *ar, struct sk_buff *skb) case WMI_10_2_MCAST_BUF_RELEASE_EVENTID: case WMI_10_2_MCAST_LIST_AGEOUT_EVENTID: case WMI_10_2_WDS_PEER_EVENTID: - ath10k_dbg(ATH10K_DBG_WMI, + ath10k_dbg(ar, ATH10K_DBG_WMI, "received event id %d not implemented\n", id); break; default: - ath10k_warn("Unknown eventid: %d\n", id); + ath10k_warn(ar, "Unknown eventid: %d\n", id); break; } @@ -2766,7 +2770,7 @@ int ath10k_wmi_connect(struct ath10k *ar) status = ath10k_htc_connect_service(&ar->htc, &conn_req, &conn_resp); if (status) { - ath10k_warn("failed to connect to WMI CONTROL service status: %d\n", + ath10k_warn(ar, "failed to connect to WMI CONTROL service status: %d\n", status); return status; } @@ -2782,7 +2786,7 @@ static int ath10k_wmi_main_pdev_set_regdomain(struct ath10k *ar, u16 rd, struct wmi_pdev_set_regdomain_cmd *cmd; struct sk_buff *skb; - skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); + skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) return -ENOMEM; @@ -2793,7 +2797,7 @@ static int ath10k_wmi_main_pdev_set_regdomain(struct ath10k *ar, u16 rd, cmd->conformance_test_limit_2G = __cpu_to_le32(ctl2g); cmd->conformance_test_limit_5G = __cpu_to_le32(ctl5g); - ath10k_dbg(ATH10K_DBG_WMI, + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi pdev regdomain rd %x rd2g %x rd5g %x ctl2g %x ctl5g %x\n", rd, rd2g, rd5g, ctl2g, ctl5g); @@ -2809,7 +2813,7 @@ static int ath10k_wmi_10x_pdev_set_regdomain(struct ath10k *ar, u16 rd, struct wmi_pdev_set_regdomain_cmd_10x *cmd; struct sk_buff *skb; - skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); + skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) return -ENOMEM; @@ -2821,7 +2825,7 @@ static int ath10k_wmi_10x_pdev_set_regdomain(struct ath10k *ar, u16 rd, cmd->conformance_test_limit_5G = __cpu_to_le32(ctl5g); cmd->dfs_domain = __cpu_to_le32(dfs_reg); - ath10k_dbg(ATH10K_DBG_WMI, + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi pdev regdomain rd %x rd2g %x rd5g %x ctl2g %x ctl5g %x dfs_region %x\n", rd, rd2g, rd5g, ctl2g, ctl5g, dfs_reg); @@ -2851,7 +2855,7 @@ int ath10k_wmi_pdev_set_channel(struct ath10k *ar, if (arg->passive) return -EINVAL; - skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); + skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) return -ENOMEM; @@ -2869,7 +2873,7 @@ int ath10k_wmi_pdev_set_channel(struct ath10k *ar, cmd->chan.reg_classid = arg->reg_class_id; cmd->chan.antenna_max = arg->max_antenna_gain; - ath10k_dbg(ATH10K_DBG_WMI, + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi set channel mode %d freq %d\n", arg->mode, arg->freq); @@ -2882,7 +2886,7 @@ int ath10k_wmi_pdev_suspend_target(struct ath10k *ar, u32 suspend_opt) struct wmi_pdev_suspend_cmd *cmd; struct sk_buff *skb; - skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); + skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) return -ENOMEM; @@ -2896,7 +2900,7 @@ int ath10k_wmi_pdev_resume_target(struct ath10k *ar) { struct sk_buff *skb; - skb = ath10k_wmi_alloc_skb(0); + skb = ath10k_wmi_alloc_skb(ar, 0); if (skb == NULL) return -ENOMEM; @@ -2909,11 +2913,12 @@ int ath10k_wmi_pdev_set_param(struct ath10k *ar, u32 id, u32 value) struct sk_buff *skb; if (id == WMI_PDEV_PARAM_UNSUPPORTED) { - ath10k_warn("pdev param %d not supported by firmware\n", id); + ath10k_warn(ar, "pdev param %d not supported by firmware\n", + id); return -EOPNOTSUPP; } - skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); + skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) return -ENOMEM; @@ -2921,7 +2926,7 @@ int ath10k_wmi_pdev_set_param(struct ath10k *ar, u32 id, u32 value) cmd->param_id = __cpu_to_le32(id); cmd->param_value = __cpu_to_le32(value); - ath10k_dbg(ATH10K_DBG_WMI, "wmi pdev set param %d value %d\n", + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi pdev set param %d value %d\n", id, value); return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->pdev_set_param_cmdid); } @@ -2988,7 +2993,7 @@ static int ath10k_wmi_main_cmd_init(struct ath10k *ar) len = sizeof(*cmd) + (sizeof(struct host_memory_chunk) * ar->wmi.num_mem_chunks); - buf = ath10k_wmi_alloc_skb(len); + buf = ath10k_wmi_alloc_skb(ar, len); if (!buf) return -ENOMEM; @@ -2999,7 +3004,7 @@ static int ath10k_wmi_main_cmd_init(struct ath10k *ar) goto out; } - ath10k_dbg(ATH10K_DBG_WMI, "wmi sending %d memory chunks info.\n", + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi sending %d memory chunks info.\n", ar->wmi.num_mem_chunks); cmd->num_host_mem_chunks = __cpu_to_le32(ar->wmi.num_mem_chunks); @@ -3012,7 +3017,7 @@ static int ath10k_wmi_main_cmd_init(struct ath10k *ar) cmd->host_mem_chunks[i].req_id = __cpu_to_le32(ar->wmi.mem_chunks[i].req_id); - ath10k_dbg(ATH10K_DBG_WMI, + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi chunk %d len %d requested, addr 0x%llx\n", i, ar->wmi.mem_chunks[i].len, @@ -3021,7 +3026,7 @@ static int ath10k_wmi_main_cmd_init(struct ath10k *ar) out: memcpy(&cmd->resource_config, &config, sizeof(config)); - ath10k_dbg(ATH10K_DBG_WMI, "wmi init\n"); + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi init\n"); return ath10k_wmi_cmd_send(ar, buf, ar->wmi.cmd->init_cmdid); } @@ -3079,7 +3084,7 @@ static int ath10k_wmi_10x_cmd_init(struct ath10k *ar) len = sizeof(*cmd) + (sizeof(struct host_memory_chunk) * ar->wmi.num_mem_chunks); - buf = ath10k_wmi_alloc_skb(len); + buf = ath10k_wmi_alloc_skb(ar, len); if (!buf) return -ENOMEM; @@ -3090,7 +3095,7 @@ static int ath10k_wmi_10x_cmd_init(struct ath10k *ar) goto out; } - ath10k_dbg(ATH10K_DBG_WMI, "wmi sending %d memory chunks info.\n", + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi sending %d memory chunks info.\n", ar->wmi.num_mem_chunks); cmd->num_host_mem_chunks = __cpu_to_le32(ar->wmi.num_mem_chunks); @@ -3103,7 +3108,7 @@ static int ath10k_wmi_10x_cmd_init(struct ath10k *ar) cmd->host_mem_chunks[i].req_id = __cpu_to_le32(ar->wmi.mem_chunks[i].req_id); - ath10k_dbg(ATH10K_DBG_WMI, + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi chunk %d len %d requested, addr 0x%llx\n", i, ar->wmi.mem_chunks[i].len, @@ -3112,7 +3117,7 @@ static int ath10k_wmi_10x_cmd_init(struct ath10k *ar) out: memcpy(&cmd->resource_config, &config, sizeof(config)); - ath10k_dbg(ATH10K_DBG_WMI, "wmi init 10x\n"); + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi init 10x\n"); return ath10k_wmi_cmd_send(ar, buf, ar->wmi.cmd->init_cmdid); } @@ -3170,7 +3175,7 @@ static int ath10k_wmi_10_2_cmd_init(struct ath10k *ar) len = sizeof(*cmd) + (sizeof(struct host_memory_chunk) * ar->wmi.num_mem_chunks); - buf = ath10k_wmi_alloc_skb(len); + buf = ath10k_wmi_alloc_skb(ar, len); if (!buf) return -ENOMEM; @@ -3181,7 +3186,7 @@ static int ath10k_wmi_10_2_cmd_init(struct ath10k *ar) goto out; } - ath10k_dbg(ATH10K_DBG_WMI, "wmi sending %d memory chunks info.\n", + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi sending %d memory chunks info.\n", ar->wmi.num_mem_chunks); cmd->num_host_mem_chunks = __cpu_to_le32(ar->wmi.num_mem_chunks); @@ -3194,7 +3199,7 @@ static int ath10k_wmi_10_2_cmd_init(struct ath10k *ar) cmd->host_mem_chunks[i].req_id = __cpu_to_le32(ar->wmi.mem_chunks[i].req_id); - ath10k_dbg(ATH10K_DBG_WMI, + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi chunk %d len %d requested, addr 0x%llx\n", i, ar->wmi.mem_chunks[i].len, @@ -3203,7 +3208,7 @@ static int ath10k_wmi_10_2_cmd_init(struct ath10k *ar) out: memcpy(&cmd->resource_config.common, &config, sizeof(config)); - ath10k_dbg(ATH10K_DBG_WMI, "wmi init 10.2\n"); + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi init 10.2\n"); return ath10k_wmi_cmd_send(ar, buf, ar->wmi.cmd->init_cmdid); } @@ -3295,7 +3300,7 @@ int ath10k_wmi_start_scan(struct ath10k *ar, if (len < 0) return len; /* len contains error code here */ - skb = ath10k_wmi_alloc_skb(len); + skb = ath10k_wmi_alloc_skb(ar, len); if (!skb) return -ENOMEM; @@ -3391,7 +3396,7 @@ int ath10k_wmi_start_scan(struct ath10k *ar, return -EINVAL; } - ath10k_dbg(ATH10K_DBG_WMI, "wmi start scan\n"); + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi start scan\n"); return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->start_scan_cmdid); } @@ -3433,7 +3438,7 @@ int ath10k_wmi_stop_scan(struct ath10k *ar, const struct wmi_stop_scan_arg *arg) if (arg->req_type == WMI_SCAN_STOP_ONE && arg->u.scan_id > 0xFFF) return -EINVAL; - skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); + skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) return -ENOMEM; @@ -3449,7 +3454,7 @@ int ath10k_wmi_stop_scan(struct ath10k *ar, const struct wmi_stop_scan_arg *arg) cmd->scan_id = __cpu_to_le32(scan_id); cmd->scan_req_id = __cpu_to_le32(req_id); - ath10k_dbg(ATH10K_DBG_WMI, + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi stop scan reqid %d req_type %d vdev/scan_id %d\n", arg->req_id, arg->req_type, arg->u.scan_id); return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->stop_scan_cmdid); @@ -3463,7 +3468,7 @@ int ath10k_wmi_vdev_create(struct ath10k *ar, u32 vdev_id, struct wmi_vdev_create_cmd *cmd; struct sk_buff *skb; - skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); + skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) return -ENOMEM; @@ -3473,7 +3478,7 @@ int ath10k_wmi_vdev_create(struct ath10k *ar, u32 vdev_id, cmd->vdev_subtype = __cpu_to_le32(subtype); memcpy(cmd->vdev_macaddr.addr, macaddr, ETH_ALEN); - ath10k_dbg(ATH10K_DBG_WMI, + ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI vdev create: id %d type %d subtype %d macaddr %pM\n", vdev_id, type, subtype, macaddr); @@ -3485,14 +3490,14 @@ int ath10k_wmi_vdev_delete(struct ath10k *ar, u32 vdev_id) struct wmi_vdev_delete_cmd *cmd; struct sk_buff *skb; - skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); + skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) return -ENOMEM; cmd = (struct wmi_vdev_delete_cmd *)skb->data; cmd->vdev_id = __cpu_to_le32(vdev_id); - ath10k_dbg(ATH10K_DBG_WMI, + ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI vdev delete id %d\n", vdev_id); return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_delete_cmdid); @@ -3525,7 +3530,7 @@ static int ath10k_wmi_vdev_start_restart(struct ath10k *ar, else return -EINVAL; /* should not happen, we already check cmd_id */ - skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); + skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) return -ENOMEM; @@ -3563,7 +3568,7 @@ static int ath10k_wmi_vdev_start_restart(struct ath10k *ar, cmd->chan.reg_classid = arg->channel.reg_class_id; cmd->chan.antenna_max = arg->channel.max_antenna_gain; - ath10k_dbg(ATH10K_DBG_WMI, + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi vdev %s id 0x%x flags: 0x%0X, freq %d, mode %d, " "ch_flags: 0x%0X, max_power: %d\n", cmdname, arg->vdev_id, flags, arg->channel.freq, arg->channel.mode, @@ -3593,14 +3598,14 @@ int ath10k_wmi_vdev_stop(struct ath10k *ar, u32 vdev_id) struct wmi_vdev_stop_cmd *cmd; struct sk_buff *skb; - skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); + skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) return -ENOMEM; cmd = (struct wmi_vdev_stop_cmd *)skb->data; cmd->vdev_id = __cpu_to_le32(vdev_id); - ath10k_dbg(ATH10K_DBG_WMI, "wmi vdev stop id 0x%x\n", vdev_id); + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi vdev stop id 0x%x\n", vdev_id); return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_stop_cmdid); } @@ -3610,7 +3615,7 @@ int ath10k_wmi_vdev_up(struct ath10k *ar, u32 vdev_id, u32 aid, const u8 *bssid) struct wmi_vdev_up_cmd *cmd; struct sk_buff *skb; - skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); + skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) return -ENOMEM; @@ -3619,7 +3624,7 @@ int ath10k_wmi_vdev_up(struct ath10k *ar, u32 vdev_id, u32 aid, const u8 *bssid) cmd->vdev_assoc_id = __cpu_to_le32(aid); memcpy(&cmd->vdev_bssid.addr, bssid, ETH_ALEN); - ath10k_dbg(ATH10K_DBG_WMI, + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi mgmt vdev up id 0x%x assoc id %d bssid %pM\n", vdev_id, aid, bssid); @@ -3631,14 +3636,14 @@ int ath10k_wmi_vdev_down(struct ath10k *ar, u32 vdev_id) struct wmi_vdev_down_cmd *cmd; struct sk_buff *skb; - skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); + skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) return -ENOMEM; cmd = (struct wmi_vdev_down_cmd *)skb->data; cmd->vdev_id = __cpu_to_le32(vdev_id); - ath10k_dbg(ATH10K_DBG_WMI, + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi mgmt vdev down id 0x%x\n", vdev_id); return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_down_cmdid); @@ -3651,13 +3656,13 @@ int ath10k_wmi_vdev_set_param(struct ath10k *ar, u32 vdev_id, struct sk_buff *skb; if (param_id == WMI_VDEV_PARAM_UNSUPPORTED) { - ath10k_dbg(ATH10K_DBG_WMI, + ath10k_dbg(ar, ATH10K_DBG_WMI, "vdev param %d not supported by firmware\n", param_id); return -EOPNOTSUPP; } - skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); + skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) return -ENOMEM; @@ -3666,7 +3671,7 @@ int ath10k_wmi_vdev_set_param(struct ath10k *ar, u32 vdev_id, cmd->param_id = __cpu_to_le32(param_id); cmd->param_value = __cpu_to_le32(param_value); - ath10k_dbg(ATH10K_DBG_WMI, + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi vdev id 0x%x set param %d value %d\n", vdev_id, param_id, param_value); @@ -3684,7 +3689,7 @@ int ath10k_wmi_vdev_install_key(struct ath10k *ar, if (arg->key_cipher != WMI_CIPHER_NONE && arg->key_data == NULL) return -EINVAL; - skb = ath10k_wmi_alloc_skb(sizeof(*cmd) + arg->key_len); + skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd) + arg->key_len); if (!skb) return -ENOMEM; @@ -3702,7 +3707,7 @@ int ath10k_wmi_vdev_install_key(struct ath10k *ar, if (arg->key_data) memcpy(cmd->key_data, arg->key_data, arg->key_len); - ath10k_dbg(ATH10K_DBG_WMI, + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi vdev install key idx %d cipher %d len %d\n", arg->key_idx, arg->key_cipher, arg->key_len); return ath10k_wmi_cmd_send(ar, skb, @@ -3716,7 +3721,7 @@ int ath10k_wmi_vdev_spectral_conf(struct ath10k *ar, struct sk_buff *skb; u32 cmdid; - skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); + skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) return -ENOMEM; @@ -3752,7 +3757,7 @@ int ath10k_wmi_vdev_spectral_enable(struct ath10k *ar, u32 vdev_id, u32 trigger, struct sk_buff *skb; u32 cmdid; - skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); + skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) return -ENOMEM; @@ -3771,7 +3776,7 @@ int ath10k_wmi_peer_create(struct ath10k *ar, u32 vdev_id, struct wmi_peer_create_cmd *cmd; struct sk_buff *skb; - skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); + skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) return -ENOMEM; @@ -3779,7 +3784,7 @@ int ath10k_wmi_peer_create(struct ath10k *ar, u32 vdev_id, cmd->vdev_id = __cpu_to_le32(vdev_id); memcpy(cmd->peer_macaddr.addr, peer_addr, ETH_ALEN); - ath10k_dbg(ATH10K_DBG_WMI, + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi peer create vdev_id %d peer_addr %pM\n", vdev_id, peer_addr); return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_create_cmdid); @@ -3791,7 +3796,7 @@ int ath10k_wmi_peer_delete(struct ath10k *ar, u32 vdev_id, struct wmi_peer_delete_cmd *cmd; struct sk_buff *skb; - skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); + skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) return -ENOMEM; @@ -3799,7 +3804,7 @@ int ath10k_wmi_peer_delete(struct ath10k *ar, u32 vdev_id, cmd->vdev_id = __cpu_to_le32(vdev_id); memcpy(cmd->peer_macaddr.addr, peer_addr, ETH_ALEN); - ath10k_dbg(ATH10K_DBG_WMI, + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi peer delete vdev_id %d peer_addr %pM\n", vdev_id, peer_addr); return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_delete_cmdid); @@ -3811,7 +3816,7 @@ int ath10k_wmi_peer_flush(struct ath10k *ar, u32 vdev_id, struct wmi_peer_flush_tids_cmd *cmd; struct sk_buff *skb; - skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); + skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) return -ENOMEM; @@ -3820,7 +3825,7 @@ int ath10k_wmi_peer_flush(struct ath10k *ar, u32 vdev_id, cmd->peer_tid_bitmap = __cpu_to_le32(tid_bitmap); memcpy(cmd->peer_macaddr.addr, peer_addr, ETH_ALEN); - ath10k_dbg(ATH10K_DBG_WMI, + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi peer flush vdev_id %d peer_addr %pM tids %08x\n", vdev_id, peer_addr, tid_bitmap); return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_flush_tids_cmdid); @@ -3833,7 +3838,7 @@ int ath10k_wmi_peer_set_param(struct ath10k *ar, u32 vdev_id, struct wmi_peer_set_param_cmd *cmd; struct sk_buff *skb; - skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); + skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) return -ENOMEM; @@ -3843,7 +3848,7 @@ int ath10k_wmi_peer_set_param(struct ath10k *ar, u32 vdev_id, cmd->param_value = __cpu_to_le32(param_value); memcpy(&cmd->peer_macaddr.addr, peer_addr, ETH_ALEN); - ath10k_dbg(ATH10K_DBG_WMI, + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi vdev %d peer 0x%pM set param %d value %d\n", vdev_id, peer_addr, param_id, param_value); @@ -3856,7 +3861,7 @@ int ath10k_wmi_set_psmode(struct ath10k *ar, u32 vdev_id, struct wmi_sta_powersave_mode_cmd *cmd; struct sk_buff *skb; - skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); + skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) return -ENOMEM; @@ -3864,7 +3869,7 @@ int ath10k_wmi_set_psmode(struct ath10k *ar, u32 vdev_id, cmd->vdev_id = __cpu_to_le32(vdev_id); cmd->sta_ps_mode = __cpu_to_le32(psmode); - ath10k_dbg(ATH10K_DBG_WMI, + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi set powersave id 0x%x mode %d\n", vdev_id, psmode); @@ -3879,7 +3884,7 @@ int ath10k_wmi_set_sta_ps_param(struct ath10k *ar, u32 vdev_id, struct wmi_sta_powersave_param_cmd *cmd; struct sk_buff *skb; - skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); + skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) return -ENOMEM; @@ -3888,7 +3893,7 @@ int ath10k_wmi_set_sta_ps_param(struct ath10k *ar, u32 vdev_id, cmd->param_id = __cpu_to_le32(param_id); cmd->param_value = __cpu_to_le32(value); - ath10k_dbg(ATH10K_DBG_WMI, + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi sta ps param vdev_id 0x%x param %d value %d\n", vdev_id, param_id, value); return ath10k_wmi_cmd_send(ar, skb, @@ -3904,7 +3909,7 @@ int ath10k_wmi_set_ap_ps_param(struct ath10k *ar, u32 vdev_id, const u8 *mac, if (!mac) return -EINVAL; - skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); + skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) return -ENOMEM; @@ -3914,7 +3919,7 @@ int ath10k_wmi_set_ap_ps_param(struct ath10k *ar, u32 vdev_id, const u8 *mac, cmd->param_value = __cpu_to_le32(value); memcpy(&cmd->peer_macaddr, mac, ETH_ALEN); - ath10k_dbg(ATH10K_DBG_WMI, + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi ap ps param vdev_id 0x%X param %d value %d mac_addr %pM\n", vdev_id, param_id, value, mac); @@ -3934,7 +3939,7 @@ int ath10k_wmi_scan_chan_list(struct ath10k *ar, len = sizeof(*cmd) + arg->n_channels * sizeof(struct wmi_channel); - skb = ath10k_wmi_alloc_skb(len); + skb = ath10k_wmi_alloc_skb(ar, len); if (!skb) return -EINVAL; @@ -4076,7 +4081,7 @@ int ath10k_wmi_peer_assoc(struct ath10k *ar, len = sizeof(struct wmi_main_peer_assoc_complete_cmd); } - skb = ath10k_wmi_alloc_skb(len); + skb = ath10k_wmi_alloc_skb(ar, len); if (!skb) return -ENOMEM; @@ -4089,7 +4094,7 @@ int ath10k_wmi_peer_assoc(struct ath10k *ar, ath10k_wmi_peer_assoc_fill_main(ar, skb->data, arg); } - ath10k_dbg(ATH10K_DBG_WMI, + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi peer assoc vdev %d addr %pM (%s)\n", arg->vdev_id, arg->addr, arg->peer_reassoc ? "reassociate" : "new"); @@ -4107,7 +4112,7 @@ int ath10k_wmi_beacon_send_ref_nowait(struct ath10k_vif *arvif) int ret; u16 fc; - skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); + skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) return -ENOMEM; @@ -4155,7 +4160,7 @@ int ath10k_wmi_pdev_set_wmm_params(struct ath10k *ar, struct wmi_pdev_set_wmm_params *cmd; struct sk_buff *skb; - skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); + skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) return -ENOMEM; @@ -4165,7 +4170,7 @@ int ath10k_wmi_pdev_set_wmm_params(struct ath10k *ar, ath10k_wmi_pdev_set_wmm_param(&cmd->ac_vi, &arg->ac_vi); ath10k_wmi_pdev_set_wmm_param(&cmd->ac_vo, &arg->ac_vo); - ath10k_dbg(ATH10K_DBG_WMI, "wmi pdev set wmm params\n"); + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi pdev set wmm params\n"); return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->pdev_set_wmm_params_cmdid); } @@ -4175,14 +4180,14 @@ int ath10k_wmi_request_stats(struct ath10k *ar, enum wmi_stats_id stats_id) struct wmi_request_stats_cmd *cmd; struct sk_buff *skb; - skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); + skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) return -ENOMEM; cmd = (struct wmi_request_stats_cmd *)skb->data; cmd->stats_id = __cpu_to_le32(stats_id); - ath10k_dbg(ATH10K_DBG_WMI, "wmi request stats %d\n", (int)stats_id); + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi request stats %d\n", (int)stats_id); return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->request_stats_cmdid); } @@ -4192,7 +4197,7 @@ int ath10k_wmi_force_fw_hang(struct ath10k *ar, struct wmi_force_fw_hang_cmd *cmd; struct sk_buff *skb; - skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); + skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) return -ENOMEM; @@ -4200,7 +4205,7 @@ int ath10k_wmi_force_fw_hang(struct ath10k *ar, cmd->type = __cpu_to_le32(type); cmd->delay_ms = __cpu_to_le32(delay_ms); - ath10k_dbg(ATH10K_DBG_WMI, "wmi force fw hang %d delay %d\n", + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi force fw hang %d delay %d\n", type, delay_ms); return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->force_fw_hang_cmdid); } @@ -4211,7 +4216,7 @@ int ath10k_wmi_dbglog_cfg(struct ath10k *ar, u32 module_enable) struct sk_buff *skb; u32 cfg; - skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); + skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) return -ENOMEM; @@ -4232,7 +4237,7 @@ int ath10k_wmi_dbglog_cfg(struct ath10k *ar, u32 module_enable) cmd->config_enable = __cpu_to_le32(cfg); cmd->config_valid = __cpu_to_le32(ATH10K_DBGLOG_CFG_LOG_LVL_MASK); - ath10k_dbg(ATH10K_DBG_WMI, + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi dbglog cfg modules %08x %08x config %08x %08x\n", __le32_to_cpu(cmd->module_enable), __le32_to_cpu(cmd->module_valid), From 1bbb119db00dc1aff188df0f5705a759ede39b37 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Mon, 25 Aug 2014 12:13:14 +0200 Subject: [PATCH 127/221] ath10k: fix fw crash dumping Recent crash dump patches introduced a regression. If debugfs was disabled upon crash user could only see the following: [ 793.880000] ath10k: firmware crashed! (uuid n/a) [ 793.890000] ath10k: qca988x hw2.0 (0x4100016c, 0x043202ff) fw 10.1.467.2-1 api 2 htt 2.1 [ 793.890000] ath10k: debug 0 debugfs 0 tracing 0 dfs 1 The report was missing register dump. Fix it by printing registers regardless if crash_data is present or not. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 83ef6ef622fa..144eb8a30e2d 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -916,6 +916,9 @@ static void ath10k_pci_dump_registers(struct ath10k *ar, reg_dump_values[i + 2], reg_dump_values[i + 3]); + if (!crash_data) + return; + /* crash_data is in little endian */ for (i = 0; i < REG_DUMP_COUNT_QCA988X; i++) crash_data->registers[i] = cpu_to_le32(reg_dump_values[i]); @@ -937,13 +940,8 @@ static void ath10k_pci_fw_crashed_dump(struct ath10k *ar) ath10k_err(ar, "firmware crashed! (uuid %s)\n", uuid); ath10k_print_driver_info(ar); - - if (!crash_data) - goto exit; - ath10k_pci_dump_registers(ar, crash_data); -exit: spin_unlock_bh(&ar->data_lock); queue_work(ar->workqueue, &ar->restart_work); From 2688eba9d5ba2a35ac8e5efa2e228f105f0a379f Mon Sep 17 00:00:00 2001 From: Andreea-Cristina Bernat Date: Sun, 17 Aug 2014 16:18:02 +0300 Subject: [PATCH 128/221] mac80211: Replace rcu_dereference() with rcu_access_pointer() The "rcu_dereference()" calls are used directly in conditions. Since their return values are never dereferenced it is recommended to use "rcu_access_pointer()" instead of "rcu_dereference()". Therefore, this patch makes the replacements. The following Coccinelle semantic patch was used: @@ @@ ( if( (<+... - rcu_dereference + rcu_access_pointer (...) ...+>)) {...} | while( (<+... - rcu_dereference + rcu_access_pointer (...) ...+>)) {...} ) Signed-off-by: Andreea-Cristina Bernat Signed-off-by: Johannes Berg --- net/mac80211/mesh_pathtbl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index cf032a8db9d7..a6699dceae7c 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c @@ -729,7 +729,7 @@ void mesh_plink_broken(struct sta_info *sta) tbl = rcu_dereference(mesh_paths); for_each_mesh_entry(tbl, node, i) { mpath = node->mpath; - if (rcu_dereference(mpath->next_hop) == sta && + if (rcu_access_pointer(mpath->next_hop) == sta && mpath->flags & MESH_PATH_ACTIVE && !(mpath->flags & MESH_PATH_FIXED)) { spin_lock_bh(&mpath->state_lock); @@ -794,7 +794,7 @@ void mesh_path_flush_by_nexthop(struct sta_info *sta) tbl = resize_dereference_mesh_paths(); for_each_mesh_entry(tbl, node, i) { mpath = node->mpath; - if (rcu_dereference(mpath->next_hop) == sta) { + if (rcu_access_pointer(mpath->next_hop) == sta) { spin_lock(&tbl->hashwlock[i]); __mesh_path_del(tbl, node); spin_unlock(&tbl->hashwlock[i]); From d7bfb7aa54031905a87e0f1d049d160259d71808 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Tue, 26 Aug 2014 19:14:02 +0300 Subject: [PATCH 129/221] ath10k: move pci init structures It doesn't make much sense to have copy engine configuration structures spread across the whole source file. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 192 +++++++++++++------------- 1 file changed, 96 insertions(+), 96 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 144eb8a30e2d..71ac01868d69 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -222,6 +222,102 @@ static const struct ce_pipe_config target_ce_config_wlan[] = { /* CE7 used only by Host */ }; +/* + * Map from service/endpoint to Copy Engine. + * This table is derived from the CE_PCI TABLE, above. + * It is passed to the Target at startup for use by firmware. + */ +static const struct service_to_pipe target_service_to_ce_map_wlan[] = { + { + ATH10K_HTC_SVC_ID_WMI_DATA_VO, + PIPEDIR_OUT, /* out = UL = host -> target */ + 3, + }, + { + ATH10K_HTC_SVC_ID_WMI_DATA_VO, + PIPEDIR_IN, /* in = DL = target -> host */ + 2, + }, + { + ATH10K_HTC_SVC_ID_WMI_DATA_BK, + PIPEDIR_OUT, /* out = UL = host -> target */ + 3, + }, + { + ATH10K_HTC_SVC_ID_WMI_DATA_BK, + PIPEDIR_IN, /* in = DL = target -> host */ + 2, + }, + { + ATH10K_HTC_SVC_ID_WMI_DATA_BE, + PIPEDIR_OUT, /* out = UL = host -> target */ + 3, + }, + { + ATH10K_HTC_SVC_ID_WMI_DATA_BE, + PIPEDIR_IN, /* in = DL = target -> host */ + 2, + }, + { + ATH10K_HTC_SVC_ID_WMI_DATA_VI, + PIPEDIR_OUT, /* out = UL = host -> target */ + 3, + }, + { + ATH10K_HTC_SVC_ID_WMI_DATA_VI, + PIPEDIR_IN, /* in = DL = target -> host */ + 2, + }, + { + ATH10K_HTC_SVC_ID_WMI_CONTROL, + PIPEDIR_OUT, /* out = UL = host -> target */ + 3, + }, + { + ATH10K_HTC_SVC_ID_WMI_CONTROL, + PIPEDIR_IN, /* in = DL = target -> host */ + 2, + }, + { + ATH10K_HTC_SVC_ID_RSVD_CTRL, + PIPEDIR_OUT, /* out = UL = host -> target */ + 0, /* could be moved to 3 (share with WMI) */ + }, + { + ATH10K_HTC_SVC_ID_RSVD_CTRL, + PIPEDIR_IN, /* in = DL = target -> host */ + 1, + }, + { + ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS, /* not currently used */ + PIPEDIR_OUT, /* out = UL = host -> target */ + 0, + }, + { + ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS, /* not currently used */ + PIPEDIR_IN, /* in = DL = target -> host */ + 1, + }, + { + ATH10K_HTC_SVC_ID_HTT_DATA_MSG, + PIPEDIR_OUT, /* out = UL = host -> target */ + 4, + }, + { + ATH10K_HTC_SVC_ID_HTT_DATA_MSG, + PIPEDIR_IN, /* in = DL = target -> host */ + 1, + }, + + /* (Additions here) */ + + { /* Must be last */ + 0, + 0, + 0, + }, +}; + static bool ath10k_pci_irq_pending(struct ath10k *ar) { u32 cause; @@ -1377,102 +1473,6 @@ static int ath10k_pci_bmi_wait(struct ath10k_ce_pipe *tx_pipe, return -ETIMEDOUT; } -/* - * Map from service/endpoint to Copy Engine. - * This table is derived from the CE_PCI TABLE, above. - * It is passed to the Target at startup for use by firmware. - */ -static const struct service_to_pipe target_service_to_ce_map_wlan[] = { - { - ATH10K_HTC_SVC_ID_WMI_DATA_VO, - PIPEDIR_OUT, /* out = UL = host -> target */ - 3, - }, - { - ATH10K_HTC_SVC_ID_WMI_DATA_VO, - PIPEDIR_IN, /* in = DL = target -> host */ - 2, - }, - { - ATH10K_HTC_SVC_ID_WMI_DATA_BK, - PIPEDIR_OUT, /* out = UL = host -> target */ - 3, - }, - { - ATH10K_HTC_SVC_ID_WMI_DATA_BK, - PIPEDIR_IN, /* in = DL = target -> host */ - 2, - }, - { - ATH10K_HTC_SVC_ID_WMI_DATA_BE, - PIPEDIR_OUT, /* out = UL = host -> target */ - 3, - }, - { - ATH10K_HTC_SVC_ID_WMI_DATA_BE, - PIPEDIR_IN, /* in = DL = target -> host */ - 2, - }, - { - ATH10K_HTC_SVC_ID_WMI_DATA_VI, - PIPEDIR_OUT, /* out = UL = host -> target */ - 3, - }, - { - ATH10K_HTC_SVC_ID_WMI_DATA_VI, - PIPEDIR_IN, /* in = DL = target -> host */ - 2, - }, - { - ATH10K_HTC_SVC_ID_WMI_CONTROL, - PIPEDIR_OUT, /* out = UL = host -> target */ - 3, - }, - { - ATH10K_HTC_SVC_ID_WMI_CONTROL, - PIPEDIR_IN, /* in = DL = target -> host */ - 2, - }, - { - ATH10K_HTC_SVC_ID_RSVD_CTRL, - PIPEDIR_OUT, /* out = UL = host -> target */ - 0, /* could be moved to 3 (share with WMI) */ - }, - { - ATH10K_HTC_SVC_ID_RSVD_CTRL, - PIPEDIR_IN, /* in = DL = target -> host */ - 1, - }, - { - ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS, /* not currently used */ - PIPEDIR_OUT, /* out = UL = host -> target */ - 0, - }, - { - ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS, /* not currently used */ - PIPEDIR_IN, /* in = DL = target -> host */ - 1, - }, - { - ATH10K_HTC_SVC_ID_HTT_DATA_MSG, - PIPEDIR_OUT, /* out = UL = host -> target */ - 4, - }, - { - ATH10K_HTC_SVC_ID_HTT_DATA_MSG, - PIPEDIR_IN, /* in = DL = target -> host */ - 1, - }, - - /* (Additions here) */ - - { /* Must be last */ - 0, - 0, - 0, - }, -}; - /* * Send an interrupt to the device to wake up the Target CPU * so it has an opportunity to notice any changed state. From 7c6aa25db481f0c6e83ddf358001894a62ca294c Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Tue, 26 Aug 2014 19:14:03 +0300 Subject: [PATCH 130/221] ath10k: dont duplicate service-pipe mapping The mapping is already defined in a structure. It makes little sense to duplicate information stored in it within a function. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 79 ++++++++++++--------------- 1 file changed, 34 insertions(+), 45 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 71ac01868d69..fa0e2450a9a8 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -1094,68 +1094,57 @@ static void ath10k_pci_kill_tasklet(struct ath10k *ar) del_timer_sync(&ar_pci->rx_post_retry); } -/* TODO - temporary mapping while we have too few CE's */ static int ath10k_pci_hif_map_service_to_pipe(struct ath10k *ar, u16 service_id, u8 *ul_pipe, u8 *dl_pipe, int *ul_is_polled, int *dl_is_polled) { - int ret = 0; + const struct service_to_pipe *entry; + bool ul_set = false, dl_set = false; + int i; ath10k_dbg(ar, ATH10K_DBG_PCI, "pci hif map service\n"); /* polling for received messages not supported */ *dl_is_polled = 0; - switch (service_id) { - case ATH10K_HTC_SVC_ID_HTT_DATA_MSG: - /* - * Host->target HTT gets its own pipe, so it can be polled - * while other pipes are interrupt driven. - */ - *ul_pipe = 4; - /* - * Use the same target->host pipe for HTC ctrl, HTC raw - * streams, and HTT. - */ - *dl_pipe = 1; - break; + for (i = 0; i < ARRAY_SIZE(target_service_to_ce_map_wlan); i++) { + entry = &target_service_to_ce_map_wlan[i]; - case ATH10K_HTC_SVC_ID_RSVD_CTRL: - case ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS: - /* - * Note: HTC_RAW_STREAMS_SVC is currently unused, and - * HTC_CTRL_RSVD_SVC could share the same pipe as the - * WMI services. So, if another CE is needed, change - * this to *ul_pipe = 3, which frees up CE 0. - */ - /* *ul_pipe = 3; */ - *ul_pipe = 0; - *dl_pipe = 1; - break; + if (entry->service_id != service_id) + continue; - case ATH10K_HTC_SVC_ID_WMI_DATA_BK: - case ATH10K_HTC_SVC_ID_WMI_DATA_BE: - case ATH10K_HTC_SVC_ID_WMI_DATA_VI: - case ATH10K_HTC_SVC_ID_WMI_DATA_VO: - - case ATH10K_HTC_SVC_ID_WMI_CONTROL: - *ul_pipe = 3; - *dl_pipe = 2; - break; - - /* pipe 5 unused */ - /* pipe 6 reserved */ - /* pipe 7 reserved */ - - default: - ret = -1; - break; + switch (entry->pipedir) { + case PIPEDIR_NONE: + break; + case PIPEDIR_IN: + WARN_ON(dl_set); + *dl_pipe = entry->pipenum; + dl_set = true; + break; + case PIPEDIR_OUT: + WARN_ON(ul_set); + *ul_pipe = entry->pipenum; + ul_set = true; + break; + case PIPEDIR_INOUT: + WARN_ON(dl_set); + WARN_ON(ul_set); + *dl_pipe = entry->pipenum; + *ul_pipe = entry->pipenum; + dl_set = true; + ul_set = true; + break; + } } + + if (WARN_ON(!ul_set || !dl_set)) + return -ENOENT; + *ul_is_polled = (host_ce_config_wlan[*ul_pipe].flags & CE_ATTR_DIS_INTR) != 0; - return ret; + return 0; } static void ath10k_pci_hif_get_default_pipe(struct ath10k *ar, From 0fdc14e42b40ecd7115cc670981d39a89eeee6c3 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Tue, 26 Aug 2014 19:14:03 +0300 Subject: [PATCH 131/221] ath10k: make target endianess more explicit Some copy engine structures are target specific and are uploaded to the device during init/configuration. This also cleans up a bit diag_mem_read/write implicit byteswap mess leaving only diag_access_read/write with an implicit endianess byteswap. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 263 +++++++++++++------------- drivers/net/wireless/ath/ath10k/pci.h | 18 +- 2 files changed, 142 insertions(+), 139 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index fa0e2450a9a8..1ff2f34e6457 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -149,74 +149,74 @@ static const struct ce_attr host_ce_config_wlan[] = { static const struct ce_pipe_config target_ce_config_wlan[] = { /* CE0: host->target HTC control and raw streams */ { - .pipenum = 0, - .pipedir = PIPEDIR_OUT, - .nentries = 32, - .nbytes_max = 256, - .flags = CE_ATTR_FLAGS, - .reserved = 0, + .pipenum = __cpu_to_le32(0), + .pipedir = __cpu_to_le32(PIPEDIR_OUT), + .nentries = __cpu_to_le32(32), + .nbytes_max = __cpu_to_le32(256), + .flags = __cpu_to_le32(CE_ATTR_FLAGS), + .reserved = __cpu_to_le32(0), }, /* CE1: target->host HTT + HTC control */ { - .pipenum = 1, - .pipedir = PIPEDIR_IN, - .nentries = 32, - .nbytes_max = 512, - .flags = CE_ATTR_FLAGS, - .reserved = 0, + .pipenum = __cpu_to_le32(1), + .pipedir = __cpu_to_le32(PIPEDIR_IN), + .nentries = __cpu_to_le32(32), + .nbytes_max = __cpu_to_le32(512), + .flags = __cpu_to_le32(CE_ATTR_FLAGS), + .reserved = __cpu_to_le32(0), }, /* CE2: target->host WMI */ { - .pipenum = 2, - .pipedir = PIPEDIR_IN, - .nentries = 32, - .nbytes_max = 2048, - .flags = CE_ATTR_FLAGS, - .reserved = 0, + .pipenum = __cpu_to_le32(2), + .pipedir = __cpu_to_le32(PIPEDIR_IN), + .nentries = __cpu_to_le32(32), + .nbytes_max = __cpu_to_le32(2048), + .flags = __cpu_to_le32(CE_ATTR_FLAGS), + .reserved = __cpu_to_le32(0), }, /* CE3: host->target WMI */ { - .pipenum = 3, - .pipedir = PIPEDIR_OUT, - .nentries = 32, - .nbytes_max = 2048, - .flags = CE_ATTR_FLAGS, - .reserved = 0, + .pipenum = __cpu_to_le32(3), + .pipedir = __cpu_to_le32(PIPEDIR_OUT), + .nentries = __cpu_to_le32(32), + .nbytes_max = __cpu_to_le32(2048), + .flags = __cpu_to_le32(CE_ATTR_FLAGS), + .reserved = __cpu_to_le32(0), }, /* CE4: host->target HTT */ { - .pipenum = 4, - .pipedir = PIPEDIR_OUT, - .nentries = 256, - .nbytes_max = 256, - .flags = CE_ATTR_FLAGS, - .reserved = 0, + .pipenum = __cpu_to_le32(4), + .pipedir = __cpu_to_le32(PIPEDIR_OUT), + .nentries = __cpu_to_le32(256), + .nbytes_max = __cpu_to_le32(256), + .flags = __cpu_to_le32(CE_ATTR_FLAGS), + .reserved = __cpu_to_le32(0), }, /* NB: 50% of src nentries, since tx has 2 frags */ /* CE5: unused */ { - .pipenum = 5, - .pipedir = PIPEDIR_OUT, - .nentries = 32, - .nbytes_max = 2048, - .flags = CE_ATTR_FLAGS, - .reserved = 0, + .pipenum = __cpu_to_le32(5), + .pipedir = __cpu_to_le32(PIPEDIR_OUT), + .nentries = __cpu_to_le32(32), + .nbytes_max = __cpu_to_le32(2048), + .flags = __cpu_to_le32(CE_ATTR_FLAGS), + .reserved = __cpu_to_le32(0), }, /* CE6: Reserved for target autonomous hif_memcpy */ { - .pipenum = 6, - .pipedir = PIPEDIR_INOUT, - .nentries = 32, - .nbytes_max = 4096, - .flags = CE_ATTR_FLAGS, - .reserved = 0, + .pipenum = __cpu_to_le32(6), + .pipedir = __cpu_to_le32(PIPEDIR_INOUT), + .nentries = __cpu_to_le32(32), + .nbytes_max = __cpu_to_le32(4096), + .flags = __cpu_to_le32(CE_ATTR_FLAGS), + .reserved = __cpu_to_le32(0), }, /* CE7 used only by Host */ @@ -229,92 +229,92 @@ static const struct ce_pipe_config target_ce_config_wlan[] = { */ static const struct service_to_pipe target_service_to_ce_map_wlan[] = { { - ATH10K_HTC_SVC_ID_WMI_DATA_VO, - PIPEDIR_OUT, /* out = UL = host -> target */ - 3, + __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VO), + __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */ + __cpu_to_le32(3), }, { - ATH10K_HTC_SVC_ID_WMI_DATA_VO, - PIPEDIR_IN, /* in = DL = target -> host */ - 2, + __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VO), + __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ + __cpu_to_le32(2), }, { - ATH10K_HTC_SVC_ID_WMI_DATA_BK, - PIPEDIR_OUT, /* out = UL = host -> target */ - 3, + __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_BK), + __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */ + __cpu_to_le32(3), }, { - ATH10K_HTC_SVC_ID_WMI_DATA_BK, - PIPEDIR_IN, /* in = DL = target -> host */ - 2, + __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_BK), + __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ + __cpu_to_le32(2), }, { - ATH10K_HTC_SVC_ID_WMI_DATA_BE, - PIPEDIR_OUT, /* out = UL = host -> target */ - 3, + __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_BE), + __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */ + __cpu_to_le32(3), }, { - ATH10K_HTC_SVC_ID_WMI_DATA_BE, - PIPEDIR_IN, /* in = DL = target -> host */ - 2, + __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_BE), + __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ + __cpu_to_le32(2), }, { - ATH10K_HTC_SVC_ID_WMI_DATA_VI, - PIPEDIR_OUT, /* out = UL = host -> target */ - 3, + __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VI), + __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */ + __cpu_to_le32(3), }, { - ATH10K_HTC_SVC_ID_WMI_DATA_VI, - PIPEDIR_IN, /* in = DL = target -> host */ - 2, + __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VI), + __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ + __cpu_to_le32(2), }, { - ATH10K_HTC_SVC_ID_WMI_CONTROL, - PIPEDIR_OUT, /* out = UL = host -> target */ - 3, + __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_CONTROL), + __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */ + __cpu_to_le32(3), }, { - ATH10K_HTC_SVC_ID_WMI_CONTROL, - PIPEDIR_IN, /* in = DL = target -> host */ - 2, + __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_CONTROL), + __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ + __cpu_to_le32(2), }, { - ATH10K_HTC_SVC_ID_RSVD_CTRL, - PIPEDIR_OUT, /* out = UL = host -> target */ - 0, /* could be moved to 3 (share with WMI) */ + __cpu_to_le32(ATH10K_HTC_SVC_ID_RSVD_CTRL), + __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */ + __cpu_to_le32(0), }, { - ATH10K_HTC_SVC_ID_RSVD_CTRL, - PIPEDIR_IN, /* in = DL = target -> host */ - 1, + __cpu_to_le32(ATH10K_HTC_SVC_ID_RSVD_CTRL), + __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ + __cpu_to_le32(1), + }, + { /* not used */ + __cpu_to_le32(ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS), + __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */ + __cpu_to_le32(0), + }, + { /* not used */ + __cpu_to_le32(ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS), + __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ + __cpu_to_le32(1), }, { - ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS, /* not currently used */ - PIPEDIR_OUT, /* out = UL = host -> target */ - 0, + __cpu_to_le32(ATH10K_HTC_SVC_ID_HTT_DATA_MSG), + __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */ + __cpu_to_le32(4), }, { - ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS, /* not currently used */ - PIPEDIR_IN, /* in = DL = target -> host */ - 1, - }, - { - ATH10K_HTC_SVC_ID_HTT_DATA_MSG, - PIPEDIR_OUT, /* out = UL = host -> target */ - 4, - }, - { - ATH10K_HTC_SVC_ID_HTT_DATA_MSG, - PIPEDIR_IN, /* in = DL = target -> host */ - 1, + __cpu_to_le32(ATH10K_HTC_SVC_ID_HTT_DATA_MSG), + __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ + __cpu_to_le32(1), }, /* (Additions here) */ - { /* Must be last */ - 0, - 0, - 0, + { /* must be last */ + __cpu_to_le32(0), + __cpu_to_le32(0), + __cpu_to_le32(0), }, }; @@ -602,14 +602,9 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data, } done: - if (ret == 0) { - /* Copy data from allocated DMA buf to caller's buf */ - WARN_ON_ONCE(orig_nbytes & 3); - for (i = 0; i < orig_nbytes / sizeof(__le32); i++) { - ((u32 *)data)[i] = - __le32_to_cpu(((__le32 *)data_buf)[i]); - } - } else + if (ret == 0) + memcpy(data, data_buf, orig_nbytes); + else ath10k_warn(ar, "failed to read diag value at 0x%x: %d\n", address, ret); @@ -622,7 +617,13 @@ done: static int ath10k_pci_diag_read32(struct ath10k *ar, u32 address, u32 *value) { - return ath10k_pci_diag_read_mem(ar, address, value, sizeof(u32)); + __le32 val = 0; + int ret; + + ret = ath10k_pci_diag_read_mem(ar, address, &val, sizeof(val)); + *value = __le32_to_cpu(val); + + return ret; } static int __ath10k_pci_diag_read_hi(struct ath10k *ar, void *dest, @@ -699,9 +700,7 @@ static int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address, } /* Copy caller's data to allocated DMA buf */ - WARN_ON_ONCE(orig_nbytes & 3); - for (i = 0; i < orig_nbytes / sizeof(__le32); i++) - ((__le32 *)data_buf)[i] = __cpu_to_le32(((u32 *)data)[i]); + memcpy(data_buf, data, orig_nbytes); /* * The address supplied by the caller is in the @@ -797,14 +796,20 @@ done: return ret; } +static int ath10k_pci_diag_write32(struct ath10k *ar, u32 address, u32 value) +{ + __le32 val = __cpu_to_le32(value); + + return ath10k_pci_diag_write_mem(ar, address, &val, sizeof(val)); +} + /* Write 4B data to Target memory or register */ static int ath10k_pci_diag_write_access(struct ath10k *ar, u32 address, u32 data) { /* Assume range doesn't cross this boundary */ if (address >= DRAM_BASE_ADDRESS) - return ath10k_pci_diag_write_mem(ar, address, &data, - sizeof(u32)); + return ath10k_pci_diag_write32(ar, address, data); ath10k_pci_write32(ar, address, data); return 0; @@ -988,14 +993,14 @@ static u16 ath10k_pci_hif_get_free_queue_number(struct ath10k *ar, u8 pipe) static void ath10k_pci_dump_registers(struct ath10k *ar, struct ath10k_fw_crash_data *crash_data) { - u32 i, reg_dump_values[REG_DUMP_COUNT_QCA988X] = {}; - int ret; + __le32 reg_dump_values[REG_DUMP_COUNT_QCA988X] = {}; + int i, ret; lockdep_assert_held(&ar->data_lock); ret = ath10k_pci_diag_read_hi(ar, ®_dump_values[0], hi_failure_state, - REG_DUMP_COUNT_QCA988X * sizeof(u32)); + REG_DUMP_COUNT_QCA988X * sizeof(__le32)); if (ret) { ath10k_err(ar, "failed to read firmware dump area: %d\n", ret); return; @@ -1007,17 +1012,16 @@ static void ath10k_pci_dump_registers(struct ath10k *ar, for (i = 0; i < REG_DUMP_COUNT_QCA988X; i += 4) ath10k_err(ar, "[%02d]: 0x%08X 0x%08X 0x%08X 0x%08X\n", i, - reg_dump_values[i], - reg_dump_values[i + 1], - reg_dump_values[i + 2], - reg_dump_values[i + 3]); + __le32_to_cpu(reg_dump_values[i]), + __le32_to_cpu(reg_dump_values[i + 1]), + __le32_to_cpu(reg_dump_values[i + 2]), + __le32_to_cpu(reg_dump_values[i + 3])); if (!crash_data) return; - /* crash_data is in little endian */ for (i = 0; i < REG_DUMP_COUNT_QCA988X; i++) - crash_data->registers[i] = cpu_to_le32(reg_dump_values[i]); + crash_data->registers[i] = reg_dump_values[i]; } static void ath10k_pci_fw_crashed_dump(struct ath10k *ar) @@ -1111,27 +1115,27 @@ static int ath10k_pci_hif_map_service_to_pipe(struct ath10k *ar, for (i = 0; i < ARRAY_SIZE(target_service_to_ce_map_wlan); i++) { entry = &target_service_to_ce_map_wlan[i]; - if (entry->service_id != service_id) + if (__le32_to_cpu(entry->service_id) != service_id) continue; - switch (entry->pipedir) { + switch (__le32_to_cpu(entry->pipedir)) { case PIPEDIR_NONE: break; case PIPEDIR_IN: WARN_ON(dl_set); - *dl_pipe = entry->pipenum; + *dl_pipe = __le32_to_cpu(entry->pipenum); dl_set = true; break; case PIPEDIR_OUT: WARN_ON(ul_set); - *ul_pipe = entry->pipenum; + *ul_pipe = __le32_to_cpu(entry->pipenum); ul_set = true; break; case PIPEDIR_INOUT: WARN_ON(dl_set); WARN_ON(ul_set); - *dl_pipe = entry->pipenum; - *ul_pipe = entry->pipenum; + *dl_pipe = __le32_to_cpu(entry->pipenum); + *ul_pipe = __le32_to_cpu(entry->pipenum); dl_set = true; ul_set = true; break; @@ -1583,10 +1587,9 @@ static int ath10k_pci_init_config(struct ath10k *ar) pcie_config_flags &= ~PCIE_CONFIG_FLAG_ENABLE_L1; - ret = ath10k_pci_diag_write_mem(ar, pcie_state_targ_addr + + ret = ath10k_pci_diag_write_access(ar, pcie_state_targ_addr + offsetof(struct pcie_state, config_flags), - &pcie_config_flags, - sizeof(pcie_config_flags)); + pcie_config_flags); if (ret != 0) { ath10k_err(ar, "Failed to write pcie config_flags: %d\n", ret); return ret; diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h index d88928cf60ce..cf36511c7f4d 100644 --- a/drivers/net/wireless/ath/ath10k/pci.h +++ b/drivers/net/wireless/ath/ath10k/pci.h @@ -100,12 +100,12 @@ struct pcie_state { * NOTE: Structure is shared between Host software and Target firmware! */ struct ce_pipe_config { - u32 pipenum; - u32 pipedir; - u32 nentries; - u32 nbytes_max; - u32 flags; - u32 reserved; + __le32 pipenum; + __le32 pipedir; + __le32 nentries; + __le32 nbytes_max; + __le32 flags; + __le32 reserved; }; /* @@ -127,9 +127,9 @@ struct ce_pipe_config { /* Establish a mapping between a service/direction and a pipe. */ struct service_to_pipe { - u32 service_id; - u32 pipedir; - u32 pipenum; + __le32 service_id; + __le32 pipedir; + __le32 pipenum; }; /* Per-pipe state. */ From 1eb3b2167433a7ae1950c6ed4cc4aaad30498f09 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 11 Aug 2014 13:14:25 +0300 Subject: [PATCH 132/221] MAINTAINTERS: The NFC list is subscribers-only It's not moderated, it's subscribers-only. Signed-off-by: Dan Carpenter Signed-off-by: John W. Linville --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index b0a9003a1334..0b7007a9c8a4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6357,7 +6357,7 @@ M: Lauro Ramos Venancio M: Aloisio Almeida Jr M: Samuel Ortiz L: linux-wireless@vger.kernel.org -L: linux-nfc@lists.01.org (moderated for non-subscribers) +L: linux-nfc@lists.01.org (subscribers-only) S: Supported F: net/nfc/ F: include/net/nfc/ From ba1fa3cd615976ba5241060ceb2ab0c79c9b2605 Mon Sep 17 00:00:00 2001 From: Csaba Kiraly Date: Mon, 18 Aug 2014 01:53:34 +0200 Subject: [PATCH 133/221] ath9k_htc: advertise support for TDLS Based on a quick test with AR9271, TDLS seems to be working fine. Tests were done with 2 Atheros AR9271 based devices with firmware 1.3 (sha1 8d49f928aa40ac53c729189bff1333cd373a7fb5), associated with a WAP54G access point. TDLS worked fine both in WPA2 mode and without encryption. Stations maintained ping flood traffic between each other and towards the AP without significant losses. Not tested with AR7010. TDLS was enabled in earlier patches the same way for other Atheros drivers: ath9k (fd6562344dea2b8b2a5d644cf971f4e56004500a), and carl9170 (d1f3de71a584a82ee4e84505fce9acccf40215ff). Signed-off-by: Csaba Kiraly Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/htc_drv_init.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index 8a3bd5fe3a54..d779f4fa50e3 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -592,6 +592,8 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv, hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; + hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS; + hw->queues = 4; hw->max_listen_interval = 1; From 2618d4fb0fb8e28d81f4f922727225470e31e717 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Tue, 19 Aug 2014 08:24:24 -0400 Subject: [PATCH 134/221] mwifiex: fix left_len calculation issue While updating 'left_len' in each iteration, we should subtract last TLV length not the accumulated length of TLVs parsed till now. This bug in parsing logic is exposed by newer firmware which adds two TLVs in GET_HW_SPEC command response. Earlier firmwares used to add only one TLV. Signed-off-by: Amitkumar Karwar Signed-off-by: Avinash Patil Signed-off-by: Cathy Luo Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/cmdevt.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index baf0aab63c04..0c212394dc1f 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -1567,7 +1567,8 @@ int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv, } parsed_len += le16_to_cpu(tlv->len) + sizeof(struct mwifiex_ie_types_header); - left_len -= parsed_len; + left_len -= le16_to_cpu(tlv->len) + + sizeof(struct mwifiex_ie_types_header); } } From 4b9fede594f05550a5b3e061784781aa13540d09 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Tue, 19 Aug 2014 08:24:25 -0400 Subject: [PATCH 135/221] mwifiex: rename macro and variables related to API revision We will remove 'fw' prefix from these variable and macro names and make them generic. Signed-off-by: Amitkumar Karwar Signed-off-by: Avinash Patil Signed-off-by: Cathy Luo Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/cmdevt.c | 18 +++++++++--------- drivers/net/wireless/mwifiex/fw.h | 8 ++++---- drivers/net/wireless/mwifiex/init.c | 4 ++-- drivers/net/wireless/mwifiex/main.h | 2 +- drivers/net/wireless/mwifiex/sta_cmd.c | 2 +- drivers/net/wireless/mwifiex/sta_cmdresp.c | 2 +- drivers/net/wireless/mwifiex/sta_ioctl.c | 4 ++-- 7 files changed, 20 insertions(+), 20 deletions(-) diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index 0c212394dc1f..720e5198b437 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -1470,7 +1470,7 @@ int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv, struct host_cmd_ds_get_hw_spec *hw_spec = &resp->params.hw_spec; struct mwifiex_adapter *adapter = priv->adapter; struct mwifiex_ie_types_header *tlv; - struct hw_spec_fw_api_rev *api_rev; + struct hw_spec_api_rev *api_rev; u16 resp_size, api_id; int i, left_len, parsed_len = 0; @@ -1538,23 +1538,23 @@ int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv, while (left_len > sizeof(struct mwifiex_ie_types_header)) { tlv = (void *)&hw_spec->tlvs + parsed_len; switch (le16_to_cpu(tlv->type)) { - case TLV_TYPE_FW_API_REV: - api_rev = (struct hw_spec_fw_api_rev *)tlv; + case TLV_TYPE_API_REV: + api_rev = (struct hw_spec_api_rev *)tlv; api_id = le16_to_cpu(api_rev->api_id); switch (api_id) { case KEY_API_VER_ID: - adapter->fw_key_api_major_ver = + adapter->key_api_major_ver = api_rev->major_ver; - adapter->fw_key_api_minor_ver = + adapter->key_api_minor_ver = api_rev->minor_ver; dev_dbg(adapter->dev, - "fw_key_api v%d.%d\n", - adapter->fw_key_api_major_ver, - adapter->fw_key_api_minor_ver); + "key_api v%d.%d\n", + adapter->key_api_major_ver, + adapter->key_api_minor_ver); break; default: dev_warn(adapter->dev, - "Unknown FW api_id: %d\n", + "Unknown api_id: %d\n", api_id); break; } diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index 49da2d53d294..adc47f3ea122 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -83,7 +83,7 @@ enum KEY_TYPE_ID { #define WPA_PN_SIZE 8 #define KEY_PARAMS_FIXED_LEN 10 #define KEY_INDEX_MASK 0xf -#define FW_KEY_API_VER_MAJOR_V2 2 +#define KEY_API_VER_MAJOR_V2 2 #define KEY_MCAST BIT(0) #define KEY_UNICAST BIT(1) @@ -170,7 +170,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { #define TLV_TYPE_COALESCE_RULE (PROPRIETARY_TLV_BASE_ID + 154) #define TLV_TYPE_KEY_PARAM_V2 (PROPRIETARY_TLV_BASE_ID + 156) #define TLV_TYPE_TDLS_IDLE_TIMEOUT (PROPRIETARY_TLV_BASE_ID + 194) -#define TLV_TYPE_FW_API_REV (PROPRIETARY_TLV_BASE_ID + 199) +#define TLV_TYPE_API_REV (PROPRIETARY_TLV_BASE_ID + 199) #define MWIFIEX_TX_DATA_BUF_SIZE_2K 2048 @@ -844,11 +844,11 @@ struct host_cmd_ds_802_11_ps_mode_enh { } params; } __packed; -enum FW_API_VER_ID { +enum API_VER_ID { KEY_API_VER_ID = 1, }; -struct hw_spec_fw_api_rev { +struct hw_spec_api_rev { struct mwifiex_ie_types_header header; __le16 api_id; u8 major_ver; diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index 269a277d0a2e..80bda8087508 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -282,8 +282,8 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter) adapter->max_mgmt_ie_index = MAX_MGMT_IE_INDEX; adapter->empty_tx_q_cnt = 0; adapter->ext_scan = true; - adapter->fw_key_api_major_ver = 0; - adapter->fw_key_api_minor_ver = 0; + adapter->key_api_major_ver = 0; + adapter->key_api_minor_ver = 0; } /* diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index a2733b1e63f9..54399631599a 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -833,7 +833,7 @@ struct mwifiex_adapter { struct semaphore *card_sem; bool ext_scan; u8 fw_api_ver; - u8 fw_key_api_major_ver, fw_key_api_minor_ver; + u8 key_api_major_ver, key_api_minor_ver; struct work_struct iface_work; unsigned long iface_work_flags; struct memory_type_mapping *mem_type_mapping_tbl; diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c index 733de92a4c61..225f7498048b 100644 --- a/drivers/net/wireless/mwifiex/sta_cmd.c +++ b/drivers/net/wireless/mwifiex/sta_cmd.c @@ -965,7 +965,7 @@ mwifiex_cmd_802_11_key_material(struct mwifiex_private *priv, u16 cmd_action, u32 cmd_oid, struct mwifiex_ds_encrypt_key *enc_key) { - if (priv->adapter->fw_key_api_major_ver == FW_KEY_API_VER_MAJOR_V2) + if (priv->adapter->key_api_major_ver == KEY_API_VER_MAJOR_V2) return mwifiex_cmd_802_11_key_material_v2(priv, cmd, cmd_action, cmd_oid, enc_key); diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c index 08b78baeb846..62866b0f0830 100644 --- a/drivers/net/wireless/mwifiex/sta_cmdresp.c +++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c @@ -637,7 +637,7 @@ static int mwifiex_ret_802_11_key_material_v2(struct mwifiex_private *priv, static int mwifiex_ret_802_11_key_material(struct mwifiex_private *priv, struct host_cmd_ds_command *resp) { - if (priv->adapter->fw_key_api_major_ver == FW_KEY_API_VER_MAJOR_V2) + if (priv->adapter->key_api_major_ver == KEY_API_VER_MAJOR_V2) return mwifiex_ret_802_11_key_material_v2(priv, resp); else return mwifiex_ret_802_11_key_material_v1(priv, resp); diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index caae9738100a..b95a29b868d1 100644 --- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c @@ -877,7 +877,7 @@ static int mwifiex_sec_ioctl_set_wep_key(struct mwifiex_private *priv, return -1; } - if (adapter->fw_key_api_major_ver == FW_KEY_API_VER_MAJOR_V2) { + if (adapter->key_api_major_ver == KEY_API_VER_MAJOR_V2) { memcpy(encrypt_key->key_material, wep_key->key_material, wep_key->key_length); encrypt_key->key_len = wep_key->key_length; @@ -903,7 +903,7 @@ static int mwifiex_sec_ioctl_set_wep_key(struct mwifiex_private *priv, memset(&priv->wep_key[index], 0, sizeof(struct mwifiex_wep_key)); - if (adapter->fw_key_api_major_ver == FW_KEY_API_VER_MAJOR_V2) + if (adapter->key_api_major_ver == KEY_API_VER_MAJOR_V2) enc_key = encrypt_key; else enc_key = NULL; From 89be7ceb80835238f04c09cb6efc2c70aabd02e8 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Tue, 19 Aug 2014 08:24:26 -0400 Subject: [PATCH 136/221] mwifiex: use firmware API revision from GET_HW_SPEC response Newer firmware returns API revision in GET_HW_SPEC command response. We will make use of it instead of parsing this information from FW release number. Signed-off-by: Amitkumar Karwar Signed-off-by: Avinash Patil Signed-off-by: Cathy Luo Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/cmdevt.c | 8 +++++++- drivers/net/wireless/mwifiex/fw.h | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index 720e5198b437..985f6c2654fb 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -1508,7 +1508,6 @@ int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv, } adapter->fw_release_number = le32_to_cpu(hw_spec->fw_release_number); - adapter->fw_api_ver = (adapter->fw_release_number >> 16) & 0xff; adapter->number_of_antenna = le16_to_cpu(hw_spec->number_of_antenna); if (le32_to_cpu(hw_spec->dot_11ac_dev_cap)) { @@ -1552,6 +1551,13 @@ int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv, adapter->key_api_major_ver, adapter->key_api_minor_ver); break; + case FW_API_VER_ID: + adapter->fw_api_ver = + api_rev->major_ver; + dev_dbg(adapter->dev, + "Firmware api version %d\n", + adapter->fw_api_ver); + break; default: dev_warn(adapter->dev, "Unknown api_id: %d\n", diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index adc47f3ea122..6a703ea18800 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -846,6 +846,7 @@ struct host_cmd_ds_802_11_ps_mode_enh { enum API_VER_ID { KEY_API_VER_ID = 1, + FW_API_VER_ID = 2, }; struct hw_spec_api_rev { From ecf47e9bb796558423fa87b43a8fe55f086ca56e Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Fri, 22 Aug 2014 08:44:52 +0200 Subject: [PATCH 137/221] bcma: only map wrapper if its address is available MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Chipcommon B core does not have a wrap address and it would fail here. Signed-off-by: Hauke Mehrtens Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/bcma/host_soc.c | 4 ++++ drivers/bcma/scan.c | 11 +++++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/bcma/host_soc.c b/drivers/bcma/host_soc.c index 3475e600011a..1edd7e064621 100644 --- a/drivers/bcma/host_soc.c +++ b/drivers/bcma/host_soc.c @@ -134,12 +134,16 @@ static void bcma_host_soc_block_write(struct bcma_device *core, static u32 bcma_host_soc_aread32(struct bcma_device *core, u16 offset) { + if (WARN_ONCE(!core->io_wrap, "Accessed core has no wrapper/agent\n")) + return ~0; return readl(core->io_wrap + offset); } static void bcma_host_soc_awrite32(struct bcma_device *core, u16 offset, u32 value) { + if (WARN_ONCE(!core->io_wrap, "Accessed core has no wrapper/agent\n")) + return; writel(value, core->io_wrap + offset); } diff --git a/drivers/bcma/scan.c b/drivers/bcma/scan.c index b4764c6bcf17..e9bd77249a4c 100644 --- a/drivers/bcma/scan.c +++ b/drivers/bcma/scan.c @@ -421,10 +421,13 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr, core->io_addr = ioremap_nocache(core->addr, BCMA_CORE_SIZE); if (!core->io_addr) return -ENOMEM; - core->io_wrap = ioremap_nocache(core->wrap, BCMA_CORE_SIZE); - if (!core->io_wrap) { - iounmap(core->io_addr); - return -ENOMEM; + if (core->wrap) { + core->io_wrap = ioremap_nocache(core->wrap, + BCMA_CORE_SIZE); + if (!core->io_wrap) { + iounmap(core->io_addr); + return -ENOMEM; + } } } return 0; From c94c3c5e5e6bb3dd4041490a0202bab6e4c6e424 Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Mon, 25 Aug 2014 09:59:29 +0200 Subject: [PATCH 138/221] ray_cs: Add include guards The files ray_cs.h and rayctl.h both contain two thirds of what appears to be an include guard using the macro name RAYLINK_H (both lack the #define). Since RAYLINK_H is not defined anywhere, the #ifndefs are confusing no-ops. Add proper include guards using different macro names. Signed-off-by: Rasmus Villemoes Signed-off-by: John W. Linville --- drivers/net/wireless/ray_cs.h | 5 +++-- drivers/net/wireless/rayctl.h | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ray_cs.h b/drivers/net/wireless/ray_cs.h index e79848fbcca1..524c2f02dd82 100644 --- a/drivers/net/wireless/ray_cs.h +++ b/drivers/net/wireless/ray_cs.h @@ -3,7 +3,8 @@ Written by Corey Thomas */ -#ifndef RAYLINK_H +#ifndef _RAY_CS_H_ +#define _RAY_CS_H_ struct beacon_rx { struct mac_header mac; @@ -69,4 +70,4 @@ typedef struct ray_dev_t { } ray_dev_t; /*****************************************************************************/ -#endif /* RAYLINK_H */ +#endif /* _RAY_CS_H_ */ diff --git a/drivers/net/wireless/rayctl.h b/drivers/net/wireless/rayctl.h index 3c3b98b152c3..b21ed64e15df 100644 --- a/drivers/net/wireless/rayctl.h +++ b/drivers/net/wireless/rayctl.h @@ -1,4 +1,5 @@ -#ifndef RAYLINK_H +#ifndef _RAYCTL_H_ +#define _RAYCTL_H_ typedef unsigned char UCHAR; @@ -729,4 +730,4 @@ typedef struct snaphdr_t #define RAY_IPX_TYPE 0x8137 #define APPLEARP_TYPE 0x80f3 /*****************************************************************************/ -#endif /* #ifndef RAYLINK_H */ +#endif /* _RAYCTL_H_ */ From e6938ea4d56cca1dc7984428d3af79b27ce1db51 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Fri, 22 Aug 2014 09:18:00 -0400 Subject: [PATCH 139/221] ath5k: drop useless comparison rxs->rate_idx is unsigned, so it will always be >= 0. Found by Coverity. Signed-off-by: Bob Copeland Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/base.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 8ad2550bce7f..59a87247aac4 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -1423,7 +1423,7 @@ ath5k_receive_frame(struct ath5k_hw *ah, struct sk_buff *skb, break; } - if (rxs->rate_idx >= 0 && rs->rs_rate == + if (rs->rs_rate == ah->sbands[ah->curchan->band].bitrates[rxs->rate_idx].hw_value_short) rxs->flag |= RX_FLAG_SHORTPRE; From daf9669bea30aa22d44671e0d9ce90234579e1db Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Fri, 22 Aug 2014 09:18:01 -0400 Subject: [PATCH 140/221] ath5k: ensure led name is null terminated Add the missing null termination after strncpy(). This isn't actually a buffer overflow in this case since we use snprintf() appropriately to fill the buffer passed by the caller, but in the interest of not turning this into a bug down the road, go ahead and force termination here. Found by Coverity. Signed-off-by: Bob Copeland Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/led.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/ath/ath5k/led.c b/drivers/net/wireless/ath/ath5k/led.c index 48a6a69b57bc..2062d1190556 100644 --- a/drivers/net/wireless/ath/ath5k/led.c +++ b/drivers/net/wireless/ath/ath5k/led.c @@ -130,6 +130,7 @@ ath5k_register_led(struct ath5k_hw *ah, struct ath5k_led *led, led->ah = ah; strncpy(led->name, name, sizeof(led->name)); + led->name[sizeof(led->name)-1] = 0; led->led_dev.name = led->name; led->led_dev.default_trigger = trigger; led->led_dev.brightness_set = ath5k_led_brightness_set; From dcb784050a518c59f695f76a0a3f802c0a9d92ab Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Fri, 22 Aug 2014 09:18:02 -0400 Subject: [PATCH 141/221] ath5k: remove redundant null check before kfree() kfree() null-checks its argument. Found by smatch. Signed-off-by: Bob Copeland Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/attach.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c index 7106547a14dd..66b6366158b9 100644 --- a/drivers/net/wireless/ath/ath5k/attach.c +++ b/drivers/net/wireless/ath/ath5k/attach.c @@ -351,8 +351,7 @@ void ath5k_hw_deinit(struct ath5k_hw *ah) { __set_bit(ATH_STAT_INVALID, ah->status); - if (ah->ah_rf_banks != NULL) - kfree(ah->ah_rf_banks); + kfree(ah->ah_rf_banks); ath5k_eeprom_detach(ah); From 27328a75daa92035265a74199ff4fb919739357a Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 22 Aug 2014 20:39:24 +0530 Subject: [PATCH 142/221] ath9k: Add a debug level for channel context Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath.h | 1 + drivers/net/wireless/ath/ath9k/init.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index fd9e5305e77f..c1a4ade32772 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h @@ -261,6 +261,7 @@ enum ATH_DEBUG { ATH_DBG_MCI = 0x00008000, ATH_DBG_DFS = 0x00010000, ATH_DBG_WOW = 0x00020000, + ATH_DBG_CHAN_CTX = 0x00040000, ATH_DBG_ANY = 0xffffffff }; diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 39419ea845cc..76771f37aa86 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -778,6 +778,8 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) hw->chanctx_data_size = sizeof(void *); hw->extra_beacon_tailroom = sizeof(struct ieee80211_p2p_noa_attr) + 9; + + ath_dbg(common, CHAN_CTX, "Use channel contexts\n"); } } From 4f6816913f5e0bc4c983674a14a08c6e3729b449 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 22 Aug 2014 20:39:25 +0530 Subject: [PATCH 143/221] ath9k: Handle failure to allocate HW timer Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/init.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 76771f37aa86..4219e7bd4759 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -601,7 +601,9 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, goto err_btcoex; sc->p2p_ps_timer = ath_gen_timer_alloc(sc->sc_ah, ath9k_p2p_ps_timer, - NULL, sc, AR_FIRST_NDP_TIMER); + NULL, sc, AR_FIRST_NDP_TIMER); + if (!sc->p2p_ps_timer) + goto err_btcoex; ath9k_cmn_init_crypto(sc->sc_ah); ath9k_init_misc(sc); From dfcbb3e8f4992b9f618cbe03a0ce90f704135ebf Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 22 Aug 2014 20:39:26 +0530 Subject: [PATCH 144/221] ath9k: Move channel operations to channel.c This reduces clutter in main.c Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 3 + drivers/net/wireless/ath/ath9k/channel.c | 202 +++++++++++++++++++++++ drivers/net/wireless/ath/ath9k/main.c | 202 ----------------------- 3 files changed, 205 insertions(+), 202 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 7fc13a8da675..17b198e067b3 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -432,6 +432,9 @@ struct ath_chanctx *ath_chanctx_get_oper_chan(struct ath_softc *sc, void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, enum ath_chanctx_event ev); void ath_chanctx_timer(unsigned long data); +void ath_offchannel_next(struct ath_softc *sc); +void ath_scan_complete(struct ath_softc *sc, bool abort); +void ath_roc_complete(struct ath_softc *sc, bool abort); int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan); int ath_startrecv(struct ath_softc *sc); diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index ba214ebdcd16..0ce9e40c7ce1 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -683,3 +683,205 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, spin_unlock_bh(&sc->chan_lock); } + +static int ath_scan_channel_duration(struct ath_softc *sc, + struct ieee80211_channel *chan) +{ + struct cfg80211_scan_request *req = sc->offchannel.scan_req; + + if (!req->n_ssids || (chan->flags & IEEE80211_CHAN_NO_IR)) + return (HZ / 9); /* ~110 ms */ + + return (HZ / 16); /* ~60 ms */ +} + +static void +ath_scan_next_channel(struct ath_softc *sc) +{ + struct cfg80211_scan_request *req = sc->offchannel.scan_req; + struct ieee80211_channel *chan; + + if (sc->offchannel.scan_idx >= req->n_channels) { + sc->offchannel.state = ATH_OFFCHANNEL_IDLE; + ath_chanctx_switch(sc, ath_chanctx_get_oper_chan(sc, false), + NULL); + return; + } + + chan = req->channels[sc->offchannel.scan_idx++]; + sc->offchannel.duration = ath_scan_channel_duration(sc, chan); + sc->offchannel.state = ATH_OFFCHANNEL_PROBE_SEND; + ath_chanctx_offchan_switch(sc, chan); +} + +void ath_offchannel_next(struct ath_softc *sc) +{ + struct ieee80211_vif *vif; + + if (sc->offchannel.scan_req) { + vif = sc->offchannel.scan_vif; + sc->offchannel.chan.txpower = vif->bss_conf.txpower; + ath_scan_next_channel(sc); + } else if (sc->offchannel.roc_vif) { + vif = sc->offchannel.roc_vif; + sc->offchannel.chan.txpower = vif->bss_conf.txpower; + sc->offchannel.duration = sc->offchannel.roc_duration; + sc->offchannel.state = ATH_OFFCHANNEL_ROC_START; + ath_chanctx_offchan_switch(sc, sc->offchannel.roc_chan); + } else { + ath_chanctx_switch(sc, ath_chanctx_get_oper_chan(sc, false), + NULL); + sc->offchannel.state = ATH_OFFCHANNEL_IDLE; + if (sc->ps_idle) + ath_cancel_work(sc); + } +} + +void ath_roc_complete(struct ath_softc *sc, bool abort) +{ + sc->offchannel.roc_vif = NULL; + sc->offchannel.roc_chan = NULL; + if (!abort) + ieee80211_remain_on_channel_expired(sc->hw); + ath_offchannel_next(sc); + ath9k_ps_restore(sc); +} + +void ath_scan_complete(struct ath_softc *sc, bool abort) +{ + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + + sc->offchannel.scan_req = NULL; + sc->offchannel.scan_vif = NULL; + sc->offchannel.state = ATH_OFFCHANNEL_IDLE; + ieee80211_scan_completed(sc->hw, abort); + clear_bit(ATH_OP_SCANNING, &common->op_flags); + ath_offchannel_next(sc); + ath9k_ps_restore(sc); +} + +static void ath_scan_send_probe(struct ath_softc *sc, + struct cfg80211_ssid *ssid) +{ + struct cfg80211_scan_request *req = sc->offchannel.scan_req; + struct ieee80211_vif *vif = sc->offchannel.scan_vif; + struct ath_tx_control txctl = {}; + struct sk_buff *skb; + struct ieee80211_tx_info *info; + int band = sc->offchannel.chan.chandef.chan->band; + + skb = ieee80211_probereq_get(sc->hw, vif, + ssid->ssid, ssid->ssid_len, req->ie_len); + if (!skb) + return; + + info = IEEE80211_SKB_CB(skb); + if (req->no_cck) + info->flags |= IEEE80211_TX_CTL_NO_CCK_RATE; + + if (req->ie_len) + memcpy(skb_put(skb, req->ie_len), req->ie, req->ie_len); + + skb_set_queue_mapping(skb, IEEE80211_AC_VO); + + if (!ieee80211_tx_prepare_skb(sc->hw, vif, skb, band, NULL)) + goto error; + + txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO]; + txctl.force_channel = true; + if (ath_tx_start(sc->hw, skb, &txctl)) + goto error; + + return; + +error: + ieee80211_free_txskb(sc->hw, skb); +} + +static void ath_scan_channel_start(struct ath_softc *sc) +{ + struct cfg80211_scan_request *req = sc->offchannel.scan_req; + int i; + + if (!(sc->cur_chan->chandef.chan->flags & IEEE80211_CHAN_NO_IR) && + req->n_ssids) { + for (i = 0; i < req->n_ssids; i++) + ath_scan_send_probe(sc, &req->ssids[i]); + + } + + sc->offchannel.state = ATH_OFFCHANNEL_PROBE_WAIT; + mod_timer(&sc->offchannel.timer, jiffies + sc->offchannel.duration); +} + +void ath_offchannel_channel_change(struct ath_softc *sc) +{ + switch (sc->offchannel.state) { + case ATH_OFFCHANNEL_PROBE_SEND: + if (!sc->offchannel.scan_req) + return; + + if (sc->cur_chan->chandef.chan != + sc->offchannel.chan.chandef.chan) + return; + + ath_scan_channel_start(sc); + break; + case ATH_OFFCHANNEL_IDLE: + if (!sc->offchannel.scan_req) + return; + + ath_scan_complete(sc, false); + break; + case ATH_OFFCHANNEL_ROC_START: + if (sc->cur_chan != &sc->offchannel.chan) + break; + + sc->offchannel.state = ATH_OFFCHANNEL_ROC_WAIT; + mod_timer(&sc->offchannel.timer, jiffies + + msecs_to_jiffies(sc->offchannel.duration)); + ieee80211_ready_on_channel(sc->hw); + break; + case ATH_OFFCHANNEL_ROC_DONE: + ath_roc_complete(sc, false); + break; + default: + break; + } +} + +void ath_offchannel_timer(unsigned long data) +{ + struct ath_softc *sc = (struct ath_softc *)data; + struct ath_chanctx *ctx; + + switch (sc->offchannel.state) { + case ATH_OFFCHANNEL_PROBE_WAIT: + if (!sc->offchannel.scan_req) + return; + + /* get first active channel context */ + ctx = ath_chanctx_get_oper_chan(sc, true); + if (ctx->active) { + sc->offchannel.state = ATH_OFFCHANNEL_SUSPEND; + ath_chanctx_switch(sc, ctx, NULL); + mod_timer(&sc->offchannel.timer, jiffies + HZ / 10); + break; + } + /* fall through */ + case ATH_OFFCHANNEL_SUSPEND: + if (!sc->offchannel.scan_req) + return; + + ath_scan_next_channel(sc); + break; + case ATH_OFFCHANNEL_ROC_START: + case ATH_OFFCHANNEL_ROC_WAIT: + ctx = ath_chanctx_get_oper_chan(sc, false); + sc->offchannel.state = ATH_OFFCHANNEL_ROC_DONE; + ath_chanctx_switch(sc, ctx, NULL); + break; + default: + break; + } +} diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index e6ac8d2e610c..b1d15f31b0a9 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2207,208 +2207,6 @@ static void ath9k_sw_scan_complete(struct ieee80211_hw *hw) clear_bit(ATH_OP_SCANNING, &common->op_flags); } -static int ath_scan_channel_duration(struct ath_softc *sc, - struct ieee80211_channel *chan) -{ - struct cfg80211_scan_request *req = sc->offchannel.scan_req; - - if (!req->n_ssids || (chan->flags & IEEE80211_CHAN_NO_IR)) - return (HZ / 9); /* ~110 ms */ - - return (HZ / 16); /* ~60 ms */ -} - -static void -ath_scan_next_channel(struct ath_softc *sc) -{ - struct cfg80211_scan_request *req = sc->offchannel.scan_req; - struct ieee80211_channel *chan; - - if (sc->offchannel.scan_idx >= req->n_channels) { - sc->offchannel.state = ATH_OFFCHANNEL_IDLE; - ath_chanctx_switch(sc, ath_chanctx_get_oper_chan(sc, false), - NULL); - return; - } - - chan = req->channels[sc->offchannel.scan_idx++]; - sc->offchannel.duration = ath_scan_channel_duration(sc, chan); - sc->offchannel.state = ATH_OFFCHANNEL_PROBE_SEND; - ath_chanctx_offchan_switch(sc, chan); -} - -static void ath_offchannel_next(struct ath_softc *sc) -{ - struct ieee80211_vif *vif; - - if (sc->offchannel.scan_req) { - vif = sc->offchannel.scan_vif; - sc->offchannel.chan.txpower = vif->bss_conf.txpower; - ath_scan_next_channel(sc); - } else if (sc->offchannel.roc_vif) { - vif = sc->offchannel.roc_vif; - sc->offchannel.chan.txpower = vif->bss_conf.txpower; - sc->offchannel.duration = sc->offchannel.roc_duration; - sc->offchannel.state = ATH_OFFCHANNEL_ROC_START; - ath_chanctx_offchan_switch(sc, sc->offchannel.roc_chan); - } else { - ath_chanctx_switch(sc, ath_chanctx_get_oper_chan(sc, false), - NULL); - sc->offchannel.state = ATH_OFFCHANNEL_IDLE; - if (sc->ps_idle) - ath_cancel_work(sc); - } -} - -static void ath_roc_complete(struct ath_softc *sc, bool abort) -{ - sc->offchannel.roc_vif = NULL; - sc->offchannel.roc_chan = NULL; - if (!abort) - ieee80211_remain_on_channel_expired(sc->hw); - ath_offchannel_next(sc); - ath9k_ps_restore(sc); -} - -static void ath_scan_complete(struct ath_softc *sc, bool abort) -{ - struct ath_common *common = ath9k_hw_common(sc->sc_ah); - - sc->offchannel.scan_req = NULL; - sc->offchannel.scan_vif = NULL; - sc->offchannel.state = ATH_OFFCHANNEL_IDLE; - ieee80211_scan_completed(sc->hw, abort); - clear_bit(ATH_OP_SCANNING, &common->op_flags); - ath_offchannel_next(sc); - ath9k_ps_restore(sc); -} - -static void ath_scan_send_probe(struct ath_softc *sc, - struct cfg80211_ssid *ssid) -{ - struct cfg80211_scan_request *req = sc->offchannel.scan_req; - struct ieee80211_vif *vif = sc->offchannel.scan_vif; - struct ath_tx_control txctl = {}; - struct sk_buff *skb; - struct ieee80211_tx_info *info; - int band = sc->offchannel.chan.chandef.chan->band; - - skb = ieee80211_probereq_get(sc->hw, vif, - ssid->ssid, ssid->ssid_len, req->ie_len); - if (!skb) - return; - - info = IEEE80211_SKB_CB(skb); - if (req->no_cck) - info->flags |= IEEE80211_TX_CTL_NO_CCK_RATE; - - if (req->ie_len) - memcpy(skb_put(skb, req->ie_len), req->ie, req->ie_len); - - skb_set_queue_mapping(skb, IEEE80211_AC_VO); - - if (!ieee80211_tx_prepare_skb(sc->hw, vif, skb, band, NULL)) - goto error; - - txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO]; - txctl.force_channel = true; - if (ath_tx_start(sc->hw, skb, &txctl)) - goto error; - - return; - -error: - ieee80211_free_txskb(sc->hw, skb); -} - -static void ath_scan_channel_start(struct ath_softc *sc) -{ - struct cfg80211_scan_request *req = sc->offchannel.scan_req; - int i; - - if (!(sc->cur_chan->chandef.chan->flags & IEEE80211_CHAN_NO_IR) && - req->n_ssids) { - for (i = 0; i < req->n_ssids; i++) - ath_scan_send_probe(sc, &req->ssids[i]); - - } - - sc->offchannel.state = ATH_OFFCHANNEL_PROBE_WAIT; - mod_timer(&sc->offchannel.timer, jiffies + sc->offchannel.duration); -} - -void ath_offchannel_channel_change(struct ath_softc *sc) -{ - switch (sc->offchannel.state) { - case ATH_OFFCHANNEL_PROBE_SEND: - if (!sc->offchannel.scan_req) - return; - - if (sc->cur_chan->chandef.chan != - sc->offchannel.chan.chandef.chan) - return; - - ath_scan_channel_start(sc); - break; - case ATH_OFFCHANNEL_IDLE: - if (!sc->offchannel.scan_req) - return; - - ath_scan_complete(sc, false); - break; - case ATH_OFFCHANNEL_ROC_START: - if (sc->cur_chan != &sc->offchannel.chan) - break; - - sc->offchannel.state = ATH_OFFCHANNEL_ROC_WAIT; - mod_timer(&sc->offchannel.timer, jiffies + - msecs_to_jiffies(sc->offchannel.duration)); - ieee80211_ready_on_channel(sc->hw); - break; - case ATH_OFFCHANNEL_ROC_DONE: - ath_roc_complete(sc, false); - break; - default: - break; - } -} - -void ath_offchannel_timer(unsigned long data) -{ - struct ath_softc *sc = (struct ath_softc *)data; - struct ath_chanctx *ctx; - - switch (sc->offchannel.state) { - case ATH_OFFCHANNEL_PROBE_WAIT: - if (!sc->offchannel.scan_req) - return; - - /* get first active channel context */ - ctx = ath_chanctx_get_oper_chan(sc, true); - if (ctx->active) { - sc->offchannel.state = ATH_OFFCHANNEL_SUSPEND; - ath_chanctx_switch(sc, ctx, NULL); - mod_timer(&sc->offchannel.timer, jiffies + HZ / 10); - break; - } - /* fall through */ - case ATH_OFFCHANNEL_SUSPEND: - if (!sc->offchannel.scan_req) - return; - - ath_scan_next_channel(sc); - break; - case ATH_OFFCHANNEL_ROC_START: - case ATH_OFFCHANNEL_ROC_WAIT: - ctx = ath_chanctx_get_oper_chan(sc, false); - sc->offchannel.state = ATH_OFFCHANNEL_ROC_DONE; - ath_chanctx_switch(sc, ctx, NULL); - break; - default: - break; - } -} - static int ath9k_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_scan_request *hw_req) { From bc81d43ad21ede28cec6b21a4c0a36aa37fe8d0b Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 22 Aug 2014 20:39:27 +0530 Subject: [PATCH 145/221] ath9k: Add debug information Add a few statements to debug channel context operation. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/channel.c | 61 +++++++++++++++++++- drivers/net/wireless/ath/ath9k/main.c | 73 ++++++++++++++++++++---- 2 files changed, 122 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index 0ce9e40c7ce1..2f10b0c069a1 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -16,6 +16,23 @@ #include "ath9k.h" +static const char *offchannel_state_string(enum ath_offchannel_state state) +{ +#define case_rtn_string(val) case val: return #val + + switch (state) { + case_rtn_string(ATH_OFFCHANNEL_IDLE); + case_rtn_string(ATH_OFFCHANNEL_PROBE_SEND); + case_rtn_string(ATH_OFFCHANNEL_PROBE_WAIT); + case_rtn_string(ATH_OFFCHANNEL_SUSPEND); + case_rtn_string(ATH_OFFCHANNEL_ROC_START); + case_rtn_string(ATH_OFFCHANNEL_ROC_WAIT); + case_rtn_string(ATH_OFFCHANNEL_ROC_DONE); + default: + return "unknown"; + } +} + /* Set/change channels. If the channel is really being changed, it's done * by reseting the chip. To accomplish this we must first cleanup any pending * DMA, then restart stuff. @@ -373,13 +390,23 @@ void ath_chanctx_switch(struct ath_softc *sc, struct ath_chanctx *ctx, } sc->next_chan = ctx; - if (chandef) + if (chandef) { ctx->chandef = *chandef; + ath_dbg(common, CHAN_CTX, + "Assigned next_chan to %d MHz\n", chandef->center_freq1); + } if (sc->next_chan == &sc->offchannel.chan) { sc->sched.offchannel_duration = TU_TO_USEC(sc->offchannel.duration) + sc->sched.channel_switch_time; + + if (chandef) { + ath_dbg(common, CHAN_CTX, + "Offchannel duration for chan %d MHz : %u\n", + chandef->center_freq1, + sc->sched.offchannel_duration); + } } spin_unlock_bh(&sc->chan_lock); ieee80211_queue_work(sc->hw, &sc->chanctx_work); @@ -422,9 +449,12 @@ struct ath_chanctx *ath_chanctx_get_oper_chan(struct ath_softc *sc, bool active) void ath_chanctx_offchan_switch(struct ath_softc *sc, struct ieee80211_channel *chan) { + struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct cfg80211_chan_def chandef; cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_NO_HT); + ath_dbg(common, CHAN_CTX, + "Channel definition created: %d MHz\n", chandef.center_freq1); ath_chanctx_switch(sc, &sc->offchannel.chan, &chandef); } @@ -698,19 +728,30 @@ static int ath_scan_channel_duration(struct ath_softc *sc, static void ath_scan_next_channel(struct ath_softc *sc) { + struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct cfg80211_scan_request *req = sc->offchannel.scan_req; struct ieee80211_channel *chan; if (sc->offchannel.scan_idx >= req->n_channels) { + ath_dbg(common, CHAN_CTX, + "Moving to ATH_OFFCHANNEL_IDLE state, scan_idx: %d, n_channels: %d\n", + sc->offchannel.scan_idx, + req->n_channels); + sc->offchannel.state = ATH_OFFCHANNEL_IDLE; ath_chanctx_switch(sc, ath_chanctx_get_oper_chan(sc, false), NULL); return; } + ath_dbg(common, CHAN_CTX, + "Moving to ATH_OFFCHANNEL_PROBE_SEND state, scan_idx: %d\n", + sc->offchannel.scan_idx); + chan = req->channels[sc->offchannel.scan_idx++]; sc->offchannel.duration = ath_scan_channel_duration(sc, chan); sc->offchannel.state = ATH_OFFCHANNEL_PROBE_SEND; + ath_chanctx_offchan_switch(sc, chan); } @@ -751,6 +792,11 @@ void ath_scan_complete(struct ath_softc *sc, bool abort) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); + if (abort) + ath_dbg(common, CHAN_CTX, "HW scan aborted\n"); + else + ath_dbg(common, CHAN_CTX, "HW scan complete\n"); + sc->offchannel.scan_req = NULL; sc->offchannel.scan_vif = NULL; sc->offchannel.state = ATH_OFFCHANNEL_IDLE; @@ -800,6 +846,7 @@ error: static void ath_scan_channel_start(struct ath_softc *sc) { + struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct cfg80211_scan_request *req = sc->offchannel.scan_req; int i; @@ -810,12 +857,20 @@ static void ath_scan_channel_start(struct ath_softc *sc) } + ath_dbg(common, CHAN_CTX, + "Moving to ATH_OFFCHANNEL_PROBE_WAIT state\n"); + sc->offchannel.state = ATH_OFFCHANNEL_PROBE_WAIT; mod_timer(&sc->offchannel.timer, jiffies + sc->offchannel.duration); } void ath_offchannel_channel_change(struct ath_softc *sc) { + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + + ath_dbg(common, CHAN_CTX, "%s: state: %s\n", + __func__, offchannel_state_string(sc->offchannel.state)); + switch (sc->offchannel.state) { case ATH_OFFCHANNEL_PROBE_SEND: if (!sc->offchannel.scan_req) @@ -854,6 +909,10 @@ void ath_offchannel_timer(unsigned long data) { struct ath_softc *sc = (struct ath_softc *)data; struct ath_chanctx *ctx; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + + ath_dbg(common, CHAN_CTX, "%s: state: %s\n", + __func__, offchannel_state_string(sc->offchannel.state)); switch (sc->offchannel.state) { case ATH_OFFCHANNEL_PROBE_WAIT: diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index b1d15f31b0a9..194895bf654f 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2228,8 +2228,13 @@ static int ath9k_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, sc->offchannel.scan_req = req; sc->offchannel.scan_idx = 0; - if (sc->offchannel.state == ATH_OFFCHANNEL_IDLE) + ath_dbg(common, CHAN_CTX, "HW scan request received on vif: %pM\n", + vif->addr); + + if (sc->offchannel.state == ATH_OFFCHANNEL_IDLE) { + ath_dbg(common, CHAN_CTX, "Starting HW scan\n"); ath_offchannel_next(sc); + } out: mutex_unlock(&sc->mutex); @@ -2241,6 +2246,9 @@ static void ath9k_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct ath_softc *sc = hw->priv; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + + ath_dbg(common, CHAN_CTX, "Cancel HW scan on vif: %pM\n", vif->addr); mutex_lock(&sc->mutex); del_timer_sync(&sc->offchannel.timer); @@ -2254,6 +2262,7 @@ static int ath9k_remain_on_channel(struct ieee80211_hw *hw, enum ieee80211_roc_type type) { struct ath_softc *sc = hw->priv; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); int ret = 0; mutex_lock(&sc->mutex); @@ -2268,8 +2277,14 @@ static int ath9k_remain_on_channel(struct ieee80211_hw *hw, sc->offchannel.roc_chan = chan; sc->offchannel.roc_duration = duration; - if (sc->offchannel.state == ATH_OFFCHANNEL_IDLE) + ath_dbg(common, CHAN_CTX, + "RoC request on vif: %pM, type: %d duration: %d\n", + vif->addr, type, duration); + + if (sc->offchannel.state == ATH_OFFCHANNEL_IDLE) { + ath_dbg(common, CHAN_CTX, "Starting RoC period\n"); ath_offchannel_next(sc); + } out: mutex_unlock(&sc->mutex); @@ -2280,9 +2295,11 @@ out: static int ath9k_cancel_remain_on_channel(struct ieee80211_hw *hw) { struct ath_softc *sc = hw->priv; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); mutex_lock(&sc->mutex); + ath_dbg(common, CHAN_CTX, "Cancel RoC\n"); del_timer_sync(&sc->offchannel.timer); if (sc->offchannel.roc_vif) { @@ -2299,6 +2316,7 @@ static int ath9k_add_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *conf) { struct ath_softc *sc = hw->priv; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_chanctx *ctx, **ptr; int pos; @@ -2313,10 +2331,16 @@ static int ath9k_add_chanctx(struct ieee80211_hw *hw, ctx->assigned = true; pos = ctx - &sc->chanctx[0]; ctx->hw_queue_base = pos * IEEE80211_NUM_ACS; + + ath_dbg(common, CHAN_CTX, + "Add channel context: %d MHz\n", + conf->def.chan->center_freq); + ath_chanctx_set_channel(sc, ctx, &conf->def); mutex_unlock(&sc->mutex); return 0; } + mutex_unlock(&sc->mutex); return -ENOSPC; } @@ -2326,12 +2350,19 @@ static void ath9k_remove_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *conf) { struct ath_softc *sc = hw->priv; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_chanctx *ctx = ath_chanctx_get(conf); mutex_lock(&sc->mutex); + + ath_dbg(common, CHAN_CTX, + "Remove channel context: %d MHz\n", + conf->def.chan->center_freq); + ctx->assigned = false; ctx->hw_queue_base = -1; ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_UNASSIGN); + mutex_unlock(&sc->mutex); } @@ -2340,9 +2371,13 @@ static void ath9k_change_chanctx(struct ieee80211_hw *hw, u32 changed) { struct ath_softc *sc = hw->priv; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_chanctx *ctx = ath_chanctx_get(conf); mutex_lock(&sc->mutex); + ath_dbg(common, CHAN_CTX, + "Change channel context: %d MHz\n", + conf->def.chan->center_freq); ath_chanctx_set_channel(sc, ctx, &conf->def); mutex_unlock(&sc->mutex); } @@ -2352,16 +2387,24 @@ static int ath9k_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *conf) { struct ath_softc *sc = hw->priv; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_vif *avp = (void *)vif->drv_priv; struct ath_chanctx *ctx = ath_chanctx_get(conf); int i; mutex_lock(&sc->mutex); + + ath_dbg(common, CHAN_CTX, + "Assign VIF (addr: %pM, type: %d, p2p: %d) to channel context: %d MHz\n", + vif->addr, vif->type, vif->p2p, + conf->def.chan->center_freq); + avp->chanctx = ctx; list_add_tail(&avp->list, &ctx->vifs); ath9k_calculate_summary_state(sc, ctx); for (i = 0; i < IEEE80211_NUM_ACS; i++) vif->hw_queue[i] = ctx->hw_queue_base + i; + mutex_unlock(&sc->mutex); return 0; @@ -2372,16 +2415,24 @@ static void ath9k_unassign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *conf) { struct ath_softc *sc = hw->priv; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_vif *avp = (void *)vif->drv_priv; struct ath_chanctx *ctx = ath_chanctx_get(conf); int ac; mutex_lock(&sc->mutex); + + ath_dbg(common, CHAN_CTX, + "Remove VIF (addr: %pM, type: %d, p2p: %d) from channel context: %d MHz\n", + vif->addr, vif->type, vif->p2p, + conf->def.chan->center_freq); + avp->chanctx = NULL; list_del(&avp->list); ath9k_calculate_summary_state(sc, ctx); for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) vif->hw_queue[ac] = IEEE80211_INVAL_HW_QUEUE; + mutex_unlock(&sc->mutex); } @@ -2390,16 +2441,16 @@ void ath9k_fill_chanctx_ops(void) if (!ath9k_use_chanctx) return; - ath9k_ops.hw_scan = ath9k_hw_scan; - ath9k_ops.cancel_hw_scan = ath9k_cancel_hw_scan; - ath9k_ops.remain_on_channel = ath9k_remain_on_channel; + ath9k_ops.hw_scan = ath9k_hw_scan; + ath9k_ops.cancel_hw_scan = ath9k_cancel_hw_scan; + ath9k_ops.remain_on_channel = ath9k_remain_on_channel; ath9k_ops.cancel_remain_on_channel = ath9k_cancel_remain_on_channel; - ath9k_ops.add_chanctx = ath9k_add_chanctx; - ath9k_ops.remove_chanctx = ath9k_remove_chanctx; - ath9k_ops.change_chanctx = ath9k_change_chanctx; - ath9k_ops.assign_vif_chanctx = ath9k_assign_vif_chanctx; - ath9k_ops.unassign_vif_chanctx = ath9k_unassign_vif_chanctx; - ath9k_ops.mgd_prepare_tx = ath9k_chanctx_force_active; + ath9k_ops.add_chanctx = ath9k_add_chanctx; + ath9k_ops.remove_chanctx = ath9k_remove_chanctx; + ath9k_ops.change_chanctx = ath9k_change_chanctx; + ath9k_ops.assign_vif_chanctx = ath9k_assign_vif_chanctx; + ath9k_ops.unassign_vif_chanctx = ath9k_unassign_vif_chanctx; + ath9k_ops.mgd_prepare_tx = ath9k_chanctx_force_active; } struct ieee80211_ops ath9k_ops = { From 0e721bd061c15417db388988d494e9f80389dc73 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 22 Aug 2014 20:39:28 +0530 Subject: [PATCH 146/221] ath9k: Add a config option for channel context Channel contexts are supported only for P2P right now, so make sure that the 'normal' path remains unaffected by using a config option. This will also reduce the size of the driver. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/Kconfig | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig index 8fcc029a76a6..b8f570ed39ad 100644 --- a/drivers/net/wireless/ath/ath9k/Kconfig +++ b/drivers/net/wireless/ath/ath9k/Kconfig @@ -130,6 +130,15 @@ config ATH9K_RFKILL seconds. Turn off to save power, but enable it if you have a platform that can toggle the RF-Kill GPIO. +config ATH9K_CHANNEL_CONTEXT + bool "Channel Context support" + depends on ATH9K + default n + ---help--- + This option enables channel context support in ath9k, which is needed + for multi-channel concurrency. Enable this if P2P PowerSave support + is required. + config ATH9K_HTC tristate "Atheros HTC based wireless cards support" depends on USB && MAC80211 From 2471adff1f085ec049358f16dcbc97ca7f29d2ef Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 22 Aug 2014 20:39:29 +0530 Subject: [PATCH 147/221] ath9k: Move P2P functions to channel.c Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 1 + drivers/net/wireless/ath/ath9k/channel.c | 86 +++++++++++++++++++++++ drivers/net/wireless/ath/ath9k/main.c | 87 ------------------------ 3 files changed, 87 insertions(+), 87 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 17b198e067b3..aea3979ad25a 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -601,6 +601,7 @@ void ath_update_survey_nf(struct ath_softc *sc, int channel); void ath9k_queue_reset(struct ath_softc *sc, enum ath_reset_type type); void ath_ps_full_sleep(unsigned long data); void ath9k_p2p_ps_timer(void *priv); +void ath9k_update_p2p_ps_timer(struct ath_softc *sc, struct ath_vif *avp); void ath9k_update_p2p_ps(struct ath_softc *sc, struct ieee80211_vif *vif); void __ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop); diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index 2f10b0c069a1..77bf0055e953 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -944,3 +944,89 @@ void ath_offchannel_timer(unsigned long data) break; } } + +void ath9k_update_p2p_ps_timer(struct ath_softc *sc, struct ath_vif *avp) +{ + struct ath_hw *ah = sc->sc_ah; + s32 tsf, target_tsf; + + if (!avp || !avp->noa.has_next_tsf) + return; + + ath9k_hw_gen_timer_stop(ah, sc->p2p_ps_timer); + + tsf = ath9k_hw_gettsf32(sc->sc_ah); + + target_tsf = avp->noa.next_tsf; + if (!avp->noa.absent) + target_tsf -= ATH_P2P_PS_STOP_TIME; + + if (target_tsf - tsf < ATH_P2P_PS_STOP_TIME) + target_tsf = tsf + ATH_P2P_PS_STOP_TIME; + + ath9k_hw_gen_timer_start(ah, sc->p2p_ps_timer, (u32) target_tsf, 1000000); +} + +void ath9k_p2p_ps_timer(void *priv) +{ + struct ath_softc *sc = priv; + struct ath_vif *avp = sc->p2p_ps_vif; + struct ieee80211_vif *vif; + struct ieee80211_sta *sta; + struct ath_node *an; + u32 tsf; + + del_timer_sync(&sc->sched.timer); + ath9k_hw_gen_timer_stop(sc->sc_ah, sc->p2p_ps_timer); + ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_TSF_TIMER); + + if (!avp || avp->chanctx != sc->cur_chan) + return; + + tsf = ath9k_hw_gettsf32(sc->sc_ah); + if (!avp->noa.absent) + tsf += ATH_P2P_PS_STOP_TIME; + + if (!avp->noa.has_next_tsf || + avp->noa.next_tsf - tsf > BIT(31)) + ieee80211_update_p2p_noa(&avp->noa, tsf); + + ath9k_update_p2p_ps_timer(sc, avp); + + rcu_read_lock(); + + vif = avp->vif; + sta = ieee80211_find_sta(vif, vif->bss_conf.bssid); + if (!sta) + goto out; + + an = (void *) sta->drv_priv; + if (an->sleeping == !!avp->noa.absent) + goto out; + + an->sleeping = avp->noa.absent; + if (an->sleeping) + ath_tx_aggr_sleep(sta, sc, an); + else + ath_tx_aggr_wakeup(sc, an); + +out: + rcu_read_unlock(); +} + +void ath9k_update_p2p_ps(struct ath_softc *sc, struct ieee80211_vif *vif) +{ + struct ath_vif *avp = (void *)vif->drv_priv; + u32 tsf; + + if (!sc->p2p_ps_timer) + return; + + if (vif->type != NL80211_IFTYPE_STATION || !vif->p2p) + return; + + sc->p2p_ps_vif = avp; + tsf = ath9k_hw_gettsf32(sc->sc_ah); + ieee80211_parse_p2p_noa(&vif->bss_conf.p2p_noa_attr, &avp->noa, tsf); + ath9k_update_p2p_ps_timer(sc, avp); +} diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 194895bf654f..dd2d52eb35bb 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1202,29 +1202,6 @@ static int ath9k_change_interface(struct ieee80211_hw *hw, return 0; } -static void -ath9k_update_p2p_ps_timer(struct ath_softc *sc, struct ath_vif *avp) -{ - struct ath_hw *ah = sc->sc_ah; - s32 tsf, target_tsf; - - if (!avp || !avp->noa.has_next_tsf) - return; - - ath9k_hw_gen_timer_stop(ah, sc->p2p_ps_timer); - - tsf = ath9k_hw_gettsf32(sc->sc_ah); - - target_tsf = avp->noa.next_tsf; - if (!avp->noa.absent) - target_tsf -= ATH_P2P_PS_STOP_TIME; - - if (target_tsf - tsf < ATH_P2P_PS_STOP_TIME) - target_tsf = tsf + ATH_P2P_PS_STOP_TIME; - - ath9k_hw_gen_timer_start(ah, sc->p2p_ps_timer, (u32) target_tsf, 1000000); -} - static void ath9k_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { @@ -1687,70 +1664,6 @@ static int ath9k_set_key(struct ieee80211_hw *hw, return ret; } -void ath9k_p2p_ps_timer(void *priv) -{ - struct ath_softc *sc = priv; - struct ath_vif *avp = sc->p2p_ps_vif; - struct ieee80211_vif *vif; - struct ieee80211_sta *sta; - struct ath_node *an; - u32 tsf; - - del_timer_sync(&sc->sched.timer); - ath9k_hw_gen_timer_stop(sc->sc_ah, sc->p2p_ps_timer); - ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_TSF_TIMER); - - if (!avp || avp->chanctx != sc->cur_chan) - return; - - tsf = ath9k_hw_gettsf32(sc->sc_ah); - if (!avp->noa.absent) - tsf += ATH_P2P_PS_STOP_TIME; - - if (!avp->noa.has_next_tsf || - avp->noa.next_tsf - tsf > BIT(31)) - ieee80211_update_p2p_noa(&avp->noa, tsf); - - ath9k_update_p2p_ps_timer(sc, avp); - - rcu_read_lock(); - - vif = avp->vif; - sta = ieee80211_find_sta(vif, vif->bss_conf.bssid); - if (!sta) - goto out; - - an = (void *) sta->drv_priv; - if (an->sleeping == !!avp->noa.absent) - goto out; - - an->sleeping = avp->noa.absent; - if (an->sleeping) - ath_tx_aggr_sleep(sta, sc, an); - else - ath_tx_aggr_wakeup(sc, an); - -out: - rcu_read_unlock(); -} - -void ath9k_update_p2p_ps(struct ath_softc *sc, struct ieee80211_vif *vif) -{ - struct ath_vif *avp = (void *)vif->drv_priv; - u32 tsf; - - if (!sc->p2p_ps_timer) - return; - - if (vif->type != NL80211_IFTYPE_STATION || !vif->p2p) - return; - - sc->p2p_ps_vif = avp; - tsf = ath9k_hw_gettsf32(sc->sc_ah); - ieee80211_parse_p2p_noa(&vif->bss_conf.p2p_noa_attr, &avp->noa, tsf); - ath9k_update_p2p_ps_timer(sc, avp); -} - static void ath9k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, From c7dd40c92af1f28b84995a07aa88ccd3068ee4de Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 22 Aug 2014 20:39:30 +0530 Subject: [PATCH 148/221] ath9k: Isolate P2P powersave routines Use CONFIG_ATH9K_CHANNEL_CONTEXT to conditionally compile P2P-PS code. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 38 ++++++++++- drivers/net/wireless/ath/ath9k/channel.c | 84 ++++++++++++++++++++---- drivers/net/wireless/ath/ath9k/init.c | 9 +-- drivers/net/wireless/ath/ath9k/main.c | 18 +---- drivers/net/wireless/ath/ath9k/recv.c | 4 +- 5 files changed, 114 insertions(+), 39 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index aea3979ad25a..642cc19f5652 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -436,6 +436,39 @@ void ath_offchannel_next(struct ath_softc *sc); void ath_scan_complete(struct ath_softc *sc, bool abort); void ath_roc_complete(struct ath_softc *sc, bool abort); +#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT +int ath9k_init_p2p(struct ath_softc *sc); +void ath9k_deinit_p2p(struct ath_softc *sc); +void ath9k_p2p_remove_vif(struct ath_softc *sc, + struct ieee80211_vif *vif); +void ath9k_p2p_beacon_sync(struct ath_softc *sc); +void ath9k_p2p_bss_info_changed(struct ath_softc *sc, + struct ieee80211_vif *vif); +void ath9k_p2p_ps_timer(void *priv); +#else +static inline int ath9k_init_p2p(struct ath_softc *sc) +{ + return 0; +} +static inline void ath9k_deinit_p2p(struct ath_softc *sc) +{ +} +static inline void ath9k_p2p_remove_vif(struct ath_softc *sc, + struct ieee80211_vif *vif) +{ +} +static inline void ath9k_p2p_beacon_sync(struct ath_softc *sc) +{ +} +static inline void ath9k_p2p_bss_info_changed(struct ath_softc *sc, + struct ieee80211_vif *vif) +{ +} +static inline void ath9k_p2p_ps_timer(struct ath_softc *sc) +{ +} +#endif /* CONFIG_ATH9K_CHANNEL_CONTEXT */ + int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan); int ath_startrecv(struct ath_softc *sc); bool ath_stoprecv(struct ath_softc *sc); @@ -600,9 +633,6 @@ int ath_update_survey_stats(struct ath_softc *sc); void ath_update_survey_nf(struct ath_softc *sc, int channel); void ath9k_queue_reset(struct ath_softc *sc, enum ath_reset_type type); void ath_ps_full_sleep(unsigned long data); -void ath9k_p2p_ps_timer(void *priv); -void ath9k_update_p2p_ps_timer(struct ath_softc *sc, struct ath_vif *avp); -void ath9k_update_p2p_ps(struct ath_softc *sc, struct ieee80211_vif *vif); void __ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop); /**********/ @@ -857,8 +887,10 @@ struct ath_softc { struct completion paprd_complete; wait_queue_head_t tx_wait; +#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT struct ath_gen_timer *p2p_ps_timer; struct ath_vif *p2p_ps_vif; +#endif unsigned long driver_data; diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index 77bf0055e953..c54a3dfb42b6 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -514,7 +514,9 @@ static void ath_chanctx_setup_timer(struct ath_softc *sc, u32 tsf_time) { struct ath_hw *ah = sc->sc_ah; +#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT ath9k_hw_gen_timer_start(ah, sc->p2p_ps_timer, tsf_time, 1000000); +#endif tsf_time -= ath9k_hw_gettsf32(ah); tsf_time = msecs_to_jiffies(tsf_time / 1000) + 1; mod_timer(&sc->sched.timer, tsf_time); @@ -945,7 +947,13 @@ void ath_offchannel_timer(unsigned long data) } } -void ath9k_update_p2p_ps_timer(struct ath_softc *sc, struct ath_vif *avp) +#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT + +/*****************/ +/* P2P Powersave */ +/*****************/ + +static void ath9k_update_p2p_ps_timer(struct ath_softc *sc, struct ath_vif *avp) { struct ath_hw *ah = sc->sc_ah; s32 tsf, target_tsf; @@ -967,6 +975,23 @@ void ath9k_update_p2p_ps_timer(struct ath_softc *sc, struct ath_vif *avp) ath9k_hw_gen_timer_start(ah, sc->p2p_ps_timer, (u32) target_tsf, 1000000); } +static void ath9k_update_p2p_ps(struct ath_softc *sc, struct ieee80211_vif *vif) +{ + struct ath_vif *avp = (void *)vif->drv_priv; + u32 tsf; + + if (!sc->p2p_ps_timer) + return; + + if (vif->type != NL80211_IFTYPE_STATION || !vif->p2p) + return; + + sc->p2p_ps_vif = avp; + tsf = ath9k_hw_gettsf32(sc->sc_ah); + ieee80211_parse_p2p_noa(&vif->bss_conf.p2p_noa_attr, &avp->noa, tsf); + ath9k_update_p2p_ps_timer(sc, avp); +} + void ath9k_p2p_ps_timer(void *priv) { struct ath_softc *sc = priv; @@ -1014,19 +1039,52 @@ out: rcu_read_unlock(); } -void ath9k_update_p2p_ps(struct ath_softc *sc, struct ieee80211_vif *vif) +void ath9k_p2p_bss_info_changed(struct ath_softc *sc, + struct ieee80211_vif *vif) +{ + unsigned long flags; + + spin_lock_bh(&sc->sc_pcu_lock); + spin_lock_irqsave(&sc->sc_pm_lock, flags); + if (!(sc->ps_flags & PS_BEACON_SYNC)) + ath9k_update_p2p_ps(sc, vif); + spin_unlock_irqrestore(&sc->sc_pm_lock, flags); + spin_unlock_bh(&sc->sc_pcu_lock); +} + +void ath9k_p2p_beacon_sync(struct ath_softc *sc) +{ + if (sc->p2p_ps_vif) + ath9k_update_p2p_ps(sc, sc->p2p_ps_vif->vif); +} + +void ath9k_p2p_remove_vif(struct ath_softc *sc, + struct ieee80211_vif *vif) { struct ath_vif *avp = (void *)vif->drv_priv; - u32 tsf; - if (!sc->p2p_ps_timer) - return; - - if (vif->type != NL80211_IFTYPE_STATION || !vif->p2p) - return; - - sc->p2p_ps_vif = avp; - tsf = ath9k_hw_gettsf32(sc->sc_ah); - ieee80211_parse_p2p_noa(&vif->bss_conf.p2p_noa_attr, &avp->noa, tsf); - ath9k_update_p2p_ps_timer(sc, avp); + spin_lock_bh(&sc->sc_pcu_lock); + if (avp == sc->p2p_ps_vif) { + sc->p2p_ps_vif = NULL; + ath9k_update_p2p_ps_timer(sc, NULL); + } + spin_unlock_bh(&sc->sc_pcu_lock); } + +int ath9k_init_p2p(struct ath_softc *sc) +{ + sc->p2p_ps_timer = ath_gen_timer_alloc(sc->sc_ah, ath9k_p2p_ps_timer, + NULL, sc, AR_FIRST_NDP_TIMER); + if (!sc->p2p_ps_timer) + return -ENOMEM; + + return 0; +} + +void ath9k_deinit_p2p(struct ath_softc *sc) +{ + if (sc->p2p_ps_timer) + ath_gen_timer_free(sc->sc_ah, sc->p2p_ps_timer); +} + +#endif /* CONFIG_ATH9K_CHANNEL_CONTEXT */ diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 4219e7bd4759..5c48be95f983 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -600,9 +600,8 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, if (ret) goto err_btcoex; - sc->p2p_ps_timer = ath_gen_timer_alloc(sc->sc_ah, ath9k_p2p_ps_timer, - NULL, sc, AR_FIRST_NDP_TIMER); - if (!sc->p2p_ps_timer) + ret = ath9k_init_p2p(sc); + if (ret) goto err_btcoex; ath9k_cmn_init_crypto(sc->sc_ah); @@ -919,9 +918,7 @@ static void ath9k_deinit_softc(struct ath_softc *sc) { int i = 0; - if (sc->p2p_ps_timer) - ath_gen_timer_free(sc->sc_ah, sc->p2p_ps_timer); - + ath9k_deinit_p2p(sc); ath9k_deinit_btcoex(sc); for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index dd2d52eb35bb..32e80fc8849c 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1213,12 +1213,7 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, mutex_lock(&sc->mutex); - spin_lock_bh(&sc->sc_pcu_lock); - if (avp == sc->p2p_ps_vif) { - sc->p2p_ps_vif = NULL; - ath9k_update_p2p_ps_timer(sc, NULL); - } - spin_unlock_bh(&sc->sc_pcu_lock); + ath9k_p2p_remove_vif(sc, vif); sc->nvifs--; sc->tx99_vif = NULL; @@ -1678,7 +1673,6 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); struct ath_vif *avp = (void *)vif->drv_priv; - unsigned long flags; int slottime; ath9k_ps_wakeup(sc); @@ -1727,14 +1721,8 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, } } - if (changed & BSS_CHANGED_P2P_PS) { - spin_lock_bh(&sc->sc_pcu_lock); - spin_lock_irqsave(&sc->sc_pm_lock, flags); - if (!(sc->ps_flags & PS_BEACON_SYNC)) - ath9k_update_p2p_ps(sc, vif); - spin_unlock_irqrestore(&sc->sc_pm_lock, flags); - spin_unlock_bh(&sc->sc_pcu_lock); - } + if (changed & BSS_CHANGED_P2P_PS) + ath9k_p2p_bss_info_changed(sc, vif); if (changed & CHECK_ANI) ath_check_ani(sc); diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 74ab1d02013b..e6669fd0559b 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -547,8 +547,8 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) "Reconfigure beacon timers based on synchronized timestamp\n"); if (!(WARN_ON_ONCE(sc->cur_chan->beacon.beacon_interval == 0))) ath9k_set_beacon(sc); - if (sc->p2p_ps_vif) - ath9k_update_p2p_ps(sc, sc->p2p_ps_vif->vif); + + ath9k_p2p_beacon_sync(sc); } if (ath_beacon_dtim_pending_cab(skb)) { From 499afaccf6f3d5d3180f4155e85becf15d09ff71 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 22 Aug 2014 20:39:31 +0530 Subject: [PATCH 149/221] ath9k: Isolate ath9k_use_chanctx module parameter This patch ensures that the module parameter "use_chanctx" is visible only when CONFIG_ATH9K_CHANNEL_CONTEXT is selected. Also register the channel context callbacks with mac80211 only when it is explicitly enabled and compile them out of the driver when CONFIG_ATH9K_CHANNEL_CONTEXT is not selected. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 10 +++- drivers/net/wireless/ath/ath9k/channel.c | 5 ++ drivers/net/wireless/ath/ath9k/init.c | 63 ++++++++++++++---------- drivers/net/wireless/ath/ath9k/main.c | 14 ++++-- drivers/net/wireless/ath/ath9k/recv.c | 2 +- 5 files changed, 62 insertions(+), 32 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 642cc19f5652..035f6f9f1a38 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -408,7 +408,6 @@ struct ath_offchannel { ctx <= &sc->chanctx[ARRAY_SIZE(sc->chanctx) - 1]; \ ctx++) -void ath9k_fill_chanctx_ops(void); void ath9k_chanctx_force_active(struct ieee80211_hw *hw, struct ieee80211_vif *vif); static inline struct ath_chanctx * @@ -437,6 +436,8 @@ void ath_scan_complete(struct ath_softc *sc, bool abort); void ath_roc_complete(struct ath_softc *sc, bool abort); #ifdef CONFIG_ATH9K_CHANNEL_CONTEXT +bool ath9k_is_chanctx_enabled(void); +void ath9k_fill_chanctx_ops(void); int ath9k_init_p2p(struct ath_softc *sc); void ath9k_deinit_p2p(struct ath_softc *sc); void ath9k_p2p_remove_vif(struct ath_softc *sc, @@ -446,6 +447,13 @@ void ath9k_p2p_bss_info_changed(struct ath_softc *sc, struct ieee80211_vif *vif); void ath9k_p2p_ps_timer(void *priv); #else +static inline bool ath9k_is_chanctx_enabled(void) +{ + return false; +} +static inline void ath9k_fill_chanctx_ops(void) +{ +} static inline int ath9k_init_p2p(struct ath_softc *sc) { return 0; diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index c54a3dfb42b6..36d73c0b18cd 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -949,6 +949,11 @@ void ath_offchannel_timer(unsigned long data) #ifdef CONFIG_ATH9K_CHANNEL_CONTEXT +bool ath9k_is_chanctx_enabled(void) +{ + return (ath9k_use_chanctx == 1); +} + /*****************/ /* P2P Powersave */ /*****************/ diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 5c48be95f983..cfd475b475c3 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -61,10 +61,14 @@ static int ath9k_ps_enable; module_param_named(ps_enable, ath9k_ps_enable, int, 0444); MODULE_PARM_DESC(ps_enable, "Enable WLAN PowerSave"); +#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT + int ath9k_use_chanctx; module_param_named(use_chanctx, ath9k_use_chanctx, int, 0444); MODULE_PARM_DESC(use_chanctx, "Enable channel context for concurrency"); +#endif /* CONFIG_ATH9K_CHANNEL_CONTEXT */ + bool is_ath9k_unloaded; #ifdef CONFIG_MAC80211_LEDS @@ -511,7 +515,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, sc->tx99_power = MAX_RATE_POWER + 1; init_waitqueue_head(&sc->tx_wait); sc->cur_chan = &sc->chanctx[0]; - if (!ath9k_use_chanctx) + if (!ath9k_is_chanctx_enabled()) sc->cur_chan->hw_queue_base = 0; if (!pdata || pdata->use_eeprom) { @@ -673,20 +677,14 @@ static const struct ieee80211_iface_limit wds_limits[] = { { .max = 2048, .types = BIT(NL80211_IFTYPE_WDS) }, }; +#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT + static const struct ieee80211_iface_limit if_limits_multi[] = { { .max = 1, .types = BIT(NL80211_IFTYPE_STATION) }, { .max = 1, .types = BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO) }, }; -static const struct ieee80211_iface_limit if_dfs_limits[] = { - { .max = 1, .types = BIT(NL80211_IFTYPE_AP) | -#ifdef CONFIG_MAC80211_MESH - BIT(NL80211_IFTYPE_MESH_POINT) | -#endif - BIT(NL80211_IFTYPE_ADHOC) }, -}; - static const struct ieee80211_iface_combination if_comb_multi[] = { { .limits = if_limits_multi, @@ -697,6 +695,16 @@ static const struct ieee80211_iface_combination if_comb_multi[] = { }, }; +#endif /* CONFIG_ATH9K_CHANNEL_CONTEXT */ + +static const struct ieee80211_iface_limit if_dfs_limits[] = { + { .max = 1, .types = BIT(NL80211_IFTYPE_AP) | +#ifdef CONFIG_MAC80211_MESH + BIT(NL80211_IFTYPE_MESH_POINT) | +#endif + BIT(NL80211_IFTYPE_ADHOC) }, +}; + static const struct ieee80211_iface_combination if_comb[] = { { .limits = if_limits, @@ -764,26 +772,31 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC) | - BIT(NL80211_IFTYPE_MESH_POINT); - if (!ath9k_use_chanctx) { + BIT(NL80211_IFTYPE_MESH_POINT) | + BIT(NL80211_IFTYPE_WDS); + hw->wiphy->iface_combinations = if_comb; hw->wiphy->n_iface_combinations = ARRAY_SIZE(if_comb); - hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_WDS); - } else { - hw->wiphy->iface_combinations = if_comb_multi; - hw->wiphy->n_iface_combinations = - ARRAY_SIZE(if_comb_multi); - hw->wiphy->max_scan_ssids = 255; - hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; - hw->wiphy->max_remain_on_channel_duration = 10000; - hw->chanctx_data_size = sizeof(void *); - hw->extra_beacon_tailroom = - sizeof(struct ieee80211_p2p_noa_attr) + 9; - - ath_dbg(common, CHAN_CTX, "Use channel contexts\n"); - } } +#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT + + if (ath9k_is_chanctx_enabled()) { + hw->wiphy->interface_modes &= ~ BIT(NL80211_IFTYPE_WDS); + hw->wiphy->iface_combinations = if_comb_multi; + hw->wiphy->n_iface_combinations = ARRAY_SIZE(if_comb_multi); + hw->wiphy->max_scan_ssids = 255; + hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; + hw->wiphy->max_remain_on_channel_duration = 10000; + hw->chanctx_data_size = sizeof(void *); + hw->extra_beacon_tailroom = + sizeof(struct ieee80211_p2p_noa_attr) + 9; + + ath_dbg(common, CHAN_CTX, "Use channel contexts\n"); + } + +#endif /* CONFIG_ATH9K_CHANNEL_CONTEXT */ + hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 32e80fc8849c..ed281ac1b742 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -268,7 +268,7 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start) ath9k_hw_set_interrupts(ah); ath9k_hw_enable_interrupts(ah); - if (!ath9k_use_chanctx) + if (!ath9k_is_chanctx_enabled()) ieee80211_wake_queues(sc->hw); else { if (sc->cur_chan == &sc->offchannel.chan) @@ -1139,7 +1139,7 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, ath9k_beacon_assign_slot(sc, vif); avp->vif = vif; - if (!ath9k_use_chanctx) { + if (!ath9k_is_chanctx_enabled()) { avp->chanctx = sc->cur_chan; list_add_tail(&avp->list, &avp->chanctx->vifs); } @@ -1217,7 +1217,7 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, sc->nvifs--; sc->tx99_vif = NULL; - if (!ath9k_use_chanctx) + if (!ath9k_is_chanctx_enabled()) list_del(&avp->list); if (ath9k_uses_beacons(vif->type)) @@ -1395,7 +1395,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) } } - if (!ath9k_use_chanctx && (changed & IEEE80211_CONF_CHANGE_CHANNEL)) { + if (!ath9k_is_chanctx_enabled() && (changed & IEEE80211_CONF_CHANGE_CHANNEL)) { ctx->offchannel = !!(conf->flags & IEEE80211_CONF_OFFCHANNEL); ath_chanctx_set_channel(sc, ctx, &hw->conf.chandef); } @@ -2108,6 +2108,8 @@ static void ath9k_sw_scan_complete(struct ieee80211_hw *hw) clear_bit(ATH_OP_SCANNING, &common->op_flags); } +#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT + static int ath9k_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_scan_request *hw_req) { @@ -2339,7 +2341,7 @@ static void ath9k_unassign_vif_chanctx(struct ieee80211_hw *hw, void ath9k_fill_chanctx_ops(void) { - if (!ath9k_use_chanctx) + if (!ath9k_is_chanctx_enabled()) return; ath9k_ops.hw_scan = ath9k_hw_scan; @@ -2354,6 +2356,8 @@ void ath9k_fill_chanctx_ops(void) ath9k_ops.mgd_prepare_tx = ath9k_chanctx_force_active; } +#endif + struct ieee80211_ops ath9k_ops = { .tx = ath9k_tx, .start = ath9k_start, diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index e6669fd0559b..ae0d1e913690 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -425,7 +425,7 @@ u32 ath_calcrxfilter(struct ath_softc *sc) if (AR_SREV_9550(sc->sc_ah) || AR_SREV_9531(sc->sc_ah)) rfilt |= ATH9K_RX_FILTER_4ADDRESS; - if (ath9k_use_chanctx && + if (ath9k_is_chanctx_enabled() && test_bit(ATH_OP_SCANNING, &common->op_flags)) rfilt |= ATH9K_RX_FILTER_BEACON; From 69e2a77170f8de7c178343e1a867ba32938a0399 Mon Sep 17 00:00:00 2001 From: Andreea-Cristina Bernat Date: Fri, 22 Aug 2014 22:14:31 +0300 Subject: [PATCH 150/221] carl9170: Remove redundant protection check The carl9170_op_ampdu_action() function is used only by the mac80211 framework. Since the mac80211 already takes care of checks and properly serializing calls to the driver's function there is no need for the driver to do the same thing. Signed-off-by: Andreea-Cristina Bernat Signed-off-by: John W. Linville --- drivers/net/wireless/ath/carl9170/main.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index f8ded84b7be8..ef5b6dc7b7f1 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c @@ -1430,18 +1430,10 @@ static int carl9170_op_ampdu_action(struct ieee80211_hw *hw, if (!sta_info->ht_sta) return -EOPNOTSUPP; - rcu_read_lock(); - if (rcu_dereference(sta_info->agg[tid])) { - rcu_read_unlock(); - return -EBUSY; - } - tid_info = kzalloc(sizeof(struct carl9170_sta_tid), GFP_ATOMIC); - if (!tid_info) { - rcu_read_unlock(); + if (!tid_info) return -ENOMEM; - } tid_info->hsn = tid_info->bsn = tid_info->snx = (*ssn); tid_info->state = CARL9170_TID_STATE_PROGRESS; @@ -1460,7 +1452,6 @@ static int carl9170_op_ampdu_action(struct ieee80211_hw *hw, list_add_tail_rcu(&tid_info->list, &ar->tx_ampdu_list); rcu_assign_pointer(sta_info->agg[tid], tid_info); spin_unlock_bh(&ar->tx_ampdu_list_lock); - rcu_read_unlock(); ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); break; From 705d0bf83dbef34d49927d3bf05c6d497f42e8b0 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Sat, 23 Aug 2014 13:29:06 +0530 Subject: [PATCH 151/221] ath9k: Add a routine for initializing channel contexts Setup the offchannel/sched timers and the chanctx work inside the new function. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 6 +++-- drivers/net/wireless/ath/ath9k/channel.c | 28 ++++++++++++++++-------- drivers/net/wireless/ath/ath9k/init.c | 6 ++--- 3 files changed, 25 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 035f6f9f1a38..eb3572ffaaea 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -422,7 +422,6 @@ void ath_chanctx_set_channel(struct ath_softc *sc, struct ath_chanctx *ctx, void ath_chanctx_switch(struct ath_softc *sc, struct ath_chanctx *ctx, struct cfg80211_chan_def *chandef); void ath_chanctx_check_active(struct ath_softc *sc, struct ath_chanctx *ctx); -void ath_offchannel_timer(unsigned long data); void ath_offchannel_channel_change(struct ath_softc *sc); void ath_chanctx_offchan_switch(struct ath_softc *sc, struct ieee80211_channel *chan); @@ -430,7 +429,6 @@ struct ath_chanctx *ath_chanctx_get_oper_chan(struct ath_softc *sc, bool active); void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, enum ath_chanctx_event ev); -void ath_chanctx_timer(unsigned long data); void ath_offchannel_next(struct ath_softc *sc); void ath_scan_complete(struct ath_softc *sc, bool abort); void ath_roc_complete(struct ath_softc *sc, bool abort); @@ -438,6 +436,7 @@ void ath_roc_complete(struct ath_softc *sc, bool abort); #ifdef CONFIG_ATH9K_CHANNEL_CONTEXT bool ath9k_is_chanctx_enabled(void); void ath9k_fill_chanctx_ops(void); +void ath9k_init_channel_context(struct ath_softc *sc); int ath9k_init_p2p(struct ath_softc *sc); void ath9k_deinit_p2p(struct ath_softc *sc); void ath9k_p2p_remove_vif(struct ath_softc *sc, @@ -454,6 +453,9 @@ static inline bool ath9k_is_chanctx_enabled(void) static inline void ath9k_fill_chanctx_ops(void) { } +static inline void ath9k_init_channel_context(struct ath_softc *sc) +{ +} static inline int ath9k_init_p2p(struct ath_softc *sc) { return 0; diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index 36d73c0b18cd..a4366c1b2684 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -499,13 +499,6 @@ static void ath_chanctx_adjust_tbtt_delta(struct ath_softc *sc) prev->tsf_val += offset; } -void ath_chanctx_timer(unsigned long data) -{ - struct ath_softc *sc = (struct ath_softc *) data; - - ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_TSF_TIMER); -} - /* Configure the TSF based hardware timer for a channel switch. * Also set up backup software timer, in case the gen timer fails. * This could be caused by a hardware reset. @@ -907,7 +900,16 @@ void ath_offchannel_channel_change(struct ath_softc *sc) } } -void ath_offchannel_timer(unsigned long data) +#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT + +static void ath_chanctx_timer(unsigned long data) +{ + struct ath_softc *sc = (struct ath_softc *) data; + + ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_TSF_TIMER); +} + +static void ath_offchannel_timer(unsigned long data) { struct ath_softc *sc = (struct ath_softc *)data; struct ath_chanctx *ctx; @@ -947,7 +949,15 @@ void ath_offchannel_timer(unsigned long data) } } -#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT +void ath9k_init_channel_context(struct ath_softc *sc) +{ + INIT_WORK(&sc->chanctx_work, ath_chanctx_work); + + setup_timer(&sc->offchannel.timer, ath_offchannel_timer, + (unsigned long)sc); + setup_timer(&sc->sched.timer, ath_chanctx_timer, + (unsigned long)sc); +} bool ath9k_is_chanctx_enabled(void) { diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index cfd475b475c3..fe0311a0cd23 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -571,11 +571,9 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, setup_timer(&sc->sleep_timer, ath_ps_full_sleep, (unsigned long)sc); INIT_WORK(&sc->hw_reset_work, ath_reset_work); INIT_WORK(&sc->paprd_work, ath_paprd_calibrate); - INIT_WORK(&sc->chanctx_work, ath_chanctx_work); INIT_DELAYED_WORK(&sc->hw_pll_work, ath_hw_pll_work); - setup_timer(&sc->offchannel.timer, ath_offchannel_timer, - (unsigned long)sc); - setup_timer(&sc->sched.timer, ath_chanctx_timer, (unsigned long)sc); + + ath9k_init_channel_context(sc); /* * Cache line size is used to size and align various From ea22df29a300d4120e2d0a0727aa55f922374f42 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Sat, 23 Aug 2014 13:29:07 +0530 Subject: [PATCH 152/221] ath9k: Add a routine to tear down channel contexts Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 4 ++++ drivers/net/wireless/ath/ath9k/channel.c | 5 +++++ drivers/net/wireless/ath/ath9k/main.c | 3 ++- drivers/net/wireless/ath/ath9k/wow.c | 3 ++- 4 files changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index eb3572ffaaea..e88e18dec52c 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -437,6 +437,7 @@ void ath_roc_complete(struct ath_softc *sc, bool abort); bool ath9k_is_chanctx_enabled(void); void ath9k_fill_chanctx_ops(void); void ath9k_init_channel_context(struct ath_softc *sc); +void ath9k_deinit_channel_context(struct ath_softc *sc); int ath9k_init_p2p(struct ath_softc *sc); void ath9k_deinit_p2p(struct ath_softc *sc); void ath9k_p2p_remove_vif(struct ath_softc *sc, @@ -456,6 +457,9 @@ static inline void ath9k_fill_chanctx_ops(void) static inline void ath9k_init_channel_context(struct ath_softc *sc) { } +static inline void ath9k_deinit_channel_context(struct ath_softc *sc) +{ +} static inline int ath9k_init_p2p(struct ath_softc *sc) { return 0; diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index a4366c1b2684..9c2cf9091583 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -959,6 +959,11 @@ void ath9k_init_channel_context(struct ath_softc *sc) (unsigned long)sc); } +void ath9k_deinit_channel_context(struct ath_softc *sc) +{ + cancel_work_sync(&sc->chanctx_work); +} + bool ath9k_is_chanctx_enabled(void) { return (ath9k_use_chanctx == 1); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index ed281ac1b742..e5c523a812c5 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -822,7 +822,8 @@ static void ath9k_stop(struct ieee80211_hw *hw) struct ath_common *common = ath9k_hw_common(ah); bool prev_idle; - cancel_work_sync(&sc->chanctx_work); + ath9k_deinit_channel_context(sc); + mutex_lock(&sc->mutex); ath_cancel_work(sc); diff --git a/drivers/net/wireless/ath/ath9k/wow.c b/drivers/net/wireless/ath/ath9k/wow.c index a4f4f0da81f6..33531d9a4d50 100644 --- a/drivers/net/wireless/ath/ath9k/wow.c +++ b/drivers/net/wireless/ath/ath9k/wow.c @@ -193,7 +193,8 @@ int ath9k_suspend(struct ieee80211_hw *hw, u32 wow_triggers_enabled = 0; int ret = 0; - cancel_work_sync(&sc->chanctx_work); + ath9k_deinit_channel_context(sc); + mutex_lock(&sc->mutex); ath_cancel_work(sc); From 0e62f8b706bd72095eb8ef4f60ccb007d1facf2e Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Sat, 23 Aug 2014 13:29:08 +0530 Subject: [PATCH 153/221] ath9k: Make ath_chanctx_work static Also compile it conditionally based on CONFIG_ATH9K_CHANNEL_CONTEXT. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 1 - drivers/net/wireless/ath/ath9k/channel.c | 18 +++++++++--------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index e88e18dec52c..f3455ce06abd 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -633,7 +633,6 @@ void ath9k_csa_update(struct ath_softc *sc); #define ATH_PAPRD_TIMEOUT 100 /* msecs */ #define ATH_PLL_WORK_INTERVAL 100 -void ath_chanctx_work(struct work_struct *work); void ath_tx_complete_poll_work(struct work_struct *work); void ath_reset_work(struct work_struct *work); bool ath_hw_check(struct ath_softc *sc); diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index 9c2cf9091583..0b84917dbfe3 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -305,15 +305,6 @@ static void ath_chanctx_set_next(struct ath_softc *sc, bool force) ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_SWITCH); } -void ath_chanctx_work(struct work_struct *work) -{ - struct ath_softc *sc = container_of(work, struct ath_softc, - chanctx_work); - mutex_lock(&sc->mutex); - ath_chanctx_set_next(sc, false); - mutex_unlock(&sc->mutex); -} - void ath_chanctx_init(struct ath_softc *sc) { struct ath_chanctx *ctx; @@ -949,6 +940,15 @@ static void ath_offchannel_timer(unsigned long data) } } +static void ath_chanctx_work(struct work_struct *work) +{ + struct ath_softc *sc = container_of(work, struct ath_softc, + chanctx_work); + mutex_lock(&sc->mutex); + ath_chanctx_set_next(sc, false); + mutex_unlock(&sc->mutex); +} + void ath9k_init_channel_context(struct ath_softc *sc) { INIT_WORK(&sc->chanctx_work, ath_chanctx_work); From e20a854ed32d30be1356fef7bf9d4f0a29d5cf6b Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Sat, 23 Aug 2014 13:29:09 +0530 Subject: [PATCH 154/221] ath9k: Cleanup mgd_prepare_tx callback Rename the callback from ath9k_chanctx_force_active() to ath9k_mgd_prepare_tx(). Also, move it to main.c and group it with the other callbacks. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 4 +-- drivers/net/wireless/ath/ath9k/channel.c | 32 +----------------------- drivers/net/wireless/ath/ath9k/main.c | 32 +++++++++++++++++++++++- 3 files changed, 34 insertions(+), 34 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index f3455ce06abd..f9863e689cd2 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -408,8 +408,6 @@ struct ath_offchannel { ctx <= &sc->chanctx[ARRAY_SIZE(sc->chanctx) - 1]; \ ctx++) -void ath9k_chanctx_force_active(struct ieee80211_hw *hw, - struct ieee80211_vif *vif); static inline struct ath_chanctx * ath_chanctx_get(struct ieee80211_chanctx_conf *ctx) { @@ -446,6 +444,8 @@ void ath9k_p2p_beacon_sync(struct ath_softc *sc); void ath9k_p2p_bss_info_changed(struct ath_softc *sc, struct ieee80211_vif *vif); void ath9k_p2p_ps_timer(void *priv); + +void ath_chanctx_set_next(struct ath_softc *sc, bool force); #else static inline bool ath9k_is_chanctx_enabled(void) { diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index 0b84917dbfe3..4525fc0f657b 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -243,7 +243,7 @@ static bool ath_chanctx_defer_switch(struct ath_softc *sc) return true; } -static void ath_chanctx_set_next(struct ath_softc *sc, bool force) +void ath_chanctx_set_next(struct ath_softc *sc, bool force) { struct timespec ts; bool measure_time = false; @@ -336,36 +336,6 @@ void ath_chanctx_init(struct ath_softc *sc) } -void ath9k_chanctx_force_active(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) -{ - struct ath_softc *sc = hw->priv; - struct ath_common *common = ath9k_hw_common(sc->sc_ah); - struct ath_vif *avp = (struct ath_vif *) vif->drv_priv; - bool changed = false; - - if (!test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags)) - return; - - if (!avp->chanctx) - return; - - mutex_lock(&sc->mutex); - - spin_lock_bh(&sc->chan_lock); - if (sc->next_chan || (sc->cur_chan != avp->chanctx)) { - sc->next_chan = avp->chanctx; - changed = true; - } - sc->sched.state = ATH_CHANCTX_STATE_FORCE_ACTIVE; - spin_unlock_bh(&sc->chan_lock); - - if (changed) - ath_chanctx_set_next(sc, true); - - mutex_unlock(&sc->mutex); -} - void ath_chanctx_switch(struct ath_softc *sc, struct ath_chanctx *ctx, struct cfg80211_chan_def *chandef) { diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index e5c523a812c5..4659168b0394 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2340,6 +2340,36 @@ static void ath9k_unassign_vif_chanctx(struct ieee80211_hw *hw, mutex_unlock(&sc->mutex); } +static void ath9k_mgd_prepare_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct ath_softc *sc = hw->priv; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_vif *avp = (struct ath_vif *) vif->drv_priv; + bool changed = false; + + if (!test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags)) + return; + + if (!avp->chanctx) + return; + + mutex_lock(&sc->mutex); + + spin_lock_bh(&sc->chan_lock); + if (sc->next_chan || (sc->cur_chan != avp->chanctx)) { + sc->next_chan = avp->chanctx; + changed = true; + } + sc->sched.state = ATH_CHANCTX_STATE_FORCE_ACTIVE; + spin_unlock_bh(&sc->chan_lock); + + if (changed) + ath_chanctx_set_next(sc, true); + + mutex_unlock(&sc->mutex); +} + void ath9k_fill_chanctx_ops(void) { if (!ath9k_is_chanctx_enabled()) @@ -2354,7 +2384,7 @@ void ath9k_fill_chanctx_ops(void) ath9k_ops.change_chanctx = ath9k_change_chanctx; ath9k_ops.assign_vif_chanctx = ath9k_assign_vif_chanctx; ath9k_ops.unassign_vif_chanctx = ath9k_unassign_vif_chanctx; - ath9k_ops.mgd_prepare_tx = ath9k_chanctx_force_active; + ath9k_ops.mgd_prepare_tx = ath9k_mgd_prepare_tx; } #endif From 6d7cbd779059fd2d79e3d54997036f6dd2dc9202 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Sat, 23 Aug 2014 13:29:10 +0530 Subject: [PATCH 155/221] ath9k: Conditionally compile a few functions Exclude these functions when CONFIG_ATH9K_CHANNEL_CONTEXT is not enabled: ath_chanctx_send_vif_ps_frame() ath_chanctx_send_ps_frame() ath_chanctx_defer_switch() ath_chanctx_set_next() Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/channel.c | 292 +++++++++++------------ 1 file changed, 146 insertions(+), 146 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index 4525fc0f657b..61ed7a72c989 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -118,53 +118,6 @@ static int ath_set_channel(struct ath_softc *sc) return 0; } -static bool -ath_chanctx_send_vif_ps_frame(struct ath_softc *sc, struct ath_vif *avp, - bool powersave) -{ - struct ieee80211_vif *vif = avp->vif; - struct ieee80211_sta *sta = NULL; - struct ieee80211_hdr_3addr *nullfunc; - struct ath_tx_control txctl; - struct sk_buff *skb; - int band = sc->cur_chan->chandef.chan->band; - - switch (vif->type) { - case NL80211_IFTYPE_STATION: - if (!vif->bss_conf.assoc) - return false; - - skb = ieee80211_nullfunc_get(sc->hw, vif); - if (!skb) - return false; - - nullfunc = (struct ieee80211_hdr_3addr *) skb->data; - if (powersave) - nullfunc->frame_control |= - cpu_to_le16(IEEE80211_FCTL_PM); - - skb_set_queue_mapping(skb, IEEE80211_AC_VO); - if (!ieee80211_tx_prepare_skb(sc->hw, vif, skb, band, &sta)) { - dev_kfree_skb_any(skb); - return false; - } - break; - default: - return false; - } - - memset(&txctl, 0, sizeof(txctl)); - txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO]; - txctl.sta = sta; - txctl.force_channel = true; - if (ath_tx_start(sc->hw, skb, &txctl)) { - ieee80211_free_txskb(sc->hw, skb); - return false; - } - - return true; -} - void ath_chanctx_check_active(struct ath_softc *sc, struct ath_chanctx *ctx) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); @@ -206,105 +159,6 @@ void ath_chanctx_check_active(struct ath_softc *sc, struct ath_chanctx *ctx) ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_ENABLE_MULTICHANNEL); } -static bool -ath_chanctx_send_ps_frame(struct ath_softc *sc, bool powersave) -{ - struct ath_vif *avp; - bool sent = false; - - rcu_read_lock(); - list_for_each_entry(avp, &sc->cur_chan->vifs, list) { - if (ath_chanctx_send_vif_ps_frame(sc, avp, powersave)) - sent = true; - } - rcu_read_unlock(); - - return sent; -} - -static bool ath_chanctx_defer_switch(struct ath_softc *sc) -{ - if (sc->cur_chan == &sc->offchannel.chan) - return false; - - switch (sc->sched.state) { - case ATH_CHANCTX_STATE_SWITCH: - return false; - case ATH_CHANCTX_STATE_IDLE: - if (!sc->cur_chan->switch_after_beacon) - return false; - - sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_BEACON; - break; - default: - break; - } - - return true; -} - -void ath_chanctx_set_next(struct ath_softc *sc, bool force) -{ - struct timespec ts; - bool measure_time = false; - bool send_ps = false; - - spin_lock_bh(&sc->chan_lock); - if (!sc->next_chan) { - spin_unlock_bh(&sc->chan_lock); - return; - } - - if (!force && ath_chanctx_defer_switch(sc)) { - spin_unlock_bh(&sc->chan_lock); - return; - } - - if (sc->cur_chan != sc->next_chan) { - sc->cur_chan->stopped = true; - spin_unlock_bh(&sc->chan_lock); - - if (sc->next_chan == &sc->offchannel.chan) { - getrawmonotonic(&ts); - measure_time = true; - } - __ath9k_flush(sc->hw, ~0, true); - - if (ath_chanctx_send_ps_frame(sc, true)) - __ath9k_flush(sc->hw, BIT(IEEE80211_AC_VO), false); - - send_ps = true; - spin_lock_bh(&sc->chan_lock); - - if (sc->cur_chan != &sc->offchannel.chan) { - getrawmonotonic(&sc->cur_chan->tsf_ts); - sc->cur_chan->tsf_val = ath9k_hw_gettsf64(sc->sc_ah); - } - } - sc->cur_chan = sc->next_chan; - sc->cur_chan->stopped = false; - sc->next_chan = NULL; - sc->sched.offchannel_duration = 0; - if (sc->sched.state != ATH_CHANCTX_STATE_FORCE_ACTIVE) - sc->sched.state = ATH_CHANCTX_STATE_IDLE; - - spin_unlock_bh(&sc->chan_lock); - - if (sc->sc_ah->chip_fullsleep || - memcmp(&sc->cur_chandef, &sc->cur_chan->chandef, - sizeof(sc->cur_chandef))) { - ath_set_channel(sc); - if (measure_time) - sc->sched.channel_switch_time = - ath9k_hw_get_tsf_offset(&ts, NULL); - } - if (send_ps) - ath_chanctx_send_ps_frame(sc, false); - - ath_offchannel_channel_change(sc); - ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_SWITCH); -} - void ath_chanctx_init(struct ath_softc *sc) { struct ath_chanctx *ctx; @@ -910,6 +764,152 @@ static void ath_offchannel_timer(unsigned long data) } } +static bool +ath_chanctx_send_vif_ps_frame(struct ath_softc *sc, struct ath_vif *avp, + bool powersave) +{ + struct ieee80211_vif *vif = avp->vif; + struct ieee80211_sta *sta = NULL; + struct ieee80211_hdr_3addr *nullfunc; + struct ath_tx_control txctl; + struct sk_buff *skb; + int band = sc->cur_chan->chandef.chan->band; + + switch (vif->type) { + case NL80211_IFTYPE_STATION: + if (!vif->bss_conf.assoc) + return false; + + skb = ieee80211_nullfunc_get(sc->hw, vif); + if (!skb) + return false; + + nullfunc = (struct ieee80211_hdr_3addr *) skb->data; + if (powersave) + nullfunc->frame_control |= + cpu_to_le16(IEEE80211_FCTL_PM); + + skb_set_queue_mapping(skb, IEEE80211_AC_VO); + if (!ieee80211_tx_prepare_skb(sc->hw, vif, skb, band, &sta)) { + dev_kfree_skb_any(skb); + return false; + } + break; + default: + return false; + } + + memset(&txctl, 0, sizeof(txctl)); + txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO]; + txctl.sta = sta; + txctl.force_channel = true; + if (ath_tx_start(sc->hw, skb, &txctl)) { + ieee80211_free_txskb(sc->hw, skb); + return false; + } + + return true; +} + +static bool +ath_chanctx_send_ps_frame(struct ath_softc *sc, bool powersave) +{ + struct ath_vif *avp; + bool sent = false; + + rcu_read_lock(); + list_for_each_entry(avp, &sc->cur_chan->vifs, list) { + if (ath_chanctx_send_vif_ps_frame(sc, avp, powersave)) + sent = true; + } + rcu_read_unlock(); + + return sent; +} + +static bool ath_chanctx_defer_switch(struct ath_softc *sc) +{ + if (sc->cur_chan == &sc->offchannel.chan) + return false; + + switch (sc->sched.state) { + case ATH_CHANCTX_STATE_SWITCH: + return false; + case ATH_CHANCTX_STATE_IDLE: + if (!sc->cur_chan->switch_after_beacon) + return false; + + sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_BEACON; + break; + default: + break; + } + + return true; +} + +void ath_chanctx_set_next(struct ath_softc *sc, bool force) +{ + struct timespec ts; + bool measure_time = false; + bool send_ps = false; + + spin_lock_bh(&sc->chan_lock); + if (!sc->next_chan) { + spin_unlock_bh(&sc->chan_lock); + return; + } + + if (!force && ath_chanctx_defer_switch(sc)) { + spin_unlock_bh(&sc->chan_lock); + return; + } + + if (sc->cur_chan != sc->next_chan) { + sc->cur_chan->stopped = true; + spin_unlock_bh(&sc->chan_lock); + + if (sc->next_chan == &sc->offchannel.chan) { + getrawmonotonic(&ts); + measure_time = true; + } + __ath9k_flush(sc->hw, ~0, true); + + if (ath_chanctx_send_ps_frame(sc, true)) + __ath9k_flush(sc->hw, BIT(IEEE80211_AC_VO), false); + + send_ps = true; + spin_lock_bh(&sc->chan_lock); + + if (sc->cur_chan != &sc->offchannel.chan) { + getrawmonotonic(&sc->cur_chan->tsf_ts); + sc->cur_chan->tsf_val = ath9k_hw_gettsf64(sc->sc_ah); + } + } + sc->cur_chan = sc->next_chan; + sc->cur_chan->stopped = false; + sc->next_chan = NULL; + sc->sched.offchannel_duration = 0; + if (sc->sched.state != ATH_CHANCTX_STATE_FORCE_ACTIVE) + sc->sched.state = ATH_CHANCTX_STATE_IDLE; + + spin_unlock_bh(&sc->chan_lock); + + if (sc->sc_ah->chip_fullsleep || + memcmp(&sc->cur_chandef, &sc->cur_chan->chandef, + sizeof(sc->cur_chandef))) { + ath_set_channel(sc); + if (measure_time) + sc->sched.channel_switch_time = + ath9k_hw_get_tsf_offset(&ts, NULL); + } + if (send_ps) + ath_chanctx_send_ps_frame(sc, false); + + ath_offchannel_channel_change(sc); + ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_SWITCH); +} + static void ath_chanctx_work(struct work_struct *work) { struct ath_softc *sc = container_of(work, struct ath_softc, From 55254eeacae622075cedc59bb2e1da9573bad9da Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Sat, 23 Aug 2014 13:29:11 +0530 Subject: [PATCH 156/221] ath9k: Exclude more functions Use CONFIG_ATH9K_CHANNEL_CONTEXT to exclude more functions: ath_offchannel_channel_change() ath_scan_channel_start() ath_scan_send_probe() Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 1 - drivers/net/wireless/ath/ath9k/channel.c | 120 +++++++++++------------ 2 files changed, 60 insertions(+), 61 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index f9863e689cd2..3b4201caee5b 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -420,7 +420,6 @@ void ath_chanctx_set_channel(struct ath_softc *sc, struct ath_chanctx *ctx, void ath_chanctx_switch(struct ath_softc *sc, struct ath_chanctx *ctx, struct cfg80211_chan_def *chandef); void ath_chanctx_check_active(struct ath_softc *sc, struct ath_chanctx *ctx); -void ath_offchannel_channel_change(struct ath_softc *sc); void ath_chanctx_offchan_switch(struct ath_softc *sc, struct ieee80211_channel *chan); struct ath_chanctx *ath_chanctx_get_oper_chan(struct ath_softc *sc, diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index 61ed7a72c989..cd8af454cf46 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -16,23 +16,6 @@ #include "ath9k.h" -static const char *offchannel_state_string(enum ath_offchannel_state state) -{ -#define case_rtn_string(val) case val: return #val - - switch (state) { - case_rtn_string(ATH_OFFCHANNEL_IDLE); - case_rtn_string(ATH_OFFCHANNEL_PROBE_SEND); - case_rtn_string(ATH_OFFCHANNEL_PROBE_WAIT); - case_rtn_string(ATH_OFFCHANNEL_SUSPEND); - case_rtn_string(ATH_OFFCHANNEL_ROC_START); - case_rtn_string(ATH_OFFCHANNEL_ROC_WAIT); - case_rtn_string(ATH_OFFCHANNEL_ROC_DONE); - default: - return "unknown"; - } -} - /* Set/change channels. If the channel is really being changed, it's done * by reseting the chip. To accomplish this we must first cleanup any pending * DMA, then restart stuff. @@ -616,6 +599,25 @@ void ath_scan_complete(struct ath_softc *sc, bool abort) ath9k_ps_restore(sc); } +#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT + +static const char *offchannel_state_string(enum ath_offchannel_state state) +{ +#define case_rtn_string(val) case val: return #val + + switch (state) { + case_rtn_string(ATH_OFFCHANNEL_IDLE); + case_rtn_string(ATH_OFFCHANNEL_PROBE_SEND); + case_rtn_string(ATH_OFFCHANNEL_PROBE_WAIT); + case_rtn_string(ATH_OFFCHANNEL_SUSPEND); + case_rtn_string(ATH_OFFCHANNEL_ROC_START); + case_rtn_string(ATH_OFFCHANNEL_ROC_WAIT); + case_rtn_string(ATH_OFFCHANNEL_ROC_DONE); + default: + return "unknown"; + } +} + static void ath_scan_send_probe(struct ath_softc *sc, struct cfg80211_ssid *ssid) { @@ -674,49 +676,6 @@ static void ath_scan_channel_start(struct ath_softc *sc) mod_timer(&sc->offchannel.timer, jiffies + sc->offchannel.duration); } -void ath_offchannel_channel_change(struct ath_softc *sc) -{ - struct ath_common *common = ath9k_hw_common(sc->sc_ah); - - ath_dbg(common, CHAN_CTX, "%s: state: %s\n", - __func__, offchannel_state_string(sc->offchannel.state)); - - switch (sc->offchannel.state) { - case ATH_OFFCHANNEL_PROBE_SEND: - if (!sc->offchannel.scan_req) - return; - - if (sc->cur_chan->chandef.chan != - sc->offchannel.chan.chandef.chan) - return; - - ath_scan_channel_start(sc); - break; - case ATH_OFFCHANNEL_IDLE: - if (!sc->offchannel.scan_req) - return; - - ath_scan_complete(sc, false); - break; - case ATH_OFFCHANNEL_ROC_START: - if (sc->cur_chan != &sc->offchannel.chan) - break; - - sc->offchannel.state = ATH_OFFCHANNEL_ROC_WAIT; - mod_timer(&sc->offchannel.timer, jiffies + - msecs_to_jiffies(sc->offchannel.duration)); - ieee80211_ready_on_channel(sc->hw); - break; - case ATH_OFFCHANNEL_ROC_DONE: - ath_roc_complete(sc, false); - break; - default: - break; - } -} - -#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT - static void ath_chanctx_timer(unsigned long data) { struct ath_softc *sc = (struct ath_softc *) data; @@ -848,6 +807,47 @@ static bool ath_chanctx_defer_switch(struct ath_softc *sc) return true; } +static void ath_offchannel_channel_change(struct ath_softc *sc) +{ + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + + ath_dbg(common, CHAN_CTX, "%s: state: %s\n", + __func__, offchannel_state_string(sc->offchannel.state)); + + switch (sc->offchannel.state) { + case ATH_OFFCHANNEL_PROBE_SEND: + if (!sc->offchannel.scan_req) + return; + + if (sc->cur_chan->chandef.chan != + sc->offchannel.chan.chandef.chan) + return; + + ath_scan_channel_start(sc); + break; + case ATH_OFFCHANNEL_IDLE: + if (!sc->offchannel.scan_req) + return; + + ath_scan_complete(sc, false); + break; + case ATH_OFFCHANNEL_ROC_START: + if (sc->cur_chan != &sc->offchannel.chan) + break; + + sc->offchannel.state = ATH_OFFCHANNEL_ROC_WAIT; + mod_timer(&sc->offchannel.timer, jiffies + + msecs_to_jiffies(sc->offchannel.duration)); + ieee80211_ready_on_channel(sc->hw); + break; + case ATH_OFFCHANNEL_ROC_DONE: + ath_roc_complete(sc, false); + break; + default: + break; + } +} + void ath_chanctx_set_next(struct ath_softc *sc, bool force) { struct timespec ts; From 22dc0deb1ff9530be53e03d567fdf4554930ab86 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Sat, 23 Aug 2014 13:29:12 +0530 Subject: [PATCH 157/221] ath9k: Conditionally compile more functions Use CONFIG_ATH9K_CHANNEL_CONTEXT to exclude: ath_scan_complete() ath_roc_complete() ath_offchannel_next() ath_scan_next_channel() ath_scan_channel_duration() Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/channel.c | 38 ++++++++++++------------ 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index cd8af454cf46..8214b3276989 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -507,6 +507,25 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, spin_unlock_bh(&sc->chan_lock); } +#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT + +static const char *offchannel_state_string(enum ath_offchannel_state state) +{ +#define case_rtn_string(val) case val: return #val + + switch (state) { + case_rtn_string(ATH_OFFCHANNEL_IDLE); + case_rtn_string(ATH_OFFCHANNEL_PROBE_SEND); + case_rtn_string(ATH_OFFCHANNEL_PROBE_WAIT); + case_rtn_string(ATH_OFFCHANNEL_SUSPEND); + case_rtn_string(ATH_OFFCHANNEL_ROC_START); + case_rtn_string(ATH_OFFCHANNEL_ROC_WAIT); + case_rtn_string(ATH_OFFCHANNEL_ROC_DONE); + default: + return "unknown"; + } +} + static int ath_scan_channel_duration(struct ath_softc *sc, struct ieee80211_channel *chan) { @@ -599,25 +618,6 @@ void ath_scan_complete(struct ath_softc *sc, bool abort) ath9k_ps_restore(sc); } -#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT - -static const char *offchannel_state_string(enum ath_offchannel_state state) -{ -#define case_rtn_string(val) case val: return #val - - switch (state) { - case_rtn_string(ATH_OFFCHANNEL_IDLE); - case_rtn_string(ATH_OFFCHANNEL_PROBE_SEND); - case_rtn_string(ATH_OFFCHANNEL_PROBE_WAIT); - case_rtn_string(ATH_OFFCHANNEL_SUSPEND); - case_rtn_string(ATH_OFFCHANNEL_ROC_START); - case_rtn_string(ATH_OFFCHANNEL_ROC_WAIT); - case_rtn_string(ATH_OFFCHANNEL_ROC_DONE); - default: - return "unknown"; - } -} - static void ath_scan_send_probe(struct ath_softc *sc, struct cfg80211_ssid *ssid) { From 344ae6abd00f7662113d91daeafa6ba8d38ed831 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Sat, 23 Aug 2014 13:29:13 +0530 Subject: [PATCH 158/221] ath9k: Make ath_chanctx_offchan_switch static Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 2 -- drivers/net/wireless/ath/ath9k/channel.c | 26 ++++++++++++------------ 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 3b4201caee5b..a77abe7f7123 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -420,8 +420,6 @@ void ath_chanctx_set_channel(struct ath_softc *sc, struct ath_chanctx *ctx, void ath_chanctx_switch(struct ath_softc *sc, struct ath_chanctx *ctx, struct cfg80211_chan_def *chandef); void ath_chanctx_check_active(struct ath_softc *sc, struct ath_chanctx *ctx); -void ath_chanctx_offchan_switch(struct ath_softc *sc, - struct ieee80211_channel *chan); struct ath_chanctx *ath_chanctx_get_oper_chan(struct ath_softc *sc, bool active); void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index 8214b3276989..7c7178781cf8 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -244,19 +244,6 @@ struct ath_chanctx *ath_chanctx_get_oper_chan(struct ath_softc *sc, bool active) return &sc->chanctx[0]; } -void ath_chanctx_offchan_switch(struct ath_softc *sc, - struct ieee80211_channel *chan) -{ - struct ath_common *common = ath9k_hw_common(sc->sc_ah); - struct cfg80211_chan_def chandef; - - cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_NO_HT); - ath_dbg(common, CHAN_CTX, - "Channel definition created: %d MHz\n", chandef.center_freq1); - - ath_chanctx_switch(sc, &sc->offchannel.chan, &chandef); -} - static struct ath_chanctx * ath_chanctx_get_next(struct ath_softc *sc, struct ath_chanctx *ctx) { @@ -537,6 +524,19 @@ static int ath_scan_channel_duration(struct ath_softc *sc, return (HZ / 16); /* ~60 ms */ } +static void ath_chanctx_offchan_switch(struct ath_softc *sc, + struct ieee80211_channel *chan) +{ + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct cfg80211_chan_def chandef; + + cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_NO_HT); + ath_dbg(common, CHAN_CTX, + "Channel definition created: %d MHz\n", chandef.center_freq1); + + ath_chanctx_switch(sc, &sc->offchannel.chan, &chandef); +} + static void ath_scan_next_channel(struct ath_softc *sc) { From 98f411b80399c45a33f18b730eb36f489fba214a Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Sat, 23 Aug 2014 13:29:14 +0530 Subject: [PATCH 159/221] ath9k: Make ath_chanctx_get_oper_chan static Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 2 -- drivers/net/wireless/ath/ath9k/channel.c | 35 ++++++++++++------------ 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index a77abe7f7123..0371b30cec64 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -420,8 +420,6 @@ void ath_chanctx_set_channel(struct ath_softc *sc, struct ath_chanctx *ctx, void ath_chanctx_switch(struct ath_softc *sc, struct ath_chanctx *ctx, struct cfg80211_chan_def *chandef); void ath_chanctx_check_active(struct ath_softc *sc, struct ath_chanctx *ctx); -struct ath_chanctx *ath_chanctx_get_oper_chan(struct ath_softc *sc, - bool active); void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, enum ath_chanctx_event ev); void ath_offchannel_next(struct ath_softc *sc); diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index 7c7178781cf8..1950da4c73fe 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -227,23 +227,6 @@ void ath_chanctx_set_channel(struct ath_softc *sc, struct ath_chanctx *ctx, ath_set_channel(sc); } -struct ath_chanctx *ath_chanctx_get_oper_chan(struct ath_softc *sc, bool active) -{ - struct ath_chanctx *ctx; - - ath_for_each_chanctx(sc, ctx) { - if (!ctx->assigned || list_empty(&ctx->vifs)) - continue; - if (active && !ctx->active) - continue; - - if (ctx->switch_after_beacon) - return ctx; - } - - return &sc->chanctx[0]; -} - static struct ath_chanctx * ath_chanctx_get_next(struct ath_softc *sc, struct ath_chanctx *ctx) { @@ -537,6 +520,24 @@ static void ath_chanctx_offchan_switch(struct ath_softc *sc, ath_chanctx_switch(sc, &sc->offchannel.chan, &chandef); } +static struct ath_chanctx *ath_chanctx_get_oper_chan(struct ath_softc *sc, + bool active) +{ + struct ath_chanctx *ctx; + + ath_for_each_chanctx(sc, ctx) { + if (!ctx->assigned || list_empty(&ctx->vifs)) + continue; + if (active && !ctx->active) + continue; + + if (ctx->switch_after_beacon) + return ctx; + } + + return &sc->chanctx[0]; +} + static void ath_scan_next_channel(struct ath_softc *sc) { From 922c943dcc48fc0085daeaa3e8038c5446f226c2 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Sat, 23 Aug 2014 13:29:15 +0530 Subject: [PATCH 160/221] ath9k: Make ath_chanctx_switch static Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 2 - drivers/net/wireless/ath/ath9k/channel.c | 74 ++++++++++++------------ 2 files changed, 37 insertions(+), 39 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 0371b30cec64..2afe79053fec 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -417,8 +417,6 @@ ath_chanctx_get(struct ieee80211_chanctx_conf *ctx) void ath_chanctx_init(struct ath_softc *sc); void ath_chanctx_set_channel(struct ath_softc *sc, struct ath_chanctx *ctx, struct cfg80211_chan_def *chandef); -void ath_chanctx_switch(struct ath_softc *sc, struct ath_chanctx *ctx, - struct cfg80211_chan_def *chandef); void ath_chanctx_check_active(struct ath_softc *sc, struct ath_chanctx *ctx); void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, enum ath_chanctx_event ev); diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index 1950da4c73fe..ceb3ce8bb25a 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -173,43 +173,6 @@ void ath_chanctx_init(struct ath_softc *sc) } -void ath_chanctx_switch(struct ath_softc *sc, struct ath_chanctx *ctx, - struct cfg80211_chan_def *chandef) -{ - struct ath_common *common = ath9k_hw_common(sc->sc_ah); - - spin_lock_bh(&sc->chan_lock); - - if (test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags) && - (sc->cur_chan != ctx) && (ctx == &sc->offchannel.chan)) { - sc->sched.offchannel_pending = true; - spin_unlock_bh(&sc->chan_lock); - return; - } - - sc->next_chan = ctx; - if (chandef) { - ctx->chandef = *chandef; - ath_dbg(common, CHAN_CTX, - "Assigned next_chan to %d MHz\n", chandef->center_freq1); - } - - if (sc->next_chan == &sc->offchannel.chan) { - sc->sched.offchannel_duration = - TU_TO_USEC(sc->offchannel.duration) + - sc->sched.channel_switch_time; - - if (chandef) { - ath_dbg(common, CHAN_CTX, - "Offchannel duration for chan %d MHz : %u\n", - chandef->center_freq1, - sc->sched.offchannel_duration); - } - } - spin_unlock_bh(&sc->chan_lock); - ieee80211_queue_work(sc->hw, &sc->chanctx_work); -} - void ath_chanctx_set_channel(struct ath_softc *sc, struct ath_chanctx *ctx, struct cfg80211_chan_def *chandef) { @@ -507,6 +470,43 @@ static int ath_scan_channel_duration(struct ath_softc *sc, return (HZ / 16); /* ~60 ms */ } +static void ath_chanctx_switch(struct ath_softc *sc, struct ath_chanctx *ctx, + struct cfg80211_chan_def *chandef) +{ + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + + spin_lock_bh(&sc->chan_lock); + + if (test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags) && + (sc->cur_chan != ctx) && (ctx == &sc->offchannel.chan)) { + sc->sched.offchannel_pending = true; + spin_unlock_bh(&sc->chan_lock); + return; + } + + sc->next_chan = ctx; + if (chandef) { + ctx->chandef = *chandef; + ath_dbg(common, CHAN_CTX, + "Assigned next_chan to %d MHz\n", chandef->center_freq1); + } + + if (sc->next_chan == &sc->offchannel.chan) { + sc->sched.offchannel_duration = + TU_TO_USEC(sc->offchannel.duration) + + sc->sched.channel_switch_time; + + if (chandef) { + ath_dbg(common, CHAN_CTX, + "Offchannel duration for chan %d MHz : %u\n", + chandef->center_freq1, + sc->sched.offchannel_duration); + } + } + spin_unlock_bh(&sc->chan_lock); + ieee80211_queue_work(sc->hw, &sc->chanctx_work); +} + static void ath_chanctx_offchan_switch(struct ath_softc *sc, struct ieee80211_channel *chan) { From 27babf9f470b5e75763703626cae710a30bf703d Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Sat, 23 Aug 2014 13:29:16 +0530 Subject: [PATCH 161/221] ath9k: Fix channel context events Check if channel context usage is enabled before calling ath_chanctx_event() from various parts of the driver. Also, make sure that ath_chanctx_event() is compiled only when CONFIG_ATH9K_CHANNEL_CONTEXT is enabled. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 9 +++-- drivers/net/wireless/ath/ath9k/beacon.c | 13 ++++--- drivers/net/wireless/ath/ath9k/channel.c | 44 +++++++++++++----------- drivers/net/wireless/ath/ath9k/main.c | 8 +++-- drivers/net/wireless/ath/ath9k/recv.c | 9 +++-- drivers/net/wireless/ath/ath9k/xmit.c | 7 ++-- 6 files changed, 57 insertions(+), 33 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 2afe79053fec..5220f2ff5c8b 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -418,8 +418,6 @@ void ath_chanctx_init(struct ath_softc *sc); void ath_chanctx_set_channel(struct ath_softc *sc, struct ath_chanctx *ctx, struct cfg80211_chan_def *chandef); void ath_chanctx_check_active(struct ath_softc *sc, struct ath_chanctx *ctx); -void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, - enum ath_chanctx_event ev); void ath_offchannel_next(struct ath_softc *sc); void ath_scan_complete(struct ath_softc *sc, bool abort); void ath_roc_complete(struct ath_softc *sc, bool abort); @@ -438,6 +436,8 @@ void ath9k_p2p_bss_info_changed(struct ath_softc *sc, struct ieee80211_vif *vif); void ath9k_p2p_ps_timer(void *priv); +void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, + enum ath_chanctx_event ev); void ath_chanctx_set_next(struct ath_softc *sc, bool force); #else static inline bool ath9k_is_chanctx_enabled(void) @@ -453,6 +453,11 @@ static inline void ath9k_init_channel_context(struct ath_softc *sc) static inline void ath9k_deinit_channel_context(struct ath_softc *sc) { } +static inline void ath_chanctx_event(struct ath_softc *sc, + struct ieee80211_vif *vif, + enum ath_chanctx_event ev) +{ +} static inline int ath9k_init_p2p(struct ath_softc *sc) { return 0; diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index eaf8f058c151..68c95d42e3d5 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -427,9 +427,11 @@ void ath9k_beacon_tasklet(unsigned long data) /* EDMA devices check that in the tx completion function. */ if (!edma) { - if (sc->sched.beacon_pending) - ath_chanctx_event(sc, NULL, - ATH_CHANCTX_EVENT_BEACON_SENT); + if (ath9k_is_chanctx_enabled()) { + if (sc->sched.beacon_pending) + ath_chanctx_event(sc, NULL, + ATH_CHANCTX_EVENT_BEACON_SENT); + } if (ath9k_csa_is_finished(sc, vif)) return; @@ -438,7 +440,10 @@ void ath9k_beacon_tasklet(unsigned long data) if (!vif || !vif->bss_conf.enable_beacon) return; - ath_chanctx_event(sc, vif, ATH_CHANCTX_EVENT_BEACON_PREPARE); + if (ath9k_is_chanctx_enabled()) { + ath_chanctx_event(sc, vif, ATH_CHANCTX_EVENT_BEACON_PREPARE); + } + bf = ath9k_beacon_generate(sc->hw, vif); if (sc->beacon.bmisscnt != 0) { diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index ceb3ce8bb25a..ae0b3f9530f1 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -139,7 +139,11 @@ void ath_chanctx_check_active(struct ath_softc *sc, struct ath_chanctx *ctx) } if (test_and_set_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags)) return; - ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_ENABLE_MULTICHANNEL); + + if (ath9k_is_chanctx_enabled()) { + ath_chanctx_event(sc, NULL, + ATH_CHANCTX_EVENT_ENABLE_MULTICHANNEL); + } } void ath_chanctx_init(struct ath_softc *sc) @@ -190,6 +194,25 @@ void ath_chanctx_set_channel(struct ath_softc *sc, struct ath_chanctx *ctx, ath_set_channel(sc); } +#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT + +static const char *offchannel_state_string(enum ath_offchannel_state state) +{ +#define case_rtn_string(val) case val: return #val + + switch (state) { + case_rtn_string(ATH_OFFCHANNEL_IDLE); + case_rtn_string(ATH_OFFCHANNEL_PROBE_SEND); + case_rtn_string(ATH_OFFCHANNEL_PROBE_WAIT); + case_rtn_string(ATH_OFFCHANNEL_SUSPEND); + case_rtn_string(ATH_OFFCHANNEL_ROC_START); + case_rtn_string(ATH_OFFCHANNEL_ROC_WAIT); + case_rtn_string(ATH_OFFCHANNEL_ROC_DONE); + default: + return "unknown"; + } +} + static struct ath_chanctx * ath_chanctx_get_next(struct ath_softc *sc, struct ath_chanctx *ctx) { @@ -440,25 +463,6 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, spin_unlock_bh(&sc->chan_lock); } -#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT - -static const char *offchannel_state_string(enum ath_offchannel_state state) -{ -#define case_rtn_string(val) case val: return #val - - switch (state) { - case_rtn_string(ATH_OFFCHANNEL_IDLE); - case_rtn_string(ATH_OFFCHANNEL_PROBE_SEND); - case_rtn_string(ATH_OFFCHANNEL_PROBE_WAIT); - case_rtn_string(ATH_OFFCHANNEL_SUSPEND); - case_rtn_string(ATH_OFFCHANNEL_ROC_START); - case_rtn_string(ATH_OFFCHANNEL_ROC_WAIT); - case_rtn_string(ATH_OFFCHANNEL_ROC_DONE); - default: - return "unknown"; - } -} - static int ath_scan_channel_duration(struct ath_softc *sc, struct ieee80211_channel *chan) { diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 4659168b0394..30e0db215387 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1684,8 +1684,12 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, bss_conf->bssid, bss_conf->assoc); ath9k_calculate_summary_state(sc, avp->chanctx); - if (bss_conf->assoc) - ath_chanctx_event(sc, vif, ATH_CHANCTX_EVENT_ASSOC); + + if (ath9k_is_chanctx_enabled()) { + if (bss_conf->assoc) + ath_chanctx_event(sc, vif, + ATH_CHANCTX_EVENT_ASSOC); + } } if (changed & BSS_CHANGED_IBSS) { diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index ae0d1e913690..cc91749035cf 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -892,9 +892,12 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc, return -EINVAL; } - if (rx_stats->is_mybeacon) { - sc->sched.next_tbtt = rx_stats->rs_tstamp; - ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_BEACON_RECEIVED); + if (ath9k_is_chanctx_enabled()) { + if (rx_stats->is_mybeacon) { + sc->sched.next_tbtt = rx_stats->rs_tstamp; + ath_chanctx_event(sc, NULL, + ATH_CHANCTX_EVENT_BEACON_RECEIVED); + } } ath9k_cmn_process_rssi(common, hw, rx_stats, rx_status); diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 704fcbcbe20b..281986613fb2 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -2632,8 +2632,11 @@ void ath_tx_edma_tasklet(struct ath_softc *sc) sc->beacon.tx_processed = true; sc->beacon.tx_last = !(ts.ts_status & ATH9K_TXERR_MASK); - ath_chanctx_event(sc, NULL, - ATH_CHANCTX_EVENT_BEACON_SENT); + if (ath9k_is_chanctx_enabled()) { + ath_chanctx_event(sc, NULL, + ATH_CHANCTX_EVENT_BEACON_SENT); + } + ath9k_csa_update(sc); continue; } From 73b5ef0bbfa03ba31bcaf781bc38b7af38e6999b Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Sat, 23 Aug 2014 13:29:17 +0530 Subject: [PATCH 162/221] ath9k: Fix function declarations These routines are required only when CONFIG_ATH9K_CHANNEL_CONTEXT is enabled. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 5220f2ff5c8b..8cf8e4f2e4f0 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -418,9 +418,6 @@ void ath_chanctx_init(struct ath_softc *sc); void ath_chanctx_set_channel(struct ath_softc *sc, struct ath_chanctx *ctx, struct cfg80211_chan_def *chandef); void ath_chanctx_check_active(struct ath_softc *sc, struct ath_chanctx *ctx); -void ath_offchannel_next(struct ath_softc *sc); -void ath_scan_complete(struct ath_softc *sc, bool abort); -void ath_roc_complete(struct ath_softc *sc, bool abort); #ifdef CONFIG_ATH9K_CHANNEL_CONTEXT bool ath9k_is_chanctx_enabled(void); @@ -439,6 +436,9 @@ void ath9k_p2p_ps_timer(void *priv); void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, enum ath_chanctx_event ev); void ath_chanctx_set_next(struct ath_softc *sc, bool force); +void ath_offchannel_next(struct ath_softc *sc); +void ath_scan_complete(struct ath_softc *sc, bool abort); +void ath_roc_complete(struct ath_softc *sc, bool abort); #else static inline bool ath9k_is_chanctx_enabled(void) { From 70b06dacfe8bd1f62de058e2116388b8f7c58531 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Sat, 23 Aug 2014 13:29:18 +0530 Subject: [PATCH 163/221] ath9k: Add wrappers for beacon events Using these wrappers allows us to move the 'sched' variable in ath_softc inside CONFIG_ATH9K_CHANNEL_CONTEXT. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 14 +++++++++++++- drivers/net/wireless/ath/ath9k/beacon.c | 5 ++--- drivers/net/wireless/ath/ath9k/channel.c | 14 ++++++++++++++ drivers/net/wireless/ath/ath9k/recv.c | 8 +++----- 4 files changed, 32 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 8cf8e4f2e4f0..352c5dabdf75 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -433,6 +433,10 @@ void ath9k_p2p_bss_info_changed(struct ath_softc *sc, struct ieee80211_vif *vif); void ath9k_p2p_ps_timer(void *priv); +void ath_chanctx_beacon_recv_ev(struct ath_softc *sc, u32 ts, + enum ath_chanctx_event ev); +void ath_chanctx_beacon_sent_ev(struct ath_softc *sc, + enum ath_chanctx_event ev); void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, enum ath_chanctx_event ev); void ath_chanctx_set_next(struct ath_softc *sc, bool force); @@ -453,6 +457,14 @@ static inline void ath9k_init_channel_context(struct ath_softc *sc) static inline void ath9k_deinit_channel_context(struct ath_softc *sc) { } +static inline void ath_chanctx_beacon_recv_ev(struct ath_softc *sc, u32 ts, + enum ath_chanctx_event ev) +{ +} +static inline void ath_chanctx_beacon_sent_ev(struct ath_softc *sc, + enum ath_chanctx_event ev) +{ +} static inline void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, enum ath_chanctx_event ev) @@ -901,6 +913,7 @@ struct ath_softc { #ifdef CONFIG_ATH9K_CHANNEL_CONTEXT struct ath_gen_timer *p2p_ps_timer; struct ath_vif *p2p_ps_vif; + struct ath_chanctx_sched sched; #endif unsigned long driver_data; @@ -925,7 +938,6 @@ struct ath_softc { struct ath_chanctx *next_chan; spinlock_t chan_lock; struct ath_offchannel offchannel; - struct ath_chanctx_sched sched; #ifdef CONFIG_MAC80211_LEDS bool led_registered; diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 68c95d42e3d5..dc68d114f2fd 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -428,9 +428,8 @@ void ath9k_beacon_tasklet(unsigned long data) /* EDMA devices check that in the tx completion function. */ if (!edma) { if (ath9k_is_chanctx_enabled()) { - if (sc->sched.beacon_pending) - ath_chanctx_event(sc, NULL, - ATH_CHANCTX_EVENT_BEACON_SENT); + ath_chanctx_beacon_sent_ev(sc, + ATH_CHANCTX_EVENT_BEACON_SENT); } if (ath9k_csa_is_finished(sc, vif)) diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index ae0b3f9530f1..39df24c964c3 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -463,6 +463,20 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, spin_unlock_bh(&sc->chan_lock); } +void ath_chanctx_beacon_sent_ev(struct ath_softc *sc, + enum ath_chanctx_event ev) +{ + if (sc->sched.beacon_pending) + ath_chanctx_event(sc, NULL, ev); +} + +void ath_chanctx_beacon_recv_ev(struct ath_softc *sc, u32 ts, + enum ath_chanctx_event ev) +{ + sc->sched.next_tbtt = ts; + ath_chanctx_event(sc, NULL, ev); +} + static int ath_scan_channel_duration(struct ath_softc *sc, struct ieee80211_channel *chan) { diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index cc91749035cf..2aaf233ee5d6 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -893,11 +893,9 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc, } if (ath9k_is_chanctx_enabled()) { - if (rx_stats->is_mybeacon) { - sc->sched.next_tbtt = rx_stats->rs_tstamp; - ath_chanctx_event(sc, NULL, - ATH_CHANCTX_EVENT_BEACON_RECEIVED); - } + if (rx_stats->is_mybeacon) + ath_chanctx_beacon_recv_ev(sc, rx_stats->rs_tstamp, + ATH_CHANCTX_EVENT_BEACON_RECEIVED); } ath9k_cmn_process_rssi(common, hw, rx_stats, rx_status); From 0e08b5fb81111662bf9fa5f67f8a412791923b6f Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Sat, 23 Aug 2014 13:29:19 +0530 Subject: [PATCH 164/221] ath9k: Add ath9k_chanctx_wake_queues Introduce a function that handles queues in channel context mode. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 4 ++++ drivers/net/wireless/ath/ath9k/channel.c | 26 ++++++++++++++++++++++++ drivers/net/wireless/ath/ath9k/main.c | 15 ++------------ 3 files changed, 32 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 352c5dabdf75..892ca4af75ef 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -432,6 +432,7 @@ void ath9k_p2p_beacon_sync(struct ath_softc *sc); void ath9k_p2p_bss_info_changed(struct ath_softc *sc, struct ieee80211_vif *vif); void ath9k_p2p_ps_timer(void *priv); +void ath9k_chanctx_wake_queues(struct ath_softc *sc); void ath_chanctx_beacon_recv_ev(struct ath_softc *sc, u32 ts, enum ath_chanctx_event ev); @@ -491,6 +492,9 @@ static inline void ath9k_p2p_bss_info_changed(struct ath_softc *sc, static inline void ath9k_p2p_ps_timer(struct ath_softc *sc) { } +static inline void ath9k_chanctx_wake_queues(struct ath_softc *sc) +{ +} #endif /* CONFIG_ATH9K_CHANNEL_CONTEXT */ int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan); diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index 39df24c964c3..f719c36fe47d 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -196,6 +196,10 @@ void ath_chanctx_set_channel(struct ath_softc *sc, struct ath_chanctx *ctx, #ifdef CONFIG_ATH9K_CHANNEL_CONTEXT +/**********************************************************/ +/* Functions to handle the channel context state machine. */ +/**********************************************************/ + static const char *offchannel_state_string(enum ath_offchannel_state state) { #define case_rtn_string(val) case val: return #val @@ -958,6 +962,28 @@ bool ath9k_is_chanctx_enabled(void) return (ath9k_use_chanctx == 1); } +/********************/ +/* Queue management */ +/********************/ + +void ath9k_chanctx_wake_queues(struct ath_softc *sc) +{ + struct ath_hw *ah = sc->sc_ah; + int i; + + if (sc->cur_chan == &sc->offchannel.chan) { + ieee80211_wake_queue(sc->hw, + sc->hw->offchannel_tx_hw_queue); + } else { + for (i = 0; i < IEEE80211_NUM_ACS; i++) + ieee80211_wake_queue(sc->hw, + sc->cur_chan->hw_queue_base + i); + } + + if (ah->opmode == NL80211_IFTYPE_AP) + ieee80211_wake_queue(sc->hw, sc->hw->queues - 2); +} + /*****************/ /* P2P Powersave */ /*****************/ diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 30e0db215387..e31f130b5137 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -223,7 +223,6 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start) struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); unsigned long flags; - int i; if (ath_startrecv(sc) != 0) { ath_err(common, "Unable to restart recv logic\n"); @@ -270,18 +269,8 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start) if (!ath9k_is_chanctx_enabled()) ieee80211_wake_queues(sc->hw); - else { - if (sc->cur_chan == &sc->offchannel.chan) - ieee80211_wake_queue(sc->hw, - sc->hw->offchannel_tx_hw_queue); - else { - for (i = 0; i < IEEE80211_NUM_ACS; i++) - ieee80211_wake_queue(sc->hw, - sc->cur_chan->hw_queue_base + i); - } - if (ah->opmode == NL80211_IFTYPE_AP) - ieee80211_wake_queue(sc->hw, sc->hw->queues - 2); - } + else + ath9k_chanctx_wake_queues(sc); ath9k_p2p_ps_timer(sc); From e90e302a15b85ed27bdc148be2eed50c8aaaee06 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Sat, 23 Aug 2014 13:29:20 +0530 Subject: [PATCH 165/221] ath9k: Add ath9k_offchannel_init This patch adds a routine to setup the offchannel instance in ath_softc. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 4 +++ drivers/net/wireless/ath/ath9k/channel.c | 33 ++++++++++++++++++------ drivers/net/wireless/ath/ath9k/init.c | 1 + 3 files changed, 30 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 892ca4af75ef..5b8bc5dd007e 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -423,6 +423,7 @@ void ath_chanctx_check_active(struct ath_softc *sc, struct ath_chanctx *ctx); bool ath9k_is_chanctx_enabled(void); void ath9k_fill_chanctx_ops(void); void ath9k_init_channel_context(struct ath_softc *sc); +void ath9k_offchannel_init(struct ath_softc *sc); void ath9k_deinit_channel_context(struct ath_softc *sc); int ath9k_init_p2p(struct ath_softc *sc); void ath9k_deinit_p2p(struct ath_softc *sc); @@ -455,6 +456,9 @@ static inline void ath9k_fill_chanctx_ops(void) static inline void ath9k_init_channel_context(struct ath_softc *sc) { } +static inline void ath9k_offchannel_init(struct ath_softc *sc) +{ +} static inline void ath9k_deinit_channel_context(struct ath_softc *sc) { } diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index f719c36fe47d..d1ad5a2db2be 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -167,14 +167,6 @@ void ath_chanctx_init(struct ath_softc *sc) for (j = 0; j < ARRAY_SIZE(ctx->acq); j++) INIT_LIST_HEAD(&ctx->acq[j]); } - ctx = &sc->offchannel.chan; - cfg80211_chandef_create(&ctx->chandef, chan, NL80211_CHAN_HT20); - INIT_LIST_HEAD(&ctx->vifs); - ctx->txpower = ATH_TXPOWER_MAX; - for (j = 0; j < ARRAY_SIZE(ctx->acq); j++) - INIT_LIST_HEAD(&ctx->acq[j]); - sc->offchannel.chan.offchannel = true; - } void ath_chanctx_set_channel(struct ath_softc *sc, struct ath_chanctx *ctx, @@ -942,6 +934,31 @@ static void ath_chanctx_work(struct work_struct *work) mutex_unlock(&sc->mutex); } +void ath9k_offchannel_init(struct ath_softc *sc) +{ + struct ath_chanctx *ctx; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ieee80211_supported_band *sband; + struct ieee80211_channel *chan; + int i; + + sband = &common->sbands[IEEE80211_BAND_2GHZ]; + if (!sband->n_channels) + sband = &common->sbands[IEEE80211_BAND_5GHZ]; + + chan = &sband->channels[0]; + + ctx = &sc->offchannel.chan; + INIT_LIST_HEAD(&ctx->vifs); + ctx->txpower = ATH_TXPOWER_MAX; + cfg80211_chandef_create(&ctx->chandef, chan, NL80211_CHAN_HT20); + + for (i = 0; i < ARRAY_SIZE(ctx->acq); i++) + INIT_LIST_HEAD(&ctx->acq[i]); + + sc->offchannel.chan.offchannel = true; +} + void ath9k_init_channel_context(struct ath_softc *sc) { INIT_WORK(&sc->chanctx_work, ath_chanctx_work); diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index fe0311a0cd23..5887499a3838 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -610,6 +610,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, ath9k_init_misc(sc); ath_fill_led_pin(sc); ath_chanctx_init(sc); + ath9k_offchannel_init(sc); if (common->bus_ops->aspm_init) common->bus_ops->aspm_init(common); From a09798f4abb30f13f141e24ae496ba75e97995da Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Sat, 23 Aug 2014 13:29:21 +0530 Subject: [PATCH 166/221] ath9k: Use ath_chanctx_check_active properly ath_chanctx_check_active() is required only when channel contexts are used. Make sure that it is not called in normal usage. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 7 +- drivers/net/wireless/ath/ath9k/channel.c | 90 ++++++++++++------------ 2 files changed, 50 insertions(+), 47 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 5b8bc5dd007e..8767aa7360ca 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -417,8 +417,6 @@ ath_chanctx_get(struct ieee80211_chanctx_conf *ctx) void ath_chanctx_init(struct ath_softc *sc); void ath_chanctx_set_channel(struct ath_softc *sc, struct ath_chanctx *ctx, struct cfg80211_chan_def *chandef); -void ath_chanctx_check_active(struct ath_softc *sc, struct ath_chanctx *ctx); - #ifdef CONFIG_ATH9K_CHANNEL_CONTEXT bool ath9k_is_chanctx_enabled(void); void ath9k_fill_chanctx_ops(void); @@ -434,6 +432,7 @@ void ath9k_p2p_bss_info_changed(struct ath_softc *sc, struct ieee80211_vif *vif); void ath9k_p2p_ps_timer(void *priv); void ath9k_chanctx_wake_queues(struct ath_softc *sc); +void ath_chanctx_check_active(struct ath_softc *sc, struct ath_chanctx *ctx); void ath_chanctx_beacon_recv_ev(struct ath_softc *sc, u32 ts, enum ath_chanctx_event ev); @@ -499,6 +498,10 @@ static inline void ath9k_p2p_ps_timer(struct ath_softc *sc) static inline void ath9k_chanctx_wake_queues(struct ath_softc *sc) { } +static inline void ath_chanctx_check_active(struct ath_softc *sc, + struct ath_chanctx *ctx) +{ +} #endif /* CONFIG_ATH9K_CHANNEL_CONTEXT */ int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan); diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index d1ad5a2db2be..08bb14c1db82 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -101,51 +101,6 @@ static int ath_set_channel(struct ath_softc *sc) return 0; } -void ath_chanctx_check_active(struct ath_softc *sc, struct ath_chanctx *ctx) -{ - struct ath_common *common = ath9k_hw_common(sc->sc_ah); - struct ath_vif *avp; - bool active = false; - u8 n_active = 0; - - if (!ctx) - return; - - list_for_each_entry(avp, &ctx->vifs, list) { - struct ieee80211_vif *vif = avp->vif; - - switch (vif->type) { - case NL80211_IFTYPE_P2P_CLIENT: - case NL80211_IFTYPE_STATION: - if (vif->bss_conf.assoc) - active = true; - break; - default: - active = true; - break; - } - } - ctx->active = active; - - ath_for_each_chanctx(sc, ctx) { - if (!ctx->assigned || list_empty(&ctx->vifs)) - continue; - n_active++; - } - - if (n_active <= 1) { - clear_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags); - return; - } - if (test_and_set_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags)) - return; - - if (ath9k_is_chanctx_enabled()) { - ath_chanctx_event(sc, NULL, - ATH_CHANCTX_EVENT_ENABLE_MULTICHANNEL); - } -} - void ath_chanctx_init(struct ath_softc *sc) { struct ath_chanctx *ctx; @@ -209,6 +164,51 @@ static const char *offchannel_state_string(enum ath_offchannel_state state) } } +void ath_chanctx_check_active(struct ath_softc *sc, struct ath_chanctx *ctx) +{ + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_vif *avp; + bool active = false; + u8 n_active = 0; + + if (!ctx) + return; + + list_for_each_entry(avp, &ctx->vifs, list) { + struct ieee80211_vif *vif = avp->vif; + + switch (vif->type) { + case NL80211_IFTYPE_P2P_CLIENT: + case NL80211_IFTYPE_STATION: + if (vif->bss_conf.assoc) + active = true; + break; + default: + active = true; + break; + } + } + ctx->active = active; + + ath_for_each_chanctx(sc, ctx) { + if (!ctx->assigned || list_empty(&ctx->vifs)) + continue; + n_active++; + } + + if (n_active <= 1) { + clear_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags); + return; + } + if (test_and_set_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags)) + return; + + if (ath9k_is_chanctx_enabled()) { + ath_chanctx_event(sc, NULL, + ATH_CHANCTX_EVENT_ENABLE_MULTICHANNEL); + } +} + static struct ath_chanctx * ath_chanctx_get_next(struct ath_softc *sc, struct ath_chanctx *ctx) { From 4b93fd297fe9914e41099d37194f7acc6a1ccb48 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Sat, 23 Aug 2014 13:29:22 +0530 Subject: [PATCH 167/221] ath9k: Fix function argument type ath9k_vif_iter() was earlier used as an iterator routine when calling a mac80211 utility. This is no longer the case and hence we can mention the argument type explicitly. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index e31f130b5137..bc7a780a2400 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -893,9 +893,9 @@ static bool ath9k_uses_beacons(int type) } } -static void ath9k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) +static void ath9k_vif_iter(struct ath9k_vif_iter_data *iter_data, + u8 *mac, struct ieee80211_vif *vif) { - struct ath9k_vif_iter_data *iter_data = data; int i; if (iter_data->has_hw_macaddr) { From 77843167a926a1b11dff812f027fc56930948c1b Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Sat, 23 Aug 2014 13:29:23 +0530 Subject: [PATCH 168/221] ath9k: Fix 'offchannel' in ath_softc Finally move the 'offchannel' instance in ath_softc inside a CONFIG_ATH9K_CHANNEL_CONTEXT cage. The offchannel usage in ath9k_calculate_iter_data() is closed off with an ifdef for now, since the state/opmode calculation is common for both the channel context mode and the normal mode. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 2 +- drivers/net/wireless/ath/ath9k/main.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 8767aa7360ca..02664b3c7c52 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -925,6 +925,7 @@ struct ath_softc { struct ath_gen_timer *p2p_ps_timer; struct ath_vif *p2p_ps_vif; struct ath_chanctx_sched sched; + struct ath_offchannel offchannel; #endif unsigned long driver_data; @@ -948,7 +949,6 @@ struct ath_softc { struct ath_chanctx *cur_chan; struct ath_chanctx *next_chan; spinlock_t chan_lock; - struct ath_offchannel offchannel; #ifdef CONFIG_MAC80211_LEDS bool led_registered; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index bc7a780a2400..da63487279df 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -958,6 +958,7 @@ void ath9k_calculate_iter_data(struct ath_softc *sc, list_for_each_entry(avp, &ctx->vifs, list) ath9k_vif_iter(iter_data, avp->vif->addr, avp->vif); +#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT if (ctx == &sc->offchannel.chan) { struct ieee80211_vif *vif; @@ -970,6 +971,7 @@ void ath9k_calculate_iter_data(struct ath_softc *sc, ath9k_vif_iter(iter_data, vif->addr, vif); iter_data->beacons = false; } +#endif } static void ath9k_set_assoc_state(struct ath_softc *sc, From fb02e95c9b3d76b658288af0c8a362c85f9d6d44 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Sat, 23 Aug 2014 19:12:13 +0530 Subject: [PATCH 169/221] ath9k: Fix channel context variables in ath_softc chanctx_work and next_chan are required only when CONFIG_ATH9K_CHANNEL_CONTEXT is enabled. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 02664b3c7c52..a2f4fa78ce76 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -324,6 +324,10 @@ struct ath_rx { u32 ampdu_ref; }; +/*******************/ +/* Channel Context */ +/*******************/ + struct ath_chanctx { struct cfg80211_chan_def chandef; struct list_head vifs; @@ -917,15 +921,16 @@ struct ath_softc { struct mutex mutex; struct work_struct paprd_work; struct work_struct hw_reset_work; - struct work_struct chanctx_work; struct completion paprd_complete; wait_queue_head_t tx_wait; #ifdef CONFIG_ATH9K_CHANNEL_CONTEXT + struct work_struct chanctx_work; struct ath_gen_timer *p2p_ps_timer; struct ath_vif *p2p_ps_vif; struct ath_chanctx_sched sched; struct ath_offchannel offchannel; + struct ath_chanctx *next_chan; #endif unsigned long driver_data; @@ -947,7 +952,6 @@ struct ath_softc { struct cfg80211_chan_def cur_chandef; struct ath_chanctx chanctx[ATH9K_NUM_CHANCTX]; struct ath_chanctx *cur_chan; - struct ath_chanctx *next_chan; spinlock_t chan_lock; #ifdef CONFIG_MAC80211_LEDS From 7d876174e7cd81912930cb5e501f5036eabfaaf3 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Sat, 23 Aug 2014 19:12:14 +0530 Subject: [PATCH 170/221] ath9k: Remove redundant ifdef This was introduced in an earlier patch to handle a compilation warning, but since the channel context code has been mostly isolated, this is not required now. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/channel.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index 08bb14c1db82..7aa953545c07 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -257,9 +257,7 @@ static void ath_chanctx_setup_timer(struct ath_softc *sc, u32 tsf_time) { struct ath_hw *ah = sc->sc_ah; -#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT ath9k_hw_gen_timer_start(ah, sc->p2p_ps_timer, tsf_time, 1000000); -#endif tsf_time -= ath9k_hw_gettsf32(ah); tsf_time = msecs_to_jiffies(tsf_time / 1000) + 1; mod_timer(&sc->sched.timer, tsf_time); From 11e39a4e054cde1aaa9f5d3830f41f86818602fd Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Sat, 23 Aug 2014 19:12:15 +0530 Subject: [PATCH 171/221] ath9k: Move ath9k_beacon_add_noa to channel.c Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 7 ++++ drivers/net/wireless/ath/ath9k/beacon.c | 49 ------------------------ drivers/net/wireless/ath/ath9k/channel.c | 49 ++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 49 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index a2f4fa78ce76..9e61679b3de2 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -31,6 +31,7 @@ #include "spectral.h" struct ath_node; +struct ath_vif; extern struct ieee80211_ops ath9k_ops; extern int ath9k_modparam_nohwcrypt; @@ -434,6 +435,8 @@ void ath9k_p2p_remove_vif(struct ath_softc *sc, void ath9k_p2p_beacon_sync(struct ath_softc *sc); void ath9k_p2p_bss_info_changed(struct ath_softc *sc, struct ieee80211_vif *vif); +void ath9k_beacon_add_noa(struct ath_softc *sc, struct ath_vif *avp, + struct sk_buff *skb); void ath9k_p2p_ps_timer(void *priv); void ath9k_chanctx_wake_queues(struct ath_softc *sc); void ath_chanctx_check_active(struct ath_softc *sc, struct ath_chanctx *ctx); @@ -496,6 +499,10 @@ static inline void ath9k_p2p_bss_info_changed(struct ath_softc *sc, struct ieee80211_vif *vif) { } +static inline void ath9k_beacon_add_noa(struct ath_softc *sc, struct ath_vif *avp, + struct sk_buff *skb) +{ +} static inline void ath9k_p2p_ps_timer(struct ath_softc *sc) { } diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index dc68d114f2fd..b2f56d8b9043 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -108,55 +108,6 @@ static void ath9k_beacon_setup(struct ath_softc *sc, struct ieee80211_vif *vif, ath9k_hw_set_txdesc(ah, bf->bf_desc, &info); } -static void ath9k_beacon_add_noa(struct ath_softc *sc, struct ath_vif *avp, - struct sk_buff *skb) -{ - static const u8 noa_ie_hdr[] = { - WLAN_EID_VENDOR_SPECIFIC, /* type */ - 0, /* length */ - 0x50, 0x6f, 0x9a, /* WFA OUI */ - 0x09, /* P2P subtype */ - 0x0c, /* Notice of Absence */ - 0x00, /* LSB of little-endian len */ - 0x00, /* MSB of little-endian len */ - }; - - struct ieee80211_p2p_noa_attr *noa; - int noa_len, noa_desc, i = 0; - u8 *hdr; - - if (!avp->offchannel_duration && !avp->periodic_noa_duration) - return; - - noa_desc = !!avp->offchannel_duration + !!avp->periodic_noa_duration; - noa_len = 2 + sizeof(struct ieee80211_p2p_noa_desc) * noa_desc; - - hdr = skb_put(skb, sizeof(noa_ie_hdr)); - memcpy(hdr, noa_ie_hdr, sizeof(noa_ie_hdr)); - hdr[1] = sizeof(noa_ie_hdr) + noa_len - 2; - hdr[7] = noa_len; - - noa = (void *) skb_put(skb, noa_len); - memset(noa, 0, noa_len); - - noa->index = avp->noa_index; - if (avp->periodic_noa_duration) { - u32 interval = TU_TO_USEC(sc->cur_chan->beacon.beacon_interval); - - noa->desc[i].count = 255; - noa->desc[i].start_time = cpu_to_le32(avp->periodic_noa_start); - noa->desc[i].duration = cpu_to_le32(avp->periodic_noa_duration); - noa->desc[i].interval = cpu_to_le32(interval); - i++; - } - - if (avp->offchannel_duration) { - noa->desc[i].count = 1; - noa->desc[i].start_time = cpu_to_le32(avp->offchannel_start); - noa->desc[i].duration = cpu_to_le32(avp->offchannel_duration); - } -} - static struct ath_buf *ath9k_beacon_generate(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index 7aa953545c07..0e64b736160e 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -1042,6 +1042,55 @@ static void ath9k_update_p2p_ps(struct ath_softc *sc, struct ieee80211_vif *vif) ath9k_update_p2p_ps_timer(sc, avp); } +void ath9k_beacon_add_noa(struct ath_softc *sc, struct ath_vif *avp, + struct sk_buff *skb) +{ + static const u8 noa_ie_hdr[] = { + WLAN_EID_VENDOR_SPECIFIC, /* type */ + 0, /* length */ + 0x50, 0x6f, 0x9a, /* WFA OUI */ + 0x09, /* P2P subtype */ + 0x0c, /* Notice of Absence */ + 0x00, /* LSB of little-endian len */ + 0x00, /* MSB of little-endian len */ + }; + + struct ieee80211_p2p_noa_attr *noa; + int noa_len, noa_desc, i = 0; + u8 *hdr; + + if (!avp->offchannel_duration && !avp->periodic_noa_duration) + return; + + noa_desc = !!avp->offchannel_duration + !!avp->periodic_noa_duration; + noa_len = 2 + sizeof(struct ieee80211_p2p_noa_desc) * noa_desc; + + hdr = skb_put(skb, sizeof(noa_ie_hdr)); + memcpy(hdr, noa_ie_hdr, sizeof(noa_ie_hdr)); + hdr[1] = sizeof(noa_ie_hdr) + noa_len - 2; + hdr[7] = noa_len; + + noa = (void *) skb_put(skb, noa_len); + memset(noa, 0, noa_len); + + noa->index = avp->noa_index; + if (avp->periodic_noa_duration) { + u32 interval = TU_TO_USEC(sc->cur_chan->beacon.beacon_interval); + + noa->desc[i].count = 255; + noa->desc[i].start_time = cpu_to_le32(avp->periodic_noa_start); + noa->desc[i].duration = cpu_to_le32(avp->periodic_noa_duration); + noa->desc[i].interval = cpu_to_le32(interval); + i++; + } + + if (avp->offchannel_duration) { + noa->desc[i].count = 1; + noa->desc[i].start_time = cpu_to_le32(avp->offchannel_start); + noa->desc[i].duration = cpu_to_le32(avp->offchannel_duration); + } +} + void ath9k_p2p_ps_timer(void *priv) { struct ath_softc *sc = priv; From 6e47fafbc38a93797f86413db8eea3e9319ebbd0 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Sat, 23 Aug 2014 19:12:16 +0530 Subject: [PATCH 172/221] ath9k: Fix ath_chanctx_get() Move it inside a CONFIG_ATH9K_CHANNEL_CONTEXT ifdef since it is not needed otherwise. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 9e61679b3de2..acbe2b7956ae 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -413,16 +413,19 @@ struct ath_offchannel { ctx <= &sc->chanctx[ARRAY_SIZE(sc->chanctx) - 1]; \ ctx++) +void ath_chanctx_init(struct ath_softc *sc); +void ath_chanctx_set_channel(struct ath_softc *sc, struct ath_chanctx *ctx, + struct cfg80211_chan_def *chandef); + +#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT + static inline struct ath_chanctx * ath_chanctx_get(struct ieee80211_chanctx_conf *ctx) { struct ath_chanctx **ptr = (void *) ctx->drv_priv; return *ptr; } -void ath_chanctx_init(struct ath_softc *sc); -void ath_chanctx_set_channel(struct ath_softc *sc, struct ath_chanctx *ctx, - struct cfg80211_chan_def *chandef); -#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT + bool ath9k_is_chanctx_enabled(void); void ath9k_fill_chanctx_ops(void); void ath9k_init_channel_context(struct ath_softc *sc); @@ -451,7 +454,9 @@ void ath_chanctx_set_next(struct ath_softc *sc, bool force); void ath_offchannel_next(struct ath_softc *sc); void ath_scan_complete(struct ath_softc *sc, bool abort); void ath_roc_complete(struct ath_softc *sc, bool abort); + #else + static inline bool ath9k_is_chanctx_enabled(void) { return false; @@ -513,6 +518,7 @@ static inline void ath_chanctx_check_active(struct ath_softc *sc, struct ath_chanctx *ctx) { } + #endif /* CONFIG_ATH9K_CHANNEL_CONTEXT */ int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan); From 02da18b7ec64135fc1b35c036acbd920d2cce2d6 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Sun, 24 Aug 2014 21:16:10 +0530 Subject: [PATCH 173/221] ath9k: Add new chanctx events This will be useful in handling addition/change of new channel contexts. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 2 ++ drivers/net/wireless/ath/ath9k/channel.c | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index acbe2b7956ae..7c8c6f158c91 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -359,7 +359,9 @@ enum ath_chanctx_event { ATH_CHANCTX_EVENT_BEACON_RECEIVED, ATH_CHANCTX_EVENT_ASSOC, ATH_CHANCTX_EVENT_SWITCH, + ATH_CHANCTX_EVENT_ASSIGN, ATH_CHANCTX_EVENT_UNASSIGN, + ATH_CHANCTX_EVENT_CHANGE, ATH_CHANCTX_EVENT_ENABLE_MULTICHANNEL, }; diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index 0e64b736160e..34ccfa0142cf 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -452,6 +452,10 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, sc->next_chan = ctx; ieee80211_queue_work(sc->hw, &sc->chanctx_work); break; + case ATH_CHANCTX_EVENT_ASSIGN: + break; + case ATH_CHANCTX_EVENT_CHANGE: + break; } spin_unlock_bh(&sc->chan_lock); From 5a8cbec7fb2be3b9a6929d8c22c3e320544d2de4 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Sun, 24 Aug 2014 21:16:11 +0530 Subject: [PATCH 174/221] ath9k: Print the event/state in ath_chanctx_event Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 3 ++ drivers/net/wireless/ath/ath9k/channel.c | 37 ++++++++++++++++++++++-- 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 7c8c6f158c91..c690601f7276 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -410,6 +410,9 @@ struct ath_offchannel { int roc_duration; int duration; }; + +#define case_rtn_string(val) case val: return #val + #define ath_for_each_chanctx(_sc, _ctx) \ for (ctx = &sc->chanctx[0]; \ ctx <= &sc->chanctx[ARRAY_SIZE(sc->chanctx) - 1]; \ diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index 34ccfa0142cf..9be92d81ef6d 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -149,8 +149,6 @@ void ath_chanctx_set_channel(struct ath_softc *sc, struct ath_chanctx *ctx, static const char *offchannel_state_string(enum ath_offchannel_state state) { -#define case_rtn_string(val) case val: return #val - switch (state) { case_rtn_string(ATH_OFFCHANNEL_IDLE); case_rtn_string(ATH_OFFCHANNEL_PROBE_SEND); @@ -164,6 +162,37 @@ static const char *offchannel_state_string(enum ath_offchannel_state state) } } +static const char *chanctx_event_string(enum ath_chanctx_event ev) +{ + switch (ev) { + case_rtn_string(ATH_CHANCTX_EVENT_BEACON_PREPARE); + case_rtn_string(ATH_CHANCTX_EVENT_BEACON_SENT); + case_rtn_string(ATH_CHANCTX_EVENT_TSF_TIMER); + case_rtn_string(ATH_CHANCTX_EVENT_BEACON_RECEIVED); + case_rtn_string(ATH_CHANCTX_EVENT_ASSOC); + case_rtn_string(ATH_CHANCTX_EVENT_SWITCH); + case_rtn_string(ATH_CHANCTX_EVENT_ASSIGN); + case_rtn_string(ATH_CHANCTX_EVENT_UNASSIGN); + case_rtn_string(ATH_CHANCTX_EVENT_CHANGE); + case_rtn_string(ATH_CHANCTX_EVENT_ENABLE_MULTICHANNEL); + default: + return "unknown"; + } +} + +static const char *chanctx_state_string(enum ath_chanctx_state state) +{ + switch (state) { + case_rtn_string(ATH_CHANCTX_STATE_IDLE); + case_rtn_string(ATH_CHANCTX_STATE_WAIT_FOR_BEACON); + case_rtn_string(ATH_CHANCTX_STATE_WAIT_FOR_TIMER); + case_rtn_string(ATH_CHANCTX_STATE_SWITCH); + case_rtn_string(ATH_CHANCTX_STATE_FORCE_ACTIVE); + default: + return "unknown"; + } +} + void ath_chanctx_check_active(struct ath_softc *sc, struct ath_chanctx *ctx) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); @@ -275,6 +304,10 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, u32 beacon_int; bool noa_changed = false; + ath_dbg(common, CHAN_CTX, "event: %s, state: %s\n", + chanctx_event_string(ev), + chanctx_state_string(sc->sched.state)); + if (vif) avp = (struct ath_vif *) vif->drv_priv; From 86162d497d4ceb995b268fc9c7756ae7bdb0bc71 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Sun, 24 Aug 2014 21:16:12 +0530 Subject: [PATCH 175/221] ath9k: Fix interface limits There is no reason why managed/p2p interfaces have to be limited to one. IBSS is the only type that needs a restriction. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/init.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 5887499a3838..ca10a8b3a381 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -679,9 +679,11 @@ static const struct ieee80211_iface_limit wds_limits[] = { #ifdef CONFIG_ATH9K_CHANNEL_CONTEXT static const struct ieee80211_iface_limit if_limits_multi[] = { - { .max = 1, .types = BIT(NL80211_IFTYPE_STATION) }, - { .max = 1, .types = BIT(NL80211_IFTYPE_P2P_CLIENT) | + { .max = 2, .types = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO) }, + { .max = 1, .types = BIT(NL80211_IFTYPE_ADHOC) }, }; static const struct ieee80211_iface_combination if_comb_multi[] = { From 4c7e9aee2d3f738924ba04baecf7bf854e72f07c Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Sun, 24 Aug 2014 21:16:13 +0530 Subject: [PATCH 176/221] ath9k: Fix channel context creation If a new context is being added in addition to the current one, then send the ASSIGN event to abort a running scan since the addition of a context is usually followed by VIF assignment and further operations. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/channel.c | 22 +++++++++++++++++++++- drivers/net/wireless/ath/ath9k/main.c | 2 ++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index 9be92d81ef6d..b369c485978e 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -127,6 +127,7 @@ void ath_chanctx_init(struct ath_softc *sc) void ath_chanctx_set_channel(struct ath_softc *sc, struct ath_chanctx *ctx, struct cfg80211_chan_def *chandef) { + struct ath_common *common = ath9k_hw_common(sc->sc_ah); bool cur_chan; spin_lock_bh(&sc->chan_lock); @@ -135,8 +136,11 @@ void ath_chanctx_set_channel(struct ath_softc *sc, struct ath_chanctx *ctx, cur_chan = sc->cur_chan == ctx; spin_unlock_bh(&sc->chan_lock); - if (!cur_chan) + if (!cur_chan) { + ath_dbg(common, CHAN_CTX, + "Current context differs from the new context\n"); return; + } ath_set_channel(sc); } @@ -486,6 +490,22 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, ieee80211_queue_work(sc->hw, &sc->chanctx_work); break; case ATH_CHANCTX_EVENT_ASSIGN: + /* + * When adding a new channel context, check if a scan + * is in progress and abort it since the addition of + * a new channel context is usually followed by VIF + * assignment, in which case we have to start multi-channel + * operation. + */ + if (test_bit(ATH_OP_SCANNING, &common->op_flags)) { + ath_dbg(common, CHAN_CTX, + "Aborting HW scan to add new context\n"); + + spin_unlock_bh(&sc->chan_lock); + del_timer_sync(&sc->offchannel.timer); + ath_scan_complete(sc, true); + spin_lock_bh(&sc->chan_lock); + } break; case ATH_CHANCTX_EVENT_CHANGE: break; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index da63487279df..2fcafa6f4eb9 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2236,6 +2236,8 @@ static int ath9k_add_chanctx(struct ieee80211_hw *hw, conf->def.chan->center_freq); ath_chanctx_set_channel(sc, ctx, &conf->def); + ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_ASSIGN); + mutex_unlock(&sc->mutex); return 0; } From ac0372abf8524a7572a9cdaac6495eb2eba20457 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Canek=20Pel=C3=A1ez=20Vald=C3=A9s?= Date: Sun, 24 Aug 2014 19:06:11 -0500 Subject: [PATCH 177/221] rt2x00: support Ralink 5362. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Canek Peláez Valdés Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800.h | 4 +++- drivers/net/wireless/rt2x00/rt2800lib.c | 6 ++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h index a394a9a95919..b7434df51e7c 100644 --- a/drivers/net/wireless/rt2x00/rt2800.h +++ b/drivers/net/wireless/rt2x00/rt2800.h @@ -52,6 +52,7 @@ * RF5592 2.4G/5G 2T2R * RF3070 2.4G 1T1R * RF5360 2.4G 1T1R + * RF5362 2.4G 1T1R * RF5370 2.4G 1T1R * RF5390 2.4G 1T1R */ @@ -72,6 +73,7 @@ #define RF3070 0x3070 #define RF3290 0x3290 #define RF5360 0x5360 +#define RF5362 0x5362 #define RF5370 0x5370 #define RF5372 0x5372 #define RF5390 0x5390 @@ -2145,7 +2147,7 @@ struct mac_iveiv_entry { /* Bits [7-4] for RF3320 (RT3370/RT3390), on other chipsets reserved */ #define RFCSR3_PA1_BIAS_CCK FIELD8(0x70) #define RFCSR3_PA2_CASCODE_BIAS_CCKK FIELD8(0x80) -/* Bits for RF3290/RF5360/RF5370/RF5372/RF5390/RF5392 */ +/* Bits for RF3290/RF5360/RF5362/RF5370/RF5372/RF5390/RF5392 */ #define RFCSR3_VCOCAL_EN FIELD8(0x80) /* Bits for RF3050 */ #define RFCSR3_BIT1 FIELD8(0x02) diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 893c9d5f3d6f..9f57a2db791c 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -3186,6 +3186,7 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, break; case RF3070: case RF5360: + case RF5362: case RF5370: case RF5372: case RF5390: @@ -3203,6 +3204,7 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, rt2x00_rf(rt2x00dev, RF3290) || rt2x00_rf(rt2x00dev, RF3322) || rt2x00_rf(rt2x00dev, RF5360) || + rt2x00_rf(rt2x00dev, RF5362) || rt2x00_rf(rt2x00dev, RF5370) || rt2x00_rf(rt2x00dev, RF5372) || rt2x00_rf(rt2x00dev, RF5390) || @@ -4317,6 +4319,7 @@ void rt2800_vco_calibration(struct rt2x00_dev *rt2x00dev) case RF3070: case RF3290: case RF5360: + case RF5362: case RF5370: case RF5372: case RF5390: @@ -7095,6 +7098,7 @@ static int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) case RF3320: case RF3322: case RF5360: + case RF5362: case RF5370: case RF5372: case RF5390: @@ -7551,6 +7555,7 @@ static int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev) case RF3320: case RF3322: case RF5360: + case RF5362: case RF5370: case RF5372: case RF5390: @@ -7680,6 +7685,7 @@ static int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev) case RF3070: case RF3290: case RF5360: + case RF5362: case RF5370: case RF5372: case RF5390: From 9ea3598b225d9ffbeee65eb0a967bd0746ba1b97 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 27 Aug 2014 12:07:23 +0530 Subject: [PATCH 178/221] ath9k: Disable fastcc for channel context mode Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 2fcafa6f4eb9..b823b5ac3490 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -303,6 +303,9 @@ int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan) if (!ath_prepare_reset(sc)) fastcc = false; + if (ath9k_is_chanctx_enabled()) + fastcc = false; + spin_lock_bh(&sc->chan_lock); sc->cur_chandef = sc->cur_chan->chandef; spin_unlock_bh(&sc->chan_lock); From 878066e745b54578409ea765cfc718fcd99a4802 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 27 Aug 2014 12:07:24 +0530 Subject: [PATCH 179/221] ath9k: Add more debug statements for channel context Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/channel.c | 90 ++++++++++++++++++++---- drivers/net/wireless/ath/ath9k/main.c | 3 + 2 files changed, 81 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index b369c485978e..f8f47571d98c 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -288,12 +288,16 @@ static void ath_chanctx_adjust_tbtt_delta(struct ath_softc *sc) */ static void ath_chanctx_setup_timer(struct ath_softc *sc, u32 tsf_time) { + struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_hw *ah = sc->sc_ah; ath9k_hw_gen_timer_start(ah, sc->p2p_ps_timer, tsf_time, 1000000); tsf_time -= ath9k_hw_gettsf32(ah); tsf_time = msecs_to_jiffies(tsf_time / 1000) + 1; mod_timer(&sc->sched.timer, tsf_time); + + ath_dbg(common, CHAN_CTX, + "Setup chanctx timer with timeout: %d ms\n", jiffies_to_msecs(tsf_time)); } void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, @@ -308,42 +312,55 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, u32 beacon_int; bool noa_changed = false; - ath_dbg(common, CHAN_CTX, "event: %s, state: %s\n", - chanctx_event_string(ev), - chanctx_state_string(sc->sched.state)); - if (vif) avp = (struct ath_vif *) vif->drv_priv; spin_lock_bh(&sc->chan_lock); + ath_dbg(common, CHAN_CTX, "cur_chan: %d MHz, event: %s, state: %s\n", + sc->cur_chan->chandef.center_freq1, + chanctx_event_string(ev), + chanctx_state_string(sc->sched.state)); + switch (ev) { case ATH_CHANCTX_EVENT_BEACON_PREPARE: if (avp->offchannel_duration) avp->offchannel_duration = 0; - if (avp->chanctx != sc->cur_chan) + if (avp->chanctx != sc->cur_chan) { + ath_dbg(common, CHAN_CTX, + "Contexts differ, not preparing beacon\n"); break; + } if (sc->sched.offchannel_pending) { sc->sched.offchannel_pending = false; sc->next_chan = &sc->offchannel.chan; sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_BEACON; + ath_dbg(common, CHAN_CTX, + "Setting offchannel_pending to false\n"); } ctx = ath_chanctx_get_next(sc, sc->cur_chan); if (ctx->active && sc->sched.state == ATH_CHANCTX_STATE_IDLE) { sc->next_chan = ctx; sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_BEACON; + ath_dbg(common, CHAN_CTX, + "Set next context, move chanctx state to WAIT_FOR_BEACON\n"); } /* if the timer missed its window, use the next interval */ - if (sc->sched.state == ATH_CHANCTX_STATE_WAIT_FOR_TIMER) + if (sc->sched.state == ATH_CHANCTX_STATE_WAIT_FOR_TIMER) { sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_BEACON; + ath_dbg(common, CHAN_CTX, + "Move chanctx state from WAIT_FOR_TIMER to WAIT_FOR_BEACON\n"); + } if (sc->sched.state != ATH_CHANCTX_STATE_WAIT_FOR_BEACON) break; + ath_dbg(common, CHAN_CTX, "Preparing beacon for vif: %pM\n", vif->addr); + sc->sched.beacon_pending = true; sc->sched.next_tbtt = REG_READ(ah, AR_NEXT_TBTT_TIMER); @@ -387,15 +404,28 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, if (noa_changed) avp->noa_index++; + + ath_dbg(common, CHAN_CTX, + "periodic_noa_duration: %d, periodic_noa_start: %d, noa_index: %d\n", + avp->periodic_noa_duration, + avp->periodic_noa_start, + avp->noa_index); + break; case ATH_CHANCTX_EVENT_BEACON_SENT: - if (!sc->sched.beacon_pending) + if (!sc->sched.beacon_pending) { + ath_dbg(common, CHAN_CTX, + "No pending beacon\n"); break; + } sc->sched.beacon_pending = false; if (sc->sched.state != ATH_CHANCTX_STATE_WAIT_FOR_BEACON) break; + ath_dbg(common, CHAN_CTX, + "Move chanctx state to WAIT_FOR_TIMER\n"); + sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_TIMER; ath_chanctx_setup_timer(sc, sc->sched.switch_start_time); break; @@ -407,6 +437,9 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, sc->sched.beacon_pending) sc->sched.beacon_miss++; + ath_dbg(common, CHAN_CTX, + "Move chanctx state to SWITCH\n"); + sc->sched.state = ATH_CHANCTX_STATE_SWITCH; ieee80211_queue_work(sc->hw, &sc->chanctx_work); break; @@ -435,6 +468,9 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, avp->chanctx != sc->cur_chan) break; + ath_dbg(common, CHAN_CTX, + "Move chanctx state from FORCE_ACTIVE to IDLE\n"); + sc->sched.state = ATH_CHANCTX_STATE_IDLE; /* fall through */ case ATH_CHANCTX_EVENT_SWITCH: @@ -450,6 +486,9 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, sc->next_chan = ath_chanctx_get_next(sc, sc->cur_chan); cur_conf = &sc->cur_chan->beacon; + ath_dbg(common, CHAN_CTX, + "Move chanctx state to WAIT_FOR_TIMER (event SWITCH)\n"); + sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_TIMER; tsf_time = TU_TO_USEC(cur_conf->beacon_interval) / 2; @@ -616,7 +655,8 @@ ath_scan_next_channel(struct ath_softc *sc) if (sc->offchannel.scan_idx >= req->n_channels) { ath_dbg(common, CHAN_CTX, - "Moving to ATH_OFFCHANNEL_IDLE state, scan_idx: %d, n_channels: %d\n", + "Moving offchannel state to ATH_OFFCHANNEL_IDLE, " + "scan_idx: %d, n_channels: %d\n", sc->offchannel.scan_idx, req->n_channels); @@ -627,7 +667,7 @@ ath_scan_next_channel(struct ath_softc *sc) } ath_dbg(common, CHAN_CTX, - "Moving to ATH_OFFCHANNEL_PROBE_SEND state, scan_idx: %d\n", + "Moving offchannel state to ATH_OFFCHANNEL_PROBE_SEND, scan_idx: %d\n", sc->offchannel.scan_idx); chan = req->channels[sc->offchannel.scan_idx++]; @@ -740,7 +780,7 @@ static void ath_scan_channel_start(struct ath_softc *sc) } ath_dbg(common, CHAN_CTX, - "Moving to ATH_OFFCHANNEL_PROBE_WAIT state\n"); + "Moving offchannel state to ATH_OFFCHANNEL_PROBE_WAIT\n"); sc->offchannel.state = ATH_OFFCHANNEL_PROBE_WAIT; mod_timer(&sc->offchannel.timer, jiffies + sc->offchannel.duration); @@ -749,6 +789,10 @@ static void ath_scan_channel_start(struct ath_softc *sc) static void ath_chanctx_timer(unsigned long data) { struct ath_softc *sc = (struct ath_softc *) data; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + + ath_dbg(common, CHAN_CTX, + "Channel context timer invoked\n"); ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_TSF_TIMER); } @@ -759,7 +803,7 @@ static void ath_offchannel_timer(unsigned long data) struct ath_chanctx *ctx; struct ath_common *common = ath9k_hw_common(sc->sc_ah); - ath_dbg(common, CHAN_CTX, "%s: state: %s\n", + ath_dbg(common, CHAN_CTX, "%s: offchannel state: %s\n", __func__, offchannel_state_string(sc->offchannel.state)); switch (sc->offchannel.state) { @@ -770,6 +814,10 @@ static void ath_offchannel_timer(unsigned long data) /* get first active channel context */ ctx = ath_chanctx_get_oper_chan(sc, true); if (ctx->active) { + ath_dbg(common, CHAN_CTX, + "Switch to oper/active context, " + "move offchannel state to ATH_OFFCHANNEL_SUSPEND\n"); + sc->offchannel.state = ATH_OFFCHANNEL_SUSPEND; ath_chanctx_switch(sc, ctx, NULL); mod_timer(&sc->offchannel.timer, jiffies + HZ / 10); @@ -858,6 +906,8 @@ ath_chanctx_send_ps_frame(struct ath_softc *sc, bool powersave) static bool ath_chanctx_defer_switch(struct ath_softc *sc) { + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + if (sc->cur_chan == &sc->offchannel.chan) return false; @@ -868,6 +918,9 @@ static bool ath_chanctx_defer_switch(struct ath_softc *sc) if (!sc->cur_chan->switch_after_beacon) return false; + ath_dbg(common, CHAN_CTX, + "Defer switch, set chanctx state to WAIT_FOR_BEACON\n"); + sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_BEACON; break; default: @@ -881,7 +934,7 @@ static void ath_offchannel_channel_change(struct ath_softc *sc) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); - ath_dbg(common, CHAN_CTX, "%s: state: %s\n", + ath_dbg(common, CHAN_CTX, "%s: offchannel state: %s\n", __func__, offchannel_state_string(sc->offchannel.state)); switch (sc->offchannel.state) { @@ -920,6 +973,7 @@ static void ath_offchannel_channel_change(struct ath_softc *sc) void ath_chanctx_set_next(struct ath_softc *sc, bool force) { + struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct timespec ts; bool measure_time = false; bool send_ps = false; @@ -935,7 +989,16 @@ void ath_chanctx_set_next(struct ath_softc *sc, bool force) return; } + ath_dbg(common, CHAN_CTX, + "%s: current: %d MHz, next: %d MHz\n", + __func__, + sc->cur_chan->chandef.center_freq1, + sc->next_chan->chandef.center_freq1); + if (sc->cur_chan != sc->next_chan) { + ath_dbg(common, CHAN_CTX, + "Stopping current chanctx: %d\n", + sc->cur_chan->chandef.center_freq1); sc->cur_chan->stopped = true; spin_unlock_bh(&sc->chan_lock); @@ -968,6 +1031,9 @@ void ath_chanctx_set_next(struct ath_softc *sc, bool force) if (sc->sc_ah->chip_fullsleep || memcmp(&sc->cur_chandef, &sc->cur_chan->chandef, sizeof(sc->cur_chandef))) { + ath_dbg(common, CHAN_CTX, + "%s: Set channel %d MHz\n", + __func__, sc->cur_chan->chandef.center_freq1); ath_set_channel(sc); if (measure_time) sc->sched.channel_switch_time = diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index b823b5ac3490..d9be83158a82 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2361,6 +2361,9 @@ static void ath9k_mgd_prepare_tx(struct ieee80211_hw *hw, sc->next_chan = avp->chanctx; changed = true; } + ath_dbg(common, CHAN_CTX, + "%s: Set chanctx state to FORCE_ACTIVE, changed: %d\n", + __func__, changed); sc->sched.state = ATH_CHANCTX_STATE_FORCE_ACTIVE; spin_unlock_bh(&sc->chan_lock); From 1a7c5b7ef0cf93b42b9181973ce283fe77fb6093 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 27 Aug 2014 12:07:25 +0530 Subject: [PATCH 180/221] ath9k: Fix channel context timer Setup the channel context correctly. Not doing this was causing beacon loss in a P2P-GO/STA concurrent setup. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/channel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index f8f47571d98c..409f912a67c7 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -294,7 +294,7 @@ static void ath_chanctx_setup_timer(struct ath_softc *sc, u32 tsf_time) ath9k_hw_gen_timer_start(ah, sc->p2p_ps_timer, tsf_time, 1000000); tsf_time -= ath9k_hw_gettsf32(ah); tsf_time = msecs_to_jiffies(tsf_time / 1000) + 1; - mod_timer(&sc->sched.timer, tsf_time); + mod_timer(&sc->sched.timer, jiffies + tsf_time); ath_dbg(common, CHAN_CTX, "Setup chanctx timer with timeout: %d ms\n", jiffies_to_msecs(tsf_time)); From 6a5d088a923854569e20eac4f3f569926d5911ec Mon Sep 17 00:00:00 2001 From: Andreea-Cristina Bernat Date: Wed, 27 Aug 2014 16:27:30 +0300 Subject: [PATCH 181/221] carl9170: tx: Replace rcu_assign_pointer() with RCU_INIT_POINTER() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to RCU_INIT_POINTER()'s block comment 3.a, it can be used if "3. The referenced data structure has already been exposed to readers either at compile time or via rcu_assign_pointer() -and- a. You have not made -any- reader-visible changes to this structure since then". This case fulfills the conditions above because between the rcu_dereference() call (cvif = rcu_dereference(ar->beacon_iter);) and the rcu_assign_pointer() call there is no update of the "cvif" variable. Therefore, this patch makes the replacement. The following Coccinelle semantic patch was used: @@ identifier v; @@ v = rcu_dereference(...); ... when != rcu_dereference(...); when != v = ...; when != (<+...v...+>)++; when != \(memcpy\|memset\)(...); ( - rcu_assign_pointer + RCU_INIT_POINTER (..., v); | if(...) { ... when != v = ...; - rcu_assign_pointer + RCU_INIT_POINTER (..., v); ... when any } ) Because there are cases where between a “rcu_dereference()” call and a “rcu_assign_pointer()” call might be updates of the value that interests us, the Coccinelle semantic patch ignores them and replaces with "RCU_INIT_POINTER()" only when the update is not happening. Signed-off-by: Andreea-Cristina Bernat Acked-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/ath/carl9170/tx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/carl9170/tx.c b/drivers/net/wireless/ath/carl9170/tx.c index 4cadfd48ffdf..ae86a600d920 100644 --- a/drivers/net/wireless/ath/carl9170/tx.c +++ b/drivers/net/wireless/ath/carl9170/tx.c @@ -1557,7 +1557,7 @@ static struct carl9170_vif_info *carl9170_pick_beaconing_vif(struct ar9170 *ar) } out: - rcu_assign_pointer(ar->beacon_iter, cvif); + RCU_INIT_POINTER(ar->beacon_iter, cvif); return cvif; } From a00f4f6e048dff90e64c6d1bde2bb4587c6d2234 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Mon, 28 Jul 2014 15:16:59 +0200 Subject: [PATCH 182/221] mac80211: fix chantype recalc warning When a device driver is unloaded local->interfaces list is cleared. If there was more than 1 interface running and connected (bound to a chanctx) then chantype recalc was called and it ended up with compat being NULL causing a call trace warning. Warn if compat becomes NULL as a result of incompatible bss_conf.chandef of interfaces bound to a given channel context only. The call trace looked like this: WARNING: CPU: 2 PID: 2594 at /devel/src/linux/net/mac80211/chan.c:557 ieee80211_recalc_chanctx_chantype+0x2cd/0x2e0() Modules linked in: ath10k_pci(-) ath10k_core ath CPU: 2 PID: 2594 Comm: rmmod Tainted: G W 3.16.0-rc1+ #150 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Bochs 01/01/2011 0000000000000009 ffff88001ea279c0 ffffffff818dfa93 0000000000000000 ffff88001ea279f8 ffffffff810514a8 ffff88001ce09cd0 ffff88001e03cc58 0000000000000000 ffff88001ce08840 ffff88001ce09cd0 ffff88001ea27a08 Call Trace: [] dump_stack+0x4d/0x66 [] warn_slowpath_common+0x78/0xa0 [] warn_slowpath_null+0x15/0x20 [] ieee80211_recalc_chanctx_chantype+0x2cd/0x2e0 [] ? ieee80211_recalc_chanctx_chantype+0x2a/0x2e0 [] ieee80211_assign_vif_chanctx+0x1a9/0x770 [] __ieee80211_vif_release_channel+0x70/0x130 [] ieee80211_vif_release_channel+0x43/0xb0 [] ieee80211_stop_ap+0x21e/0x5a0 [] __cfg80211_stop_ap+0x85/0x520 [] __cfg80211_leave+0x68/0x120 [] cfg80211_leave+0x28/0x40 [] cfg80211_netdev_notifier_call+0x373/0x6b0 [] notifier_call_chain+0x55/0x110 [] raw_notifier_call_chain+0x11/0x20 [] call_netdevice_notifiers_info+0x30/0x60 [] __dev_close_many+0x59/0xf0 [] dev_close_many+0x81/0x120 [] rollback_registered_many+0x115/0x2a0 [] unregister_netdevice_many+0x16/0xa0 [] ieee80211_remove_interfaces+0x121/0x1b0 [] ieee80211_unregister_hw+0x56/0x110 [] ath10k_mac_unregister+0x14/0x60 [ath10k_core] [] ath10k_core_unregister+0x27/0x40 [ath10k_core] [] ath10k_pci_remove+0x44/0xa0 [ath10k_pci] [] pci_device_remove+0x28/0x60 [] __device_release_driver+0x64/0xd0 [] driver_detach+0xb8/0xc0 [] bus_remove_driver+0x4a/0xb0 [] driver_unregister+0x27/0x50 Signed-off-by: Michal Kazior Signed-off-by: Johannes Berg --- net/mac80211/chan.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index 792eac6cc7b3..bd01a9f041bd 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c @@ -547,12 +547,12 @@ static void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local, compat = cfg80211_chandef_compatible( &sdata->vif.bss_conf.chandef, compat); - if (!compat) + if (WARN_ON_ONCE(!compat)) break; } rcu_read_unlock(); - if (WARN_ON_ONCE(!compat)) + if (!compat) return; ieee80211_change_chanctx(local, ctx, compat); From d0616613d9cf17919fbd46fa0274db4b0084ad62 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Tue, 19 Aug 2014 15:41:32 +0300 Subject: [PATCH 183/221] net: rfkill: gpio: Add more Broadcom bluetooth ACPI IDs This adds one more ACPI ID of a Broadcom bluetooth chip. Signed-off-by: Mika Westerberg Signed-off-by: Johannes Berg --- net/rfkill/rfkill-gpio.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/rfkill/rfkill-gpio.c b/net/rfkill/rfkill-gpio.c index 14c98e48f261..02a86a27fd84 100644 --- a/net/rfkill/rfkill-gpio.c +++ b/net/rfkill/rfkill-gpio.c @@ -158,6 +158,7 @@ static const struct acpi_device_id rfkill_acpi_match[] = { { "BCM2E1A", RFKILL_TYPE_BLUETOOTH }, { "BCM2E39", RFKILL_TYPE_BLUETOOTH }, { "BCM2E3D", RFKILL_TYPE_BLUETOOTH }, + { "BCM2E64", RFKILL_TYPE_BLUETOOTH }, { "BCM4752", RFKILL_TYPE_GPS }, { "LNV4752", RFKILL_TYPE_GPS }, { }, From 7280d1f0bd14271638bf6b4c3c9dc814af1aaafc Mon Sep 17 00:00:00 2001 From: Matti Gottlieb Date: Thu, 17 Jul 2014 16:41:14 +0300 Subject: [PATCH 184/221] iwlwifi: mvm: Add set NIC temperature debug option Add ability to set the NIC's temperature and ignore the actual temperature that the FW supplies. Signed-off-by: Matti Gottlieb Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/debugfs.c | 57 ++++++++++++++++++++++ drivers/net/wireless/iwlwifi/mvm/mvm.h | 10 ++++ drivers/net/wireless/iwlwifi/mvm/rx.c | 19 ++++++++ 3 files changed, 86 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index 7d18f466fbb3..f7e44889182a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -257,6 +257,60 @@ static ssize_t iwl_dbgfs_sram_write(struct iwl_mvm *mvm, char *buf, return count; } +static ssize_t iwl_dbgfs_set_nic_temperature_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_mvm *mvm = file->private_data; + char buf[16]; + int pos; + + if (!mvm->temperature_test) + pos = scnprintf(buf , sizeof(buf), "disabled\n"); + else + pos = scnprintf(buf , sizeof(buf), "%d\n", mvm->temperature); + + return simple_read_from_buffer(user_buf, count, ppos, buf, pos); +} + +/* + * Set NIC Temperature + * Cause the driver to ignore the actual NIC temperature reported by the FW + * Enable: any value between IWL_MVM_DEBUG_SET_TEMPERATURE_MIN - + * IWL_MVM_DEBUG_SET_TEMPERATURE_MAX + * Disable: IWL_MVM_DEBUG_SET_TEMPERATURE_DISABLE + */ +static ssize_t iwl_dbgfs_set_nic_temperature_write(struct iwl_mvm *mvm, + char *buf, size_t count, + loff_t *ppos) +{ + int temperature; + + if (kstrtoint(buf, 10, &temperature)) + return -EINVAL; + /* not a legal temperature */ + if ((temperature > IWL_MVM_DEBUG_SET_TEMPERATURE_MAX && + temperature != IWL_MVM_DEBUG_SET_TEMPERATURE_DISABLE) || + temperature < IWL_MVM_DEBUG_SET_TEMPERATURE_MIN) + return -EINVAL; + + mutex_lock(&mvm->mutex); + if (temperature == IWL_MVM_DEBUG_SET_TEMPERATURE_DISABLE) { + mvm->temperature_test = false; + } else { + mvm->temperature_test = true; + mvm->temperature = temperature; + } + IWL_DEBUG_TEMP(mvm, "%sabling debug set temperature (temp = %d)\n", + mvm->temperature_test ? "En" : "Dis" , + mvm->temperature); + /* handle the temperature change */ + iwl_mvm_tt_handler(mvm); + mutex_unlock(&mvm->mutex); + + return count; +} + static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -1296,6 +1350,7 @@ MVM_DEBUGFS_READ_WRITE_FILE_OPS(prph_reg, 64); MVM_DEBUGFS_WRITE_FILE_OPS(tx_flush, 16); MVM_DEBUGFS_WRITE_FILE_OPS(sta_drain, 8); MVM_DEBUGFS_READ_WRITE_FILE_OPS(sram, 64); +MVM_DEBUGFS_READ_WRITE_FILE_OPS(set_nic_temperature, 64); MVM_DEBUGFS_READ_FILE_OPS(stations); MVM_DEBUGFS_READ_FILE_OPS(bt_notif); MVM_DEBUGFS_READ_FILE_OPS(bt_cmd); @@ -1336,6 +1391,8 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) MVM_DEBUGFS_ADD_FILE(tx_flush, mvm->debugfs_dir, S_IWUSR); MVM_DEBUGFS_ADD_FILE(sta_drain, mvm->debugfs_dir, S_IWUSR); MVM_DEBUGFS_ADD_FILE(sram, mvm->debugfs_dir, S_IWUSR | S_IRUSR); + MVM_DEBUGFS_ADD_FILE(set_nic_temperature, mvm->debugfs_dir, + S_IWUSR | S_IRUSR); MVM_DEBUGFS_ADD_FILE(stations, dbgfs_dir, S_IRUSR); MVM_DEBUGFS_ADD_FILE(fw_error_dump, dbgfs_dir, S_IRUSR); MVM_DEBUGFS_ADD_FILE(bt_notif, dbgfs_dir, S_IRUSR); diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 2e73d3bd7757..802d29e971f7 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -512,6 +512,10 @@ enum { D0I3_PENDING_WAKEUP, }; +#define IWL_MVM_DEBUG_SET_TEMPERATURE_DISABLE 0xff +#define IWL_MVM_DEBUG_SET_TEMPERATURE_MIN -100 +#define IWL_MVM_DEBUG_SET_TEMPERATURE_MAX 200 + struct iwl_mvm { /* for logger access */ struct device *dev; @@ -694,6 +698,12 @@ struct iwl_mvm { /* Thermal Throttling and CTkill */ struct iwl_mvm_tt_mgmt thermal_throttle; s32 temperature; /* Celsius */ + /* + * Debug option to set the NIC temperature. This option makes the + * driver think this is the actual NIC temperature, and ignore the + * real temperature that is received from the fw + */ + bool temperature_test; /* Debug test temperature is enabled */ #ifdef CONFIG_NL80211_TESTMODE u32 noa_duration; diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c index 4b98987fc413..8f43affe266f 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/iwlwifi/mvm/rx.c @@ -491,10 +491,29 @@ int iwl_mvm_rx_statistics(struct iwl_mvm *mvm, .mvm = mvm, }; + /* + * set temperature debug enabled - ignore FW temperature updates + * and use the user set temperature. + */ + if (mvm->temperature_test) { + if (mvm->temperature < le32_to_cpu(common->temperature)) + IWL_DEBUG_TEMP(mvm, + "Ignoring FW temperature update that is greater than the debug set temperature (debug temp = %d, fw temp = %d)\n", + mvm->temperature, + le32_to_cpu(common->temperature)); + /* + * skip iwl_mvm_tt_handler since we are in + * temperature debug mode and we are ignoring + * the new temperature value + */ + goto update; + } + if (mvm->temperature != le32_to_cpu(common->temperature)) { mvm->temperature = le32_to_cpu(common->temperature); iwl_mvm_tt_handler(mvm); } +update: iwl_mvm_update_rx_statistics(mvm, stats); ieee80211_iterate_active_interfaces(mvm->hw, From 7ceb98a313b8a1a5d949f538f4bb5ead4fabad23 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 28 Jul 2014 12:59:45 +0300 Subject: [PATCH 185/221] iwlwifi: mvm: reduce the AMPDU size in low latency mode This allows to leave a frame in the Tx Fifo which allows the firmware to try to enter burst mode. The end result of this is a better latency since the firmware utilises the TxOP better. Also limit the AMPDU size to the limit set in the ADDBA response. This doesn't change much since the AMPDU size was limited by the configuration of the hardware scheduler, but here we add a software limit by the mean of the link quality command. Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/rs.c | 56 ++++++++++++++++++--------- 1 file changed, 38 insertions(+), 18 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index c70e959bf0e3..51fa571d5c45 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -2678,6 +2678,7 @@ static void rs_build_rates_table_from_fixed(struct iwl_mvm *mvm, int i; int num_rates = ARRAY_SIZE(lq_cmd->rs_table); __le32 ucode_rate_le32 = cpu_to_le32(ucode_rate); + u8 ant = (ucode_rate & RATE_MCS_ANT_ABC_MSK) >> RATE_MCS_ANT_POS; for (i = 0; i < num_rates; i++) lq_cmd->rs_table[i] = ucode_rate_le32; @@ -2688,6 +2689,13 @@ static void rs_build_rates_table_from_fixed(struct iwl_mvm *mvm, lq_cmd->mimo_delim = num_rates - 1; else lq_cmd->mimo_delim = 0; + + lq_cmd->reduced_tpc = 0; + + if (num_of_ant(ant) == 1) + lq_cmd->single_stream_ant_msk = ant; + + lq_cmd->agg_frame_cnt_limit = LINK_QUAL_AGG_FRAME_LIMIT_DEF; } #endif /* CONFIG_MAC80211_DEBUGFS */ @@ -2811,31 +2819,46 @@ static void rs_fill_lq_cmd(struct iwl_mvm *mvm, const struct rs_rate *initial_rate) { struct iwl_lq_cmd *lq_cmd = &lq_sta->lq; - u8 ant = initial_rate->ant; + struct iwl_mvm_sta *mvmsta; + struct iwl_mvm_vif *mvmvif; + + lq_cmd->agg_disable_start_th = LINK_QUAL_AGG_DISABLE_START_DEF; + lq_cmd->agg_time_limit = + cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF); #ifdef CONFIG_MAC80211_DEBUGFS if (lq_sta->pers.dbg_fixed_rate) { rs_build_rates_table_from_fixed(mvm, lq_cmd, lq_sta->band, lq_sta->pers.dbg_fixed_rate); - lq_cmd->reduced_tpc = 0; - ant = (lq_sta->pers.dbg_fixed_rate & RATE_MCS_ANT_ABC_MSK) >> - RATE_MCS_ANT_POS; - } else + return; + } #endif - rs_build_rates_table(mvm, lq_sta, initial_rate); + if (WARN_ON_ONCE(!sta || !initial_rate)) + return; - if (num_of_ant(ant) == 1) - lq_cmd->single_stream_ant_msk = ant; + rs_build_rates_table(mvm, lq_sta, initial_rate); - lq_cmd->agg_frame_cnt_limit = LINK_QUAL_AGG_FRAME_LIMIT_DEF; - lq_cmd->agg_disable_start_th = LINK_QUAL_AGG_DISABLE_START_DEF; + if (num_of_ant(initial_rate->ant) == 1) + lq_cmd->single_stream_ant_msk = initial_rate->ant; + + mvmsta = iwl_mvm_sta_from_mac80211(sta); + mvmvif = iwl_mvm_vif_from_mac80211(mvmsta->vif); + + if (num_of_ant(initial_rate->ant) == 1) + lq_cmd->single_stream_ant_msk = initial_rate->ant; + + lq_cmd->agg_frame_cnt_limit = mvmsta->max_agg_bufsize; + + /* + * In case of low latency, tell the firwmare to leave a frame in the + * Tx Fifo so that it can start a transaction in the same TxOP. This + * basically allows the firmware to send bursts. + */ + if (iwl_mvm_vif_low_latency(mvmvif)) + lq_cmd->agg_frame_cnt_limit--; lq_cmd->agg_time_limit = - cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF); - - if (sta) - lq_cmd->agg_time_limit = cpu_to_le16(iwl_mvm_coex_agg_time_limit(mvm, sta)); } @@ -2932,10 +2955,7 @@ static void rs_program_fix_rate(struct iwl_mvm *mvm, lq_sta->lq.sta_id, lq_sta->pers.dbg_fixed_rate); if (lq_sta->pers.dbg_fixed_rate) { - struct rs_rate rate; - rs_rate_from_ucode_rate(lq_sta->pers.dbg_fixed_rate, - lq_sta->band, &rate); - rs_fill_lq_cmd(mvm, NULL, lq_sta, &rate); + rs_fill_lq_cmd(mvm, NULL, lq_sta, NULL); iwl_mvm_send_lq_cmd(lq_sta->pers.drv, &lq_sta->lq, false); } } From 697162a13dea92cb4fbe72207e05ecf9a1552abd Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 30 Jul 2014 15:56:42 +0300 Subject: [PATCH 186/221] iwlwifi: mvm: use dynamic SMPS for P2P Client This allows to force the GO to use protection and enhances the reliability of the link. Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 6 +++++- drivers/net/wireless/iwlwifi/mvm/mvm.h | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 7c8796584c25..83c2ce60cdbb 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -1481,8 +1481,12 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, iwl_mvm_sf_update(mvm, vif, false); iwl_mvm_power_vif_assoc(mvm, vif); - if (vif->p2p) + if (vif->p2p) { iwl_mvm_ref(mvm, IWL_MVM_REF_P2P_CLIENT); + iwl_mvm_update_smps(mvm, vif, + IWL_MVM_SMPS_REQ_PROT, + IEEE80211_SMPS_DYNAMIC); + } } else if (mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) { /* * If update fails - SF might be running in associated diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 802d29e971f7..771cf468e2f8 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -253,6 +253,7 @@ struct iwl_dbgfs_bf { enum iwl_mvm_smps_type_request { IWL_MVM_SMPS_REQ_BT_COEX, IWL_MVM_SMPS_REQ_TT, + IWL_MVM_SMPS_REQ_PROT, NUM_IWL_MVM_SMPS_REQ, }; From 84fd7608a0d7b9e7ce350aab278780a3e341628f Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Wed, 30 Jul 2014 15:42:19 +0300 Subject: [PATCH 187/221] iwlwifi: mvm: add use_ps-poll debugfs power option By default, when uapsd is not used, the ucode uses null data packet to exit power-save and get then pending frames. However, some tests require the explicit usage of ps-poll. Allow setting use_ps_poll power option (through debugfs) to configure the ucode to use ps-poll instead. The ucode configuration is done by setting the advanced-pm flag while setting all the ACs to non-upasd mode. Signed-off-by: Eliad Peller Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c | 8 ++++++++ drivers/net/wireless/iwlwifi/mvm/mvm.h | 2 ++ drivers/net/wireless/iwlwifi/mvm/power.c | 9 ++++++++- 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c index 2e90ff795c13..5f5a94b9b7fc 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c @@ -119,6 +119,10 @@ static void iwl_dbgfs_update_pm(struct iwl_mvm *mvm, IWL_DEBUG_POWER(mvm, "uapsd_misbehaving_enable=%d\n", val); dbgfs_pm->uapsd_misbehaving = val; break; + case MVM_DEBUGFS_PM_USE_PS_POLL: + IWL_DEBUG_POWER(mvm, "use_ps_poll=%d\n", val); + dbgfs_pm->use_ps_poll = val; + break; } } @@ -169,6 +173,10 @@ static ssize_t iwl_dbgfs_pm_params_write(struct ieee80211_vif *vif, char *buf, if (sscanf(buf + 18, "%d", &val) != 1) return -EINVAL; param = MVM_DEBUGFS_PM_UAPSD_MISBEHAVING; + } else if (!strncmp("use_ps_poll=", buf, 12)) { + if (sscanf(buf + 12, "%d", &val) != 1) + return -EINVAL; + param = MVM_DEBUGFS_PM_USE_PS_POLL; } else { return -EINVAL; } diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 771cf468e2f8..83a00abb508d 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -203,6 +203,7 @@ enum iwl_dbgfs_pm_mask { MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD = BIT(7), MVM_DEBUGFS_PM_SNOOZE_ENABLE = BIT(8), MVM_DEBUGFS_PM_UAPSD_MISBEHAVING = BIT(9), + MVM_DEBUGFS_PM_USE_PS_POLL = BIT(10), }; struct iwl_dbgfs_pm { @@ -215,6 +216,7 @@ struct iwl_dbgfs_pm { u32 lprx_rssi_threshold; bool snooze_ena; bool uapsd_misbehaving; + bool use_ps_poll; int mask; }; diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c index 2b2d10800a55..8cbe7ea01a69 100644 --- a/drivers/net/wireless/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/iwlwifi/mvm/power.c @@ -198,8 +198,15 @@ static void iwl_mvm_power_configure_uapsd(struct iwl_mvm *mvm, } } - if (!(cmd->flags & cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK))) + if (!(cmd->flags & cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK))) { +#ifdef CONFIG_IWLWIFI_DEBUGFS + /* set advanced pm flag with no uapsd ACs to enable ps-poll */ + if (mvmvif->dbgfs_pm.use_ps_poll) + cmd->flags |= + cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK); +#endif return; + } cmd->flags |= cpu_to_le16(POWER_FLAGS_UAPSD_MISBEHAVING_ENA_MSK); From a4db848f2d0160a3fca08a5787dbef6bcc4ce2b3 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 31 Jul 2014 13:58:53 +0300 Subject: [PATCH 188/221] iwlwifi: mvm: force protection for P2P Performance is less an issue in P2P and reliability is critical. Enable protection always for P2P. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/rs.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 51fa571d5c45..b7a1efcac480 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -2858,6 +2858,9 @@ static void rs_fill_lq_cmd(struct iwl_mvm *mvm, if (iwl_mvm_vif_low_latency(mvmvif)) lq_cmd->agg_frame_cnt_limit--; + if (mvmsta->vif->p2p) + lq_cmd->flags |= LQ_FLAG_USE_RTS_MSK; + lq_cmd->agg_time_limit = cpu_to_le16(iwl_mvm_coex_agg_time_limit(mvm, sta)); } From b689fa799a1450056044a47d6afa6ad52f3a8997 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Wed, 20 Aug 2014 17:26:58 +0300 Subject: [PATCH 189/221] iwlwifi: mvm: reset the temperature when temperature test is disabled Since we can't read the actual temperature when the firmware is running, just set the temperature to 0 when the test is disabled and disable CT Kill if it was enabled. Additionally, since we rely on iwl_mvm_tt_handler() to exit CT kill when in test mode, call iwl_mvm_exit_ctkill() in that function if the temperature is low again. Also make the iwl_mvm_enter_ctkill() and iwl_mvm_exit_ctkill() return if called when not necessary anymore (e.g. when iwl_mvm_exit_ctkill() is called when we're not in CT-kill). Signed-off-by: Luciano Coelho Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/debugfs.c | 10 ++++++++++ drivers/net/wireless/iwlwifi/mvm/tt.c | 12 ++++++++++++ 2 files changed, 22 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index f7e44889182a..83e562b95a8e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -296,7 +296,15 @@ static ssize_t iwl_dbgfs_set_nic_temperature_write(struct iwl_mvm *mvm, mutex_lock(&mvm->mutex); if (temperature == IWL_MVM_DEBUG_SET_TEMPERATURE_DISABLE) { + if (!mvm->temperature_test) + goto out; + mvm->temperature_test = false; + /* Since we can't read the temp while awake, just set + * it to zero until we get the next RX stats from the + * firmware. + */ + mvm->temperature = 0; } else { mvm->temperature_test = true; mvm->temperature = temperature; @@ -306,6 +314,8 @@ static ssize_t iwl_dbgfs_set_nic_temperature_write(struct iwl_mvm *mvm, mvm->temperature); /* handle the temperature change */ iwl_mvm_tt_handler(mvm); + +out: mutex_unlock(&mvm->mutex); return count; diff --git a/drivers/net/wireless/iwlwifi/mvm/tt.c b/drivers/net/wireless/iwlwifi/mvm/tt.c index 0464599c111e..d31603cbb17d 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tt.c +++ b/drivers/net/wireless/iwlwifi/mvm/tt.c @@ -314,6 +314,9 @@ static void iwl_mvm_enter_ctkill(struct iwl_mvm *mvm) { u32 duration = mvm->thermal_throttle.params->ct_kill_duration; + if (test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status)) + return; + IWL_ERR(mvm, "Enter CT Kill\n"); iwl_mvm_set_hw_ctkill_state(mvm, true); schedule_delayed_work(&mvm->thermal_throttle.ct_kill_exit, @@ -322,6 +325,9 @@ static void iwl_mvm_enter_ctkill(struct iwl_mvm *mvm) static void iwl_mvm_exit_ctkill(struct iwl_mvm *mvm) { + if (!test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status)) + return; + IWL_ERR(mvm, "Exit CT Kill\n"); iwl_mvm_set_hw_ctkill_state(mvm, false); } @@ -444,6 +450,12 @@ void iwl_mvm_tt_handler(struct iwl_mvm *mvm) return; } + if (params->support_ct_kill && + temperature <= tt->params->ct_kill_exit) { + iwl_mvm_exit_ctkill(mvm); + return; + } + if (params->support_dynamic_smps) { if (!tt->dynamic_smps && temperature >= params->dynamic_smps_entry) { From efc36dbd5a0cbfbf0da0a6fa8e1c246bb78dab76 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Wed, 20 Aug 2014 17:58:20 +0300 Subject: [PATCH 190/221] iwlwifi: mvm: don't run automatic checks if CT was caused by debugfs If we're manually testing the CT kill functionality via debugfs, we shouldn't schedule the work to recheck the temperature after the ct_kill_duration period has passed. Signed-off-by: Luciano Coelho Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/tt.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/tt.c b/drivers/net/wireless/iwlwifi/mvm/tt.c index d31603cbb17d..4c22c0a09237 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tt.c +++ b/drivers/net/wireless/iwlwifi/mvm/tt.c @@ -319,8 +319,14 @@ static void iwl_mvm_enter_ctkill(struct iwl_mvm *mvm) IWL_ERR(mvm, "Enter CT Kill\n"); iwl_mvm_set_hw_ctkill_state(mvm, true); - schedule_delayed_work(&mvm->thermal_throttle.ct_kill_exit, - round_jiffies_relative(duration * HZ)); + + /* Don't schedule an exit work if we're in test mode, since + * the temperature will not change unless we manually set it + * again (or disable testing). + */ + if (!mvm->temperature_test) + schedule_delayed_work(&mvm->thermal_throttle.ct_kill_exit, + round_jiffies_relative(duration * HZ)); } static void iwl_mvm_exit_ctkill(struct iwl_mvm *mvm) From a2d79c5709659370cd2deeeeb8dc75bb0be5e318 Mon Sep 17 00:00:00 2001 From: Matti Gottlieb Date: Mon, 25 Aug 2014 14:41:23 +0300 Subject: [PATCH 191/221] iwlwifi: mvm: Add marker command 0xcb Add Marker command. The marker command send the ucode the time of sending the command in milliseconds since 1970-01-01 00:00:00 UTC, in addition to other metatdata. The ucode inserts this information into the usniffer logs, and returns the GP2 time stamp inside the command response. Signed-off-by: Matti Gottlieb Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/fw-api.h | 34 +++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index 95f5b3274efb..ed7d3f3d8b2f 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h @@ -184,6 +184,8 @@ enum { REPLY_RX_MPDU_CMD = 0xc1, BA_NOTIF = 0xc5, + MARKER_CMD = 0xcb, + /* BT Coex */ BT_COEX_PRIO_TABLE = 0xcc, BT_COEX_PROT_ENV = 0xcd, @@ -1307,6 +1309,38 @@ struct iwl_bcast_filter_cmd { struct iwl_fw_bcast_mac macs[NUM_MAC_INDEX_DRIVER]; } __packed; /* BCAST_FILTERING_HCMD_API_S_VER_1 */ +/* + * enum iwl_mvm_marker_id - maker ids + * + * The ids for different type of markers to insert into the usniffer logs + */ +enum iwl_mvm_marker_id { + MARKER_ID_TX_FRAME_LATENCY = 1, +}; /* MARKER_ID_API_E_VER_1 */ + +/** + * struct iwl_mvm_marker - mark info into the usniffer logs + * + * (MARKER_CMD = 0xcb) + * + * Mark the UTC time stamp into the usniffer logs together with additional + * metadata, so the usniffer output can be parsed. + * In the command response the ucode will return the GP2 time. + * + * @dw_len: The amount of dwords following this byte including this byte. + * @marker_id: A unique marker id (iwl_mvm_marker_id). + * @reserved: reserved. + * @timestamp: in milliseconds since 1970-01-01 00:00:00 UTC + * @metadata: additional meta data that will be written to the unsiffer log + */ +struct iwl_mvm_marker { + u8 dwLen; + u8 markerId; + __le16 reserved; + __le64 timestamp; + __le32 metadata[0]; +} __packed; /* MARKER_API_S_VER_1 */ + struct mvm_statistics_dbg { __le32 burst_check; __le32 burst_count; From 32be1a83af63c43fddcc39c2c1aedaa486af475f Mon Sep 17 00:00:00 2001 From: Eran Harary Date: Sun, 24 Aug 2014 08:02:46 +0300 Subject: [PATCH 192/221] iwlwifi: mvm: fix the dump_umac_error_log 1. the base_address limitation was wrong, address can be bigger than 0x80C000 2. the ucode data_struct changed. Signed-off-by: Eran Harary Reviewed-by: Liad Kaufman Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/utils.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c index ac249da8a22b..20fdca475d22 100644 --- a/drivers/net/wireless/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/iwlwifi/mvm/utils.c @@ -387,15 +387,19 @@ struct iwl_error_event_table { struct iwl_umac_error_event_table { u32 valid; /* (nonzero) valid, (0) log is empty */ u32 error_id; /* type of error */ - u32 pc; /* program counter */ u32 blink1; /* branch link */ u32 blink2; /* branch link */ u32 ilink1; /* interrupt link */ u32 ilink2; /* interrupt link */ u32 data1; /* error-specific data */ u32 data2; /* error-specific data */ - u32 line; /* source code line of error */ - u32 umac_ver; /* umac version */ + u32 data3; /* error-specific data */ + u32 umac_fw_ver; /* UMAC version */ + u32 umac_fw_api_ver; /* UMAC FW API ver */ + u32 frame_pointer; /* core register 27*/ + u32 stack_pointer; /* core register 28 */ + u32 cmd_header; /* latest host cmd sent to UMAC */ + u32 nic_isr_pref; /* ISR status register */ } __packed; #define ERROR_START_OFFSET (1 * sizeof(u32)) @@ -409,7 +413,7 @@ static void iwl_mvm_dump_umac_error_log(struct iwl_mvm *mvm) base = mvm->umac_error_event_table; - if (base < 0x800000 || base >= 0x80C000) { + if (base < 0x800000) { IWL_ERR(mvm, "Not valid error log pointer 0x%08X for %s uCode\n", base, @@ -428,14 +432,19 @@ static void iwl_mvm_dump_umac_error_log(struct iwl_mvm *mvm) IWL_ERR(mvm, "0x%08X | %-28s\n", table.error_id, desc_lookup(table.error_id)); - IWL_ERR(mvm, "0x%08X | umac uPc\n", table.pc); IWL_ERR(mvm, "0x%08X | umac branchlink1\n", table.blink1); IWL_ERR(mvm, "0x%08X | umac branchlink2\n", table.blink2); IWL_ERR(mvm, "0x%08X | umac interruptlink1\n", table.ilink1); IWL_ERR(mvm, "0x%08X | umac interruptlink2\n", table.ilink2); IWL_ERR(mvm, "0x%08X | umac data1\n", table.data1); IWL_ERR(mvm, "0x%08X | umac data2\n", table.data2); - IWL_ERR(mvm, "0x%08X | umac version\n", table.umac_ver); + IWL_ERR(mvm, "0x%08X | umac data3\n", table.data3); + IWL_ERR(mvm, "0x%08X | umac version\n", table.umac_fw_ver); + IWL_ERR(mvm, "0x%08X | umac api version\n", table.umac_fw_api_ver); + IWL_ERR(mvm, "0x%08X | frame pointer\n", table.frame_pointer); + IWL_ERR(mvm, "0x%08X | stack pointer\n", table.stack_pointer); + IWL_ERR(mvm, "0x%08X | last host cmd\n", table.cmd_header); + IWL_ERR(mvm, "0x%08X | isr status reg\n", table.nic_isr_pref); } void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm) From d6ca18de129fc4dd4374389561930b32820f35ff Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 1 Sep 2014 11:28:11 +0200 Subject: [PATCH 193/221] iwlwifi: make U-APSD default configurable at compile time With a significant number of deployed APs, enabling uAPSD leads to the AP never using aggregation sessions (likely due to the complexities involved in handling uAPSD in those.) This obviously results in a large drop in throughput with such APs. On the other hand, uAPSD can result in some power consumption benefits, but for now just disable it to get performance with affected APs back up. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/Kconfig | 10 ++++++++++ drivers/net/wireless/iwlwifi/iwl-drv.c | 8 +++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig index 6451d2b6abcf..760e96f63bb0 100644 --- a/drivers/net/wireless/iwlwifi/Kconfig +++ b/drivers/net/wireless/iwlwifi/Kconfig @@ -87,6 +87,16 @@ config IWLWIFI_BCAST_FILTERING If unsure, don't enable this option, as some programs might expect incoming broadcasts for their normal operations. +config IWLWIFI_UAPSD + bool "enable U-APSD by default" + depends on IWLMVM + help + Say Y here to enable U-APSD by default. This may cause + interoperability problems with some APs, manifesting in lower than + expected throughput due to those APs not enabling aggregation + + If unsure, say N. + menu "Debugging Options" config IWLWIFI_DEBUG diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c index 77e3178040b2..283aee0e28a4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/iwlwifi/iwl-drv.c @@ -1254,7 +1254,9 @@ struct iwl_mod_params iwlwifi_mod_params = { .bt_coex_active = true, .power_level = IWL_POWER_INDEX_1, .wd_disable = true, - .uapsd_disable = false, +#ifndef CONFIG_IWLWIFI_UAPSD + .uapsd_disable = true, +#endif /* CONFIG_IWLWIFI_UAPSD */ /* the rest are 0 by default */ }; IWL_EXPORT_SYMBOL(iwlwifi_mod_params); @@ -1370,7 +1372,11 @@ MODULE_PARM_DESC(nvm_file, "NVM file name"); module_param_named(uapsd_disable, iwlwifi_mod_params.uapsd_disable, bool, S_IRUGO); +#ifdef CONFIG_IWLWIFI_UAPSD MODULE_PARM_DESC(uapsd_disable, "disable U-APSD functionality (default: N)"); +#else +MODULE_PARM_DESC(uapsd_disable, "disable U-APSD functionality (default: Y)"); +#endif /* * set bt_coex_active to true, uCode will do kill/defer From bdd54839589f92fdfe80493e70aa7fe276da0c46 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Thu, 7 Aug 2014 18:08:56 +0300 Subject: [PATCH 194/221] iwlwifi: mvm: add debugfs entry for ps_disabled In order to make debugging easier, add an entry to export the ps_disabled value via debugfs. To make usage of the debugfs_create_*() function easier, change the ps_disabled element to u8. Signed-off-by: Luciano Coelho Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/debugfs.c | 3 +++ drivers/net/wireless/iwlwifi/mvm/mvm.h | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index 83e562b95a8e..1fcbc23678c4 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -1447,6 +1447,9 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) goto err; #endif + if (!debugfs_create_u8("ps_disabled", S_IRUSR, + mvm->debugfs_dir, &mvm->ps_disabled)) + goto err; if (!debugfs_create_blob("nvm_hw", S_IRUSR, mvm->debugfs_dir, &mvm->nvm_hw_blob)) goto err; diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 83a00abb508d..d6b00b97ae66 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -719,7 +719,7 @@ struct iwl_mvm { u8 last_agg_queue; /* Indicate if device power save is allowed */ - bool ps_disabled; + u8 ps_disabled; /* u8 instead of bool to ease debugfs_create_* usage */ struct ieee80211_vif __rcu *csa_vif; struct ieee80211_vif __rcu *csa_tx_blocked_vif; From 9ecd051ecd87d0a361c85064e57b27dc825d012e Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Thu, 28 Aug 2014 02:21:05 +0300 Subject: [PATCH 195/221] iwlwifi: mvm: disable tx aggregation on low latency vifs Aggregations hit latency so disable it by default on low latency vifs for now. Enable control over this behavior and allow control over the max frames in an AMPDU in low latency vifs via debugfs. Signed-off-by: Eyal Shapira Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/debugfs.c | 4 ++++ drivers/net/wireless/iwlwifi/mvm/mvm.h | 2 ++ drivers/net/wireless/iwlwifi/mvm/ops.c | 1 + drivers/net/wireless/iwlwifi/mvm/rs.c | 8 +++++++- 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index 1fcbc23678c4..f85d4f4519f6 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -1447,6 +1447,10 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) goto err; #endif + if (!debugfs_create_u8("low_latency_agg_frame_limit", S_IRUSR | S_IWUSR, + mvm->debugfs_dir, + &mvm->low_latency_agg_frame_limit)) + goto err; if (!debugfs_create_u8("ps_disabled", S_IRUSR, mvm->debugfs_dir, &mvm->ps_disabled)) goto err; diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index d6b00b97ae66..08cb26d86be2 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -727,6 +727,8 @@ struct iwl_mvm { /* system time of last beacon (for AP/GO interface) */ u32 ap_last_beacon_gp2; + + u8 low_latency_agg_frame_limit; }; /* Extract MVM priv from op_mode and _hw */ diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 610dbcb0dc27..e3be34f6aa41 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -415,6 +415,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, mvm->first_agg_queue = 12; } mvm->sf_state = SF_UNINIT; + mvm->low_latency_agg_frame_limit = 1; mutex_init(&mvm->mutex); mutex_init(&mvm->d0i3_suspend_mutex); diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index b7a1efcac480..940e0d025012 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -2855,9 +2855,15 @@ static void rs_fill_lq_cmd(struct iwl_mvm *mvm, * Tx Fifo so that it can start a transaction in the same TxOP. This * basically allows the firmware to send bursts. */ - if (iwl_mvm_vif_low_latency(mvmvif)) + if (iwl_mvm_vif_low_latency(mvmvif)) { lq_cmd->agg_frame_cnt_limit--; + if (mvm->low_latency_agg_frame_limit) + lq_cmd->agg_frame_cnt_limit = + min(lq_cmd->agg_frame_cnt_limit, + mvm->low_latency_agg_frame_limit); + } + if (mvmsta->vif->p2p) lq_cmd->flags |= LQ_FLAG_USE_RTS_MSK; From 228670b2e6f8d32f11d27c5165fb42a2c77f062c Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Sun, 10 Aug 2014 17:00:15 +0300 Subject: [PATCH 196/221] iwlwifi: mvm: clear d0i3 state on recovery If recovery happened after mvm entered d0i3 (e.g. due to sysassert when releasing the bus), the mvm->state wasn't cleared properly, causing the ongoing recovery to fail (due to iwl_mvm_ref_sync failure). This in turn fails the ongoing recovery, and triggers a reprobe, which terminates any ongoing wifi activity. Signed-off-by: Eliad Peller Reviewed-by: Gregory Greenman Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 83c2ce60cdbb..de4ae94f07e0 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -803,6 +803,9 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) * ucode_down ref until reconfig is complete */ iwl_mvm_unref_all_except(mvm, IWL_MVM_REF_UCODE_DOWN); + /* clear any stale d0i3 state */ + clear_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status); + mvm->vif_count = 0; mvm->rx_ba_sessions = 0; } From b1873300e15aff44c01f7c9bc275c2c6e414f2fa Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Fri, 8 Aug 2014 17:12:07 +0300 Subject: [PATCH 197/221] iwlwifi: mvm: re-enable ps when monitor interfaces are removed If a monitor interface is added and then removed, we don't reset the mvm->ps_disabled flag, so we never re-enable power saving. Fix that and rearrange the code a bit. Additionally, fix a small indentation mistake in the iwl_mvm_power_set_pm() function declaration. Signed-off-by: Luciano Coelho Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 1 + drivers/net/wireless/iwlwifi/mvm/power.c | 30 +++++++++++---------- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index de4ae94f07e0..531540c54efb 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -776,6 +776,7 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) iwl_trans_stop_device(mvm->trans); mvm->scan_status = IWL_MVM_SCAN_NONE; + mvm->ps_disabled = false; /* just in case one was running */ ieee80211_remain_on_channel_expired(mvm->hw); diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c index 8cbe7ea01a69..754f2b3eae64 100644 --- a/drivers/net/wireless/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/iwlwifi/mvm/power.c @@ -566,9 +566,8 @@ static void iwl_mvm_power_iterator(void *_data, u8 *mac, } } -static void -iwl_mvm_power_set_pm(struct iwl_mvm *mvm, - struct iwl_power_vifs *vifs) +static void iwl_mvm_power_set_pm(struct iwl_mvm *mvm, + struct iwl_power_vifs *vifs) { struct iwl_mvm_vif *bss_mvmvif = NULL; struct iwl_mvm_vif *p2p_mvmvif = NULL; @@ -830,7 +829,7 @@ int iwl_mvm_power_update_mac(struct iwl_mvm *mvm) struct iwl_power_vifs vifs = { .mvm = mvm, }; - bool ba_enable; + bool ba_enable, disable_ps; int ret; lockdep_assert_held(&mvm->mutex); @@ -838,16 +837,19 @@ int iwl_mvm_power_update_mac(struct iwl_mvm *mvm) iwl_mvm_power_set_pm(mvm, &vifs); /* disable PS if CAM */ - if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM) { - mvm->ps_disabled = true; - } else { - /* don't update device power state unless we add / remove monitor */ - if (vifs.monitor_vif) { - if (vifs.monitor_active) - mvm->ps_disabled = true; - ret = iwl_mvm_power_update_device(mvm); - if (ret) - return ret; + disable_ps = (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM); + /* ...or if there is an active monitor vif */ + disable_ps |= (vifs.monitor_vif && vifs.monitor_active); + + /* update device power state if it has changed */ + if (mvm->ps_disabled != disable_ps) { + bool old_ps_disabled = mvm->ps_disabled; + + mvm->ps_disabled = disable_ps; + ret = iwl_mvm_power_update_device(mvm); + if (ret) { + mvm->ps_disabled = old_ps_disabled; + return ret; } } From 128aa948d0606e537b743fb8e29ce09fc3473137 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Fri, 8 Aug 2014 18:36:22 +0300 Subject: [PATCH 198/221] iwlwifi: mvm: refactor iwl_mvm_power_set_pm() to spin the ps part off Separate the ps part of iwl_mvm_power_set_pm() into a new iwl_mvm_power_set_ps() function. This will enable us to update the ps part independently from the rest, which is needed by CSA (at least). This required a bit of refactoring and the creation of a new iterator function. Signed-off-by: Luciano Coelho Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/power.c | 60 +++++++++++++++++------- 1 file changed, 43 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c index 754f2b3eae64..42aaf57b6dfd 100644 --- a/drivers/net/wireless/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/iwlwifi/mvm/power.c @@ -504,13 +504,20 @@ struct iwl_power_vifs { bool p2p_tdls; }; -static void iwl_mvm_power_iterator(void *_data, u8 *mac, - struct ieee80211_vif *vif) +static void iwl_mvm_power_disable_pm_iterator(void *_data, u8* mac, + struct ieee80211_vif *vif) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + + mvmvif->pm_enabled = false; +} + +static void iwl_mvm_power_get_vifs_iterator(void *_data, u8 *mac, + struct ieee80211_vif *vif) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_power_vifs *power_iterator = _data; - mvmvif->pm_enabled = false; switch (ieee80211_vif_type_p2p(vif)) { case NL80211_IFTYPE_P2P_DEVICE: break; @@ -577,10 +584,11 @@ static void iwl_mvm_power_set_pm(struct iwl_mvm *mvm, lockdep_assert_held(&mvm->mutex); - /* get vifs info + set pm_enable to false */ + /* set pm_enable to false */ ieee80211_iterate_active_interfaces_atomic(mvm->hw, - IEEE80211_IFACE_ITER_NORMAL, - iwl_mvm_power_iterator, vifs); + IEEE80211_IFACE_ITER_NORMAL, + iwl_mvm_power_disable_pm_iterator, + NULL); if (vifs->bss_vif) bss_mvmvif = iwl_mvm_vif_from_mac80211(vifs->bss_vif); @@ -823,23 +831,16 @@ int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm, return ret; } -int iwl_mvm_power_update_mac(struct iwl_mvm *mvm) +static int iwl_mvm_power_set_ps(struct iwl_mvm *mvm, + struct iwl_power_vifs *vifs) { - struct iwl_mvm_vif *mvmvif; - struct iwl_power_vifs vifs = { - .mvm = mvm, - }; - bool ba_enable, disable_ps; + bool disable_ps; int ret; - lockdep_assert_held(&mvm->mutex); - - iwl_mvm_power_set_pm(mvm, &vifs); - /* disable PS if CAM */ disable_ps = (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM); /* ...or if there is an active monitor vif */ - disable_ps |= (vifs.monitor_vif && vifs.monitor_active); + disable_ps |= (vifs->monitor_vif && vifs->monitor_active); /* update device power state if it has changed */ if (mvm->ps_disabled != disable_ps) { @@ -853,6 +854,31 @@ int iwl_mvm_power_update_mac(struct iwl_mvm *mvm) } } + return 0; +} + +int iwl_mvm_power_update_mac(struct iwl_mvm *mvm) +{ + struct iwl_mvm_vif *mvmvif; + struct iwl_power_vifs vifs = { + .mvm = mvm, + }; + bool ba_enable; + int ret; + + lockdep_assert_held(&mvm->mutex); + + /* get vifs info */ + ieee80211_iterate_active_interfaces_atomic(mvm->hw, + IEEE80211_IFACE_ITER_NORMAL, + iwl_mvm_power_get_vifs_iterator, &vifs); + + iwl_mvm_power_set_pm(mvm, &vifs); + + ret = iwl_mvm_power_set_ps(mvm, &vifs); + if (ret) + return ret; + if (vifs.bss_vif) { ret = iwl_mvm_power_send_cmd(mvm, vifs.bss_vif); if (ret) From ef9203d23fecf11e02958de0988170a67adf7447 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Fri, 8 Aug 2014 19:18:35 +0300 Subject: [PATCH 199/221] iwlwifi: mvm: add function to update only ps Add a new iwl_mvm_power_update_ps() function that allows only ps to be updated according to changes in the vifs. This allows us to disable ps only without affecting the pm values of the vifs (and to avoid sending unnecessary MAC_PM_POWER_TABLE commands to the firmware). Signed-off-by: Luciano Coelho Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mvm.h | 1 + drivers/net/wireless/iwlwifi/mvm/power.c | 52 ++++++++++++++++++------ 2 files changed, 41 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 08cb26d86be2..108ef161ee11 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -983,6 +983,7 @@ int rs_pretty_print_rate(char *buf, const u32 rate); /* power management */ int iwl_mvm_power_update_device(struct iwl_mvm *mvm); int iwl_mvm_power_update_mac(struct iwl_mvm *mvm); +int iwl_mvm_power_update_ps(struct iwl_mvm *mvm); int iwl_mvm_power_mac_dbgfs_read(struct iwl_mvm *mvm, struct ieee80211_vif *vif, char *buf, int bufsz); diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c index 42aaf57b6dfd..18f887aa32ae 100644 --- a/drivers/net/wireless/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/iwlwifi/mvm/power.c @@ -857,13 +857,50 @@ static int iwl_mvm_power_set_ps(struct iwl_mvm *mvm, return 0; } -int iwl_mvm_power_update_mac(struct iwl_mvm *mvm) +static int iwl_mvm_power_set_ba(struct iwl_mvm *mvm, + struct iwl_power_vifs *vifs) { struct iwl_mvm_vif *mvmvif; + bool ba_enable; + + if (!vifs->bf_vif) + return 0; + + mvmvif = iwl_mvm_vif_from_mac80211(vifs->bf_vif); + + ba_enable = !(!mvmvif->pm_enabled || mvm->ps_disabled || + !vifs->bf_vif->bss_conf.ps || + iwl_mvm_vif_low_latency(mvmvif)); + + return iwl_mvm_update_beacon_abort(mvm, vifs->bf_vif, ba_enable); +} + +int iwl_mvm_power_update_ps(struct iwl_mvm *mvm) +{ + struct iwl_power_vifs vifs = { + .mvm = mvm, + }; + int ret; + + lockdep_assert_held(&mvm->mutex); + + /* get vifs info */ + ieee80211_iterate_active_interfaces_atomic(mvm->hw, + IEEE80211_IFACE_ITER_NORMAL, + iwl_mvm_power_get_vifs_iterator, &vifs); + + ret = iwl_mvm_power_set_ps(mvm, &vifs); + if (ret) + return ret; + + return iwl_mvm_power_set_ba(mvm, &vifs); +} + +int iwl_mvm_power_update_mac(struct iwl_mvm *mvm) +{ struct iwl_power_vifs vifs = { .mvm = mvm, }; - bool ba_enable; int ret; lockdep_assert_held(&mvm->mutex); @@ -891,16 +928,7 @@ int iwl_mvm_power_update_mac(struct iwl_mvm *mvm) return ret; } - if (!vifs.bf_vif) - return 0; - - mvmvif = iwl_mvm_vif_from_mac80211(vifs.bf_vif); - - ba_enable = !(!mvmvif->pm_enabled || mvm->ps_disabled || - !vifs.bf_vif->bss_conf.ps || - iwl_mvm_vif_low_latency(mvmvif)); - - return iwl_mvm_update_beacon_abort(mvm, vifs.bf_vif, ba_enable); + return iwl_mvm_power_set_ba(mvm, &vifs); } int iwl_mvm_update_d0i3_power_mode(struct iwl_mvm *mvm, From 2533edcee8aa311a24e5c0a7da955893ad65dc24 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Fri, 8 Aug 2014 19:50:46 +0300 Subject: [PATCH 200/221] iwlwifi: mvm: add option that allows a vif to disable PS We need to disable PS when a monitor vif is active or, in the future, when a channel switch is happening. Add a boolean to mvmvif that allows PS to be disabled generically. Additionally, make the monitor interface use this new flag when it gets activated. Signed-off-by: Luciano Coelho Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 4 ++++ drivers/net/wireless/iwlwifi/mvm/mvm.h | 2 ++ drivers/net/wireless/iwlwifi/mvm/power.c | 25 ++++++++++++++++----- 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 531540c54efb..98e14f9c6fbe 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -2708,7 +2708,10 @@ static int __iwl_mvm_assign_vif_chanctx(struct iwl_mvm *mvm, ret = 0; goto out; case NL80211_IFTYPE_STATION: + break; case NL80211_IFTYPE_MONITOR: + /* always disable PS when a monitor interface is active */ + mvmvif->ps_disabled = true; break; default: ret = -EINVAL; @@ -2784,6 +2787,7 @@ static void __iwl_mvm_unassign_vif_chanctx(struct iwl_mvm *mvm, goto out; case NL80211_IFTYPE_MONITOR: mvmvif->monitor_active = false; + mvmvif->ps_disabled = false; break; case NL80211_IFTYPE_AP: /* This part is triggered only during CSA */ diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 108ef161ee11..ffb509362828 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -326,6 +326,7 @@ struct iwl_mvm_vif_bf_data { * interface should get quota etc. * @low_latency: indicates that this interface is in low-latency mode * (VMACLowLatencyMode) + * @ps_disabled: indicates that this interface requires PS to be disabled * @queue_params: QoS params for this MAC * @bcast_sta: station used for broadcast packets. Used by the following * vifs: P2P_DEVICE, GO and AP. @@ -343,6 +344,7 @@ struct iwl_mvm_vif { bool pm_enabled; bool monitor_active; bool low_latency; + bool ps_disabled; struct iwl_mvm_vif_bf_data bf_data; u32 ap_beacon_time; diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c index 18f887aa32ae..b552183d0a31 100644 --- a/drivers/net/wireless/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/iwlwifi/mvm/power.c @@ -512,6 +512,17 @@ static void iwl_mvm_power_disable_pm_iterator(void *_data, u8* mac, mvmvif->pm_enabled = false; } +static void iwl_mvm_power_ps_disabled_iterator(void *_data, u8* mac, + struct ieee80211_vif *vif) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + bool *disable_ps = _data; + + if (mvmvif->phy_ctxt) + if (mvmvif->phy_ctxt->id < MAX_PHYS) + *disable_ps |= mvmvif->ps_disabled; +} + static void iwl_mvm_power_get_vifs_iterator(void *_data, u8 *mac, struct ieee80211_vif *vif) { @@ -831,16 +842,18 @@ int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm, return ret; } -static int iwl_mvm_power_set_ps(struct iwl_mvm *mvm, - struct iwl_power_vifs *vifs) +static int iwl_mvm_power_set_ps(struct iwl_mvm *mvm) { bool disable_ps; int ret; /* disable PS if CAM */ disable_ps = (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM); - /* ...or if there is an active monitor vif */ - disable_ps |= (vifs->monitor_vif && vifs->monitor_active); + /* ...or if any of the vifs require PS to be off */ + ieee80211_iterate_active_interfaces_atomic(mvm->hw, + IEEE80211_IFACE_ITER_NORMAL, + iwl_mvm_power_ps_disabled_iterator, + &disable_ps); /* update device power state if it has changed */ if (mvm->ps_disabled != disable_ps) { @@ -889,7 +902,7 @@ int iwl_mvm_power_update_ps(struct iwl_mvm *mvm) IEEE80211_IFACE_ITER_NORMAL, iwl_mvm_power_get_vifs_iterator, &vifs); - ret = iwl_mvm_power_set_ps(mvm, &vifs); + ret = iwl_mvm_power_set_ps(mvm); if (ret) return ret; @@ -912,7 +925,7 @@ int iwl_mvm_power_update_mac(struct iwl_mvm *mvm) iwl_mvm_power_set_pm(mvm, &vifs); - ret = iwl_mvm_power_set_ps(mvm, &vifs); + ret = iwl_mvm_power_set_ps(mvm); if (ret) return ret; From d20d37bc39766ecc31e68bc9cf238eab27a4157b Mon Sep 17 00:00:00 2001 From: Liad Kaufman Date: Sun, 6 Jul 2014 17:14:39 +0300 Subject: [PATCH 201/221] iwlwifi: mvm: wait for TE notif when protecting TDLS session Make sure that when running the TDLS discovery session protection - the time event that ensures we remain on channel has been scheduled and started running before leaving. Signed-off-by: Liad Kaufman Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 6 +- drivers/net/wireless/iwlwifi/mvm/time-event.c | 59 ++++++++++++++++++- drivers/net/wireless/iwlwifi/mvm/time-event.h | 6 +- 3 files changed, 64 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 98e14f9c6fbe..5bc7557d4efe 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -1480,7 +1480,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, */ u32 dur = (11 * vif->bss_conf.beacon_int) / 10; iwl_mvm_protect_session(mvm, vif, dur, dur, - 5 * dur); + 5 * dur, false); } iwl_mvm_sf_update(mvm, vif, false); @@ -2149,7 +2149,7 @@ static void iwl_mvm_mac_mgd_prepare_tx(struct ieee80211_hw *hw, mutex_lock(&mvm->mutex); /* Try really hard to protect the session and hear a beacon */ - iwl_mvm_protect_session(mvm, vif, duration, min_duration, 500); + iwl_mvm_protect_session(mvm, vif, duration, min_duration, 500, false); mutex_unlock(&mvm->mutex); iwl_mvm_unref(mvm, IWL_MVM_REF_PREPARE_TX); @@ -2170,7 +2170,7 @@ static void iwl_mvm_mac_mgd_protect_tdls_discover(struct ieee80211_hw *hw, mutex_lock(&mvm->mutex); /* Protect the session to hear the TDLS setup response on the channel */ - iwl_mvm_protect_session(mvm, vif, duration, duration, 100); + iwl_mvm_protect_session(mvm, vif, duration, duration, 100, true); mutex_unlock(&mvm->mutex); iwl_mvm_unref(mvm, IWL_MVM_REF_PROTECT_TDLS); diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.c b/drivers/net/wireless/iwlwifi/mvm/time-event.c index 33e5041f1efc..51c610f6d17b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/iwlwifi/mvm/time-event.c @@ -348,6 +348,38 @@ unlock: return 0; } +static bool iwl_mvm_te_notif(struct iwl_notif_wait_data *notif_wait, + struct iwl_rx_packet *pkt, void *data) +{ + struct iwl_mvm *mvm = + container_of(notif_wait, struct iwl_mvm, notif_wait); + struct iwl_mvm_time_event_data *te_data = data; + struct iwl_time_event_notif *resp; + int resp_len = iwl_rx_packet_payload_len(pkt); + + if (WARN_ON(pkt->hdr.cmd != TIME_EVENT_NOTIFICATION)) + return true; + + if (WARN_ON_ONCE(resp_len != sizeof(*resp))) { + IWL_ERR(mvm, "Invalid TIME_EVENT_NOTIFICATION response\n"); + return true; + } + + resp = (void *)pkt->data; + + /* te_data->uid is already set in the TIME_EVENT_CMD response */ + if (le32_to_cpu(resp->unique_id) != te_data->uid) + return false; + + IWL_DEBUG_TE(mvm, "TIME_EVENT_NOTIFICATION response - UID = 0x%x\n", + te_data->uid); + if (!resp->status) + IWL_ERR(mvm, + "TIME_EVENT_NOTIFICATION received but not executed\n"); + + return true; +} + static bool iwl_mvm_time_event_response(struct iwl_notif_wait_data *notif_wait, struct iwl_rx_packet *pkt, void *data) { @@ -441,10 +473,12 @@ static int iwl_mvm_time_event_send_add(struct iwl_mvm *mvm, void iwl_mvm_protect_session(struct iwl_mvm *mvm, struct ieee80211_vif *vif, u32 duration, u32 min_duration, - u32 max_delay) + u32 max_delay, bool wait_for_notif) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data; + const u8 te_notif_response[] = { TIME_EVENT_NOTIFICATION }; + struct iwl_notification_wait wait_te_notif; struct iwl_time_event_cmd time_cmd = {}; lockdep_assert_held(&mvm->mutex); @@ -489,7 +523,28 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm, TE_V2_NOTIF_HOST_EVENT_END | T2_V2_START_IMMEDIATELY); - iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd); + if (!wait_for_notif) { + iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd); + return; + } + + /* + * Create notification_wait for the TIME_EVENT_NOTIFICATION to use + * right after we send the time event + */ + iwl_init_notification_wait(&mvm->notif_wait, &wait_te_notif, + te_notif_response, + ARRAY_SIZE(te_notif_response), + iwl_mvm_te_notif, te_data); + + /* If TE was sent OK - wait for the notification that started */ + if (iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd)) { + IWL_ERR(mvm, "Failed to add TE to protect session\n"); + iwl_remove_notification(&mvm->notif_wait, &wait_te_notif); + } else if (iwl_wait_notification(&mvm->notif_wait, &wait_te_notif, + TU_TO_JIFFIES(max_delay))) { + IWL_ERR(mvm, "Failed to protect session until TE\n"); + } } /* diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.h b/drivers/net/wireless/iwlwifi/mvm/time-event.h index 2f48a90d4ad3..9126379ff2c6 100644 --- a/drivers/net/wireless/iwlwifi/mvm/time-event.h +++ b/drivers/net/wireless/iwlwifi/mvm/time-event.h @@ -124,10 +124,12 @@ * @min_duration: will start a new session if the current session will end * in less than min_duration. * @max_delay: maximum delay before starting the time event (in TU) + * @wait_for_notif: true if it is required that a time event notification be + * waited for (that the time event has been scheduled before returning) * * This function can be used to start a session protection which means that the * fw will stay on the channel for %duration_ms milliseconds. This function - * will block (sleep) until the session starts. This function can also be used + * can block (sleep) until the session starts. This function can also be used * to extend a currently running session. * This function is meant to be used for BSS association for example, where we * want to make sure that the fw stays on the channel during the association. @@ -135,7 +137,7 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm, struct ieee80211_vif *vif, u32 duration, u32 min_duration, - u32 max_delay); + u32 max_delay, bool wait_for_notif); /** * iwl_mvm_stop_session_protection - cancel the session protection. From 680073b78a5ac2b559bb7315528aa9f95e57ae24 Mon Sep 17 00:00:00 2001 From: Avri Altman Date: Mon, 14 Jul 2014 09:40:27 +0300 Subject: [PATCH 202/221] iwlwifi: consolidate hw scheduler configuration code Configuring the hw scheduler during queue enablement is done by writing the appropriate values to the scheduler peripherals, and it is essentially the same for all buses. Whenever writing is done via the standard iwl_write_prph, we can avoid duplicating the code for each bus. Those operations are queue deactivation, RA/TID mapping, chain-building settings, enabling/disabling aggregations and activating/deactivating the TX FIFOs. Consolidate this code using static inlines in a new header file. Signed-off-by: Avri Altman Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-scd.h | 112 +++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/pcie/tx.c | 39 ++------- 2 files changed, 121 insertions(+), 30 deletions(-) create mode 100644 drivers/net/wireless/iwlwifi/iwl-scd.h diff --git a/drivers/net/wireless/iwlwifi/iwl-scd.h b/drivers/net/wireless/iwlwifi/iwl-scd.h new file mode 100644 index 000000000000..5f099d45c09a --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-scd.h @@ -0,0 +1,112 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2014 Intel Mobile Communications GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * Contact Information: + * Intel Linux Wireless + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2014 Intel Mobile Communications GmbH + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ + +#ifndef __iwl_scd_h__ +#define __iwl_scd_h__ + +#include "iwl-trans.h" +#include "iwl-io.h" +#include "iwl-prph.h" + + +static inline void iwl_scd_txq_set_inactive(struct iwl_trans *trans, + u16 txq_id) +{ + iwl_write_prph(trans, SCD_QUEUE_STATUS_BITS(txq_id), + (0 << SCD_QUEUE_STTS_REG_POS_ACTIVE)| + (1 << SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN)); +} + +static inline void iwl_scd_txq_set_chain(struct iwl_trans *trans, + u16 txq_id) +{ + iwl_set_bits_prph(trans, SCD_QUEUECHAIN_SEL, BIT(txq_id)); +} + +static inline void iwl_scd_txq_enable_agg(struct iwl_trans *trans, + u16 txq_id) +{ + iwl_set_bits_prph(trans, SCD_AGGR_SEL, BIT(txq_id)); +} + +static inline void iwl_scd_txq_disable_agg(struct iwl_trans *trans, + u16 txq_id) +{ + iwl_clear_bits_prph(trans, SCD_AGGR_SEL, BIT(txq_id)); +} + +static inline void iwl_scd_disable_agg(struct iwl_trans *trans) +{ + iwl_set_bits_prph(trans, SCD_AGGR_SEL, 0); +} + +static inline void iwl_scd_activate_fifos(struct iwl_trans *trans) +{ + iwl_write_prph(trans, SCD_TXFACT, IWL_MASK(0, 7)); +} + +static inline void iwl_scd_deactivate_fifos(struct iwl_trans *trans) +{ + iwl_write_prph(trans, SCD_TXFACT, 0); +} +#endif diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index 6acccb19c4f3..84c3a0115c4d 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c @@ -34,6 +34,7 @@ #include "iwl-csr.h" #include "iwl-prph.h" #include "iwl-io.h" +#include "iwl-scd.h" #include "iwl-op-mode.h" #include "internal.h" /* FIXME: need to abstract out TX command (once we know what it looks like) */ @@ -644,17 +645,6 @@ static void iwl_pcie_txq_free(struct iwl_trans *trans, int txq_id) memset(txq, 0, sizeof(*txq)); } -/* - * Activate/Deactivate Tx DMA/FIFO channels according tx fifos mask - */ -static void iwl_pcie_txq_set_sched(struct iwl_trans *trans, u32 mask) -{ - struct iwl_trans_pcie __maybe_unused *trans_pcie = - IWL_TRANS_GET_PCIE_TRANS(trans); - - iwl_write_prph(trans, SCD_TXFACT, mask); -} - void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); @@ -692,7 +682,7 @@ void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr) trans_pcie->cmd_fifo); /* Activate all Tx DMA/FIFO channels */ - iwl_pcie_txq_set_sched(trans, IWL_MASK(0, 7)); + iwl_scd_activate_fifos(trans); /* Enable DMA channel */ for (chan = 0; chan < FH_TCSR_CHNL_NUM; chan++) @@ -745,7 +735,7 @@ int iwl_pcie_tx_stop(struct iwl_trans *trans) /* Turn off all Tx DMA fifos */ spin_lock(&trans_pcie->irq_lock); - iwl_pcie_txq_set_sched(trans, 0); + iwl_scd_deactivate_fifos(trans); /* Stop each Tx DMA channel, and wait for it to be idle */ for (ch = 0; ch < FH_TCSR_CHNL_NUM; ch++) { @@ -886,7 +876,7 @@ int iwl_pcie_tx_init(struct iwl_trans *trans) spin_lock(&trans_pcie->irq_lock); /* Turn off all Tx DMA fifos */ - iwl_write_prph(trans, SCD_TXFACT, 0); + iwl_scd_deactivate_fifos(trans); /* Tell NIC where to find the "keep warm" buffer */ iwl_write_direct32(trans, FH_KW_MEM_ADDR_REG, @@ -1072,17 +1062,6 @@ static int iwl_pcie_txq_set_ratid_map(struct iwl_trans *trans, u16 ra_tid, return 0; } -static inline void iwl_pcie_txq_set_inactive(struct iwl_trans *trans, - u16 txq_id) -{ - /* Simply stop the queue, but don't change any configuration; - * the SCD_ACT_EN bit is the write-enable mask for the ACTIVE bit. */ - iwl_write_prph(trans, - SCD_QUEUE_STATUS_BITS(txq_id), - (0 << SCD_QUEUE_STTS_REG_POS_ACTIVE)| - (1 << SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN)); -} - /* Receiver address (actually, Rx station's index into station table), * combined with Traffic ID (QOS priority), in format used by Tx Scheduler */ #define BUILD_RAxTID(sta_id, tid) (((sta_id) << 4) + (tid)) @@ -1096,11 +1075,11 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, int fifo, WARN_ONCE(1, "queue %d already used - expect issues", txq_id); /* Stop this Tx queue before configuring it */ - iwl_pcie_txq_set_inactive(trans, txq_id); + iwl_scd_txq_set_inactive(trans, txq_id); /* Set this queue as a chain-building queue unless it is CMD queue */ if (txq_id != trans_pcie->cmd_queue) - iwl_set_bits_prph(trans, SCD_QUEUECHAIN_SEL, BIT(txq_id)); + iwl_scd_txq_set_chain(trans, txq_id); /* If this queue is mapped to a certain station: it is an AGG queue */ if (sta_id >= 0) { @@ -1110,7 +1089,7 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, int fifo, iwl_pcie_txq_set_ratid_map(trans, ra_tid, txq_id); /* enable aggregations for the queue */ - iwl_set_bits_prph(trans, SCD_AGGR_SEL, BIT(txq_id)); + iwl_scd_txq_enable_agg(trans, txq_id); trans_pcie->txq[txq_id].ampdu = true; } else { /* @@ -1118,7 +1097,7 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, int fifo, * ra_tid mapping configuration irrelevant since it is now a * non-AGG queue. */ - iwl_clear_bits_prph(trans, SCD_AGGR_SEL, BIT(txq_id)); + iwl_scd_txq_disable_agg(trans, txq_id); ssn = trans_pcie->txq[txq_id].q.read_ptr; } @@ -1172,7 +1151,7 @@ void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int txq_id) return; } - iwl_pcie_txq_set_inactive(trans, txq_id); + iwl_scd_txq_set_inactive(trans, txq_id); iwl_trans_write_mem(trans, stts_addr, (void *)zero_val, ARRAY_SIZE(zero_val)); From fea7795f1c976513a3262284c4001606075abf5c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 1 Aug 2014 11:58:47 +0200 Subject: [PATCH 203/221] iwlwifi: trans: refactor txq_enable arguments Instead of having all arguments passed to the function, add a struct to hold them and only pass some directly. This will make future work in this area cleaner. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-trans.h | 21 ++++++++++++++++---- drivers/net/wireless/iwlwifi/pcie/internal.h | 4 ++-- drivers/net/wireless/iwlwifi/pcie/tx.c | 13 ++++++------ 3 files changed, 26 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index 656371a668da..c198dde339c6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -401,6 +401,13 @@ struct iwl_trans_dump_data { struct iwl_trans; +struct iwl_trans_txq_scd_cfg { + u8 fifo; + s8 sta_id; + u8 tid; + int frame_limit; +}; + /** * struct iwl_trans_ops - transport specific operations * @@ -492,8 +499,8 @@ struct iwl_trans_ops { void (*reclaim)(struct iwl_trans *trans, int queue, int ssn, struct sk_buff_head *skbs); - void (*txq_enable)(struct iwl_trans *trans, int queue, int fifo, - int sta_id, int tid, int frame_limit, u16 ssn); + void (*txq_enable)(struct iwl_trans *trans, int queue, u16 ssn, + const struct iwl_trans_txq_scd_cfg *cfg); void (*txq_disable)(struct iwl_trans *trans, int queue); int (*dbgfs_register)(struct iwl_trans *trans, struct dentry* dir); @@ -775,13 +782,19 @@ static inline void iwl_trans_txq_enable(struct iwl_trans *trans, int queue, int fifo, int sta_id, int tid, int frame_limit, u16 ssn) { + struct iwl_trans_txq_scd_cfg cfg = { + .fifo = fifo, + .sta_id = sta_id, + .tid = tid, + .frame_limit = frame_limit, + }; + might_sleep(); if (unlikely((trans->state != IWL_TRANS_FW_ALIVE))) IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state); - trans->ops->txq_enable(trans, queue, fifo, sta_id, tid, - frame_limit, ssn); + trans->ops->txq_enable(trans, queue, ssn, &cfg); } static inline void iwl_trans_ac_txq_enable(struct iwl_trans *trans, int queue, diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h index 78f72c34438a..5760405a9cad 100644 --- a/drivers/net/wireless/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/iwlwifi/pcie/internal.h @@ -364,8 +364,8 @@ int iwl_pcie_tx_init(struct iwl_trans *trans); void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr); int iwl_pcie_tx_stop(struct iwl_trans *trans); void iwl_pcie_tx_free(struct iwl_trans *trans); -void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, int fifo, - int sta_id, int tid, int frame_limit, u16 ssn); +void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int queue, u16 ssn, + const struct iwl_trans_txq_scd_cfg *cfg); void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int queue); int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, struct iwl_device_cmd *dev_cmd, int txq_id); diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index 84c3a0115c4d..5c95386c72bf 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c @@ -1066,10 +1066,11 @@ static int iwl_pcie_txq_set_ratid_map(struct iwl_trans *trans, u16 ra_tid, * combined with Traffic ID (QOS priority), in format used by Tx Scheduler */ #define BUILD_RAxTID(sta_id, tid) (((sta_id) << 4) + (tid)) -void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, int fifo, - int sta_id, int tid, int frame_limit, u16 ssn) +void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, u16 ssn, + const struct iwl_trans_txq_scd_cfg *cfg) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + u8 frame_limit = cfg->frame_limit; if (test_and_set_bit(txq_id, trans_pcie->queue_used)) WARN_ONCE(1, "queue %d already used - expect issues", txq_id); @@ -1082,8 +1083,8 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, int fifo, iwl_scd_txq_set_chain(trans, txq_id); /* If this queue is mapped to a certain station: it is an AGG queue */ - if (sta_id >= 0) { - u16 ra_tid = BUILD_RAxTID(sta_id, tid); + if (cfg->sta_id >= 0) { + u16 ra_tid = BUILD_RAxTID(cfg->sta_id, cfg->tid); /* Map receiver-address / traffic-ID to this queue */ iwl_pcie_txq_set_ratid_map(trans, ra_tid, txq_id); @@ -1124,12 +1125,12 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, int fifo, /* Set up Status area in SRAM, map to Tx DMA/FIFO, activate the queue */ iwl_write_prph(trans, SCD_QUEUE_STATUS_BITS(txq_id), (1 << SCD_QUEUE_STTS_REG_POS_ACTIVE) | - (fifo << SCD_QUEUE_STTS_REG_POS_TXF) | + (cfg->fifo << SCD_QUEUE_STTS_REG_POS_TXF) | (1 << SCD_QUEUE_STTS_REG_POS_WSL) | SCD_QUEUE_STTS_REG_MSK); trans_pcie->txq[txq_id].active = true; IWL_DEBUG_TX_QUEUES(trans, "Activate queue %d on FIFO %d WrPtr: %d\n", - txq_id, fifo, ssn & 0xff); + txq_id, cfg->fifo, ssn & 0xff); } void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int txq_id) From 2ce89cd6dfc2ea57497ab38f88d4878c06869a81 Mon Sep 17 00:00:00 2001 From: David Spinadel Date: Tue, 22 Jul 2014 13:11:18 +0300 Subject: [PATCH 204/221] iwlwifi: mvm: enable passive fragmented scan changes Enable fragmented scan that was diabled due to a FW bug. New fixed FWs use a TLV bit to advertise fragmented scan support. Signed-off-by: David Spinadel Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-fw.h | 3 ++ drivers/net/wireless/iwlwifi/mvm/scan.c | 48 ++++++++++++++++++++----- 2 files changed, 42 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h index 1bb5193c5b1b..99e0ec4635ee 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw.h @@ -125,6 +125,8 @@ enum iwl_ucode_tlv_flag { * @IWL_UCODE_TLV_API_CSA_FLOW: ucode can do unbind-bind flow for CSA. * @IWL_UCODE_TLV_API_DISABLE_STA_TX: ucode supports tx_disable bit. * @IWL_UCODE_TLV_API_LMAC_SCAN: This ucode uses LMAC unified scan API. + * @IWL_UCODE_TLV_API_FRAGMENTED_SCAN: This ucode supports active dwell time + * longer than the passive one, which is essential for fragmented scan. */ enum iwl_ucode_tlv_api { IWL_UCODE_TLV_API_WOWLAN_CONFIG_TID = BIT(0), @@ -133,6 +135,7 @@ enum iwl_ucode_tlv_api { IWL_UCODE_TLV_API_CSA_FLOW = BIT(4), IWL_UCODE_TLV_API_DISABLE_STA_TX = BIT(5), IWL_UCODE_TLV_API_LMAC_SCAN = BIT(6), + IWL_UCODE_TLV_API_FRAGMENTED_SCAN = BIT(8), }; /** diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index 004b1f5d0314..d01954dcc75d 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -279,6 +279,7 @@ static void iwl_mvm_scan_calc_params(struct iwl_mvm *mvm, { bool global_bound = false; enum ieee80211_band band; + u8 frag_passive_dwell = 0; ieee80211_iterate_active_interfaces_atomic(mvm->hw, IEEE80211_IFACE_ITER_NORMAL, @@ -288,12 +289,36 @@ static void iwl_mvm_scan_calc_params(struct iwl_mvm *mvm, if (!global_bound) goto not_bound; - params->suspend_time = 100; - params->max_out_time = 600; + params->suspend_time = 30; + params->max_out_time = 170; if (iwl_mvm_low_latency(mvm)) { - params->suspend_time = 250; - params->max_out_time = 250; + if (mvm->fw->ucode_capa.api[0] & + IWL_UCODE_TLV_API_FRAGMENTED_SCAN) { + params->suspend_time = 105; + params->max_out_time = 70; + frag_passive_dwell = 20; + } else { + params->suspend_time = 120; + params->max_out_time = 120; + } + } + + if (frag_passive_dwell && (mvm->fw->ucode_capa.api[0] & + IWL_UCODE_TLV_API_FRAGMENTED_SCAN)) { + /* + * P2P device scan should not be fragmented to avoid negative + * impact on P2P device discovery. Configure max_out_time to be + * equal to dwell time on passive channel. Take a longest + * possible value, one that corresponds to 2GHz band + */ + if (vif->type == NL80211_IFTYPE_P2P_DEVICE) { + u32 passive_dwell = + iwl_mvm_get_passive_dwell(IEEE80211_BAND_2GHZ); + params->max_out_time = passive_dwell; + } else { + params->passive_fragmented = true; + } } if (flags & NL80211_SCAN_FLAG_LOW_PRIORITY) @@ -302,7 +327,11 @@ static void iwl_mvm_scan_calc_params(struct iwl_mvm *mvm, not_bound: for (band = IEEE80211_BAND_2GHZ; band < IEEE80211_NUM_BANDS; band++) { - params->dwell[band].passive = iwl_mvm_get_passive_dwell(band); + if (params->passive_fragmented) + params->dwell[band].passive = frag_passive_dwell; + else + params->dwell[band].passive = + iwl_mvm_get_passive_dwell(band); params->dwell[band].active = iwl_mvm_get_active_dwell(band, n_ssids); } @@ -1100,10 +1129,11 @@ iwl_mvm_build_generic_unified_scan_cmd(struct iwl_mvm *mvm, struct iwl_mvm_scan_params *params) { memset(cmd, 0, ksize(cmd)); - cmd->active_dwell = (u8)params->dwell[IEEE80211_BAND_2GHZ].active; - cmd->passive_dwell = (u8)params->dwell[IEEE80211_BAND_2GHZ].passive; - /* TODO: Use params; now fragmented isn't used. */ - cmd->fragmented_dwell = 0; + cmd->active_dwell = params->dwell[IEEE80211_BAND_2GHZ].active; + cmd->passive_dwell = params->dwell[IEEE80211_BAND_2GHZ].passive; + if (params->passive_fragmented) + cmd->fragmented_dwell = + params->dwell[IEEE80211_BAND_2GHZ].passive; cmd->rx_chain_select = iwl_mvm_scan_rx_chain(mvm); cmd->max_out_time = cpu_to_le32(params->max_out_time); cmd->suspend_time = cpu_to_le32(params->suspend_time); From a43ad46a450b1a4466f34b057522f56c125710fb Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 4 Aug 2014 16:39:54 +0200 Subject: [PATCH 205/221] iwlwifi: mvm: add some debugging to quota allocation In order to follow more easily what's going on, add some debug statements to the quota allocation algorithm. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-debug.h | 2 ++ drivers/net/wireless/iwlwifi/mvm/quota.c | 12 ++++++++++++ 2 files changed, 14 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index 295083510e72..0a70bcd241f5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -145,6 +145,7 @@ do { \ #define IWL_DL_HCMD 0x00000004 #define IWL_DL_STATE 0x00000008 /* 0x000000F0 - 0x00000010 */ +#define IWL_DL_QUOTA 0x00000010 #define IWL_DL_TE 0x00000020 #define IWL_DL_EEPROM 0x00000040 #define IWL_DL_RADIO 0x00000080 @@ -189,6 +190,7 @@ do { \ #define IWL_DEBUG_LED(p, f, a...) IWL_DEBUG(p, IWL_DL_LED, f, ## a) #define IWL_DEBUG_WEP(p, f, a...) IWL_DEBUG(p, IWL_DL_WEP, f, ## a) #define IWL_DEBUG_HC(p, f, a...) IWL_DEBUG(p, IWL_DL_HCMD, f, ## a) +#define IWL_DEBUG_QUOTA(p, f, a...) IWL_DEBUG(p, IWL_DL_QUOTA, f, ## a) #define IWL_DEBUG_TE(p, f, a...) IWL_DEBUG(p, IWL_DL_TE, f, ## a) #define IWL_DEBUG_EEPROM(d, f, a...) IWL_DEBUG_DEV(d, IWL_DL_EEPROM, f, ## a) #define IWL_DEBUG_CALIB(p, f, a...) IWL_DEBUG(p, IWL_DL_CALIB, f, ## a) diff --git a/drivers/net/wireless/iwlwifi/mvm/quota.c b/drivers/net/wireless/iwlwifi/mvm/quota.c index 4e20b3ce2b6a..300639ce78be 100644 --- a/drivers/net/wireless/iwlwifi/mvm/quota.c +++ b/drivers/net/wireless/iwlwifi/mvm/quota.c @@ -161,6 +161,9 @@ static void iwl_mvm_adjust_quota_for_noa(struct iwl_mvm *mvm, quota *= (beacon_int - mvm->noa_duration); quota /= beacon_int; + IWL_DEBUG_QUOTA(mvm, "quota: adjust for NoA from %d to %d\n", + le32_to_cpu(cmd->quotas[i].quota), quota); + cmd->quotas[i].quota = cpu_to_le32(quota); } #endif @@ -222,6 +225,9 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, quota = (QUOTA_100 - QUOTA_LOWLAT_MIN) / n_non_lowlat; quota_rem = QUOTA_100 - n_non_lowlat * quota - QUOTA_LOWLAT_MIN; + IWL_DEBUG_QUOTA(mvm, + "quota: low-latency binding active, remaining quota per other binding: %d\n", + quota); } else if (num_active_macs) { /* * There are 0 or more than 1 low latency bindings, or all the @@ -230,6 +236,9 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, */ quota = QUOTA_100 / num_active_macs; quota_rem = QUOTA_100 % num_active_macs; + IWL_DEBUG_QUOTA(mvm, + "quota: splitting evenly per binding: %d\n", + quota); } else { /* values don't really matter - won't be used */ quota = 0; @@ -271,6 +280,9 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, for (i = 0; i < MAX_BINDINGS; i++) { if (le32_to_cpu(cmd.quotas[i].quota) != 0) { le32_add_cpu(&cmd.quotas[i].quota, quota_rem); + IWL_DEBUG_QUOTA(mvm, + "quota: giving remainder of %d to binding %d\n", + quota_rem, i); break; } } From 532cf5c683ab027091ffc19d45e3a67a49f76f5d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 5 Aug 2014 10:36:54 +0200 Subject: [PATCH 206/221] iwlwifi: don't export tracepoints unnecessarily The tracepoints that are only used in code linked with iwlwifi.ko, as are the tracepoints, don't need to be exported, so don't. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-devtrace.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.c b/drivers/net/wireless/iwlwifi/iwl-devtrace.c index 23e7351e02de..90987d6f348e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-devtrace.c +++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.c @@ -36,15 +36,8 @@ EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_iowrite8); EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ioread32); EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_iowrite32); -EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_rx); -EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_tx); EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_event); EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_error); EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_cont_event); EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_wrap_event); -EXPORT_TRACEPOINT_SYMBOL(iwlwifi_info); -EXPORT_TRACEPOINT_SYMBOL(iwlwifi_warn); -EXPORT_TRACEPOINT_SYMBOL(iwlwifi_crit); -EXPORT_TRACEPOINT_SYMBOL(iwlwifi_err); -EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dbg); #endif From 0ade579cce06806353e5f601ff3285a0a7d1e398 Mon Sep 17 00:00:00 2001 From: Eran Harary Date: Mon, 4 Aug 2014 12:21:05 +0300 Subject: [PATCH 207/221] iwlwifi: mvm: fix comment typo Signed-off-by: Eran Harary Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/ops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index e3be34f6aa41..166d17c48f85 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -495,7 +495,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, goto out_free; /* - * Even if nvm exists in the nvm_file driver should read agin the nvm + * Even if nvm exists in the nvm_file driver should read again the nvm * from the nic because there might be entries that exist in the OTP * and not in the file. * for nics with no_power_up_nic_in_init: rely completley on nvm_file From d4578ea810ce468fdb8e1b7014818c31db9be5e2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 1 Aug 2014 12:17:40 +0200 Subject: [PATCH 208/221] iwlwifi: trans: allow skipping scheduler hardware config In a later patch, the hardware configuration will be moved to firmware. Prepare for this by allowing hardware configuration in the transport to be skipped by not passing a configuration on enable and passing configure_scd=false on disable. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/dvm/tx.c | 6 +- drivers/net/wireless/iwlwifi/iwl-trans.h | 47 +++++++--- drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c | 8 +- drivers/net/wireless/iwlwifi/mvm/sta.c | 4 +- drivers/net/wireless/iwlwifi/mvm/tx.c | 2 +- drivers/net/wireless/iwlwifi/pcie/internal.h | 3 +- drivers/net/wireless/iwlwifi/pcie/tx.c | 97 +++++++++++--------- 7 files changed, 103 insertions(+), 64 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/dvm/tx.c b/drivers/net/wireless/iwlwifi/dvm/tx.c index 3255a1723d17..d1ce3ce13591 100644 --- a/drivers/net/wireless/iwlwifi/dvm/tx.c +++ b/drivers/net/wireless/iwlwifi/dvm/tx.c @@ -580,7 +580,7 @@ turn_off: * time, or we hadn't time to drain the AC queues. */ if (agg_state == IWL_AGG_ON) - iwl_trans_txq_disable(priv->trans, txq_id); + iwl_trans_txq_disable(priv->trans, txq_id, true); else IWL_DEBUG_TX_QUEUES(priv, "Don't disable tx agg: %d\n", agg_state); @@ -686,7 +686,7 @@ int iwlagn_tx_agg_flush(struct iwl_priv *priv, struct ieee80211_vif *vif, * time, or we hadn't time to drain the AC queues. */ if (agg_state == IWL_AGG_ON) - iwl_trans_txq_disable(priv->trans, txq_id); + iwl_trans_txq_disable(priv->trans, txq_id, true); else IWL_DEBUG_TX_QUEUES(priv, "Don't disable tx agg: %d\n", agg_state); @@ -781,7 +781,7 @@ static void iwlagn_check_ratid_empty(struct iwl_priv *priv, int sta_id, u8 tid) "Can continue DELBA flow ssn = next_recl = %d\n", tid_data->next_reclaimed); iwl_trans_txq_disable(priv->trans, - tid_data->agg.txq_id); + tid_data->agg.txq_id, true); iwlagn_dealloc_agg_txq(priv, tid_data->agg.txq_id); tid_data->agg.state = IWL_AGG_OFF; ieee80211_stop_tx_ba_cb_irqsafe(vif, addr, tid); diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index c198dde339c6..dd3aefc0ad2d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -444,7 +444,9 @@ struct iwl_trans_txq_scd_cfg { * Must be atomic * @txq_enable: setup a queue. To setup an AC queue, use the * iwl_trans_ac_txq_enable wrapper. fw_alive must have been called before - * this one. The op_mode must not configure the HCMD queue. May sleep. + * this one. The op_mode must not configure the HCMD queue. The scheduler + * configuration may be %NULL, in which case the hardware will not be + * configured. May sleep. * @txq_disable: de-configure a Tx queue to send AMPDUs * Must be atomic * @wait_tx_queue_empty: wait until tx queues are empty. May sleep. @@ -501,7 +503,8 @@ struct iwl_trans_ops { void (*txq_enable)(struct iwl_trans *trans, int queue, u16 ssn, const struct iwl_trans_txq_scd_cfg *cfg); - void (*txq_disable)(struct iwl_trans *trans, int queue); + void (*txq_disable)(struct iwl_trans *trans, int queue, + bool configure_scd); int (*dbgfs_register)(struct iwl_trans *trans, struct dentry* dir); int (*wait_tx_queue_empty)(struct iwl_trans *trans, u32 txq_bm); @@ -773,9 +776,22 @@ static inline void iwl_trans_reclaim(struct iwl_trans *trans, int queue, trans->ops->reclaim(trans, queue, ssn, skbs); } -static inline void iwl_trans_txq_disable(struct iwl_trans *trans, int queue) +static inline void iwl_trans_txq_disable(struct iwl_trans *trans, int queue, + bool configure_scd) { - trans->ops->txq_disable(trans, queue); + trans->ops->txq_disable(trans, queue, configure_scd); +} + +static inline void +iwl_trans_txq_enable_cfg(struct iwl_trans *trans, int queue, u16 ssn, + const struct iwl_trans_txq_scd_cfg *cfg) +{ + might_sleep(); + + if (unlikely((trans->state != IWL_TRANS_FW_ALIVE))) + IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state); + + trans->ops->txq_enable(trans, queue, ssn, cfg); } static inline void iwl_trans_txq_enable(struct iwl_trans *trans, int queue, @@ -789,19 +805,26 @@ static inline void iwl_trans_txq_enable(struct iwl_trans *trans, int queue, .frame_limit = frame_limit, }; - might_sleep(); - - if (unlikely((trans->state != IWL_TRANS_FW_ALIVE))) - IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state); - - trans->ops->txq_enable(trans, queue, ssn, &cfg); + iwl_trans_txq_enable_cfg(trans, queue, ssn, &cfg); } static inline void iwl_trans_ac_txq_enable(struct iwl_trans *trans, int queue, int fifo) { - iwl_trans_txq_enable(trans, queue, fifo, -1, - IWL_MAX_TID_COUNT, IWL_FRAME_LIMIT, 0); + struct iwl_trans_txq_scd_cfg cfg = { + .fifo = fifo, + .sta_id = -1, + .tid = IWL_MAX_TID_COUNT, + .frame_limit = IWL_FRAME_LIMIT, + }; + + iwl_trans_txq_enable_cfg(trans, queue, 0, &cfg); +} + +static inline void +iwl_trans_txq_enable_no_scd(struct iwl_trans *trans, int queue, u16 ssn) +{ + iwl_trans_txq_enable_cfg(trans, queue, ssn, NULL); } static inline int iwl_trans_wait_tx_queue_empty(struct iwl_trans *trans, diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c index 0e523e28cabf..08162043c897 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c @@ -452,14 +452,16 @@ void iwl_mvm_mac_ctxt_release(struct iwl_mvm *mvm, struct ieee80211_vif *vif) switch (vif->type) { case NL80211_IFTYPE_P2P_DEVICE: - iwl_trans_txq_disable(mvm->trans, IWL_MVM_OFFCHANNEL_QUEUE); + iwl_trans_txq_disable(mvm->trans, IWL_MVM_OFFCHANNEL_QUEUE, + true); break; case NL80211_IFTYPE_AP: - iwl_trans_txq_disable(mvm->trans, vif->cab_queue); + iwl_trans_txq_disable(mvm->trans, vif->cab_queue, true); /* fall through */ default: for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) - iwl_trans_txq_disable(mvm->trans, vif->hw_queue[ac]); + iwl_trans_txq_disable(mvm->trans, vif->hw_queue[ac], + true); } } diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index 763548880399..863a5363c416 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c @@ -910,7 +910,7 @@ int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif, } tid_data->ssn = 0xffff; - iwl_trans_txq_disable(mvm->trans, txq_id); + iwl_trans_txq_disable(mvm->trans, txq_id, true); /* fall through */ case IWL_AGG_STARTING: case IWL_EMPTYING_HW_QUEUE_ADDBA: @@ -965,7 +965,7 @@ int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif, if (iwl_mvm_flush_tx_path(mvm, BIT(txq_id), true)) IWL_ERR(mvm, "Couldn't flush the AGG queue\n"); - iwl_trans_txq_disable(mvm->trans, tid_data->txq_id); + iwl_trans_txq_disable(mvm->trans, tid_data->txq_id, true); } mvm->queue_to_mac80211[tid_data->txq_id] = diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index dbc870713882..748b16993bda 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c @@ -482,7 +482,7 @@ static void iwl_mvm_check_ratid_empty(struct iwl_mvm *mvm, IWL_DEBUG_TX_QUEUES(mvm, "Can continue DELBA flow ssn = next_recl = %d\n", tid_data->next_reclaimed); - iwl_trans_txq_disable(mvm->trans, tid_data->txq_id); + iwl_trans_txq_disable(mvm->trans, tid_data->txq_id, true); tid_data->state = IWL_AGG_OFF; /* * we can't hold the mutex - but since we are after a sequence diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h index 5760405a9cad..163aac563f90 100644 --- a/drivers/net/wireless/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/iwlwifi/pcie/internal.h @@ -366,7 +366,8 @@ int iwl_pcie_tx_stop(struct iwl_trans *trans); void iwl_pcie_tx_free(struct iwl_trans *trans); void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int queue, u16 ssn, const struct iwl_trans_txq_scd_cfg *cfg); -void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int queue); +void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int queue, + bool configure_scd); int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, struct iwl_device_cmd *dev_cmd, int txq_id); void iwl_pcie_txq_check_wrptrs(struct iwl_trans *trans); diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index 5c95386c72bf..eb39e584cc6d 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c @@ -1070,37 +1070,41 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, u16 ssn, const struct iwl_trans_txq_scd_cfg *cfg) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - u8 frame_limit = cfg->frame_limit; + int fifo = -1; if (test_and_set_bit(txq_id, trans_pcie->queue_used)) WARN_ONCE(1, "queue %d already used - expect issues", txq_id); - /* Stop this Tx queue before configuring it */ - iwl_scd_txq_set_inactive(trans, txq_id); + if (cfg) { + fifo = cfg->fifo; - /* Set this queue as a chain-building queue unless it is CMD queue */ - if (txq_id != trans_pcie->cmd_queue) - iwl_scd_txq_set_chain(trans, txq_id); + /* Stop this Tx queue before configuring it */ + iwl_scd_txq_set_inactive(trans, txq_id); - /* If this queue is mapped to a certain station: it is an AGG queue */ - if (cfg->sta_id >= 0) { - u16 ra_tid = BUILD_RAxTID(cfg->sta_id, cfg->tid); + /* Set this queue as a chain-building queue unless it is CMD */ + if (txq_id != trans_pcie->cmd_queue) + iwl_scd_txq_set_chain(trans, txq_id); - /* Map receiver-address / traffic-ID to this queue */ - iwl_pcie_txq_set_ratid_map(trans, ra_tid, txq_id); + /* If this queue is mapped to a certain station: it is an AGG */ + if (cfg->sta_id >= 0) { + u16 ra_tid = BUILD_RAxTID(cfg->sta_id, cfg->tid); - /* enable aggregations for the queue */ - iwl_scd_txq_enable_agg(trans, txq_id); - trans_pcie->txq[txq_id].ampdu = true; - } else { - /* - * disable aggregations for the queue, this will also make the - * ra_tid mapping configuration irrelevant since it is now a - * non-AGG queue. - */ - iwl_scd_txq_disable_agg(trans, txq_id); + /* Map receiver-address / traffic-ID to this queue */ + iwl_pcie_txq_set_ratid_map(trans, ra_tid, txq_id); - ssn = trans_pcie->txq[txq_id].q.read_ptr; + /* enable aggregations for the queue */ + iwl_scd_txq_enable_agg(trans, txq_id); + trans_pcie->txq[txq_id].ampdu = true; + } else { + /* + * disable aggregations for the queue, this will also + * make the ra_tid mapping configuration irrelevant + * since it is now a non-AGG queue. + */ + iwl_scd_txq_disable_agg(trans, txq_id); + + ssn = trans_pcie->txq[txq_id].q.read_ptr; + } } /* Place first TFD at index corresponding to start sequence number. @@ -1108,32 +1112,39 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, u16 ssn, trans_pcie->txq[txq_id].q.read_ptr = (ssn & 0xff); trans_pcie->txq[txq_id].q.write_ptr = (ssn & 0xff); - iwl_write_direct32(trans, HBUS_TARG_WRPTR, - (ssn & 0xff) | (txq_id << 8)); - iwl_write_prph(trans, SCD_QUEUE_RDPTR(txq_id), ssn); + if (cfg) { + u8 frame_limit = cfg->frame_limit; - /* Set up Tx window size and frame limit for this queue */ - iwl_trans_write_mem32(trans, trans_pcie->scd_base_addr + - SCD_CONTEXT_QUEUE_OFFSET(txq_id), 0); - iwl_trans_write_mem32(trans, trans_pcie->scd_base_addr + + iwl_write_direct32(trans, HBUS_TARG_WRPTR, + (ssn & 0xff) | (txq_id << 8)); + iwl_write_prph(trans, SCD_QUEUE_RDPTR(txq_id), ssn); + + /* Set up Tx window size and frame limit for this queue */ + iwl_trans_write_mem32(trans, trans_pcie->scd_base_addr + + SCD_CONTEXT_QUEUE_OFFSET(txq_id), 0); + iwl_trans_write_mem32(trans, + trans_pcie->scd_base_addr + SCD_CONTEXT_QUEUE_OFFSET(txq_id) + sizeof(u32), ((frame_limit << SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) & - SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) | + SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) | ((frame_limit << SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) & - SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK)); + SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK)); + + /* Set up status area in SRAM, map to Tx DMA/FIFO, activate */ + iwl_write_prph(trans, SCD_QUEUE_STATUS_BITS(txq_id), + (1 << SCD_QUEUE_STTS_REG_POS_ACTIVE) | + (cfg->fifo << SCD_QUEUE_STTS_REG_POS_TXF) | + (1 << SCD_QUEUE_STTS_REG_POS_WSL) | + SCD_QUEUE_STTS_REG_MSK); + } - /* Set up Status area in SRAM, map to Tx DMA/FIFO, activate the queue */ - iwl_write_prph(trans, SCD_QUEUE_STATUS_BITS(txq_id), - (1 << SCD_QUEUE_STTS_REG_POS_ACTIVE) | - (cfg->fifo << SCD_QUEUE_STTS_REG_POS_TXF) | - (1 << SCD_QUEUE_STTS_REG_POS_WSL) | - SCD_QUEUE_STTS_REG_MSK); trans_pcie->txq[txq_id].active = true; IWL_DEBUG_TX_QUEUES(trans, "Activate queue %d on FIFO %d WrPtr: %d\n", - txq_id, cfg->fifo, ssn & 0xff); + txq_id, fifo, ssn & 0xff); } -void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int txq_id) +void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int txq_id, + bool configure_scd) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); u32 stts_addr = trans_pcie->scd_base_addr + @@ -1152,10 +1163,12 @@ void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int txq_id) return; } - iwl_scd_txq_set_inactive(trans, txq_id); + if (configure_scd) { + iwl_scd_txq_set_inactive(trans, txq_id); - iwl_trans_write_mem(trans, stts_addr, (void *)zero_val, - ARRAY_SIZE(zero_val)); + iwl_trans_write_mem(trans, stts_addr, (void *)zero_val, + ARRAY_SIZE(zero_val)); + } iwl_pcie_txq_unmap(trans, txq_id); trans_pcie->txq[txq_id].ampdu = false; From 64ba893066528a03d7d21d7e187005748027a309 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 1 Aug 2014 13:33:46 +0200 Subject: [PATCH 209/221] iwlwifi: trans: make aggregation explicit for TX queue handling Currently a valid sta_id is assumed to mean that the queue is meant to also be aggregated, but that assumption will not be true in the future, so don't make it in the lower level but only in the inline wrapper. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-trans.h | 3 +++ drivers/net/wireless/iwlwifi/pcie/tx.c | 3 +-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index dd3aefc0ad2d..7e8dc3a2b2df 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -405,6 +405,7 @@ struct iwl_trans_txq_scd_cfg { u8 fifo; s8 sta_id; u8 tid; + bool aggregate; int frame_limit; }; @@ -803,6 +804,7 @@ static inline void iwl_trans_txq_enable(struct iwl_trans *trans, int queue, .sta_id = sta_id, .tid = tid, .frame_limit = frame_limit, + .aggregate = sta_id >= 0, }; iwl_trans_txq_enable_cfg(trans, queue, ssn, &cfg); @@ -816,6 +818,7 @@ static inline void iwl_trans_ac_txq_enable(struct iwl_trans *trans, int queue, .sta_id = -1, .tid = IWL_MAX_TID_COUNT, .frame_limit = IWL_FRAME_LIMIT, + .aggregate = false, }; iwl_trans_txq_enable_cfg(trans, queue, 0, &cfg); diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index eb39e584cc6d..a24c1df2b1b5 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c @@ -1085,8 +1085,7 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, u16 ssn, if (txq_id != trans_pcie->cmd_queue) iwl_scd_txq_set_chain(trans, txq_id); - /* If this queue is mapped to a certain station: it is an AGG */ - if (cfg->sta_id >= 0) { + if (cfg->aggregate) { u16 ra_tid = BUILD_RAxTID(cfg->sta_id, cfg->tid); /* Map receiver-address / traffic-ID to this queue */ From 002a9e2677cc2a8b0d320731f9749737db5ed23b Mon Sep 17 00:00:00 2001 From: Avri Altman Date: Thu, 24 Jul 2014 19:25:10 +0300 Subject: [PATCH 210/221] iwlwifi: trans: configure the scheduler enable register Currently the firmware is handling this, but that is wrong as it then needs to assume a certain command queue, therefore this should be in the driver; add it here so it can be removed from the firmware in the future. Signed-off-by: Avri Altman Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-prph.h | 1 + drivers/net/wireless/iwlwifi/iwl-scd.h | 6 ++++++ drivers/net/wireless/iwlwifi/pcie/tx.c | 8 ++++++++ 3 files changed, 15 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index 47033a35a402..9e152734ed43 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h @@ -281,6 +281,7 @@ #define SCD_CHAINEXT_EN (SCD_BASE + 0x244) #define SCD_AGGR_SEL (SCD_BASE + 0x248) #define SCD_INTERRUPT_MASK (SCD_BASE + 0x108) +#define SCD_EN_CTRL (SCD_BASE + 0x254) static inline unsigned int SCD_QUEUE_WRPTR(unsigned int chnl) { diff --git a/drivers/net/wireless/iwlwifi/iwl-scd.h b/drivers/net/wireless/iwlwifi/iwl-scd.h index 5f099d45c09a..6c622b21bba7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scd.h +++ b/drivers/net/wireless/iwlwifi/iwl-scd.h @@ -109,4 +109,10 @@ static inline void iwl_scd_deactivate_fifos(struct iwl_trans *trans) { iwl_write_prph(trans, SCD_TXFACT, 0); } + +static inline void iwl_scd_enable_set_active(struct iwl_trans *trans, + u32 value) +{ + iwl_write_prph(trans, SCD_EN_CTRL, value); +} #endif diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index a24c1df2b1b5..9fdfed8fcd8f 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c @@ -1078,6 +1078,10 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, u16 ssn, if (cfg) { fifo = cfg->fifo; + /* Disable the scheduler prior configuring the cmd queue */ + if (txq_id == trans_pcie->cmd_queue) + iwl_scd_enable_set_active(trans, 0); + /* Stop this Tx queue before configuring it */ iwl_scd_txq_set_inactive(trans, txq_id); @@ -1135,6 +1139,10 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, u16 ssn, (cfg->fifo << SCD_QUEUE_STTS_REG_POS_TXF) | (1 << SCD_QUEUE_STTS_REG_POS_WSL) | SCD_QUEUE_STTS_REG_MSK); + + /* enable the scheduler for this queue (only) */ + if (txq_id == trans_pcie->cmd_queue) + iwl_scd_enable_set_active(trans, BIT(txq_id)); } trans_pcie->txq[txq_id].active = true; From 8b4139dc9f2171f313fc703c08269f6f8a6f6fc4 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 24 Jul 2014 14:05:26 +0200 Subject: [PATCH 211/221] iwlwifi: add Intel Mobile Communications copyright Our legal structure changed at some point (see wikipedia), but we forgot to immediately switch over to the new copyright notice. For files that we have modified in the time since the change, add the proper copyright notice now. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-7000.c | 2 ++ drivers/net/wireless/iwlwifi/iwl-8000.c | 2 ++ drivers/net/wireless/iwlwifi/iwl-csr.h | 2 ++ drivers/net/wireless/iwlwifi/iwl-drv.c | 2 ++ drivers/net/wireless/iwlwifi/iwl-drv.h | 2 ++ drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h | 2 ++ drivers/net/wireless/iwlwifi/iwl-fw-file.h | 2 ++ drivers/net/wireless/iwlwifi/iwl-fw.h | 2 ++ drivers/net/wireless/iwlwifi/iwl-nvm-parse.c | 2 ++ drivers/net/wireless/iwlwifi/iwl-op-mode.h | 2 ++ drivers/net/wireless/iwlwifi/iwl-prph.h | 2 ++ drivers/net/wireless/iwlwifi/iwl-trans.h | 2 ++ drivers/net/wireless/iwlwifi/mvm/coex.c | 2 ++ drivers/net/wireless/iwlwifi/mvm/coex_legacy.c | 2 ++ drivers/net/wireless/iwlwifi/mvm/constants.h | 2 ++ drivers/net/wireless/iwlwifi/mvm/d3.c | 2 ++ drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c | 2 ++ drivers/net/wireless/iwlwifi/mvm/debugfs.c | 2 ++ drivers/net/wireless/iwlwifi/mvm/debugfs.h | 2 ++ drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h | 2 ++ drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h | 2 ++ drivers/net/wireless/iwlwifi/mvm/fw-api-power.h | 2 ++ drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h | 2 ++ drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h | 2 ++ drivers/net/wireless/iwlwifi/mvm/fw-api.h | 2 ++ drivers/net/wireless/iwlwifi/mvm/fw.c | 2 ++ drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c | 2 ++ drivers/net/wireless/iwlwifi/mvm/mac80211.c | 2 ++ drivers/net/wireless/iwlwifi/mvm/mvm.h | 2 ++ drivers/net/wireless/iwlwifi/mvm/nvm.c | 2 ++ drivers/net/wireless/iwlwifi/mvm/offloading.c | 2 ++ drivers/net/wireless/iwlwifi/mvm/ops.c | 2 ++ drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c | 2 ++ drivers/net/wireless/iwlwifi/mvm/power.c | 2 ++ drivers/net/wireless/iwlwifi/mvm/quota.c | 2 ++ drivers/net/wireless/iwlwifi/mvm/rs.c | 1 + drivers/net/wireless/iwlwifi/mvm/rx.c | 2 ++ drivers/net/wireless/iwlwifi/mvm/scan.c | 2 ++ drivers/net/wireless/iwlwifi/mvm/sf.c | 2 ++ drivers/net/wireless/iwlwifi/mvm/sta.c | 2 ++ drivers/net/wireless/iwlwifi/mvm/sta.h | 2 ++ drivers/net/wireless/iwlwifi/mvm/testmode.h | 2 ++ drivers/net/wireless/iwlwifi/mvm/time-event.c | 2 ++ drivers/net/wireless/iwlwifi/mvm/time-event.h | 2 ++ drivers/net/wireless/iwlwifi/mvm/tt.c | 2 ++ drivers/net/wireless/iwlwifi/mvm/tx.c | 2 ++ drivers/net/wireless/iwlwifi/mvm/utils.c | 2 ++ drivers/net/wireless/iwlwifi/pcie/drv.c | 2 ++ drivers/net/wireless/iwlwifi/pcie/internal.h | 1 + drivers/net/wireless/iwlwifi/pcie/rx.c | 1 + drivers/net/wireless/iwlwifi/pcie/trans.c | 2 ++ drivers/net/wireless/iwlwifi/pcie/tx.c | 1 + 52 files changed, 100 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/iwl-7000.c b/drivers/net/wireless/iwlwifi/iwl-7000.c index 48730064da73..446654aed017 100644 --- a/drivers/net/wireless/iwlwifi/iwl-7000.c +++ b/drivers/net/wireless/iwlwifi/iwl-7000.c @@ -6,6 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,6 +32,7 @@ * BSD LICENSE * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-8000.c b/drivers/net/wireless/iwlwifi/iwl-8000.c index 44b19e015102..90388e70db9b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-8000.c +++ b/drivers/net/wireless/iwlwifi/iwl-8000.c @@ -6,6 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,6 +32,7 @@ * BSD LICENSE * * Copyright(c) 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2014 Intel Mobile Communications GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index fe129c94ae3e..23d059af6476 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h @@ -6,6 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,6 +32,7 @@ * BSD LICENSE * * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c index 283aee0e28a4..aefd94cb6e91 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/iwlwifi/iwl-drv.c @@ -6,6 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,6 +32,7 @@ * BSD LICENSE * * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.h b/drivers/net/wireless/iwlwifi/iwl-drv.h index 3c72cb710b0c..be4f8972241a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.h +++ b/drivers/net/wireless/iwlwifi/iwl-drv.h @@ -6,6 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,6 +32,7 @@ * BSD LICENSE * * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h index de5994a776c7..e30a41d04c8b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h @@ -6,6 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,6 +32,7 @@ * BSD LICENSE * * Copyright(c) 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2014 Intel Mobile Communications GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h index 929a8063354c..401f7be36b93 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h @@ -6,6 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,6 +32,7 @@ * BSD LICENSE * * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h index 99e0ec4635ee..f68cba4e0444 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw.h @@ -6,6 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,6 +32,7 @@ * BSD LICENSE * * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c index 018af2957d3b..8e7af798abd1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c @@ -6,6 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,6 +32,7 @@ * BSD LICENSE * * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-op-mode.h b/drivers/net/wireless/iwlwifi/iwl-op-mode.h index 99785c892f96..b6d666ee8359 100644 --- a/drivers/net/wireless/iwlwifi/iwl-op-mode.h +++ b/drivers/net/wireless/iwlwifi/iwl-op-mode.h @@ -6,6 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,6 +32,7 @@ * BSD LICENSE * * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index 9e152734ed43..1560f4576c7d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h @@ -6,6 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,6 +32,7 @@ * BSD LICENSE * * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index 7e8dc3a2b2df..c89985a58803 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -6,6 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,6 +32,7 @@ * BSD LICENSE * * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/mvm/coex.c b/drivers/net/wireless/iwlwifi/mvm/coex.c index 2291bbcaaeab..2262d6dc61ae 100644 --- a/drivers/net/wireless/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/iwlwifi/mvm/coex.c @@ -6,6 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,6 +32,7 @@ * BSD LICENSE * * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c b/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c index a3be33359927..585c0ab4a3ec 100644 --- a/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c +++ b/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c @@ -6,6 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,6 +32,7 @@ * BSD LICENSE * * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/mvm/constants.h b/drivers/net/wireless/iwlwifi/mvm/constants.h index ca79f7160573..dd00e8f7f765 100644 --- a/drivers/net/wireless/iwlwifi/mvm/constants.h +++ b/drivers/net/wireless/iwlwifi/mvm/constants.h @@ -6,6 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,6 +32,7 @@ * BSD LICENSE * * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index 645b3cfc29a5..607dfdbe0d5e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c @@ -6,6 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,6 +32,7 @@ * BSD LICENSE * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c index 5f5a94b9b7fc..d919b4ebc83c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c @@ -6,6 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,6 +32,7 @@ * BSD LICENSE * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index f85d4f4519f6..d98ee109c5e9 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -6,6 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,6 +32,7 @@ * BSD LICENSE * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.h b/drivers/net/wireless/iwlwifi/mvm/debugfs.h index e3a9774af495..8c4190e7e027 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.h +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.h @@ -6,6 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,6 +32,7 @@ * BSD LICENSE * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h index 69875716dcdb..816883f9ff94 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h @@ -6,6 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,6 +32,7 @@ * BSD LICENSE * * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h index 13696fe419b7..e74cdf2132f8 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h @@ -6,6 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,6 +32,7 @@ * BSD LICENSE * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h index c3a8c86b550d..27dd86395b39 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h @@ -6,6 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,6 +32,7 @@ * BSD LICENSE * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h index c02a9e45ec5e..8f2216694004 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h @@ -6,6 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,6 +32,7 @@ * BSD LICENSE * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h index 47bd0406355d..21dd5b771660 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h @@ -6,6 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,6 +32,7 @@ * BSD LICENSE * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index ed7d3f3d8b2f..4274f8dcb4cb 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h @@ -6,6 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,6 +32,7 @@ * BSD LICENSE * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index 883e702152d5..c958a7d0458d 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c @@ -6,6 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,6 +32,7 @@ * BSD LICENSE * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c index 08162043c897..7171d1734df3 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c @@ -6,6 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,6 +32,7 @@ * BSD LICENSE * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 5bc7557d4efe..cbe9ff09995a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -6,6 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,6 +32,7 @@ * BSD LICENSE * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index ffb509362828..b66a8afd6550 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -6,6 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,6 +32,7 @@ * BSD LICENSE * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/mvm/nvm.c b/drivers/net/wireless/iwlwifi/mvm/nvm.c index cfdd314fdd5d..4fafd4bd89f4 100644 --- a/drivers/net/wireless/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/iwlwifi/mvm/nvm.c @@ -6,6 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,6 +32,7 @@ * BSD LICENSE * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/mvm/offloading.c b/drivers/net/wireless/iwlwifi/mvm/offloading.c index 9bfb95e89cfb..adcbf4c8edd8 100644 --- a/drivers/net/wireless/iwlwifi/mvm/offloading.c +++ b/drivers/net/wireless/iwlwifi/mvm/offloading.c @@ -6,6 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,6 +32,7 @@ * BSD LICENSE * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 166d17c48f85..8139adcb2ef8 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -6,6 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,6 +32,7 @@ * BSD LICENSE * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c index 6cc243f7cf60..12283b55ee84 100644 --- a/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c +++ b/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c @@ -6,6 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,6 +32,7 @@ * BSD LICENSE * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c index b552183d0a31..e7a6626fe839 100644 --- a/drivers/net/wireless/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/iwlwifi/mvm/power.c @@ -6,6 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,6 +32,7 @@ * BSD LICENSE * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/mvm/quota.c b/drivers/net/wireless/iwlwifi/mvm/quota.c index 300639ce78be..5fd502db03d1 100644 --- a/drivers/net/wireless/iwlwifi/mvm/quota.c +++ b/drivers/net/wireless/iwlwifi/mvm/quota.c @@ -6,6 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,6 +32,7 @@ * BSD LICENSE * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 940e0d025012..17002cf437db 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -1,6 +1,7 @@ /****************************************************************************** * * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c index 8f43affe266f..48144e3ad527 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/iwlwifi/mvm/rx.c @@ -6,6 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,6 +32,7 @@ * BSD LICENSE * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index d01954dcc75d..bf9c63dc4a7d 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -6,6 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,6 +32,7 @@ * BSD LICENSE * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/mvm/sf.c b/drivers/net/wireless/iwlwifi/mvm/sf.c index 7edfd15efc9d..d1922afe06f4 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sf.c +++ b/drivers/net/wireless/iwlwifi/mvm/sf.c @@ -6,6 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,6 +32,7 @@ * BSD LICENSE * * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index 863a5363c416..960687bf92f9 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c @@ -6,6 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,6 +32,7 @@ * BSD LICENSE * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.h b/drivers/net/wireless/iwlwifi/mvm/sta.h index 3b1c8bd6cb54..ea4985eb8fa9 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.h +++ b/drivers/net/wireless/iwlwifi/mvm/sta.h @@ -6,6 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,6 +32,7 @@ * BSD LICENSE * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/mvm/testmode.h b/drivers/net/wireless/iwlwifi/mvm/testmode.h index 0241665925f7..79ab6beb6b26 100644 --- a/drivers/net/wireless/iwlwifi/mvm/testmode.h +++ b/drivers/net/wireless/iwlwifi/mvm/testmode.h @@ -6,6 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,6 +32,7 @@ * BSD LICENSE * * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.c b/drivers/net/wireless/iwlwifi/mvm/time-event.c index 51c610f6d17b..447d3b1003df 100644 --- a/drivers/net/wireless/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/iwlwifi/mvm/time-event.c @@ -6,6 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,6 +32,7 @@ * BSD LICENSE * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.h b/drivers/net/wireless/iwlwifi/mvm/time-event.h index 9126379ff2c6..bee3b2446b35 100644 --- a/drivers/net/wireless/iwlwifi/mvm/time-event.h +++ b/drivers/net/wireless/iwlwifi/mvm/time-event.h @@ -6,6 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,6 +32,7 @@ * BSD LICENSE * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/mvm/tt.c b/drivers/net/wireless/iwlwifi/mvm/tt.c index 4c22c0a09237..c3e1fe4282f1 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tt.c +++ b/drivers/net/wireless/iwlwifi/mvm/tt.c @@ -6,6 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,6 +32,7 @@ * BSD LICENSE * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index 748b16993bda..963edb8656ad 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c @@ -6,6 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,6 +32,7 @@ * BSD LICENSE * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c index 20fdca475d22..1958f298ac8b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/iwlwifi/mvm/utils.c @@ -6,6 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,6 +32,7 @@ * BSD LICENSE * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/pcie/drv.c b/drivers/net/wireless/iwlwifi/pcie/drv.c index f0e722ced080..dbbbf23082a2 100644 --- a/drivers/net/wireless/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/iwlwifi/pcie/drv.c @@ -6,6 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,6 +32,7 @@ * BSD LICENSE * * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h index 163aac563f90..a4fedc4a7448 100644 --- a/drivers/net/wireless/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/iwlwifi/pcie/internal.h @@ -1,6 +1,7 @@ /****************************************************************************** * * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c index a2698e5e062c..702f47fb16fe 100644 --- a/drivers/net/wireless/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/iwlwifi/pcie/rx.c @@ -1,6 +1,7 @@ /****************************************************************************** * * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 06e04aaf61ee..3076e0e9a490 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -6,6 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,6 +32,7 @@ * BSD LICENSE * * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index 9fdfed8fcd8f..a6336b4aa3a4 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c @@ -1,6 +1,7 @@ /****************************************************************************** * * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. From 0ce04ce797f87cdb6e10deef6a6081366be8bcc0 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Thu, 8 May 2014 16:03:39 +0300 Subject: [PATCH 212/221] iwlwifi: mvm: set the TX disable bit when doing a chanctx switch During a channel switch we should tell the firmware to disable TX temporarily and re-enable it after the switch is done. Signed-off-by: Luciano Coelho Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index cbe9ff09995a..3bbeedfb789c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -2748,6 +2748,19 @@ static int __iwl_mvm_assign_vif_chanctx(struct iwl_mvm *mvm, iwl_mvm_mac_ctxt_changed(mvm, vif, false); } + if (vif->csa_active && vif->type == NL80211_IFTYPE_STATION) { + struct iwl_mvm_sta *mvmsta; + + mvmsta = iwl_mvm_sta_from_staid_protected(mvm, + mvmvif->ap_sta_id); + + if (WARN_ON(!mvmsta)) + goto out; + + /* TODO: only re-enable after the first beacon */ + iwl_mvm_sta_modify_disable_tx(mvm, mvmsta, false); + } + goto out; out_remove_binding: @@ -2779,6 +2792,7 @@ static void __iwl_mvm_unassign_vif_chanctx(struct iwl_mvm *mvm, { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct ieee80211_vif *disabled_vif = NULL; + struct iwl_mvm_sta *mvmsta; lockdep_assert_held(&mvm->mutex); @@ -2810,6 +2824,12 @@ static void __iwl_mvm_unassign_vif_chanctx(struct iwl_mvm *mvm, disabled_vif = vif; + mvmsta = iwl_mvm_sta_from_staid_protected(mvm, + mvmvif->ap_sta_id); + + if (!WARN_ON(!mvmsta)) + iwl_mvm_sta_modify_disable_tx(mvm, mvmsta, true); + iwl_mvm_mac_ctxt_changed(mvm, vif, true); break; default: From 3dfd3a97c8b0484e85e365472fe7e292e6e8de7e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 11 Aug 2014 21:37:30 +0200 Subject: [PATCH 213/221] iwlwifi: mvm: correct firmware disassoc command sequence The firmware would like to have a MAC context (unassoc) before the AP station is removed (we do this) but would like to keep the BSSID until after it is removed, so we need to send two commands - one with the BSSID before and one without the BSSID after. In order to do this, we need to store the BSSID as it will have been cleared by mac80211 by the time we get notified of the disassociation. Also pass it around as an override to the various functions needing it, and keep taking it from the mac80211 data otherwise. This avoids having to keep track of the BSSID in all modes. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/d3.c | 2 +- drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c | 34 ++++++++++++--------- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 34 ++++++++++++++++----- drivers/net/wireless/iwlwifi/mvm/mvm.h | 8 ++++- 4 files changed, 55 insertions(+), 23 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index 607dfdbe0d5e..c17be0fb7283 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c @@ -702,7 +702,7 @@ static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif, return ret; rcu_assign_pointer(mvm->fw_id_to_mac_id[mvmvif->ap_sta_id], ap_sta); - ret = iwl_mvm_mac_ctxt_changed(mvm, vif, false); + ret = iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL); if (ret) return ret; diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c index 7171d1734df3..115bb3656d91 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c @@ -590,6 +590,7 @@ static void iwl_mvm_mac_ctxt_set_ht_flags(struct iwl_mvm *mvm, static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct iwl_mac_ctx_cmd *cmd, + const u8 *bssid_override, u32 action) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); @@ -597,6 +598,7 @@ static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm, bool ht_enabled = !!(vif->bss_conf.ht_operation_mode & IEEE80211_HT_OP_MODE_PROTECTION); u8 cck_ack_rates, ofdm_ack_rates; + const u8 *bssid = bssid_override ?: vif->bss_conf.bssid; int i; cmd->id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, @@ -629,8 +631,9 @@ static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm, cmd->tsf_id = cpu_to_le32(mvmvif->tsf_id); memcpy(cmd->node_addr, vif->addr, ETH_ALEN); - if (vif->bss_conf.bssid) - memcpy(cmd->bssid_addr, vif->bss_conf.bssid, ETH_ALEN); + + if (bssid) + memcpy(cmd->bssid_addr, bssid, ETH_ALEN); else eth_broadcast_addr(cmd->bssid_addr); @@ -699,7 +702,8 @@ static int iwl_mvm_mac_ctxt_send_cmd(struct iwl_mvm *mvm, static int iwl_mvm_mac_ctxt_cmd_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - u32 action, bool force_assoc_off) + u32 action, bool force_assoc_off, + const u8 *bssid_override) { struct iwl_mac_ctx_cmd cmd = {}; struct iwl_mac_data_sta *ctxt_sta; @@ -707,7 +711,7 @@ static int iwl_mvm_mac_ctxt_cmd_sta(struct iwl_mvm *mvm, WARN_ON(vif->type != NL80211_IFTYPE_STATION); /* Fill the common data for all mac context types */ - iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action); + iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, bssid_override, action); if (vif->p2p) { struct ieee80211_p2p_noa_attr *noa = @@ -788,7 +792,7 @@ static int iwl_mvm_mac_ctxt_cmd_listener(struct iwl_mvm *mvm, WARN_ON(vif->type != NL80211_IFTYPE_MONITOR); - iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action); + iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, NULL, action); cmd.filter_flags = cpu_to_le32(MAC_FILTER_IN_PROMISC | MAC_FILTER_IN_CONTROL_AND_MGMT | @@ -809,7 +813,7 @@ static int iwl_mvm_mac_ctxt_cmd_ibss(struct iwl_mvm *mvm, WARN_ON(vif->type != NL80211_IFTYPE_ADHOC); - iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action); + iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, NULL, action); cmd.filter_flags = cpu_to_le32(MAC_FILTER_IN_BEACON | MAC_FILTER_IN_PROBE_REQUEST); @@ -848,7 +852,7 @@ static int iwl_mvm_mac_ctxt_cmd_p2p_device(struct iwl_mvm *mvm, WARN_ON(vif->type != NL80211_IFTYPE_P2P_DEVICE); - iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action); + iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, NULL, action); cmd.protection_flags |= cpu_to_le32(MAC_PROT_FLG_TGG_PROTECT); @@ -1076,7 +1080,7 @@ static int iwl_mvm_mac_ctxt_cmd_ap(struct iwl_mvm *mvm, WARN_ON(vif->type != NL80211_IFTYPE_AP || vif->p2p); /* Fill the common data for all mac context types */ - iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action); + iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, NULL, action); /* * pass probe requests and beacons from other APs (needed @@ -1102,7 +1106,7 @@ static int iwl_mvm_mac_ctxt_cmd_go(struct iwl_mvm *mvm, WARN_ON(vif->type != NL80211_IFTYPE_AP || !vif->p2p); /* Fill the common data for all mac context types */ - iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action); + iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, NULL, action); /* * pass probe requests and beacons from other APs (needed @@ -1125,12 +1129,14 @@ static int iwl_mvm_mac_ctxt_cmd_go(struct iwl_mvm *mvm, } static int iwl_mvm_mac_ctx_send(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - u32 action, bool force_assoc_off) + u32 action, bool force_assoc_off, + const u8 *bssid_override) { switch (vif->type) { case NL80211_IFTYPE_STATION: return iwl_mvm_mac_ctxt_cmd_sta(mvm, vif, action, - force_assoc_off); + force_assoc_off, + bssid_override); break; case NL80211_IFTYPE_AP: if (!vif->p2p) @@ -1161,7 +1167,7 @@ int iwl_mvm_mac_ctxt_add(struct iwl_mvm *mvm, struct ieee80211_vif *vif) return -EIO; ret = iwl_mvm_mac_ctx_send(mvm, vif, FW_CTXT_ACTION_ADD, - true); + true, NULL); if (ret) return ret; @@ -1173,7 +1179,7 @@ int iwl_mvm_mac_ctxt_add(struct iwl_mvm *mvm, struct ieee80211_vif *vif) } int iwl_mvm_mac_ctxt_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - bool force_assoc_off) + bool force_assoc_off, const u8 *bssid_override) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); @@ -1182,7 +1188,7 @@ int iwl_mvm_mac_ctxt_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif, return -EIO; return iwl_mvm_mac_ctx_send(mvm, vif, FW_CTXT_ACTION_MODIFY, - force_assoc_off); + force_assoc_off, bssid_override); } int iwl_mvm_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 3bbeedfb789c..ea79f1ac3ecc 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -1451,10 +1451,23 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, if (changes & BSS_CHANGED_ASSOC && bss_conf->assoc) iwl_mvm_mac_ctxt_recalc_tsf_id(mvm, vif); - ret = iwl_mvm_mac_ctxt_changed(mvm, vif, false); + /* + * If we're not associated yet, take the (new) BSSID before associating + * so the firmware knows. If we're already associated, then use the old + * BSSID here, and we'll send a cleared one later in the CHANGED_ASSOC + * branch for disassociation below. + */ + if (changes & BSS_CHANGED_BSSID && !mvmvif->associated) + memcpy(mvmvif->bssid, bss_conf->bssid, ETH_ALEN); + + ret = iwl_mvm_mac_ctxt_changed(mvm, vif, false, mvmvif->bssid); if (ret) IWL_ERR(mvm, "failed to update MAC %pM\n", vif->addr); + /* after sending it once, adopt mac80211 data */ + memcpy(mvmvif->bssid, bss_conf->bssid, ETH_ALEN); + mvmvif->associated = bss_conf->assoc; + if (changes & BSS_CHANGED_ASSOC) { if (bss_conf->assoc) { /* add quota for this interface */ @@ -1516,6 +1529,13 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, if (vif->p2p) iwl_mvm_unref(mvm, IWL_MVM_REF_P2P_CLIENT); + + /* this will take the cleared BSSID from bss_conf */ + ret = iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL); + if (ret) + IWL_ERR(mvm, + "failed to update MAC %pM (clear after unassoc)\n", + vif->addr); } iwl_mvm_recalc_multicast(mvm); @@ -1627,7 +1647,7 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw, /* Need to update the P2P Device MAC (only GO, IBSS is single vif) */ if (vif->p2p && mvm->p2p_device_vif) - iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif, false); + iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif, false, NULL); iwl_mvm_ref(mvm, IWL_MVM_REF_AP_IBSS); @@ -1685,7 +1705,7 @@ static void iwl_mvm_stop_ap_ibss(struct ieee80211_hw *hw, /* Need to update the P2P Device MAC (only GO, IBSS is single vif) */ if (vif->p2p && mvm->p2p_device_vif) - iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif, false); + iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif, false, NULL); iwl_mvm_update_quotas(mvm, NULL); iwl_mvm_send_rm_bcast_sta(mvm, &mvmvif->bcast_sta); @@ -1712,7 +1732,7 @@ iwl_mvm_bss_info_changed_ap_ibss(struct iwl_mvm *mvm, if (changes & (BSS_CHANGED_ERP_CTS_PROT | BSS_CHANGED_HT | BSS_CHANGED_BANDWIDTH) && - iwl_mvm_mac_ctxt_changed(mvm, vif, false)) + iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL)) IWL_ERR(mvm, "failed to update MAC %pM\n", vif->addr); /* Need to send a new beacon template to the FW */ @@ -2123,7 +2143,7 @@ static int iwl_mvm_mac_conf_tx(struct ieee80211_hw *hw, int ret; mutex_lock(&mvm->mutex); - ret = iwl_mvm_mac_ctxt_changed(mvm, vif, false); + ret = iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL); mutex_unlock(&mvm->mutex); return ret; } @@ -2745,7 +2765,7 @@ static int __iwl_mvm_assign_vif_chanctx(struct iwl_mvm *mvm, if ((vif->type == NL80211_IFTYPE_AP) || (switching_chanctx && (vif->type == NL80211_IFTYPE_STATION))) { iwl_mvm_update_quotas(mvm, NULL); - iwl_mvm_mac_ctxt_changed(mvm, vif, false); + iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL); } if (vif->csa_active && vif->type == NL80211_IFTYPE_STATION) { @@ -2830,7 +2850,7 @@ static void __iwl_mvm_unassign_vif_chanctx(struct iwl_mvm *mvm, if (!WARN_ON(!mvmsta)) iwl_mvm_sta_modify_disable_tx(mvm, mvmsta, true); - iwl_mvm_mac_ctxt_changed(mvm, vif, true); + iwl_mvm_mac_ctxt_changed(mvm, vif, true, NULL); break; default: break; diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index b66a8afd6550..43f536446162 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -320,6 +320,9 @@ struct iwl_mvm_vif_bf_data { * @id: between 0 and 3 * @color: to solve races upon MAC addition and removal * @ap_sta_id: the sta_id of the AP - valid only if VIF type is STA + * @bssid: BSSID for this (client) interface + * @associated: indicates that we're currently associated, used only for + * managing the firmware state in iwl_mvm_bss_info_changed_station() * @uploaded: indicates the MAC context has been added to the device * @ap_ibss_active: indicates that AP/IBSS is configured and that the interface * should get quota etc. @@ -341,6 +344,9 @@ struct iwl_mvm_vif { u16 color; u8 ap_sta_id; + u8 bssid[ETH_ALEN]; + bool associated; + bool uploaded; bool ap_ibss_active; bool pm_enabled; @@ -897,7 +903,7 @@ int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif); void iwl_mvm_mac_ctxt_release(struct iwl_mvm *mvm, struct ieee80211_vif *vif); int iwl_mvm_mac_ctxt_add(struct iwl_mvm *mvm, struct ieee80211_vif *vif); int iwl_mvm_mac_ctxt_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - bool force_assoc_off); + bool force_assoc_off, const u8 *bssid_override); int iwl_mvm_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif); u32 iwl_mvm_mac_get_queues_mask(struct iwl_mvm *mvm, struct ieee80211_vif *vif); From b2d81db7b3d3e51f6f465cae8d450acf0ca8d2dc Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 1 Aug 2014 20:48:25 +0200 Subject: [PATCH 214/221] iwlwifi: mvm: clean up FIFO definitions Move all FIFO definitions together into the firmware API header file and use the same enum/naming scheme for the command FIFO. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/fw-api.h | 9 ++++++++- drivers/net/wireless/iwlwifi/mvm/mvm.h | 8 -------- drivers/net/wireless/iwlwifi/mvm/ops.c | 2 +- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index 4274f8dcb4cb..94342dbe69e9 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h @@ -84,7 +84,14 @@ enum { IWL_MVM_CMD_QUEUE = 9, }; -#define IWL_MVM_CMD_FIFO 7 +enum iwl_mvm_tx_fifo { + IWL_MVM_TX_FIFO_BK = 0, + IWL_MVM_TX_FIFO_BE, + IWL_MVM_TX_FIFO_VI, + IWL_MVM_TX_FIFO_VO, + IWL_MVM_TX_FIFO_MCAST = 5, + IWL_MVM_TX_FIFO_CMD = 7, +}; #define IWL_MVM_STATION_COUNT 16 diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 43f536446162..b529cf64a5b6 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -105,14 +105,6 @@ */ #define IWL_MVM_CS_UNBLOCK_TX_TIMEOUT 3 -enum iwl_mvm_tx_fifo { - IWL_MVM_TX_FIFO_BK = 0, - IWL_MVM_TX_FIFO_BE, - IWL_MVM_TX_FIFO_VI, - IWL_MVM_TX_FIFO_VO, - IWL_MVM_TX_FIFO_MCAST = 5, -}; - extern const struct ieee80211_ops iwl_mvm_hw_ops; /** diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 8139adcb2ef8..d7ec07d48d98 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -459,7 +459,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, trans_cfg.command_names = iwl_mvm_cmd_strings; trans_cfg.cmd_queue = IWL_MVM_CMD_QUEUE; - trans_cfg.cmd_fifo = IWL_MVM_CMD_FIFO; + trans_cfg.cmd_fifo = IWL_MVM_TX_FIFO_CMD; snprintf(mvm->hw->wiphy->fw_version, sizeof(mvm->hw->wiphy->fw_version), From df197c00bf1dbdee888aa886e5e93b49b42a268b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 1 Aug 2014 18:14:45 +0200 Subject: [PATCH 215/221] iwlwifi: mvm: clarify stop_count, remove transport_stopped The queue handling is a bit unclear - we have an array for stop_count[IWL_MAX_HW_QUEUES] but indices really are the mac80211 queue numbers. Change the array to be only of the right size for mac80211 queues (IEEE80211_MAX_QUEUES) and rename it to be clearer. While at it, also remove the unused transport queue stop bitmap in mvm. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/fw.c | 4 ++-- drivers/net/wireless/iwlwifi/mvm/mvm.h | 3 +-- drivers/net/wireless/iwlwifi/mvm/ops.c | 9 +++------ 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index c958a7d0458d..21d606028ca6 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c @@ -244,10 +244,10 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm, mvm->queue_to_mac80211[i] = i; else mvm->queue_to_mac80211[i] = IWL_INVALID_MAC80211_QUEUE; - atomic_set(&mvm->queue_stop_count[i], 0); } - mvm->transport_queue_stop = 0; + for (i = 0; i < IEEE80211_MAX_QUEUES; i++) + atomic_set(&mvm->mac80211_queue_stop_count[i], 0); mvm->ucode_loaded = true; diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index b529cf64a5b6..e292de96e09a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -562,9 +562,8 @@ struct iwl_mvm { struct mvm_statistics_rx rx_stats; - unsigned long transport_queue_stop; u8 queue_to_mac80211[IWL_MAX_HW_QUEUES]; - atomic_t queue_stop_count[IWL_MAX_HW_QUEUES]; + atomic_t mac80211_queue_stop_count[IEEE80211_MAX_QUEUES]; const char *nvm_file_name; struct iwl_nvm_data *nvm_data; diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index d7ec07d48d98..87f278cc9b2c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -703,14 +703,13 @@ static void iwl_mvm_stop_sw_queue(struct iwl_op_mode *op_mode, int queue) if (WARN_ON_ONCE(mq == IWL_INVALID_MAC80211_QUEUE)) return; - if (atomic_inc_return(&mvm->queue_stop_count[mq]) > 1) { + if (atomic_inc_return(&mvm->mac80211_queue_stop_count[mq]) > 1) { IWL_DEBUG_TX_QUEUES(mvm, "queue %d (mac80211 %d) already stopped\n", queue, mq); return; } - set_bit(mq, &mvm->transport_queue_stop); ieee80211_stop_queue(mvm->hw, mq); } @@ -722,15 +721,13 @@ static void iwl_mvm_wake_sw_queue(struct iwl_op_mode *op_mode, int queue) if (WARN_ON_ONCE(mq == IWL_INVALID_MAC80211_QUEUE)) return; - if (atomic_dec_return(&mvm->queue_stop_count[mq]) > 0) { + if (atomic_dec_return(&mvm->mac80211_queue_stop_count[mq]) > 0) { IWL_DEBUG_TX_QUEUES(mvm, - "queue %d (mac80211 %d) already awake\n", + "queue %d (mac80211 %d) still stopped\n", queue, mq); return; } - clear_bit(mq, &mvm->transport_queue_stop); - ieee80211_wake_queue(mvm->hw, mq); } From 9e848010bfa1c0da21292afb7a98957b5c35622d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 4 Aug 2014 14:33:42 +0200 Subject: [PATCH 216/221] iwlwifi: mvm: use tdls indication from mac80211 Instead of checking whether a given station is the first to be added on a client interface check for the new TDLS flag and warn in the unexpected cases. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/sta.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index 960687bf92f9..ccfc256b710a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c @@ -252,10 +252,14 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm, if (ret) return ret; - /* The first station added is the AP, the others are TDLS STAs */ - if (vif->type == NL80211_IFTYPE_STATION && - mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT) - mvmvif->ap_sta_id = sta_id; + if (vif->type == NL80211_IFTYPE_STATION) { + if (!sta->tdls) { + WARN_ON(mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT); + mvmvif->ap_sta_id = sta_id; + } else { + WARN_ON(mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT); + } + } rcu_assign_pointer(mvm->fw_id_to_mac_id[sta_id], sta); From 110cf810852f0f5333bcfb10065995006d8ecbbb Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 1 Aug 2014 23:14:24 +0200 Subject: [PATCH 217/221] iwlwifi: mvm: use iwl_mvm_mac_get_queues_mask() more There are a few places that can call the function iwl_mvm_mac_get_queues_mask() instead of open-coding the equivalent, so do that. This requires changing it to return the multicast queue as part of the bitmap, which broke GO mode because including it in the broadcast station queues seems to confuse the firmware, so work around that. Also, the API defines that the CAB queue shouldn't be included in the TFD queue mask, adjust the comment accordingly (not a bug). Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/fw-api.h | 3 - drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c | 62 ++++++++++----------- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 18 +++--- 3 files changed, 40 insertions(+), 43 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index 94342dbe69e9..9c975f9ecfcb 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h @@ -75,9 +75,6 @@ #include "fw-api-coex.h" #include "fw-api-scan.h" -/* maximal number of Tx queues in any platform */ -#define IWL_MVM_MAX_QUEUES 20 - /* Tx queue numbers */ enum { IWL_MVM_OFFCHANNEL_QUEUE = 8, diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c index 115bb3656d91..9cbb192f680e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c @@ -83,7 +83,7 @@ struct iwl_mvm_mac_iface_iterator_data { struct ieee80211_vif *vif; unsigned long available_mac_ids[BITS_TO_LONGS(NUM_MAC_INDEX_DRIVER)]; unsigned long available_tsf_ids[BITS_TO_LONGS(NUM_TSF_IDS)]; - unsigned long used_hw_queues[BITS_TO_LONGS(IWL_MVM_MAX_QUEUES)]; + u32 used_hw_queues; enum iwl_tsf_id preferred_tsf; bool found_vif; }; @@ -194,12 +194,31 @@ static void iwl_mvm_mac_tsf_id_iter(void *_data, u8 *mac, data->preferred_tsf = NUM_TSF_IDS; } +/* + * Get the mask of the queues used by the vif + */ +u32 iwl_mvm_mac_get_queues_mask(struct iwl_mvm *mvm, + struct ieee80211_vif *vif) +{ + u32 qmask = 0, ac; + + if (vif->type == NL80211_IFTYPE_P2P_DEVICE) + return BIT(IWL_MVM_OFFCHANNEL_QUEUE); + + for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) + qmask |= BIT(vif->hw_queue[ac]); + + if (vif->type == NL80211_IFTYPE_AP) + qmask |= BIT(vif->cab_queue); + + return qmask; +} + static void iwl_mvm_mac_iface_iterator(void *_data, u8 *mac, struct ieee80211_vif *vif) { struct iwl_mvm_mac_iface_iterator_data *data = _data; struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - u32 ac; /* Iterator may already find the interface being added -- skip it */ if (vif == data->vif) { @@ -208,12 +227,7 @@ static void iwl_mvm_mac_iface_iterator(void *_data, u8 *mac, } /* Mark the queues used by the vif */ - for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) - if (vif->hw_queue[ac] != IEEE80211_INVAL_HW_QUEUE) - __set_bit(vif->hw_queue[ac], data->used_hw_queues); - - if (vif->cab_queue != IEEE80211_INVAL_HW_QUEUE) - __set_bit(vif->cab_queue, data->used_hw_queues); + data->used_hw_queues |= iwl_mvm_mac_get_queues_mask(data->mvm, vif); /* Mark MAC IDs as used by clearing the available bit, and * (below) mark TSFs as used if their existing use is not @@ -227,24 +241,6 @@ static void iwl_mvm_mac_iface_iterator(void *_data, u8 *mac, iwl_mvm_mac_tsf_id_iter(_data, mac, vif); } -/* - * Get the mask of the queus used by the vif - */ -u32 iwl_mvm_mac_get_queues_mask(struct iwl_mvm *mvm, - struct ieee80211_vif *vif) -{ - u32 qmask = 0, ac; - - if (vif->type == NL80211_IFTYPE_P2P_DEVICE) - return BIT(IWL_MVM_OFFCHANNEL_QUEUE); - - for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) - if (vif->hw_queue[ac] != IEEE80211_INVAL_HW_QUEUE) - qmask |= BIT(vif->hw_queue[ac]); - - return qmask; -} - void iwl_mvm_mac_ctxt_recalc_tsf_id(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { @@ -279,15 +275,15 @@ static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm, .available_tsf_ids = { (1 << NUM_TSF_IDS) - 1 }, /* no preference yet */ .preferred_tsf = NUM_TSF_IDS, - .used_hw_queues = { + .used_hw_queues = BIT(IWL_MVM_OFFCHANNEL_QUEUE) | BIT(mvm->aux_queue) | - BIT(IWL_MVM_CMD_QUEUE) - }, + BIT(IWL_MVM_CMD_QUEUE), .found_vif = false, }; u32 ac; int ret, i; + unsigned long used_hw_queues; /* * Allocate a MAC ID and a TSF for this MAC, along with the queues @@ -370,9 +366,11 @@ static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm, return 0; } + used_hw_queues = data.used_hw_queues; + /* Find available queues, and allocate them to the ACs */ for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { - u8 queue = find_first_zero_bit(data.used_hw_queues, + u8 queue = find_first_zero_bit(&used_hw_queues, mvm->first_agg_queue); if (queue >= mvm->first_agg_queue) { @@ -381,13 +379,13 @@ static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm, goto exit_fail; } - __set_bit(queue, data.used_hw_queues); + __set_bit(queue, &used_hw_queues); vif->hw_queue[ac] = queue; } /* Allocate the CAB queue for softAP and GO interfaces */ if (vif->type == NL80211_IFTYPE_AP) { - u8 queue = find_first_zero_bit(data.used_hw_queues, + u8 queue = find_first_zero_bit(&used_hw_queues, mvm->first_agg_queue); if (queue >= mvm->first_agg_queue) { diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index ea79f1ac3ecc..ac2b11a52b9f 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -972,6 +972,15 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, if (vif->type == NL80211_IFTYPE_AP || vif->type == NL80211_IFTYPE_ADHOC) { u32 qmask = iwl_mvm_mac_get_queues_mask(mvm, vif); + + /* + * The firmware defines the TFD queue mask to only be relevant + * for *unicast* queues, so the multicast (CAB) queue should + * be excluded. + */ + if (vif->type == NL80211_IFTYPE_AP) + qmask &= ~BIT(vif->cab_queue); + ret = iwl_mvm_allocate_int_sta(mvm, &mvmvif->bcast_sta, qmask, ieee80211_vif_type_p2p(vif)); @@ -1063,14 +1072,7 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, static void iwl_mvm_prepare_mac_removal(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { - u32 tfd_msk = 0, ac; - - for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) - if (vif->hw_queue[ac] != IEEE80211_INVAL_HW_QUEUE) - tfd_msk |= BIT(vif->hw_queue[ac]); - - if (vif->cab_queue != IEEE80211_INVAL_HW_QUEUE) - tfd_msk |= BIT(vif->cab_queue); + u32 tfd_msk = iwl_mvm_mac_get_queues_mask(mvm, vif); if (tfd_msk) { mutex_lock(&mvm->mutex); From 013290aa46689a97447ef93c7058436315e476d7 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 4 Aug 2014 13:38:48 +0200 Subject: [PATCH 218/221] iwlwifi: mvm: clean up broadcast station handling Unify all the functions that handle the per-interface broadcast station and make them have mvm and vif parameters. While at it, add a new function to allocate the broadcast station instead of open-coding it, and make the combined alloc+send and free+send functions use the alloc/free & send functions. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 26 +++------ drivers/net/wireless/iwlwifi/mvm/sta.c | 61 ++++++++++++++------- drivers/net/wireless/iwlwifi/mvm/sta.h | 15 ++--- 3 files changed, 57 insertions(+), 45 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index ac2b11a52b9f..78ed6bc326a0 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -971,19 +971,7 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, */ if (vif->type == NL80211_IFTYPE_AP || vif->type == NL80211_IFTYPE_ADHOC) { - u32 qmask = iwl_mvm_mac_get_queues_mask(mvm, vif); - - /* - * The firmware defines the TFD queue mask to only be relevant - * for *unicast* queues, so the multicast (CAB) queue should - * be excluded. - */ - if (vif->type == NL80211_IFTYPE_AP) - qmask &= ~BIT(vif->cab_queue); - - ret = iwl_mvm_allocate_int_sta(mvm, &mvmvif->bcast_sta, - qmask, - ieee80211_vif_type_p2p(vif)); + ret = iwl_mvm_alloc_bcast_sta(mvm, vif); if (ret) { IWL_ERR(mvm, "Failed to allocate bcast sta\n"); goto out_release; @@ -1031,7 +1019,7 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, if (ret) goto out_unref_phy; - ret = iwl_mvm_add_bcast_sta(mvm, vif, &mvmvif->bcast_sta); + ret = iwl_mvm_add_bcast_sta(mvm, vif); if (ret) goto out_unbind; @@ -1128,13 +1116,13 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw, mvm->noa_duration = 0; } #endif - iwl_mvm_dealloc_int_sta(mvm, &mvmvif->bcast_sta); + iwl_mvm_dealloc_bcast_sta(mvm, vif); goto out_release; } if (vif->type == NL80211_IFTYPE_P2P_DEVICE) { mvm->p2p_device_vif = NULL; - iwl_mvm_rm_bcast_sta(mvm, &mvmvif->bcast_sta); + iwl_mvm_rm_bcast_sta(mvm, vif); iwl_mvm_binding_remove_vif(mvm, vif); iwl_mvm_phy_ctxt_unref(mvm, mvmvif->phy_ctxt); mvmvif->phy_ctxt = NULL; @@ -1633,7 +1621,7 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw, /* Send the bcast station. At this stage the TBTT and DTIM time events * are added and applied to the scheduler */ - ret = iwl_mvm_send_bcast_sta(mvm, vif, &mvmvif->bcast_sta); + ret = iwl_mvm_send_add_bcast_sta(mvm, vif); if (ret) goto out_unbind; @@ -1665,7 +1653,7 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw, out_quota_failed: iwl_mvm_power_update_mac(mvm); mvmvif->ap_ibss_active = false; - iwl_mvm_send_rm_bcast_sta(mvm, &mvmvif->bcast_sta); + iwl_mvm_send_rm_bcast_sta(mvm, vif); out_unbind: iwl_mvm_binding_remove_vif(mvm, vif); out_remove: @@ -1710,7 +1698,7 @@ static void iwl_mvm_stop_ap_ibss(struct ieee80211_hw *hw, iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif, false, NULL); iwl_mvm_update_quotas(mvm, NULL); - iwl_mvm_send_rm_bcast_sta(mvm, &mvmvif->bcast_sta); + iwl_mvm_send_rm_bcast_sta(mvm, vif); iwl_mvm_binding_remove_vif(mvm, vif); iwl_mvm_power_update_mac(mvm); diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index ccfc256b710a..ef61979aa286 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c @@ -558,10 +558,10 @@ int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm) * @vif: the interface to which the broadcast station is added * @bsta: the broadcast station to add. */ -int iwl_mvm_send_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - struct iwl_mvm_int_sta *bsta) +int iwl_mvm_send_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mvm_int_sta *bsta = &mvmvif->bcast_sta; static const u8 _baddr[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; const u8 *baddr = _baddr; @@ -579,19 +579,40 @@ int iwl_mvm_send_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, /* Send the FW a request to remove the station from it's internal data * structures, but DO NOT remove the entry from the local data structures. */ -int iwl_mvm_send_rm_bcast_sta(struct iwl_mvm *mvm, - struct iwl_mvm_int_sta *bsta) +int iwl_mvm_send_rm_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); int ret; lockdep_assert_held(&mvm->mutex); - ret = iwl_mvm_rm_sta_common(mvm, bsta->sta_id); + ret = iwl_mvm_rm_sta_common(mvm, mvmvif->bcast_sta.sta_id); if (ret) IWL_WARN(mvm, "Failed sending remove station\n"); return ret; } +int iwl_mvm_alloc_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + u32 qmask; + + lockdep_assert_held(&mvm->mutex); + + qmask = iwl_mvm_mac_get_queues_mask(mvm, vif); + + /* + * The firmware defines the TFD queue mask to only be relevant + * for *unicast* queues, so the multicast (CAB) queue shouldn't + * be included. + */ + if (vif->type == NL80211_IFTYPE_AP) + qmask &= ~BIT(vif->cab_queue); + + return iwl_mvm_allocate_int_sta(mvm, &mvmvif->bcast_sta, qmask, + ieee80211_vif_type_p2p(vif)); +} + /* Allocate a new station entry for the broadcast station to the given vif, * and send it to the FW. * Note that each P2P mac should have its own broadcast station. @@ -599,45 +620,47 @@ int iwl_mvm_send_rm_bcast_sta(struct iwl_mvm *mvm, * @mvm: the mvm component * @vif: the interface to which the broadcast station is added * @bsta: the broadcast station to add. */ -int iwl_mvm_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - struct iwl_mvm_int_sta *bsta) +int iwl_mvm_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - static const u8 baddr[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; - u32 qmask; + struct iwl_mvm_int_sta *bsta = &mvmvif->bcast_sta; int ret; lockdep_assert_held(&mvm->mutex); - qmask = iwl_mvm_mac_get_queues_mask(mvm, vif); - ret = iwl_mvm_allocate_int_sta(mvm, bsta, qmask, - ieee80211_vif_type_p2p(vif)); + ret = iwl_mvm_alloc_bcast_sta(mvm, vif); if (ret) return ret; - ret = iwl_mvm_add_int_sta_common(mvm, bsta, baddr, - mvmvif->id, mvmvif->color); + ret = iwl_mvm_send_add_bcast_sta(mvm, vif); if (ret) iwl_mvm_dealloc_int_sta(mvm, bsta); + return ret; } +void iwl_mvm_dealloc_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + + iwl_mvm_dealloc_int_sta(mvm, &mvmvif->bcast_sta); +} + /* * Send the FW a request to remove the station from it's internal data * structures, and in addition remove it from the local data structure. */ -int iwl_mvm_rm_bcast_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *bsta) +int iwl_mvm_rm_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { int ret; lockdep_assert_held(&mvm->mutex); - ret = iwl_mvm_rm_sta_common(mvm, bsta->sta_id); - if (ret) - return ret; + ret = iwl_mvm_send_rm_bcast_sta(mvm, vif); + + iwl_mvm_dealloc_bcast_sta(mvm, vif); - iwl_mvm_dealloc_int_sta(mvm, bsta); return ret; } diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.h b/drivers/net/wireless/iwlwifi/mvm/sta.h index ea4985eb8fa9..15984fef12b2 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.h +++ b/drivers/net/wireless/iwlwifi/mvm/sta.h @@ -393,13 +393,14 @@ int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta, u32 qmask, enum nl80211_iftype iftype); void iwl_mvm_dealloc_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta); -int iwl_mvm_send_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - struct iwl_mvm_int_sta *bsta); -int iwl_mvm_send_rm_bcast_sta(struct iwl_mvm *mvm, - struct iwl_mvm_int_sta *bsta); -int iwl_mvm_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - struct iwl_mvm_int_sta *bsta); -int iwl_mvm_rm_bcast_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *bsta); + +int iwl_mvm_alloc_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif); +int iwl_mvm_send_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif); +int iwl_mvm_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif); +int iwl_mvm_send_rm_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif); +int iwl_mvm_rm_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif); +void iwl_mvm_dealloc_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif); + void iwl_mvm_sta_drained_wk(struct work_struct *wk); void iwl_mvm_sta_modify_ps_wake(struct iwl_mvm *mvm, struct ieee80211_sta *sta); From 712b24adc105518f7cbbb6f9f353efea48954bb9 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 4 Aug 2014 14:14:14 +0200 Subject: [PATCH 219/221] iwlwifi: mvm: clean up AUX station handling The auxiliary station is being handled using the internal station helper functions, clean that up and make the helpers static. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 2 +- drivers/net/wireless/iwlwifi/mvm/sta.c | 15 ++++++++++++--- drivers/net/wireless/iwlwifi/mvm/sta.h | 5 +---- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 78ed6bc326a0..8d1d4b40b0a3 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -886,7 +886,7 @@ static void iwl_mvm_mac_stop(struct ieee80211_hw *hw) /* async_handlers_list is empty and will stay empty: HW is stopped */ /* the fw is stopped, the aux sta is dead: clean up driver state */ - iwl_mvm_dealloc_int_sta(mvm, &mvm->aux_sta); + iwl_mvm_del_aux_sta(mvm); mutex_unlock(&mvm->mutex); diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index ef61979aa286..dd9f3a4347f6 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c @@ -464,8 +464,9 @@ int iwl_mvm_rm_sta_id(struct iwl_mvm *mvm, return ret; } -int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta, - u32 qmask, enum nl80211_iftype iftype) +static int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm, + struct iwl_mvm_int_sta *sta, + u32 qmask, enum nl80211_iftype iftype) { if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { sta->sta_id = iwl_mvm_find_free_sta_id(mvm, iftype); @@ -480,7 +481,8 @@ int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta, return 0; } -void iwl_mvm_dealloc_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta) +static void iwl_mvm_dealloc_int_sta(struct iwl_mvm *mvm, + struct iwl_mvm_int_sta *sta) { RCU_INIT_POINTER(mvm->fw_id_to_mac_id[sta->sta_id], NULL); memset(sta, 0, sizeof(struct iwl_mvm_int_sta)); @@ -550,6 +552,13 @@ int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm) return ret; } +void iwl_mvm_del_aux_sta(struct iwl_mvm *mvm) +{ + lockdep_assert_held(&mvm->mutex); + + iwl_mvm_dealloc_int_sta(mvm, &mvm->aux_sta); +} + /* * Send the add station command for the vif's broadcast station. * Assumes that the station was already allocated. diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.h b/drivers/net/wireless/iwlwifi/mvm/sta.h index 15984fef12b2..aeb3a7f80ceb 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.h +++ b/drivers/net/wireless/iwlwifi/mvm/sta.h @@ -389,10 +389,7 @@ int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_sta *sta, u16 tid); int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm); -int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta, - u32 qmask, enum nl80211_iftype iftype); -void iwl_mvm_dealloc_int_sta(struct iwl_mvm *mvm, - struct iwl_mvm_int_sta *sta); +void iwl_mvm_del_aux_sta(struct iwl_mvm *mvm); int iwl_mvm_alloc_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif); int iwl_mvm_send_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif); From 87fed556d08d21dd7dd3e0222c94c187e4c2d5e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Wed, 3 Sep 2014 10:35:13 +0200 Subject: [PATCH 220/221] bcma: get info about flash type SoC booted from MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is an ongoing work on cleaning MIPS's nvram support so it could be re-used on other platforms (bcm53xx to say precisely). This will require a bit of extra logic in bcma this patch implements. Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/bcma/driver_mips.c | 62 ++++++++++++++++++++++++++++++++++ include/linux/bcma/bcma_regs.h | 5 +++ 2 files changed, 67 insertions(+) diff --git a/drivers/bcma/driver_mips.c b/drivers/bcma/driver_mips.c index 11115bbe115c..004d6aa671ce 100644 --- a/drivers/bcma/driver_mips.c +++ b/drivers/bcma/driver_mips.c @@ -21,6 +21,14 @@ #include #include +enum bcma_boot_dev { + BCMA_BOOT_DEV_UNK = 0, + BCMA_BOOT_DEV_ROM, + BCMA_BOOT_DEV_PARALLEL, + BCMA_BOOT_DEV_SERIAL, + BCMA_BOOT_DEV_NAND, +}; + static const char * const part_probes[] = { "bcm47xxpart", NULL }; static struct physmap_flash_data bcma_pflash_data = { @@ -229,11 +237,51 @@ u32 bcma_cpu_clock(struct bcma_drv_mips *mcore) } EXPORT_SYMBOL(bcma_cpu_clock); +static enum bcma_boot_dev bcma_boot_dev(struct bcma_bus *bus) +{ + struct bcma_drv_cc *cc = &bus->drv_cc; + u8 cc_rev = cc->core->id.rev; + + if (cc_rev == 42) { + struct bcma_device *core; + + core = bcma_find_core(bus, BCMA_CORE_NS_ROM); + if (core) { + switch (bcma_aread32(core, BCMA_IOST) & + BCMA_NS_ROM_IOST_BOOT_DEV_MASK) { + case BCMA_NS_ROM_IOST_BOOT_DEV_NOR: + return BCMA_BOOT_DEV_SERIAL; + case BCMA_NS_ROM_IOST_BOOT_DEV_NAND: + return BCMA_BOOT_DEV_NAND; + case BCMA_NS_ROM_IOST_BOOT_DEV_ROM: + default: + return BCMA_BOOT_DEV_ROM; + } + } + } else { + if (cc_rev == 38) { + if (cc->status & BCMA_CC_CHIPST_5357_NAND_BOOT) + return BCMA_BOOT_DEV_NAND; + else if (cc->status & BIT(5)) + return BCMA_BOOT_DEV_ROM; + } + + if ((cc->capabilities & BCMA_CC_CAP_FLASHT) == + BCMA_CC_FLASHT_PARA) + return BCMA_BOOT_DEV_PARALLEL; + else + return BCMA_BOOT_DEV_SERIAL; + } + + return BCMA_BOOT_DEV_SERIAL; +} + static void bcma_core_mips_flash_detect(struct bcma_drv_mips *mcore) { struct bcma_bus *bus = mcore->core->bus; struct bcma_drv_cc *cc = &bus->drv_cc; struct bcma_pflash *pflash = &cc->pflash; + enum bcma_boot_dev boot_dev; switch (cc->capabilities & BCMA_CC_CAP_FLASHT) { case BCMA_CC_FLASHT_STSER: @@ -269,6 +317,20 @@ static void bcma_core_mips_flash_detect(struct bcma_drv_mips *mcore) bcma_nflash_init(cc); } } + + /* Determine flash type this SoC boots from */ + boot_dev = bcma_boot_dev(bus); + switch (boot_dev) { + case BCMA_BOOT_DEV_PARALLEL: + case BCMA_BOOT_DEV_SERIAL: + /* TODO: Init NVRAM using BCMA_SOC_FLASH2 window */ + break; + case BCMA_BOOT_DEV_NAND: + /* TODO: Init NVRAM using BCMA_SOC_FLASH1 window */ + break; + default: + break; + } } void bcma_core_mips_early_init(struct bcma_drv_mips *mcore) diff --git a/include/linux/bcma/bcma_regs.h b/include/linux/bcma/bcma_regs.h index 917dcd7965e7..e64ae7bf80a1 100644 --- a/include/linux/bcma/bcma_regs.h +++ b/include/linux/bcma/bcma_regs.h @@ -39,6 +39,11 @@ #define BCMA_RESET_CTL_RESET 0x0001 #define BCMA_RESET_ST 0x0804 +#define BCMA_NS_ROM_IOST_BOOT_DEV_MASK 0x0003 +#define BCMA_NS_ROM_IOST_BOOT_DEV_NOR 0x0000 +#define BCMA_NS_ROM_IOST_BOOT_DEV_NAND 0x0001 +#define BCMA_NS_ROM_IOST_BOOT_DEV_ROM 0x0002 + /* BCMA PCI config space registers. */ #define BCMA_PCI_PMCSR 0x44 #define BCMA_PCI_PE 0x100 From db906eb2101b0564b0c65edf4a8647395196342e Mon Sep 17 00:00:00 2001 From: Jade Bilkey Date: Sat, 30 Aug 2014 15:14:14 -0400 Subject: [PATCH 221/221] ath5k: added debugfs file for dumping eeprom Signed-off-by: Jade Bilkey Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/debug.c | 96 ++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c index b8d031ae63c2..30e4e1fd4b04 100644 --- a/drivers/net/wireless/ath/ath5k/debug.c +++ b/drivers/net/wireless/ath/ath5k/debug.c @@ -894,6 +894,100 @@ static const struct file_operations fops_queue = { .llseek = default_llseek, }; +/* debugfs: eeprom */ + +struct eeprom_private { + u16 *buf; + int len; +}; + +static int open_file_eeprom(struct inode *inode, struct file *file) +{ + struct eeprom_private *ep; + struct ath5k_hw *ah = inode->i_private; + bool res; + int i, ret; + u32 eesize; + u16 val, *buf; + + /* Get eeprom size */ + + res = ath5k_hw_nvram_read(ah, AR5K_EEPROM_SIZE_UPPER, &val); + if (!res) + return -EACCES; + + if (val == 0) { + eesize = AR5K_EEPROM_INFO_MAX + AR5K_EEPROM_INFO_BASE; + } else { + eesize = (val & AR5K_EEPROM_SIZE_UPPER_MASK) << + AR5K_EEPROM_SIZE_ENDLOC_SHIFT; + ath5k_hw_nvram_read(ah, AR5K_EEPROM_SIZE_LOWER, &val); + eesize = eesize | val; + } + + if (eesize > 4096) + return -EINVAL; + + /* Create buffer and read in eeprom */ + + buf = vmalloc(eesize); + if (!buf) { + ret = -ENOMEM; + goto err; + } + + for (i = 0; i < eesize; ++i) { + AR5K_EEPROM_READ(i, val); + buf[i] = val; + } + + /* Create private struct and assign to file */ + + ep = kmalloc(sizeof(*ep), GFP_KERNEL); + if (!ep) { + ret = -ENOMEM; + goto freebuf; + } + + ep->buf = buf; + ep->len = i; + + file->private_data = (void *)ep; + + return 0; + +freebuf: + vfree(buf); +err: + return ret; + +} + +static ssize_t read_file_eeprom(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct eeprom_private *ep = file->private_data; + + return simple_read_from_buffer(user_buf, count, ppos, ep->buf, ep->len); +} + +static int release_file_eeprom(struct inode *inode, struct file *file) +{ + struct eeprom_private *ep = file->private_data; + + vfree(ep->buf); + kfree(ep); + + return 0; +} + +static const struct file_operations fops_eeprom = { + .open = open_file_eeprom, + .read = read_file_eeprom, + .release = release_file_eeprom, + .owner = THIS_MODULE, +}; + void ath5k_debug_init_device(struct ath5k_hw *ah) @@ -921,6 +1015,8 @@ ath5k_debug_init_device(struct ath5k_hw *ah) debugfs_create_file("misc", S_IRUSR, phydir, ah, &fops_misc); + debugfs_create_file("eeprom", S_IRUSR, phydir, ah, &fops_eeprom); + debugfs_create_file("frameerrors", S_IWUSR | S_IRUSR, phydir, ah, &fops_frameerrors);