/* * Copyright (C) 2016 Felix Fietkau * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #include "mt76.h" #define CHAN2G(_idx, _freq) { \ .band = IEEE80211_BAND_2GHZ, \ .center_freq = (_freq), \ .hw_value = (_idx), \ .max_power = 30, \ } #define CHAN5G(_idx, _freq) { \ .band = IEEE80211_BAND_5GHZ, \ .center_freq = (_freq), \ .hw_value = (_idx), \ .max_power = 30, \ } static const struct ieee80211_channel mt76_channels_2ghz[] = { CHAN2G(1, 2412), CHAN2G(2, 2417), CHAN2G(3, 2422), CHAN2G(4, 2427), CHAN2G(5, 2432), CHAN2G(6, 2437), CHAN2G(7, 2442), CHAN2G(8, 2447), CHAN2G(9, 2452), CHAN2G(10, 2457), CHAN2G(11, 2462), CHAN2G(12, 2467), CHAN2G(13, 2472), CHAN2G(14, 2484), }; static const struct ieee80211_channel mt76_channels_5ghz[] = { CHAN5G(36, 5180), CHAN5G(40, 5200), CHAN5G(44, 5220), CHAN5G(48, 5240), CHAN5G(52, 5260), CHAN5G(56, 5280), CHAN5G(60, 5300), CHAN5G(64, 5320), CHAN5G(100, 5500), CHAN5G(104, 5520), CHAN5G(108, 5540), CHAN5G(112, 5560), CHAN5G(116, 5580), CHAN5G(120, 5600), CHAN5G(124, 5620), CHAN5G(128, 5640), CHAN5G(132, 5660), CHAN5G(136, 5680), CHAN5G(140, 5700), CHAN5G(149, 5745), CHAN5G(153, 5765), CHAN5G(157, 5785), CHAN5G(161, 5805), CHAN5G(165, 5825), }; static int mt76_init_sband(struct mt76_dev *dev, struct ieee80211_supported_band *sband, const struct ieee80211_channel *chan, int n_chan, struct ieee80211_rate *rates, int n_rates, bool vht) { struct ieee80211_sta_ht_cap *ht_cap; struct ieee80211_sta_vht_cap *vht_cap; void *chanlist; u16 mcs_map; int size; size = n_chan * sizeof(*chan); chanlist = devm_kmemdup(dev->dev, chan, size, GFP_KERNEL); if (!chanlist) return -ENOMEM; sband->channels = chanlist; sband->n_channels = n_chan; sband->bitrates = rates; sband->n_bitrates = n_rates; ht_cap = &sband->ht_cap; ht_cap->ht_supported = true; ht_cap->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40 | IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_TX_STBC | (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT); ht_cap->mcs.rx_mask[0] = 0xff; ht_cap->mcs.rx_mask[1] = 0xff; ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; ht_cap->ampdu_density = IEEE80211_HT_MPDU_DENSITY_4; if (!vht) return 0; vht_cap = &sband->vht_cap; vht_cap->vht_supported = true; mcs_map = (IEEE80211_VHT_MCS_SUPPORT_0_9 << (0 * 2)) | (IEEE80211_VHT_MCS_SUPPORT_0_9 << (1 * 2)) | (IEEE80211_VHT_MCS_NOT_SUPPORTED << (2 * 2)) | (IEEE80211_VHT_MCS_NOT_SUPPORTED << (3 * 2)) | (IEEE80211_VHT_MCS_NOT_SUPPORTED << (4 * 2)) | (IEEE80211_VHT_MCS_NOT_SUPPORTED << (5 * 2)) | (IEEE80211_VHT_MCS_NOT_SUPPORTED << (6 * 2)) | (IEEE80211_VHT_MCS_NOT_SUPPORTED << (7 * 2)); vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map); vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map); vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC | IEEE80211_VHT_CAP_TXSTBC | IEEE80211_VHT_CAP_RXSTBC_1 | IEEE80211_VHT_CAP_SHORT_GI_80; return 0; } static int mt76_init_sband_2g(struct mt76_dev *dev, struct ieee80211_rate *rates, int n_rates) { dev->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &dev->sband_2g; return mt76_init_sband(dev, &dev->sband_2g, mt76_channels_2ghz, ARRAY_SIZE(mt76_channels_2ghz), rates, n_rates, false); } static int mt76_init_sband_5g(struct mt76_dev *dev, struct ieee80211_rate *rates, int n_rates, bool vht) { dev->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &dev->sband_5g; return mt76_init_sband(dev, &dev->sband_5g, mt76_channels_5ghz, ARRAY_SIZE(mt76_channels_5ghz), rates, n_rates, vht); } 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); spin_lock_init(&dev->lock); INIT_LIST_HEAD(&dev->txwi_cache); SET_IEEE80211_DEV(hw, dev->dev); SET_IEEE80211_PERM_ADDR(hw, dev->macaddr); 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->features |= NL80211_FEATURE_ACTIVE_MONITOR; 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, SUPPORTS_HT_CCK_RATES); 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); 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; } return ieee80211_register_hw(hw); } EXPORT_SYMBOL_GPL(mt76_register_device); void mt76_unregister_device(struct mt76_dev *dev) { struct ieee80211_hw *hw = dev->hw; mt76_tx_free(dev); ieee80211_unregister_hw(hw); } EXPORT_SYMBOL_GPL(mt76_unregister_device); void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb) { if (!test_bit(MT76_STATE_RUNNING, &dev->state)) { dev_kfree_skb(skb); return; } __skb_queue_tail(&dev->rx_skb[q], skb); } EXPORT_SYMBOL_GPL(mt76_rx); void mt76_rx_complete(struct mt76_dev *dev, enum mt76_rxq_id q) { struct sk_buff *skb; while ((skb = __skb_dequeue(&dev->rx_skb[q])) != NULL) ieee80211_rx_napi(dev->hw, skb, &dev->napi[q]); }