diff --git a/Makefile b/Makefile index 4de47b9d..fbde0167 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ EXTRA_CFLAGS += -Werror obj-m := mt76.o mt76x2e.o mt7603e.o mt76-y := \ - mmio.o util.o trace.o dma.o + mmio.o util.o trace.o dma.o mac80211.o mt76x2e-y := \ mt76x2_pci.o mt76x2_dma.o \ diff --git a/mac80211.c b/mac80211.c new file mode 100644 index 00000000..4e29e5a3 --- /dev/null +++ b/mac80211.c @@ -0,0 +1,222 @@ +/* + * Copyright (C) 2015 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_LDPC_CODING | + 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); +} + +static const struct ieee80211_iface_limit if_limits[] = { + { + .max = 1, + .types = BIT(NL80211_IFTYPE_ADHOC) + }, { + .max = 8, + .types = BIT(NL80211_IFTYPE_STATION) | +#ifdef CONFIG_MAC80211_MESH + BIT(NL80211_IFTYPE_MESH_POINT) | +#endif + BIT(NL80211_IFTYPE_AP) + }, +}; + +static const struct ieee80211_iface_combination if_comb[] = { + { + .limits = if_limits, + .n_limits = ARRAY_SIZE(if_limits), + .max_interfaces = 8, + .num_different_channels = 1, + .beacon_int_infra_match = true, + } +}; + +int mt76_register_device(struct mt76_dev *dev, int bands, bool vht, + struct ieee80211_rate *rates, int n_rates) +{ + struct ieee80211_hw *hw = dev->hw; + struct wiphy *wiphy = hw->wiphy; + int ret; + + SET_IEEE80211_DEV(hw, dev->dev); + + 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); + + wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR; + + if (bands & BIT(IEEE80211_BAND_2GHZ)) { + ret = mt76_init_sband_2g(dev, rates, n_rates); + if (ret) + return ret; + } + + if (bands & BIT(IEEE80211_BAND_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); diff --git a/mt76.h b/mt76.h index 99b0cf08..11979907 100644 --- a/mt76.h +++ b/mt76.h @@ -103,6 +103,17 @@ struct mt76_dev { u32 rev; unsigned long state; + + struct ieee80211_supported_band sband_2g; + struct ieee80211_supported_band sband_5g; +}; + +enum mt76_phy_type { + MT_PHY_TYPE_CCK, + MT_PHY_TYPE_OFDM, + MT_PHY_TYPE_HT, + MT_PHY_TYPE_HT_GF, + MT_PHY_TYPE_VHT, }; #define mt76_rr(dev, ...) (dev)->mt76.bus->rr(&((dev)->mt76), __VA_ARGS__) @@ -146,4 +157,7 @@ static inline u16 mt76_rev(struct mt76_dev *dev) #define mt76_queue_cleanup(dev, ...) (dev)->mt76.queue_ops->cleanup(&((dev)->mt76), __VA_ARGS__) #define mt76_queue_kick(dev, ...) (dev)->mt76.queue_ops->kick(&((dev)->mt76), __VA_ARGS__) +int mt76_register_device(struct mt76_dev *dev, int bands, bool vht, + struct ieee80211_rate *rates, int n_rates); + #endif diff --git a/mt76x2.h b/mt76x2.h index 69cec127..2e7bd506 100644 --- a/mt76x2.h +++ b/mt76x2.h @@ -122,8 +122,6 @@ struct mt76x2_dev { unsigned long wcid_mask[256 / BITS_PER_LONG]; struct cfg80211_chan_def chandef; - struct ieee80211_supported_band sband_2g; - struct ieee80211_supported_band sband_5g; int txpower_conf; int txpower_cur; diff --git a/mt76x2_init.c b/mt76x2_init.c index da10ee5a..a2352a2e 100644 --- a/mt76x2_init.c +++ b/mt76x2_init.c @@ -577,67 +577,6 @@ struct mt76x2_dev *mt76x2_alloc_device(struct device *pdev) return dev; } -#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 mt76x2_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 mt76x2_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), -}; - #define CCK_RATE(_idx, _rate) { \ .bitrate = _rate, \ .flags = IEEE80211_RATE_SHORT_PREAMBLE, \ @@ -666,127 +605,15 @@ static struct ieee80211_rate mt76x2_rates[] = { OFDM_RATE(7, 540), }; -static int -mt76x2_init_sband(struct mt76x2_dev *dev, struct ieee80211_supported_band *sband, - const struct ieee80211_channel *chan, int n_chan, - struct ieee80211_rate *rates, int n_rates) -{ - 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->mt76.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_LDPC_CODING | - 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 (dev->cap.has_5ghz) - { - 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; - } - - dev->chandef.chan = &sband->channels[0]; - - return 0; -} - -static int -mt76x2_init_sband_2g(struct mt76x2_dev *dev) -{ - if (!dev->cap.has_2ghz) - return 0; - - mt76_hw(dev)->wiphy->bands[IEEE80211_BAND_2GHZ] = &dev->sband_2g; - return mt76x2_init_sband(dev, &dev->sband_2g, - mt76x2_channels_2ghz, - ARRAY_SIZE(mt76x2_channels_2ghz), - mt76x2_rates, ARRAY_SIZE(mt76x2_rates)); -} - -static int -mt76x2_init_sband_5g(struct mt76x2_dev *dev) -{ - if (!dev->cap.has_5ghz) - return 0; - - mt76_hw(dev)->wiphy->bands[IEEE80211_BAND_5GHZ] = &dev->sband_5g; - return mt76x2_init_sband(dev, &dev->sband_5g, - mt76x2_channels_5ghz, - ARRAY_SIZE(mt76x2_channels_5ghz), - mt76x2_rates + 4, ARRAY_SIZE(mt76x2_rates) - 4); -} - -static const struct ieee80211_iface_limit if_limits[] = { - { - .max = 1, - .types = BIT(NL80211_IFTYPE_ADHOC) - }, { - .max = 8, - .types = BIT(NL80211_IFTYPE_STATION) | -#ifdef CONFIG_MAC80211_MESH - BIT(NL80211_IFTYPE_MESH_POINT) | -#endif - BIT(NL80211_IFTYPE_AP) - }, -}; - -static const struct ieee80211_iface_combination if_comb[] = { - { - .limits = if_limits, - .n_limits = ARRAY_SIZE(if_limits), - .max_interfaces = 8, - .num_different_channels = 1, - .beacon_int_infra_match = true, - } -}; - 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; + int bands; fifo_size = roundup_pow_of_two(32 * sizeof(struct mt76x2_tx_status)); status_fifo = devm_kzalloc(dev->mt76.dev, fifo_size, GFP_KERNEL); @@ -799,8 +626,6 @@ int mt76x2_register_device(struct mt76x2_dev *dev) if (ret) return ret; - SET_IEEE80211_DEV(hw, dev->mt76.dev); - hw->queues = 4; hw->max_rates = 1; hw->max_report_rates = 7; @@ -835,35 +660,22 @@ int mt76x2_register_device(struct mt76x2_dev *dev) 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 = mt76x2_init_sband_2g(dev); - if (ret) - goto fail; - - ret = mt76x2_init_sband_5g(dev); - if (ret) - goto fail; - INIT_LIST_HEAD(&dev->txwi_cache); INIT_DELAYED_WORK(&dev->cal_work, mt76x2_phy_calibrate); INIT_DELAYED_WORK(&dev->mac_work, mt76x2_mac_work); - ret = ieee80211_register_hw(hw); + bands = (!!dev->cap.has_2ghz * BIT(IEEE80211_BAND_2GHZ)) | + (!!dev->cap.has_5ghz * BIT(IEEE80211_BAND_5GHZ)); + + ret = mt76_register_device(&dev->mt76, bands, true, + mt76x2_rates, ARRAY_SIZE(mt76x2_rates)); if (ret) goto fail; + sband = wiphy->bands[dev->cap.has_5ghz ? IEEE80211_BAND_5GHZ : + IEEE80211_BAND_2GHZ]; + dev->chandef.chan = &sband->channels[0]; + mt76x2_init_debugfs(dev); return 0; diff --git a/mt76x2_mac.h b/mt76x2_mac.h index a6d6b275..90b6e70b 100644 --- a/mt76x2_mac.h +++ b/mt76x2_mac.h @@ -107,14 +107,6 @@ struct mt76x2_rxwi { #define MT_RATE_INDEX_VHT_IDX GENMASK(3, 0) #define MT_RATE_INDEX_VHT_NSS GENMASK(5, 4) -enum mt76x2_phy_type { - MT_PHY_TYPE_CCK, - MT_PHY_TYPE_OFDM, - MT_PHY_TYPE_HT, - MT_PHY_TYPE_HT_GF, - MT_PHY_TYPE_VHT, -}; - enum mt76x2_phy_bandwith { MT_PHY_BW_20, MT_PHY_BW_40,