int mt76_register_device(struct mt76_dev *dev) { struct ieee80211_hw *hw = dev->hw; struct wiphy *wiphy = hw->wiphy; void *status_fifo; int fifo_size; int i, ret; fifo_size = roundup_pow_of_two(32 * sizeof(struct mt76_tx_status)); status_fifo = devm_kzalloc(dev->dev, fifo_size, GFP_KERNEL); if (!status_fifo) return -ENOMEM; kfifo_init(&dev->txstatus_fifo, status_fifo, fifo_size); ret = mt76_init_hardware(dev); if (ret) return ret; SET_IEEE80211_DEV(hw, dev->dev); hw->queues = 4; hw->flags = IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_PS_NULLFUNC_STACK | IEEE80211_HW_SUPPORTS_HT_CCK_RATES | IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | IEEE80211_HW_AMPDU_AGGREGATION | IEEE80211_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); hw->txq_data_size = sizeof(struct mt76_txq); dev->macaddr[0] &= ~BIT(1); SET_IEEE80211_PERM_ADDR(hw, dev->macaddr); for (i = 0; i < ARRAY_SIZE(dev->macaddr_list); i++) { u8 *addr = dev->macaddr_list[i].addr; memcpy(addr, dev->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->features |= NL80211_FEATURE_ACTIVE_MONITOR; wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP) | #ifdef CONFIG_MAC80211_MESH BIT(NL80211_IFTYPE_MESH_POINT) | #endif BIT(NL80211_IFTYPE_ADHOC); wiphy->iface_combinations = if_comb; wiphy->n_iface_combinations = ARRAY_SIZE(if_comb); ret = mt76_init_sband_2g(dev); if (ret) goto fail; ret = mt76_init_sband_5g(dev); if (ret) goto fail; INIT_LIST_HEAD(&dev->txwi_cache); INIT_DELAYED_WORK(&dev->cal_work, mt76_phy_calibrate); INIT_DELAYED_WORK(&dev->mac_work, mt76_mac_work); ret = ieee80211_register_hw(hw); if (ret) goto fail; mt76_init_debugfs(dev); return 0; fail: mt76_stop_hardware(dev); return ret; }
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); }