Example #1
0
static void rt2x00lib_intf_scheduled(struct work_struct *work)
{
	struct rt2x00_dev *rt2x00dev =
	    container_of(work, struct rt2x00_dev, intf_work);

	/*
	 * Iterate over each interface and perform the
	 * requested configurations.
	 */
	ieee80211_iterate_active_interfaces(rt2x00dev->hw,
					    rt2x00lib_intf_scheduled_iter,
					    rt2x00dev);
}
Example #2
0
void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev)
{
	if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
		return;

	/* send buffered bc/mc frames out for every bssid */
	ieee80211_iterate_active_interfaces(rt2x00dev->hw,
					    rt2x00lib_bc_buffer_iter,
					    rt2x00dev);
	/*
	 * Devices with pre tbtt interrupt don't need to update the beacon
	 * here as they will fetch the next beacon directly prior to
	 * transmission.
	 */
	if (test_bit(DRIVER_SUPPORT_PRE_TBTT_INTERRUPT, &rt2x00dev->flags))
		return;

	/* fetch next beacon */
	ieee80211_iterate_active_interfaces(rt2x00dev->hw,
					    rt2x00lib_beaconupdate_iter,
					    rt2x00dev);
}
static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw,
					 struct ieee80211_vif *vif)
{
	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);

	iwl_mvm_prepare_mac_removal(mvm, vif);

	mutex_lock(&mvm->mutex);

	iwl_mvm_vif_dbgfs_clean(mvm, vif);

	/*
	 * For AP/GO interface, the tear down of the resources allocated to the
	 * interface is be handled as part of the stop_ap flow.
	 */
	if (vif->type == NL80211_IFTYPE_AP) {
		iwl_mvm_dealloc_int_sta(mvm, &mvmvif->bcast_sta);
		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_binding_remove_vif(mvm, vif);
		iwl_mvm_phy_ctxt_remove(mvm, mvmvif->phy_ctxt);
		mvmvif->phy_ctxt = NULL;
	}

	/*
	 * TODO: remove this temporary code.
	 * Currently MVM FW supports power management only on single MAC.
	 * Check if only one additional interface remains after removing
	 * current one. Update power mode on the remaining interface.
	 */
	if (mvm->vif_count && vif->type != NL80211_IFTYPE_P2P_DEVICE)
		mvm->vif_count--;
	IWL_DEBUG_MAC80211(mvm, "Currently %d interfaces active\n",
			   mvm->vif_count);
	if (mvm->vif_count == 1) {
		ieee80211_iterate_active_interfaces(
					mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
					iwl_mvm_power_update_iterator, mvm);
	}

	iwl_mvm_mac_ctxt_remove(mvm, vif);

out_release:
	iwl_mvm_mac_ctxt_release(mvm, vif);
	mutex_unlock(&mvm->mutex);
}
static void _iwl_mvm_power_update_binding(struct iwl_mvm *mvm,
					  struct ieee80211_vif *vif,
					  bool assign)
{
	if (vif->type == NL80211_IFTYPE_MONITOR) {
		int ret = _iwl_mvm_power_update_device(mvm, assign);
		mvm->ps_prevented = assign;
		WARN_ONCE(ret, "Failed to update power device state\n");
	}

	ieee80211_iterate_active_interfaces(mvm->hw,
					    IEEE80211_IFACE_ITER_NORMAL,
					    iwl_mvm_power_binding_iterator,
					    mvm);
}
Example #5
0
static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw,
        struct ieee80211_vif *vif)
{
    struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
    struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(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);

    if (tfd_msk) {
        mutex_lock(&mvm->mutex);
        iwl_mvm_flush_tx_path(mvm, tfd_msk, true);
        mutex_unlock(&mvm->mutex);
    }

    if (vif->type == NL80211_IFTYPE_P2P_DEVICE) {
        /*
         * Flush the ROC worker which will flush the OFFCHANNEL queue.
         * We assume here that all the packets sent to the OFFCHANNEL
         * queue are sent in ROC session.
         */
        flush_work(&mvm->roc_done_wk);
    } else {
        /*
         * By now, all the AC queues are empty. The AGG queues are
         * empty too. We already got all the Tx responses for all the
         * packets in the queues. The drain work can have been
         * triggered. Flush it. This work item takes the mutex, so kill
         * it before we take it.
         */
        flush_work(&mvm->sta_drained_wk);
    }

    mutex_lock(&mvm->mutex);

    /*
     * For AP/GO interface, the tear down of the resources allocated to the
     * interface should be handled as part of the bss_info_changed flow.
     */
    if (vif->type == NL80211_IFTYPE_AP) {
        iwl_mvm_dealloc_int_sta(mvm, &mvmvif->bcast_sta);
        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_binding_remove_vif(mvm, vif);
        iwl_mvm_phy_ctxt_remove(mvm, mvmvif->phy_ctxt);
        mvmvif->phy_ctxt = NULL;
    }

    /*
     * TODO: remove this temporary code.
     * Currently MVM FW supports power management only on single MAC.
     * Check if only one additional interface remains after removing
     * current one. Update power mode on the remaining interface.
     */
    if (mvm->vif_count)
        mvm->vif_count--;
    IWL_DEBUG_MAC80211(mvm, "Currently %d interfaces active\n",
                       mvm->vif_count);
    if (mvm->vif_count == 1) {
        ieee80211_iterate_active_interfaces(
            mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
            iwl_mvm_power_update_iterator, mvm);
    }

    iwl_mvm_mac_ctxt_remove(mvm, vif);

out_release:
    iwl_mvm_mac_ctxt_release(mvm, vif);
    mutex_unlock(&mvm->mutex);
}
Example #6
0
static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
                                     struct ieee80211_vif *vif)
{
    struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
    struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
    int ret;

    /*
     * Not much to do here. The stack will not allow interface
     * types or combinations that we didn't advertise, so we
     * don't really have to check the types.
     */

    mutex_lock(&mvm->mutex);

    /* Allocate resources for the MAC context, and add it the the fw  */
    ret = iwl_mvm_mac_ctxt_init(mvm, vif);
    if (ret)
        goto out_unlock;

    /*
     * The AP binding flow can be done only after the beacon
     * template is configured (which happens only in the mac80211
     * start_ap() flow), and adding the broadcast station can happen
     * only after the binding.
     * In addition, since modifying the MAC before adding a bcast
     * station is not allowed by the FW, delay the adding of MAC context to
     * the point where we can also add the bcast station.
     * In short: there's not much we can do at this point, other than
     * allocating resources :)
     */
    if (vif->type == NL80211_IFTYPE_AP) {
        u32 qmask = iwl_mvm_mac_get_queues_mask(mvm, vif);
        ret = iwl_mvm_allocate_int_sta(mvm, &mvmvif->bcast_sta,
                                       qmask);
        if (ret) {
            IWL_ERR(mvm, "Failed to allocate bcast sta\n");
            goto out_release;
        }

        goto out_unlock;
    }

    /*
     * TODO: remove this temporary code.
     * Currently MVM FW supports power management only on single MAC.
     * Iterate and disable PM on all active interfaces.
     * Note: the method below does not count the new interface being added
     * at this moment.
     */
    mvm->vif_count++;
    if (mvm->vif_count > 1) {
        IWL_DEBUG_MAC80211(mvm,
                           "Disable power on existing interfaces\n");
        ieee80211_iterate_active_interfaces_atomic(
            mvm->hw,
            IEEE80211_IFACE_ITER_NORMAL,
            iwl_mvm_pm_disable_iterator, mvm);
    }

    ret = iwl_mvm_mac_ctxt_add(mvm, vif);
    if (ret)
        goto out_release;

    /*
     * Update power state on the new interface. Admittedly, based on
     * mac80211 logics this power update will disable power management
     */
    iwl_mvm_power_update_mode(mvm, vif);

    /*
     * P2P_DEVICE interface does not have a channel context assigned to it,
     * so a dedicated PHY context is allocated to it and the corresponding
     * MAC context is bound to it at this stage.
     */
    if (vif->type == NL80211_IFTYPE_P2P_DEVICE) {
        struct ieee80211_channel *chan;
        struct cfg80211_chan_def chandef;

        mvmvif->phy_ctxt = &mvm->phy_ctxt_roc;

        /*
         * The channel used here isn't relevant as it's
         * going to be overwritten as part of the ROC flow.
         * For now use the first channel we have.
         */
        chan = &mvm->hw->wiphy->bands[IEEE80211_BAND_2GHZ]->channels[0];
        cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_NO_HT);
        ret = iwl_mvm_phy_ctxt_add(mvm, mvmvif->phy_ctxt,
                                   &chandef, 1, 1);
        if (ret)
            goto out_remove_mac;

        ret = iwl_mvm_binding_add_vif(mvm, vif);
        if (ret)
            goto out_remove_phy;

        ret = iwl_mvm_add_bcast_sta(mvm, vif, &mvmvif->bcast_sta);
        if (ret)
            goto out_unbind;

        /* Save a pointer to p2p device vif, so it can later be used to
         * update the p2p device MAC when a GO is started/stopped */
        mvm->p2p_device_vif = vif;
    }

    goto out_unlock;

out_unbind:
    iwl_mvm_binding_remove_vif(mvm, vif);
out_remove_phy:
    iwl_mvm_phy_ctxt_remove(mvm, mvmvif->phy_ctxt);
out_remove_mac:
    mvmvif->phy_ctxt = NULL;
    iwl_mvm_mac_ctxt_remove(mvm, vif);
out_release:
    /*
     * TODO: remove this temporary code.
     * Currently MVM FW supports power management only on single MAC.
     * Check if only one additional interface remains after rereasing
     * current one. Update power mode on the remaining interface.
     */
    mvm->vif_count--;
    IWL_DEBUG_MAC80211(mvm, "Currently %d interfaces active\n",
                       mvm->vif_count);
    if (mvm->vif_count == 1) {
        ieee80211_iterate_active_interfaces(
            mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
            iwl_mvm_power_update_iterator, mvm);
    }
    iwl_mvm_mac_ctxt_release(mvm, vif);
out_unlock:
    mutex_unlock(&mvm->mutex);

    return ret;
}
int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev)
{
	int retval;

	NOTICE(rt2x00dev, "Waking up.\n");

	/*
	 * Restore/enable extra components.
	 */
	rt2x00debug_register(rt2x00dev);
	rt2x00leds_resume(rt2x00dev);

	/*
	 * Only continue if mac80211 had open interfaces.
	 */
	if (!__test_and_clear_bit(DEVICE_STARTED_SUSPEND, &rt2x00dev->flags))
		return 0;

	/*
	 * Reinitialize device and all active interfaces.
	 */
	retval = rt2x00lib_start(rt2x00dev);
	if (retval)
		goto exit;

	/*
	 * Reconfigure device.
	 */
	retval = rt2x00mac_config(rt2x00dev->hw, &rt2x00dev->hw->conf);
	if (retval)
		goto exit;

	/*
	 * Iterator over each active interface to
	 * reconfigure the hardware.
	 */
	ieee80211_iterate_active_interfaces(rt2x00dev->hw,
					    rt2x00lib_resume_intf, rt2x00dev);

	/*
	 * We are ready again to receive requests from mac80211.
	 */
	__set_bit(DEVICE_PRESENT, &rt2x00dev->flags);

	/*
	 * It is possible that during that mac80211 has attempted
	 * to send frames while we were suspending or resuming.
	 * In that case we have disabled the TX queue and should
	 * now enable it again
	 */
	ieee80211_wake_queues(rt2x00dev->hw);

	/*
	 * During interface iteration we might have changed the
	 * delayed_flags, time to handles the event by calling
	 * the work handler directly.
	 */
	rt2x00lib_intf_scheduled(&rt2x00dev->intf_work);

	return 0;

exit:
	rt2x00lib_disable_radio(rt2x00dev);
	rt2x00lib_uninitialize(rt2x00dev);
	rt2x00debug_deregister(rt2x00dev);

	return retval;
}