Esempio n. 1
0
void wl1271_scan_sched_scan_stop(struct wl1271 *wl,  struct wl12xx_vif *wlvif)
{
	struct wl1271_cmd_sched_scan_stop *stop;
	int ret = 0;

	wl1271_debug(DEBUG_CMD, "cmd periodic scan stop");

	/* FIXME: what to do if alloc'ing to stop fails? */
	stop = kzalloc(sizeof(*stop), GFP_KERNEL);
	if (!stop) {
		wl1271_error("failed to alloc memory to send sched scan stop");
		return;
	}

	stop->role_id = wlvif->dev_role_id;
	stop->tag = WL1271_SCAN_DEFAULT_TAG;

	ret = wl1271_cmd_send(wl, CMD_STOP_PERIODIC_SCAN, stop,
			      sizeof(*stop), 0);
	if (ret < 0) {
		wl1271_error("failed to send sched scan stop command");
		/*
		 * sched scan is expected to be stopped even if cmd execution
		 * failed. clear the state correctly.
		 */
		wl->sched_vif = NULL;
		ieee80211_sched_scan_stopped(wl->hw);
		goto out_free;
	}

out_free:
	kfree(stop);
}
Esempio n. 2
0
File: scan.c Progetto: 3bsa/linux
int iwl_mvm_scan_offload_stop(struct iwl_mvm *mvm, bool notify)
{
	int ret;
	struct iwl_notification_wait wait_scan_done;
	static const u8 scan_done_notif[] = { SCAN_OFFLOAD_COMPLETE, };
	bool sched = mvm->scan_status == IWL_MVM_SCAN_SCHED;

	lockdep_assert_held(&mvm->mutex);

	if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN)
		return iwl_umac_scan_stop(mvm, IWL_UMAC_SCAN_UID_SCHED_SCAN,
					  notify);

	if (mvm->scan_status == IWL_MVM_SCAN_NONE)
		return 0;

	if (iwl_mvm_is_radio_killed(mvm)) {
		ret = 0;
		goto out;
	}

	iwl_init_notification_wait(&mvm->notif_wait, &wait_scan_done,
				   scan_done_notif,
				   ARRAY_SIZE(scan_done_notif),
				   NULL, NULL);

	ret = iwl_mvm_send_scan_offload_abort(mvm);
	if (ret) {
		IWL_DEBUG_SCAN(mvm, "Send stop %sscan failed %d\n",
			       sched ? "offloaded " : "", ret);
		iwl_remove_notification(&mvm->notif_wait, &wait_scan_done);
		goto out;
	}

	IWL_DEBUG_SCAN(mvm, "Successfully sent stop %sscan\n",
		       sched ? "offloaded " : "");

	ret = iwl_wait_notification(&mvm->notif_wait, &wait_scan_done, 1 * HZ);
out:
	/*
	 * Clear the scan status so the next scan requests will succeed. This
	 * also ensures the Rx handler doesn't do anything, as the scan was
	 * stopped from above. Since the rx handler won't do anything now,
	 * we have to release the scan reference here.
	 */
	if (mvm->scan_status == IWL_MVM_SCAN_OS)
		iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);

	mvm->scan_status = IWL_MVM_SCAN_NONE;

	if (notify) {
		if (sched)
			ieee80211_sched_scan_stopped(mvm->hw);
		else
			ieee80211_scan_completed(mvm->hw, true);
	}

	return ret;
}
Esempio n. 3
0
File: scan.c Progetto: 3bsa/linux
int iwl_mvm_rx_scan_offload_complete_notif(struct iwl_mvm *mvm,
					   struct iwl_rx_cmd_buffer *rxb,
					   struct iwl_device_cmd *cmd)
{
	struct iwl_rx_packet *pkt = rxb_addr(rxb);
	struct iwl_periodic_scan_complete *scan_notif;

	scan_notif = (void *)pkt->data;

	/* scan status must be locked for proper checking */
	lockdep_assert_held(&mvm->mutex);

	IWL_DEBUG_SCAN(mvm,
		       "%s completed, status %s, EBS status %s\n",
		       mvm->scan_status == IWL_MVM_SCAN_SCHED ?
				"Scheduled scan" : "Scan",
		       scan_notif->status == IWL_SCAN_OFFLOAD_COMPLETED ?
				"completed" : "aborted",
		       scan_notif->ebs_status == IWL_SCAN_EBS_SUCCESS ?
				"success" : "failed");


	/* only call mac80211 completion if the stop was initiated by FW */
	if (mvm->scan_status == IWL_MVM_SCAN_SCHED) {
		mvm->scan_status = IWL_MVM_SCAN_NONE;
		ieee80211_sched_scan_stopped(mvm->hw);
	} else if (mvm->scan_status == IWL_MVM_SCAN_OS) {
		mvm->scan_status = IWL_MVM_SCAN_NONE;
		ieee80211_scan_completed(mvm->hw,
				scan_notif->status == IWL_SCAN_OFFLOAD_ABORTED);
		iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
	}

	if (scan_notif->ebs_status)
		mvm->last_ebs_successful = false;

	return 0;
}
static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
{
	int ret;
	u32 vector;
	bool beacon_loss = false;
	bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
	bool disconnect_sta = false;
	unsigned long sta_bitmap = 0;

	wl1271_event_mbox_dump(mbox);

	vector = le32_to_cpu(mbox->events_vector);
	vector &= ~(le32_to_cpu(mbox->events_mask));
	wl1271_debug(DEBUG_EVENT, "vector: 0x%x", vector);

	if (vector & SCAN_COMPLETE_EVENT_ID) {
		wl1271_debug(DEBUG_EVENT, "status: 0x%x",
			     mbox->scheduled_scan_status);

		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) {
			ieee80211_sched_scan_stopped(wl->hw);
			wl->sched_scanning = false;
		}
	}

	if (vector & SOFT_GEMINI_SENSE_EVENT_ID &&
	    wl->bss_type == BSS_TYPE_STA_BSS)
		wl12xx_event_soft_gemini_sense(wl,
					       mbox->soft_gemini_sense_info);

	if (vector & CHANGE_AUTO_MODE_TIMEOUT_EVENT_ID &&
	    wl->bss_type == BSS_TYPE_STA_BSS) {
		int timeout = 0;
		if (mbox->change_auto_mode_timeout)
			timeout = 500;
		ieee80211_set_dyn_ps_timeout(wl->vif, timeout);
	}
	
	/*
	 * The BSS_LOSE_EVENT_ID is only needed while psm (and hence beacon
	 * filtering) is enabled. Without PSM, the stack will receive all
	 * beacons and can detect beacon loss by itself.
	 *
	 * As there's possibility that the driver disables PSM before receiving
	 * BSS_LOSE_EVENT, beacon loss has to be reported to the stack.
	 *
	 */
	if ((vector & BSS_LOSE_EVENT_ID) && !is_ap) {
		wl1271_info("Beacon loss detected.");

		/* indicate to the stack, that beacons have been lost */
		beacon_loss = true;
	}

	if ((vector & PS_REPORT_EVENT_ID) && !is_ap) {
		wl1271_debug(DEBUG_EVENT, "PS_REPORT_EVENT");
		ret = wl1271_event_ps_report(wl, mbox, &beacon_loss);
		if (ret < 0)
			return ret;
	}

	if ((vector & PSPOLL_DELIVERY_FAILURE_EVENT_ID) && !is_ap)
		wl1271_event_pspoll_delivery_fail(wl);

	if (vector & RSSI_SNR_TRIGGER_0_EVENT_ID) {
		wl1271_debug(DEBUG_EVENT, "RSSI_SNR_TRIGGER_0_EVENT");
		if (wl->vif)
			wl1271_event_rssi_trigger(wl, mbox);
	}

	if ((vector & BA_SESSION_RX_CONSTRAINT_EVENT_ID)) {
		wl1271_debug(DEBUG_EVENT, "BA_SESSION_RX_CONSTRAINT_EVENT_ID. "
			     "ba_allowed = 0x%x", mbox->rx_ba_allowed);

		wl->ba_allowed = !!mbox->rx_ba_allowed;

		if (wl->vif && !wl->ba_allowed)
			wl1271_stop_ba_event(wl);
	}

	if ((vector & CHANNEL_SWITCH_COMPLETE_EVENT_ID) && !is_ap) {
		wl1271_debug(DEBUG_EVENT, "CHANNEL_SWITCH_COMPLETE_EVENT_ID. "
					  "channel_switch_status = 0x%x",
					  mbox->channel_switch_status);
		/*
		 * That event uses for two cases:
		 * 1) channel switch complete with channel_switch_status=0
		 * 2) fixing beacon actual TSF with channel_switch_status=1
		 * calling chswitch_done only for the first option
		 */
		if (!mbox->channel_switch_status &&
		    test_and_clear_bit(WL1271_FLAG_CS_PROGRESS, &wl->flags) &&
		    (wl->vif))
			ieee80211_chswitch_done(wl->vif, true);
	}

	if ((vector & DUMMY_PACKET_EVENT_ID)) {
		wl1271_debug(DEBUG_EVENT, "DUMMY_PACKET_ID_EVENT_ID");
		if (wl->vif)
			wl1271_tx_dummy_packet(wl);
	}

	if (vector & DISCONNECT_EVENT_COMPLETE_ID)
		wl1271_debug(DEBUG_EVENT, "disconnect event");

	/*
	 * "TX retries exceeded" has a different meaning according to mode.
	 * In AP mode the offending station is disconnected.
	 */
	if ((vector & MAX_TX_RETRY_EVENT_ID) && is_ap) {
		wl1271_debug(DEBUG_EVENT, "MAX_TX_RETRY_EVENT_ID");
		sta_bitmap |= le16_to_cpu(mbox->sta_tx_retry_exceeded);
		disconnect_sta = true;
	}

	if ((vector & INACTIVE_STA_EVENT_ID) && is_ap) {
		wl1271_debug(DEBUG_EVENT, "INACTIVE_STA_EVENT_ID");
		sta_bitmap |= le16_to_cpu(mbox->sta_aging_status);
		disconnect_sta = true;
	}

	if (is_ap && disconnect_sta) {
		u32 num_packets = wl->conf.tx.max_tx_retries;
		struct ieee80211_sta *sta;
		const u8 *addr;
		int h;

		for (h = find_first_bit(&sta_bitmap, AP_MAX_LINKS);
		     h < AP_MAX_LINKS;
		     h = find_next_bit(&sta_bitmap, AP_MAX_LINKS, h+1)) {
			if (!wl1271_is_active_sta(wl, h))
				continue;

			addr = wl->links[h].addr;

			rcu_read_lock();
			sta = ieee80211_find_sta(wl->vif, addr);
			if (sta) {
				wl1271_debug(DEBUG_EVENT, "remove sta %d", h);
				ieee80211_report_low_ack(sta, num_packets);
			}
			rcu_read_unlock();
		}
	}

	if (wl->vif && beacon_loss)
		ieee80211_connection_loss(wl->vif);

	return 0;
}
Esempio n. 5
0
static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
{
	int ret;
	u32 vector;
	bool beacon_loss = false;
	bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);

	wl1271_event_mbox_dump(mbox);

	vector = le32_to_cpu(mbox->events_vector);
	vector &= ~(le32_to_cpu(mbox->events_mask));
	wl1271_debug(DEBUG_EVENT, "vector: 0x%x", vector);

	if (vector & SCAN_COMPLETE_EVENT_ID) {
		wl1271_debug(DEBUG_EVENT, "status: 0x%x",
			     mbox->scheduled_scan_status);

		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) {
		if (mbox->soft_gemini_sense_info)
			ieee80211_disable_dyn_ps(wl->vif);
		else
			ieee80211_enable_dyn_ps(wl->vif);
	}

	/*
	 * The BSS_LOSE_EVENT_ID is only needed while psm (and hence beacon
	 * filtering) is enabled. Without PSM, the stack will receive all
	 * beacons and can detect beacon loss by itself.
	 *
	 * As there's possibility that the driver disables PSM before receiving
	 * BSS_LOSE_EVENT, beacon loss has to be reported to the stack.
	 *
	 */
	if ((vector & BSS_LOSE_EVENT_ID) && !is_ap) {
		wl1271_info("Beacon loss detected.");

		/* indicate to the stack, that beacons have been lost */
		beacon_loss = true;
	}

	if ((vector & PS_REPORT_EVENT_ID) && !is_ap) {
		wl1271_debug(DEBUG_EVENT, "PS_REPORT_EVENT");
		ret = wl1271_event_ps_report(wl, mbox, &beacon_loss);
		if (ret < 0)
			return ret;
	}

	if ((vector & PSPOLL_DELIVERY_FAILURE_EVENT_ID) && !is_ap)
		wl1271_event_pspoll_delivery_fail(wl);

	if (vector & RSSI_SNR_TRIGGER_0_EVENT_ID) {
		wl1271_debug(DEBUG_EVENT, "RSSI_SNR_TRIGGER_0_EVENT");
		if (wl->vif)
			wl1271_event_rssi_trigger(wl, mbox);
	}

	if ((vector & DUMMY_PACKET_EVENT_ID) && !is_ap) {
		wl1271_debug(DEBUG_EVENT, "DUMMY_PACKET_ID_EVENT_ID");
		if (wl->vif)
			wl1271_tx_dummy_packet(wl);
	}

	if (wl->vif && beacon_loss)
		ieee80211_connection_loss(wl->vif);

	return 0;
}