Loading drivers/net/wireless/wl12xx/boot.c +3 −1 Original line number Diff line number Diff line Loading @@ -478,7 +478,9 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl) DISCONNECT_EVENT_COMPLETE_ID | RSSI_SNR_TRIGGER_0_EVENT_ID | PSPOLL_DELIVERY_FAILURE_EVENT_ID | SOFT_GEMINI_SENSE_EVENT_ID; SOFT_GEMINI_SENSE_EVENT_ID | PERIODIC_SCAN_REPORT_EVENT_ID | PERIODIC_SCAN_COMPLETE_EVENT_ID; if (wl->bss_type == BSS_TYPE_AP_BSS) wl->event_mask |= STA_REMOVE_COMPLETE_EVENT_ID; Loading drivers/net/wireless/wl12xx/conf.h +21 −0 Original line number Diff line number Diff line Loading @@ -1147,6 +1147,26 @@ struct conf_scan_settings { }; struct conf_sched_scan_settings { /* minimum time to wait on the channel for active scans (in TUs) */ u16 min_dwell_time_active; /* maximum time to wait on the channel for active scans (in TUs) */ u16 max_dwell_time_active; /* time to wait on the channel for passive scans (in TUs) */ u32 dwell_time_passive; /* number of probe requests to send on each channel in active scans */ u8 num_probe_reqs; /* RSSI threshold to be used for filtering */ s8 rssi_threshold; /* SNR threshold to be used for filtering */ s8 snr_threshold; }; /* these are number of channels on the band divided by two, rounded up */ #define CONF_TX_PWR_COMPENSATION_LEN_2 7 #define CONF_TX_PWR_COMPENSATION_LEN_5 18 Loading Loading @@ -1234,6 +1254,7 @@ struct conf_drv_settings { struct conf_pm_config_settings pm_config; struct conf_roam_trigger_settings roam_trigger; struct conf_scan_settings scan; struct conf_sched_scan_settings sched_scan; struct conf_rf_settings rf; struct conf_ht_setting ht; struct conf_memory_settings mem_wl127x; Loading drivers/net/wireless/wl12xx/debugfs.c +1 −0 Original line number Diff line number Diff line Loading @@ -377,6 +377,7 @@ static ssize_t driver_state_read(struct file *file, char __user *user_buf, DRIVER_STATE_PRINT_HEX(platform_quirks); DRIVER_STATE_PRINT_HEX(chip.id); DRIVER_STATE_PRINT_STR(chip.fw_ver_str); DRIVER_STATE_PRINT_INT(sched_scanning); #undef DRIVER_STATE_PRINT_INT #undef DRIVER_STATE_PRINT_LONG Loading drivers/net/wireless/wl12xx/event.c +23 −0 Original line number Diff line number Diff line Loading @@ -135,6 +135,13 @@ static int wl1271_event_ps_report(struct wl1271 *wl, /* enable beacon early termination */ ret = wl1271_acx_bet_enable(wl, true); if (ret < 0) break; if (wl->ps_compl) { complete(wl->ps_compl); wl->ps_compl = NULL; } break; default: break; Loading Loading @@ -188,6 +195,22 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) wl1271_scan_stm(wl); } if (vector & PERIODIC_SCAN_REPORT_EVENT_ID) { wl1271_debug(DEBUG_EVENT, "PERIODIC_SCAN_REPORT_EVENT " "(status 0x%0x)", mbox->scheduled_scan_status); wl1271_scan_sched_scan_results(wl); } if (vector & PERIODIC_SCAN_COMPLETE_EVENT_ID) { wl1271_debug(DEBUG_EVENT, "PERIODIC_SCAN_COMPLETE_EVENT " "(status 0x%0x)", mbox->scheduled_scan_status); if (wl->sched_scanning) { wl1271_scan_sched_scan_stop(wl); ieee80211_sched_scan_stopped(wl->hw); } } /* disable dynamic PS when requested by the firmware */ if (vector & SOFT_GEMINI_SENSE_EVENT_ID && wl->bss_type == BSS_TYPE_STA_BSS) { Loading drivers/net/wireless/wl12xx/main.c +247 −13 Original line number Diff line number Diff line Loading @@ -257,12 +257,16 @@ static struct conf_drv_settings default_conf = { .wake_up_event = CONF_WAKE_UP_EVENT_DTIM, .listen_interval = 1, .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED, .bcn_filt_ie_count = 1, .bcn_filt_ie_count = 2, .bcn_filt_ie = { [0] = { .ie = WLAN_EID_CHANNEL_SWITCH, .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE, } }, [1] = { .ie = WLAN_EID_HT_INFORMATION, .rule = CONF_BCN_RULE_PASS_ON_CHANGE, }, }, .synch_fail_thold = 10, .bss_lose_timeout = 100, Loading Loading @@ -302,6 +306,15 @@ static struct conf_drv_settings default_conf = { .max_dwell_time_passive = 100000, .num_probe_reqs = 2, }, .sched_scan = { /* sched_scan requires dwell times in TU instead of TU/1000 */ .min_dwell_time_active = 8, .max_dwell_time_active = 30, .dwell_time_passive = 100, .num_probe_reqs = 2, .rssi_threshold = -90, .snr_threshold = 0, }, .rf = { .tx_per_channel_power_compensation_2 = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, Loading Loading @@ -975,6 +988,11 @@ static void wl1271_recovery_work(struct work_struct *work) /* Prevent spurious TX during FW restart */ ieee80211_stop_queues(wl->hw); if (wl->sched_scanning) { ieee80211_sched_scan_stopped(wl->hw); wl->sched_scanning = false; } /* reboot the chipset */ __wl1271_op_remove_interface(wl, false); ieee80211_restart_hw(wl->hw); Loading Loading @@ -1332,6 +1350,150 @@ static struct notifier_block wl1271_dev_notifier = { .notifier_call = wl1271_dev_notify, }; static int wl1271_configure_suspend(struct wl1271 *wl) { int ret; if (wl->bss_type != BSS_TYPE_STA_BSS) return 0; mutex_lock(&wl->mutex); ret = wl1271_ps_elp_wakeup(wl); if (ret < 0) goto out_unlock; /* enter psm if needed*/ if (!test_bit(WL1271_FLAG_PSM, &wl->flags)) { DECLARE_COMPLETION_ONSTACK(compl); wl->ps_compl = &compl; ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE, wl->basic_rate, true); if (ret < 0) goto out_sleep; /* we must unlock here so we will be able to get events */ wl1271_ps_elp_sleep(wl); mutex_unlock(&wl->mutex); ret = wait_for_completion_timeout( &compl, msecs_to_jiffies(WL1271_PS_COMPLETE_TIMEOUT)); if (ret <= 0) { wl1271_warning("couldn't enter ps mode!"); ret = -EBUSY; goto out; } /* take mutex again, and wakeup */ mutex_lock(&wl->mutex); ret = wl1271_ps_elp_wakeup(wl); if (ret < 0) goto out_unlock; } out_sleep: wl1271_ps_elp_sleep(wl); out_unlock: mutex_unlock(&wl->mutex); out: return ret; } static void wl1271_configure_resume(struct wl1271 *wl) { int ret; if (wl->bss_type != BSS_TYPE_STA_BSS) return; mutex_lock(&wl->mutex); ret = wl1271_ps_elp_wakeup(wl); if (ret < 0) goto out; /* exit psm if it wasn't configured */ if (!test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE, wl->basic_rate, true); wl1271_ps_elp_sleep(wl); out: mutex_unlock(&wl->mutex); } static int wl1271_op_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wow) { struct wl1271 *wl = hw->priv; wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow); wl->wow_enabled = !!wow; if (wl->wow_enabled) { int ret; ret = wl1271_configure_suspend(wl); if (ret < 0) { wl1271_warning("couldn't prepare device to suspend"); return ret; } /* flush any remaining work */ wl1271_debug(DEBUG_MAC80211, "flushing remaining works"); flush_delayed_work(&wl->scan_complete_work); /* * disable and re-enable interrupts in order to flush * the threaded_irq */ wl1271_disable_interrupts(wl); /* * set suspended flag to avoid triggering a new threaded_irq * work. no need for spinlock as interrupts are disabled. */ set_bit(WL1271_FLAG_SUSPENDED, &wl->flags); wl1271_enable_interrupts(wl); flush_work(&wl->tx_work); flush_delayed_work(&wl->pspoll_work); flush_delayed_work(&wl->elp_work); } return 0; } static int wl1271_op_resume(struct ieee80211_hw *hw) { struct wl1271 *wl = hw->priv; wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d", wl->wow_enabled); /* * re-enable irq_work enqueuing, and call irq_work directly if * there is a pending work. */ if (wl->wow_enabled) { struct wl1271 *wl = hw->priv; unsigned long flags; bool run_irq_work = false; spin_lock_irqsave(&wl->wl_lock, flags); clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags); if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags)) run_irq_work = true; spin_unlock_irqrestore(&wl->wl_lock, flags); if (run_irq_work) { wl1271_debug(DEBUG_MAC80211, "run postponed irq_work directly"); wl1271_irq(0, wl); wl1271_enable_interrupts(wl); } wl1271_configure_resume(wl); } return 0; } static int wl1271_op_start(struct ieee80211_hw *hw) { wl1271_debug(DEBUG_MAC80211, "mac80211 start"); Loading Loading @@ -1563,6 +1725,7 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl, memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map)); wl->ap_fw_ps_map = 0; wl->ap_ps_map = 0; wl->sched_scanning = false; /* * this is performed after the cancel_work calls and the associated Loading Loading @@ -1765,6 +1928,13 @@ static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle) wl->session_counter++; if (wl->session_counter >= SESSION_COUNTER_MAX) wl->session_counter = 0; /* The current firmware only supports sched_scan in idle */ if (wl->sched_scanning) { wl1271_scan_sched_scan_stop(wl); ieee80211_sched_scan_stopped(wl->hw); } ret = wl1271_dummy_join(wl); if (ret < 0) goto out; Loading Loading @@ -2317,6 +2487,60 @@ static int wl1271_op_hw_scan(struct ieee80211_hw *hw, return ret; } static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct cfg80211_sched_scan_request *req, struct ieee80211_sched_scan_ies *ies) { struct wl1271 *wl = hw->priv; int ret; wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start"); mutex_lock(&wl->mutex); ret = wl1271_ps_elp_wakeup(wl); if (ret < 0) goto out; ret = wl1271_scan_sched_scan_config(wl, req, ies); if (ret < 0) goto out_sleep; ret = wl1271_scan_sched_scan_start(wl); if (ret < 0) goto out_sleep; wl->sched_scanning = true; out_sleep: wl1271_ps_elp_sleep(wl); out: mutex_unlock(&wl->mutex); return ret; } static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct wl1271 *wl = hw->priv; int ret; wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop"); mutex_lock(&wl->mutex); ret = wl1271_ps_elp_wakeup(wl); if (ret < 0) goto out; wl1271_scan_sched_scan_stop(wl); wl1271_ps_elp_sleep(wl); out: mutex_unlock(&wl->mutex); } static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value) { struct wl1271 *wl = hw->priv; Loading Loading @@ -2376,20 +2600,24 @@ static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value) static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb, int offset) { u8 *ptr = skb->data + offset; u8 ssid_len; const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset, skb->len - offset); /* find the location of the ssid in the beacon */ while (ptr < skb->data + skb->len) { if (ptr[0] == WLAN_EID_SSID) { wl->ssid_len = ptr[1]; memcpy(wl->ssid, ptr+2, wl->ssid_len); return 0; if (!ptr) { wl1271_error("No SSID in IEs!"); return -ENOENT; } ptr += (ptr[1] + 2); ssid_len = ptr[1]; if (ssid_len > IEEE80211_MAX_SSID_LEN) { wl1271_error("SSID is too long!"); return -EINVAL; } wl1271_error("No SSID in IEs!\n"); return -ENOENT; wl->ssid_len = ssid_len; memcpy(wl->ssid, ptr+2, ssid_len); return 0; } static int wl1271_bss_erp_info_changed(struct wl1271 *wl, Loading Loading @@ -3422,12 +3650,16 @@ static const struct ieee80211_ops wl1271_ops = { .stop = wl1271_op_stop, .add_interface = wl1271_op_add_interface, .remove_interface = wl1271_op_remove_interface, .suspend = wl1271_op_suspend, .resume = wl1271_op_resume, .config = wl1271_op_config, .prepare_multicast = wl1271_op_prepare_multicast, .configure_filter = wl1271_op_configure_filter, .tx = wl1271_op_tx, .set_key = wl1271_op_set_key, .hw_scan = wl1271_op_hw_scan, .sched_scan_start = wl1271_op_sched_scan_start, .sched_scan_stop = wl1271_op_sched_scan_stop, .bss_info_changed = wl1271_op_bss_info_changed, .set_frag_threshold = wl1271_op_set_frag_threshold, .set_rts_threshold = wl1271_op_set_rts_threshold, Loading Loading @@ -3626,6 +3858,7 @@ int wl1271_init_ieee80211(struct wl1271 *wl) IEEE80211_HW_CONNECTION_MONITOR | IEEE80211_HW_SUPPORTS_CQM_RSSI | IEEE80211_HW_REPORTS_TX_ACK_STATUS | IEEE80211_HW_SPECTRUM_MGMT | IEEE80211_HW_AP_LINK_PS; wl->hw->wiphy->cipher_suites = cipher_suites; Loading Loading @@ -3747,6 +3980,7 @@ struct ieee80211_hw *wl1271_alloc_hw(void) wl->ap_fw_ps_map = 0; wl->quirks = 0; wl->platform_quirks = 0; wl->sched_scanning = false; memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map)); for (i = 0; i < ACX_TX_DESCRIPTORS; i++) Loading Loading
drivers/net/wireless/wl12xx/boot.c +3 −1 Original line number Diff line number Diff line Loading @@ -478,7 +478,9 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl) DISCONNECT_EVENT_COMPLETE_ID | RSSI_SNR_TRIGGER_0_EVENT_ID | PSPOLL_DELIVERY_FAILURE_EVENT_ID | SOFT_GEMINI_SENSE_EVENT_ID; SOFT_GEMINI_SENSE_EVENT_ID | PERIODIC_SCAN_REPORT_EVENT_ID | PERIODIC_SCAN_COMPLETE_EVENT_ID; if (wl->bss_type == BSS_TYPE_AP_BSS) wl->event_mask |= STA_REMOVE_COMPLETE_EVENT_ID; Loading
drivers/net/wireless/wl12xx/conf.h +21 −0 Original line number Diff line number Diff line Loading @@ -1147,6 +1147,26 @@ struct conf_scan_settings { }; struct conf_sched_scan_settings { /* minimum time to wait on the channel for active scans (in TUs) */ u16 min_dwell_time_active; /* maximum time to wait on the channel for active scans (in TUs) */ u16 max_dwell_time_active; /* time to wait on the channel for passive scans (in TUs) */ u32 dwell_time_passive; /* number of probe requests to send on each channel in active scans */ u8 num_probe_reqs; /* RSSI threshold to be used for filtering */ s8 rssi_threshold; /* SNR threshold to be used for filtering */ s8 snr_threshold; }; /* these are number of channels on the band divided by two, rounded up */ #define CONF_TX_PWR_COMPENSATION_LEN_2 7 #define CONF_TX_PWR_COMPENSATION_LEN_5 18 Loading Loading @@ -1234,6 +1254,7 @@ struct conf_drv_settings { struct conf_pm_config_settings pm_config; struct conf_roam_trigger_settings roam_trigger; struct conf_scan_settings scan; struct conf_sched_scan_settings sched_scan; struct conf_rf_settings rf; struct conf_ht_setting ht; struct conf_memory_settings mem_wl127x; Loading
drivers/net/wireless/wl12xx/debugfs.c +1 −0 Original line number Diff line number Diff line Loading @@ -377,6 +377,7 @@ static ssize_t driver_state_read(struct file *file, char __user *user_buf, DRIVER_STATE_PRINT_HEX(platform_quirks); DRIVER_STATE_PRINT_HEX(chip.id); DRIVER_STATE_PRINT_STR(chip.fw_ver_str); DRIVER_STATE_PRINT_INT(sched_scanning); #undef DRIVER_STATE_PRINT_INT #undef DRIVER_STATE_PRINT_LONG Loading
drivers/net/wireless/wl12xx/event.c +23 −0 Original line number Diff line number Diff line Loading @@ -135,6 +135,13 @@ static int wl1271_event_ps_report(struct wl1271 *wl, /* enable beacon early termination */ ret = wl1271_acx_bet_enable(wl, true); if (ret < 0) break; if (wl->ps_compl) { complete(wl->ps_compl); wl->ps_compl = NULL; } break; default: break; Loading Loading @@ -188,6 +195,22 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) wl1271_scan_stm(wl); } if (vector & PERIODIC_SCAN_REPORT_EVENT_ID) { wl1271_debug(DEBUG_EVENT, "PERIODIC_SCAN_REPORT_EVENT " "(status 0x%0x)", mbox->scheduled_scan_status); wl1271_scan_sched_scan_results(wl); } if (vector & PERIODIC_SCAN_COMPLETE_EVENT_ID) { wl1271_debug(DEBUG_EVENT, "PERIODIC_SCAN_COMPLETE_EVENT " "(status 0x%0x)", mbox->scheduled_scan_status); if (wl->sched_scanning) { wl1271_scan_sched_scan_stop(wl); ieee80211_sched_scan_stopped(wl->hw); } } /* disable dynamic PS when requested by the firmware */ if (vector & SOFT_GEMINI_SENSE_EVENT_ID && wl->bss_type == BSS_TYPE_STA_BSS) { Loading
drivers/net/wireless/wl12xx/main.c +247 −13 Original line number Diff line number Diff line Loading @@ -257,12 +257,16 @@ static struct conf_drv_settings default_conf = { .wake_up_event = CONF_WAKE_UP_EVENT_DTIM, .listen_interval = 1, .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED, .bcn_filt_ie_count = 1, .bcn_filt_ie_count = 2, .bcn_filt_ie = { [0] = { .ie = WLAN_EID_CHANNEL_SWITCH, .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE, } }, [1] = { .ie = WLAN_EID_HT_INFORMATION, .rule = CONF_BCN_RULE_PASS_ON_CHANGE, }, }, .synch_fail_thold = 10, .bss_lose_timeout = 100, Loading Loading @@ -302,6 +306,15 @@ static struct conf_drv_settings default_conf = { .max_dwell_time_passive = 100000, .num_probe_reqs = 2, }, .sched_scan = { /* sched_scan requires dwell times in TU instead of TU/1000 */ .min_dwell_time_active = 8, .max_dwell_time_active = 30, .dwell_time_passive = 100, .num_probe_reqs = 2, .rssi_threshold = -90, .snr_threshold = 0, }, .rf = { .tx_per_channel_power_compensation_2 = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, Loading Loading @@ -975,6 +988,11 @@ static void wl1271_recovery_work(struct work_struct *work) /* Prevent spurious TX during FW restart */ ieee80211_stop_queues(wl->hw); if (wl->sched_scanning) { ieee80211_sched_scan_stopped(wl->hw); wl->sched_scanning = false; } /* reboot the chipset */ __wl1271_op_remove_interface(wl, false); ieee80211_restart_hw(wl->hw); Loading Loading @@ -1332,6 +1350,150 @@ static struct notifier_block wl1271_dev_notifier = { .notifier_call = wl1271_dev_notify, }; static int wl1271_configure_suspend(struct wl1271 *wl) { int ret; if (wl->bss_type != BSS_TYPE_STA_BSS) return 0; mutex_lock(&wl->mutex); ret = wl1271_ps_elp_wakeup(wl); if (ret < 0) goto out_unlock; /* enter psm if needed*/ if (!test_bit(WL1271_FLAG_PSM, &wl->flags)) { DECLARE_COMPLETION_ONSTACK(compl); wl->ps_compl = &compl; ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE, wl->basic_rate, true); if (ret < 0) goto out_sleep; /* we must unlock here so we will be able to get events */ wl1271_ps_elp_sleep(wl); mutex_unlock(&wl->mutex); ret = wait_for_completion_timeout( &compl, msecs_to_jiffies(WL1271_PS_COMPLETE_TIMEOUT)); if (ret <= 0) { wl1271_warning("couldn't enter ps mode!"); ret = -EBUSY; goto out; } /* take mutex again, and wakeup */ mutex_lock(&wl->mutex); ret = wl1271_ps_elp_wakeup(wl); if (ret < 0) goto out_unlock; } out_sleep: wl1271_ps_elp_sleep(wl); out_unlock: mutex_unlock(&wl->mutex); out: return ret; } static void wl1271_configure_resume(struct wl1271 *wl) { int ret; if (wl->bss_type != BSS_TYPE_STA_BSS) return; mutex_lock(&wl->mutex); ret = wl1271_ps_elp_wakeup(wl); if (ret < 0) goto out; /* exit psm if it wasn't configured */ if (!test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE, wl->basic_rate, true); wl1271_ps_elp_sleep(wl); out: mutex_unlock(&wl->mutex); } static int wl1271_op_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wow) { struct wl1271 *wl = hw->priv; wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow); wl->wow_enabled = !!wow; if (wl->wow_enabled) { int ret; ret = wl1271_configure_suspend(wl); if (ret < 0) { wl1271_warning("couldn't prepare device to suspend"); return ret; } /* flush any remaining work */ wl1271_debug(DEBUG_MAC80211, "flushing remaining works"); flush_delayed_work(&wl->scan_complete_work); /* * disable and re-enable interrupts in order to flush * the threaded_irq */ wl1271_disable_interrupts(wl); /* * set suspended flag to avoid triggering a new threaded_irq * work. no need for spinlock as interrupts are disabled. */ set_bit(WL1271_FLAG_SUSPENDED, &wl->flags); wl1271_enable_interrupts(wl); flush_work(&wl->tx_work); flush_delayed_work(&wl->pspoll_work); flush_delayed_work(&wl->elp_work); } return 0; } static int wl1271_op_resume(struct ieee80211_hw *hw) { struct wl1271 *wl = hw->priv; wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d", wl->wow_enabled); /* * re-enable irq_work enqueuing, and call irq_work directly if * there is a pending work. */ if (wl->wow_enabled) { struct wl1271 *wl = hw->priv; unsigned long flags; bool run_irq_work = false; spin_lock_irqsave(&wl->wl_lock, flags); clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags); if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags)) run_irq_work = true; spin_unlock_irqrestore(&wl->wl_lock, flags); if (run_irq_work) { wl1271_debug(DEBUG_MAC80211, "run postponed irq_work directly"); wl1271_irq(0, wl); wl1271_enable_interrupts(wl); } wl1271_configure_resume(wl); } return 0; } static int wl1271_op_start(struct ieee80211_hw *hw) { wl1271_debug(DEBUG_MAC80211, "mac80211 start"); Loading Loading @@ -1563,6 +1725,7 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl, memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map)); wl->ap_fw_ps_map = 0; wl->ap_ps_map = 0; wl->sched_scanning = false; /* * this is performed after the cancel_work calls and the associated Loading Loading @@ -1765,6 +1928,13 @@ static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle) wl->session_counter++; if (wl->session_counter >= SESSION_COUNTER_MAX) wl->session_counter = 0; /* The current firmware only supports sched_scan in idle */ if (wl->sched_scanning) { wl1271_scan_sched_scan_stop(wl); ieee80211_sched_scan_stopped(wl->hw); } ret = wl1271_dummy_join(wl); if (ret < 0) goto out; Loading Loading @@ -2317,6 +2487,60 @@ static int wl1271_op_hw_scan(struct ieee80211_hw *hw, return ret; } static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct cfg80211_sched_scan_request *req, struct ieee80211_sched_scan_ies *ies) { struct wl1271 *wl = hw->priv; int ret; wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start"); mutex_lock(&wl->mutex); ret = wl1271_ps_elp_wakeup(wl); if (ret < 0) goto out; ret = wl1271_scan_sched_scan_config(wl, req, ies); if (ret < 0) goto out_sleep; ret = wl1271_scan_sched_scan_start(wl); if (ret < 0) goto out_sleep; wl->sched_scanning = true; out_sleep: wl1271_ps_elp_sleep(wl); out: mutex_unlock(&wl->mutex); return ret; } static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct wl1271 *wl = hw->priv; int ret; wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop"); mutex_lock(&wl->mutex); ret = wl1271_ps_elp_wakeup(wl); if (ret < 0) goto out; wl1271_scan_sched_scan_stop(wl); wl1271_ps_elp_sleep(wl); out: mutex_unlock(&wl->mutex); } static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value) { struct wl1271 *wl = hw->priv; Loading Loading @@ -2376,20 +2600,24 @@ static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value) static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb, int offset) { u8 *ptr = skb->data + offset; u8 ssid_len; const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset, skb->len - offset); /* find the location of the ssid in the beacon */ while (ptr < skb->data + skb->len) { if (ptr[0] == WLAN_EID_SSID) { wl->ssid_len = ptr[1]; memcpy(wl->ssid, ptr+2, wl->ssid_len); return 0; if (!ptr) { wl1271_error("No SSID in IEs!"); return -ENOENT; } ptr += (ptr[1] + 2); ssid_len = ptr[1]; if (ssid_len > IEEE80211_MAX_SSID_LEN) { wl1271_error("SSID is too long!"); return -EINVAL; } wl1271_error("No SSID in IEs!\n"); return -ENOENT; wl->ssid_len = ssid_len; memcpy(wl->ssid, ptr+2, ssid_len); return 0; } static int wl1271_bss_erp_info_changed(struct wl1271 *wl, Loading Loading @@ -3422,12 +3650,16 @@ static const struct ieee80211_ops wl1271_ops = { .stop = wl1271_op_stop, .add_interface = wl1271_op_add_interface, .remove_interface = wl1271_op_remove_interface, .suspend = wl1271_op_suspend, .resume = wl1271_op_resume, .config = wl1271_op_config, .prepare_multicast = wl1271_op_prepare_multicast, .configure_filter = wl1271_op_configure_filter, .tx = wl1271_op_tx, .set_key = wl1271_op_set_key, .hw_scan = wl1271_op_hw_scan, .sched_scan_start = wl1271_op_sched_scan_start, .sched_scan_stop = wl1271_op_sched_scan_stop, .bss_info_changed = wl1271_op_bss_info_changed, .set_frag_threshold = wl1271_op_set_frag_threshold, .set_rts_threshold = wl1271_op_set_rts_threshold, Loading Loading @@ -3626,6 +3858,7 @@ int wl1271_init_ieee80211(struct wl1271 *wl) IEEE80211_HW_CONNECTION_MONITOR | IEEE80211_HW_SUPPORTS_CQM_RSSI | IEEE80211_HW_REPORTS_TX_ACK_STATUS | IEEE80211_HW_SPECTRUM_MGMT | IEEE80211_HW_AP_LINK_PS; wl->hw->wiphy->cipher_suites = cipher_suites; Loading Loading @@ -3747,6 +3980,7 @@ struct ieee80211_hw *wl1271_alloc_hw(void) wl->ap_fw_ps_map = 0; wl->quirks = 0; wl->platform_quirks = 0; wl->sched_scanning = false; memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map)); for (i = 0; i < ACX_TX_DESCRIPTORS; i++) Loading