/* * is called in brcms_pci_probe() context, therefore no locking required. */ static int ieee_hw_init(struct ieee80211_hw *hw) { ieee80211_hw_set(hw, AMPDU_AGGREGATION); ieee80211_hw_set(hw, SIGNAL_DBM); ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS); hw->extra_tx_headroom = brcms_c_get_header_len(); hw->queues = N_TX_QUEUES; hw->max_rates = 2; /* Primary rate and 1 fallback rate */ /* channel change time is dependent on chip and band */ hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_ADHOC); /* * deactivate sending probe responses by ucude, because this will * cause problems when WPS is used. * * hw->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD; */ hw->rate_control_algorithm = "minstrel_ht"; hw->sta_data_size = 0; return ieee_hw_rate_init(hw); }
int mt7601u_register_device(struct mt7601u_dev *dev) { struct ieee80211_hw *hw = dev->hw; struct wiphy *wiphy = hw->wiphy; int ret; /* Reserve WCID 0 for mcast - thanks to this APs WCID will go to * entry no. 1 like it does in the vendor driver. */ dev->wcid_mask[0] |= 1; /* init fake wcid for monitor interfaces */ dev->mon_wcid = devm_kmalloc(dev->dev, sizeof(*dev->mon_wcid), GFP_KERNEL); if (!dev->mon_wcid) return -ENOMEM; dev->mon_wcid->idx = 0xff; dev->mon_wcid->hw_key_idx = -1; SET_IEEE80211_DEV(hw, dev->dev); hw->queues = 4; ieee80211_hw_set(hw, SIGNAL_DBM); ieee80211_hw_set(hw, PS_NULLFUNC_STACK); ieee80211_hw_set(hw, SUPPORTS_HT_CCK_RATES); ieee80211_hw_set(hw, AMPDU_AGGREGATION); ieee80211_hw_set(hw, SUPPORTS_RC_TABLE); hw->max_rates = 1; hw->max_report_rates = 7; hw->max_rate_tries = 1; hw->sta_data_size = sizeof(struct mt76_sta); hw->vif_data_size = sizeof(struct mt76_vif); SET_IEEE80211_PERM_ADDR(hw, dev->macaddr); wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR; wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); ret = mt76_init_sband_2g(dev); if (ret) return ret; INIT_DELAYED_WORK(&dev->mac_work, mt7601u_mac_work); INIT_DELAYED_WORK(&dev->stat_work, mt7601u_tx_stat); ret = ieee80211_register_hw(hw); if (ret) return ret; mt7601u_init_debugfs(dev); return 0; }
static void ath9k_set_mcc_capab(struct ath_softc *sc, struct ieee80211_hw *hw) { struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); if (!ath9k_is_chanctx_enabled()) return; ieee80211_hw_set(hw, QUEUE_CONTROL); hw->queues = ATH9K_NUM_TX_QUEUES; hw->offchannel_tx_hw_queue = hw->queues - 1; 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"); }
static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) { struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); ieee80211_hw_set(hw, SUPPORTS_HT_CCK_RATES); ieee80211_hw_set(hw, SUPPORTS_RC_TABLE); ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS); ieee80211_hw_set(hw, SPECTRUM_MGMT); ieee80211_hw_set(hw, PS_NULLFUNC_STACK); ieee80211_hw_set(hw, SIGNAL_DBM); ieee80211_hw_set(hw, RX_INCLUDES_FCS); ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING); ieee80211_hw_set(hw, SUPPORT_FAST_XMIT); ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS); if (ath9k_ps_enable) ieee80211_hw_set(hw, SUPPORTS_PS); if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) { ieee80211_hw_set(hw, AMPDU_AGGREGATION); if (AR_SREV_9280_20_OR_LATER(ah)) hw->radiotap_mcs_details |= IEEE80211_RADIOTAP_MCS_HAVE_STBC; } if (AR_SREV_9160_10_OR_LATER(sc->sc_ah) || ath9k_modparam_nohwcrypt) ieee80211_hw_set(hw, MFP_CAPABLE); hw->wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR | NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE | NL80211_FEATURE_P2P_GO_CTWIN; if (!IS_ENABLED(CONFIG_ATH9K_TX99)) { hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_MESH_POINT) | #ifdef CONFIG_WIRELESS_WDS BIT(NL80211_IFTYPE_WDS) | #endif BIT(NL80211_IFTYPE_OCB); if (ath9k_is_chanctx_enabled()) hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_DEVICE); hw->wiphy->iface_combinations = if_comb; hw->wiphy->n_iface_combinations = ARRAY_SIZE(if_comb); } hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS; hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_5_10_MHZ; hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; hw->queues = 4; hw->max_rates = 4; hw->max_listen_interval = 10; hw->max_rate_tries = 10; hw->sta_data_size = sizeof(struct ath_node); hw->vif_data_size = sizeof(struct ath_vif); hw->txq_data_size = sizeof(struct ath_atx_tid); hw->extra_tx_headroom = 4; hw->wiphy->available_antennas_rx = BIT(ah->caps.max_rxchains) - 1; hw->wiphy->available_antennas_tx = BIT(ah->caps.max_txchains) - 1; /* single chain devices with rx diversity */ if (ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) hw->wiphy->available_antennas_rx = BIT(0) | BIT(1); sc->ant_rx = hw->wiphy->available_antennas_rx; sc->ant_tx = hw->wiphy->available_antennas_tx; if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) hw->wiphy->bands[NL80211_BAND_2GHZ] = &common->sbands[NL80211_BAND_2GHZ]; if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) hw->wiphy->bands[NL80211_BAND_5GHZ] = &common->sbands[NL80211_BAND_5GHZ]; #ifdef CONFIG_ATH9K_CHANNEL_CONTEXT ath9k_set_mcc_capab(sc, hw); #endif ath9k_init_wow(hw); ath9k_cmn_reload_chainmask(ah); SET_IEEE80211_PERM_ADDR(hw, common->macaddr); wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_AIRTIME_FAIRNESS); }
void mt76x02_init_device(struct mt76x02_dev *dev) { struct ieee80211_hw *hw = mt76_hw(dev); struct wiphy *wiphy = hw->wiphy; INIT_DELAYED_WORK(&dev->mac_work, mt76x02_mac_work); hw->queues = 4; hw->max_rates = 1; hw->max_report_rates = 7; hw->max_rate_tries = 1; hw->extra_tx_headroom = 2; wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | #ifdef CONFIG_MAC80211_MESH BIT(NL80211_IFTYPE_MESH_POINT) | #endif BIT(NL80211_IFTYPE_ADHOC); if (mt76_is_usb(dev)) { hw->extra_tx_headroom += sizeof(struct mt76x02_txwi) + MT_DMA_HDR_LEN; } else { INIT_DELAYED_WORK(&dev->wdt_work, mt76x02_wdt_work); mt76x02_dfs_init_detector(dev); wiphy->reg_notifier = mt76x02_regd_notifier; wiphy->iface_combinations = mt76x02_if_comb; wiphy->n_iface_combinations = ARRAY_SIZE(mt76x02_if_comb); wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP); wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; /* init led callbacks */ if (IS_ENABLED(CONFIG_MT76_LEDS)) { dev->mt76.led_cdev.brightness_set = mt76x02_led_set_brightness; dev->mt76.led_cdev.blink_set = mt76x02_led_set_blink; } } wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_VHT_IBSS); hw->sta_data_size = sizeof(struct mt76x02_sta); hw->vif_data_size = sizeof(struct mt76x02_vif); ieee80211_hw_set(hw, SUPPORTS_HT_CCK_RATES); ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER); dev->mt76.global_wcid.idx = 255; dev->mt76.global_wcid.hw_key_idx = -1; dev->slottime = 9; if (is_mt76x2(dev)) { dev->mt76.sband_2g.sband.ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING; dev->mt76.sband_5g.sband.ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING; dev->mt76.chainmask = 0x202; dev->mt76.antenna_mask = 3; } else { dev->mt76.chainmask = 0x101; dev->mt76.antenna_mask = 1; } }
/* * Not a mac80211 entry point function, but it fits in with all the * other mac80211 functions grouped here. */ int iwlagn_mac_setup_register(struct iwl_priv *priv, const struct iwl_ucode_capabilities *capa) { int ret; struct ieee80211_hw *hw = priv->hw; struct iwl_rxon_context *ctx; hw->rate_control_algorithm = "iwl-agn-rs"; /* Tell mac80211 our characteristics */ ieee80211_hw_set(hw, SIGNAL_DBM); ieee80211_hw_set(hw, AMPDU_AGGREGATION); ieee80211_hw_set(hw, NEED_DTIM_BEFORE_ASSOC); ieee80211_hw_set(hw, SPECTRUM_MGMT); ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS); ieee80211_hw_set(hw, QUEUE_CONTROL); ieee80211_hw_set(hw, SUPPORTS_PS); ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS); ieee80211_hw_set(hw, SUPPORT_FAST_XMIT); ieee80211_hw_set(hw, WANT_MONITOR_VIF); hw->offchannel_tx_hw_queue = IWL_AUX_QUEUE; hw->radiotap_mcs_details |= IEEE80211_RADIOTAP_MCS_HAVE_FMT; /* * Including the following line will crash some AP's. This * workaround removes the stimulus which causes the crash until * the AP software can be fixed. hw->max_tx_aggregation_subframes = LINK_QUAL_AGG_FRAME_LIMIT_DEF; */ if (priv->nvm_data->sku_cap_11n_enable) hw->wiphy->features |= NL80211_FEATURE_DYNAMIC_SMPS | NL80211_FEATURE_STATIC_SMPS; /* * Enable 11w if advertised by firmware and software crypto * is not enabled (as the firmware will interpret some mgmt * packets, so enabling it with software crypto isn't safe) */ if (priv->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_MFP && !iwlwifi_mod_params.sw_crypto) ieee80211_hw_set(hw, MFP_CAPABLE); hw->sta_data_size = sizeof(struct iwl_station_priv); hw->vif_data_size = sizeof(struct iwl_vif_priv); for_each_context(priv, ctx) { hw->wiphy->interface_modes |= ctx->interface_modes; hw->wiphy->interface_modes |= ctx->exclusive_interface_modes; }
int mt76x2_register_device(struct mt76x2_dev *dev) { struct ieee80211_hw *hw = mt76_hw(dev); struct ieee80211_supported_band *sband; struct wiphy *wiphy = hw->wiphy; void *status_fifo; int fifo_size; int i, ret; fifo_size = roundup_pow_of_two(32 * sizeof(struct mt76x2_tx_status)); status_fifo = devm_kzalloc(dev->mt76.dev, fifo_size, GFP_KERNEL); if (!status_fifo) return -ENOMEM; kfifo_init(&dev->txstatus_fifo, status_fifo, fifo_size); ret = mt76x2_init_hardware(dev); if (ret) return ret; hw->queues = 4; hw->max_rates = 1; hw->max_report_rates = 7; hw->max_rate_tries = 1; hw->extra_tx_headroom = 2; hw->sta_data_size = sizeof(struct mt76x2_sta); hw->vif_data_size = sizeof(struct mt76x2_vif); for (i = 0; i < ARRAY_SIZE(dev->macaddr_list); i++) { u8 *addr = dev->macaddr_list[i].addr; memcpy(addr, dev->mt76.macaddr, ETH_ALEN); if (!i) continue; addr[0] |= BIT(1); addr[0] ^= ((i - 1) << 2); } wiphy->addresses = dev->macaddr_list; wiphy->n_addresses = ARRAY_SIZE(dev->macaddr_list); wiphy->iface_combinations = if_comb; wiphy->n_iface_combinations = ARRAY_SIZE(if_comb); wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_VHT_IBSS); ieee80211_hw_set(hw, SUPPORTS_HT_CCK_RATES); INIT_DELAYED_WORK(&dev->cal_work, mt76x2_phy_calibrate); INIT_DELAYED_WORK(&dev->mac_work, mt76x2_mac_work); dev->mt76.sband_2g.ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING; dev->mt76.sband_5g.ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING; ret = mt76_register_device(&dev->mt76, true, mt76x2_rates, ARRAY_SIZE(mt76x2_rates)); if (ret) goto fail; sband = wiphy->bands[dev->mt76.cap.has_5ghz ? IEEE80211_BAND_5GHZ : IEEE80211_BAND_2GHZ]; dev->chandef.chan = &sband->channels[0]; mt76x2_init_debugfs(dev); return 0; fail: mt76x2_stop_hardware(dev); return ret; }
static struct ieee80211_hw *cw1200_init_common(const u8 *macaddr, const bool have_5ghz) { int i, band; struct ieee80211_hw *hw; struct cw1200_common *priv; hw = ieee80211_alloc_hw(sizeof(struct cw1200_common), &cw1200_ops); if (!hw) return NULL; priv = hw->priv; priv->hw = hw; priv->hw_type = -1; priv->mode = NL80211_IFTYPE_UNSPECIFIED; priv->rates = cw1200_rates; /* TODO: fetch from FW */ priv->mcs_rates = cw1200_n_rates; if (cw1200_ba_rx_tids != -1) priv->ba_rx_tid_mask = cw1200_ba_rx_tids; else priv->ba_rx_tid_mask = 0xFF; /* Enable RX BLKACK for all TIDs */ if (cw1200_ba_tx_tids != -1) priv->ba_tx_tid_mask = cw1200_ba_tx_tids; else priv->ba_tx_tid_mask = 0xff; /* Enable TX BLKACK for all TIDs */ ieee80211_hw_set(hw, NEED_DTIM_BEFORE_ASSOC); ieee80211_hw_set(hw, TX_AMPDU_SETUP_IN_HW); ieee80211_hw_set(hw, AMPDU_AGGREGATION); ieee80211_hw_set(hw, CONNECTION_MONITOR); ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS); ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS); ieee80211_hw_set(hw, SIGNAL_DBM); ieee80211_hw_set(hw, SUPPORTS_PS); hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_MESH_POINT) | BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO); #ifdef CONFIG_PM hw->wiphy->wowlan = &cw1200_wowlan_support; #endif hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; hw->queues = 4; priv->rts_threshold = -1; hw->max_rates = 8; hw->max_rate_tries = 15; hw->extra_tx_headroom = WSM_TX_EXTRA_HEADROOM + 8; /* TKIP IV */ hw->sta_data_size = sizeof(struct cw1200_sta_priv); hw->wiphy->bands[NL80211_BAND_2GHZ] = &cw1200_band_2ghz; if (have_5ghz) hw->wiphy->bands[NL80211_BAND_5GHZ] = &cw1200_band_5ghz; /* Channel params have to be cleared before registering wiphy again */ for (band = 0; band < NUM_NL80211_BANDS; band++) { struct ieee80211_supported_band *sband = hw->wiphy->bands[band]; if (!sband) continue; for (i = 0; i < sband->n_channels; i++) { sband->channels[i].flags = 0; sband->channels[i].max_antenna_gain = 0; sband->channels[i].max_power = 30; } } hw->wiphy->max_scan_ssids = 2; hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; if (macaddr) SET_IEEE80211_PERM_ADDR(hw, (u8 *)macaddr); else SET_IEEE80211_PERM_ADDR(hw, cw1200_mac_template); /* Fix up mac address if necessary */ if (hw->wiphy->perm_addr[3] == 0 && hw->wiphy->perm_addr[4] == 0 && hw->wiphy->perm_addr[5] == 0) { get_random_bytes(&hw->wiphy->perm_addr[3], 3); } mutex_init(&priv->wsm_cmd_mux); mutex_init(&priv->conf_mutex); priv->workqueue = create_singlethread_workqueue("cw1200_wq"); sema_init(&priv->scan.lock, 1); INIT_WORK(&priv->scan.work, cw1200_scan_work); INIT_DELAYED_WORK(&priv->scan.probe_work, cw1200_probe_work); INIT_DELAYED_WORK(&priv->scan.timeout, cw1200_scan_timeout); INIT_DELAYED_WORK(&priv->clear_recent_scan_work, cw1200_clear_recent_scan_work); INIT_DELAYED_WORK(&priv->join_timeout, cw1200_join_timeout); INIT_WORK(&priv->unjoin_work, cw1200_unjoin_work); INIT_WORK(&priv->join_complete_work, cw1200_join_complete_work); INIT_WORK(&priv->wep_key_work, cw1200_wep_key_work); INIT_WORK(&priv->tx_policy_upload_work, tx_policy_upload_work); spin_lock_init(&priv->event_queue_lock); INIT_LIST_HEAD(&priv->event_queue); INIT_WORK(&priv->event_handler, cw1200_event_handler); INIT_DELAYED_WORK(&priv->bss_loss_work, cw1200_bss_loss_work); INIT_WORK(&priv->bss_params_work, cw1200_bss_params_work); spin_lock_init(&priv->bss_loss_lock); spin_lock_init(&priv->ps_state_lock); INIT_WORK(&priv->set_cts_work, cw1200_set_cts_work); INIT_WORK(&priv->set_tim_work, cw1200_set_tim_work); INIT_WORK(&priv->multicast_start_work, cw1200_multicast_start_work); INIT_WORK(&priv->multicast_stop_work, cw1200_multicast_stop_work); INIT_WORK(&priv->link_id_work, cw1200_link_id_work); INIT_DELAYED_WORK(&priv->link_id_gc_work, cw1200_link_id_gc_work); INIT_WORK(&priv->linkid_reset_work, cw1200_link_id_reset); INIT_WORK(&priv->update_filtering_work, cw1200_update_filtering_work); INIT_WORK(&priv->set_beacon_wakeup_period_work, cw1200_set_beacon_wakeup_period_work); timer_setup(&priv->mcast_timeout, cw1200_mcast_timeout, 0); if (cw1200_queue_stats_init(&priv->tx_queue_stats, CW1200_LINK_ID_MAX, cw1200_skb_dtor, priv)) { ieee80211_free_hw(hw); return NULL; } for (i = 0; i < 4; ++i) { if (cw1200_queue_init(&priv->tx_queue[i], &priv->tx_queue_stats, i, 16, cw1200_ttl[i])) { for (; i > 0; i--) cw1200_queue_deinit(&priv->tx_queue[i - 1]); cw1200_queue_stats_deinit(&priv->tx_queue_stats); ieee80211_free_hw(hw); return NULL; } } init_waitqueue_head(&priv->channel_switch_done); init_waitqueue_head(&priv->wsm_cmd_wq); init_waitqueue_head(&priv->wsm_startup_done); init_waitqueue_head(&priv->ps_mode_switch_done); wsm_buf_init(&priv->wsm_cmd_buf); spin_lock_init(&priv->wsm_cmd.lock); priv->wsm_cmd.done = 1; tx_policy_init(priv); return hw; }
int mt76_register_device(struct mt76_dev *dev, bool vht, struct ieee80211_rate *rates, int n_rates) { struct ieee80211_hw *hw = dev->hw; struct wiphy *wiphy = hw->wiphy; int ret; dev_set_drvdata(dev->dev, dev); INIT_LIST_HEAD(&dev->txwi_cache); SET_IEEE80211_DEV(hw, dev->dev); SET_IEEE80211_PERM_ADDR(hw, dev->macaddr); wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR; wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); wiphy->available_antennas_tx = dev->antenna_mask; wiphy->available_antennas_rx = dev->antenna_mask; hw->txq_data_size = sizeof(struct mt76_txq); hw->max_tx_fragments = 16; ieee80211_hw_set(hw, SIGNAL_DBM); ieee80211_hw_set(hw, PS_NULLFUNC_STACK); ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING); ieee80211_hw_set(hw, AMPDU_AGGREGATION); ieee80211_hw_set(hw, SUPPORTS_RC_TABLE); ieee80211_hw_set(hw, SUPPORT_FAST_XMIT); ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS); ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU); ieee80211_hw_set(hw, TX_AMSDU); ieee80211_hw_set(hw, TX_FRAG_LIST); ieee80211_hw_set(hw, MFP_CAPABLE); ieee80211_hw_set(hw, AP_LINK_PS); ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS); ieee80211_hw_set(hw, NEEDS_UNIQUE_STA_ADDR); wiphy->flags |= WIPHY_FLAG_IBSS_RSN; if (dev->cap.has_2ghz) { ret = mt76_init_sband_2g(dev, rates, n_rates); if (ret) return ret; } if (dev->cap.has_5ghz) { ret = mt76_init_sband_5g(dev, rates + 4, n_rates - 4, vht); if (ret) return ret; } wiphy_read_of_freq_limits(dev->hw->wiphy); mt76_check_sband(dev, NL80211_BAND_2GHZ); mt76_check_sband(dev, NL80211_BAND_5GHZ); if (IS_ENABLED(CONFIG_MT76_LEDS)) { ret = mt76_led_init(dev); if (ret) return ret; } return ieee80211_register_hw(hw); }