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