Files
mt76/mt7915/init.c
T
Ryder LeeandFelix Fietkau 8e2d383fbd mt76: mt7915: report tx rate directly from tx status
Report tx rate from tx status packets instead of receving periodic mcu
event. This improves flexibility, accuracy and AQL performance, and
simplifies code flow for better readability.

Signed-off-by: Ryder Lee <[email protected]>
Signed-off-by: Felix Fietkau <[email protected]>
2021-07-14 15:54:43 +02:00

850 lines
22 KiB
C

// SPDX-License-Identifier: ISC
/* Copyright (C) 2020 MediaTek Inc. */
#include <linux/etherdevice.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/thermal.h>
#include "mt7915.h"
#include "mac.h"
#include "mcu.h"
#include "eeprom.h"
static const struct ieee80211_iface_limit if_limits[] = {
{
.max = 1,
.types = BIT(NL80211_IFTYPE_ADHOC)
}, {
.max = 16,
.types = BIT(NL80211_IFTYPE_AP)
#ifdef CONFIG_MAC80211_MESH
| BIT(NL80211_IFTYPE_MESH_POINT)
#endif
}, {
.max = MT7915_MAX_INTERFACES,
.types = BIT(NL80211_IFTYPE_STATION)
}
};
static const struct ieee80211_iface_combination if_comb[] = {
{
.limits = if_limits,
.n_limits = ARRAY_SIZE(if_limits),
.max_interfaces = MT7915_MAX_INTERFACES,
.num_different_channels = 1,
.beacon_int_infra_match = true,
.radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) |
BIT(NL80211_CHAN_WIDTH_20) |
BIT(NL80211_CHAN_WIDTH_40) |
BIT(NL80211_CHAN_WIDTH_80) |
BIT(NL80211_CHAN_WIDTH_160) |
BIT(NL80211_CHAN_WIDTH_80P80),
}
};
static ssize_t mt7915_thermal_show_temp(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct mt7915_phy *phy = dev_get_drvdata(dev);
int temperature;
temperature = mt7915_mcu_get_temperature(phy);
if (temperature < 0)
return temperature;
/* display in millidegree celcius */
return sprintf(buf, "%u\n", temperature * 1000);
}
static SENSOR_DEVICE_ATTR(temp1_input, 0444, mt7915_thermal_show_temp,
NULL, 0);
static struct attribute *mt7915_hwmon_attrs[] = {
&sensor_dev_attr_temp1_input.dev_attr.attr,
NULL,
};
ATTRIBUTE_GROUPS(mt7915_hwmon);
static int
mt7915_thermal_get_max_throttle_state(struct thermal_cooling_device *cdev,
unsigned long *state)
{
*state = MT7915_THERMAL_THROTTLE_MAX;
return 0;
}
static int
mt7915_thermal_get_cur_throttle_state(struct thermal_cooling_device *cdev,
unsigned long *state)
{
struct mt7915_phy *phy = cdev->devdata;
*state = phy->throttle_state;
return 0;
}
static int
mt7915_thermal_set_cur_throttle_state(struct thermal_cooling_device *cdev,
unsigned long state)
{
struct mt7915_phy *phy = cdev->devdata;
int ret;
if (state > MT7915_THERMAL_THROTTLE_MAX)
return -EINVAL;
if (state == phy->throttle_state)
return 0;
ret = mt7915_mcu_set_thermal_throttling(phy, state);
if (ret)
return ret;
phy->throttle_state = state;
return 0;
}
static const struct thermal_cooling_device_ops mt7915_thermal_ops = {
.get_max_state = mt7915_thermal_get_max_throttle_state,
.get_cur_state = mt7915_thermal_get_cur_throttle_state,
.set_cur_state = mt7915_thermal_set_cur_throttle_state,
};
static void mt7915_unregister_thermal(struct mt7915_phy *phy)
{
struct wiphy *wiphy = phy->mt76->hw->wiphy;
if (!phy->cdev)
return;
sysfs_remove_link(&wiphy->dev.kobj, "cooling_device");
thermal_cooling_device_unregister(phy->cdev);
}
static int mt7915_thermal_init(struct mt7915_phy *phy)
{
struct wiphy *wiphy = phy->mt76->hw->wiphy;
struct thermal_cooling_device *cdev;
struct device *hwmon;
cdev = thermal_cooling_device_register(wiphy_name(wiphy), phy,
&mt7915_thermal_ops);
if (!IS_ERR(cdev)) {
if (sysfs_create_link(&wiphy->dev.kobj, &cdev->device.kobj,
"cooling_device") < 0)
thermal_cooling_device_unregister(cdev);
else
phy->cdev = cdev;
}
if (!IS_REACHABLE(CONFIG_HWMON))
return 0;
hwmon = devm_hwmon_device_register_with_groups(&wiphy->dev,
wiphy_name(wiphy), phy,
mt7915_hwmon_groups);
if (IS_ERR(hwmon))
return PTR_ERR(hwmon);
return 0;
}
static void
mt7915_init_txpower(struct mt7915_dev *dev,
struct ieee80211_supported_band *sband)
{
int i, n_chains = hweight8(dev->mphy.antenna_mask);
int nss_delta = mt76_tx_power_nss_delta(n_chains);
int pwr_delta = mt7915_eeprom_get_power_delta(dev, sband->band);
struct mt76_power_limits limits;
for (i = 0; i < sband->n_channels; i++) {
struct ieee80211_channel *chan = &sband->channels[i];
u32 target_power = 0;
int j;
for (j = 0; j < n_chains; j++) {
u32 val;
val = mt7915_eeprom_get_target_power(dev, chan, j);
target_power = max(target_power, val);
}
target_power += pwr_delta;
target_power = mt76_get_rate_power_limits(&dev->mphy, chan,
&limits,
target_power);
target_power += nss_delta;
target_power = DIV_ROUND_UP(target_power, 2);
chan->max_power = min_t(int, chan->max_reg_power,
target_power);
chan->orig_mpwr = target_power;
}
}
static void
mt7915_regd_notifier(struct wiphy *wiphy,
struct regulatory_request *request)
{
struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
struct mt7915_dev *dev = mt7915_hw_dev(hw);
struct mt76_phy *mphy = hw->priv;
struct mt7915_phy *phy = mphy->priv;
struct cfg80211_chan_def *chandef = &mphy->chandef;
memcpy(dev->mt76.alpha2, request->alpha2, sizeof(dev->mt76.alpha2));
dev->mt76.region = request->dfs_region;
mt7915_init_txpower(dev, &mphy->sband_2g.sband);
mt7915_init_txpower(dev, &mphy->sband_5g.sband);
if (!(chandef->chan->flags & IEEE80211_CHAN_RADAR))
return;
mt7915_dfs_init_radar_detector(phy);
}
static void
mt7915_init_wiphy(struct ieee80211_hw *hw)
{
struct mt7915_phy *phy = mt7915_hw_phy(hw);
struct wiphy *wiphy = hw->wiphy;
hw->queues = 4;
hw->max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF;
hw->max_tx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF;
hw->netdev_features = NETIF_F_RXCSUM;
hw->radiotap_timestamp.units_pos =
IEEE80211_RADIOTAP_TIMESTAMP_UNIT_US;
phy->slottime = 9;
hw->sta_data_size = sizeof(struct mt7915_sta);
hw->vif_data_size = sizeof(struct mt7915_vif);
wiphy->iface_combinations = if_comb;
wiphy->n_iface_combinations = ARRAY_SIZE(if_comb);
wiphy->reg_notifier = mt7915_regd_notifier;
wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_VHT_IBSS);
ieee80211_hw_set(hw, HAS_RATE_CONTROL);
ieee80211_hw_set(hw, SUPPORTS_TX_ENCAP_OFFLOAD);
ieee80211_hw_set(hw, SUPPORTS_RX_DECAP_OFFLOAD);
ieee80211_hw_set(hw, WANT_MONITOR_VIF);
hw->max_tx_fragments = 4;
if (!phy->dev->dbdc_support)
wiphy->txq_memory_limit = 32 << 20; /* 32 MiB */
if (phy->mt76->cap.has_2ghz)
phy->mt76->sband_2g.sband.ht_cap.cap |=
IEEE80211_HT_CAP_LDPC_CODING |
IEEE80211_HT_CAP_MAX_AMSDU;
if (phy->mt76->cap.has_5ghz) {
phy->mt76->sband_5g.sband.ht_cap.cap |=
IEEE80211_HT_CAP_LDPC_CODING |
IEEE80211_HT_CAP_MAX_AMSDU;
phy->mt76->sband_5g.sband.vht_cap.cap |=
IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991 |
IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK;
}
mt76_set_stream_caps(phy->mt76, true);
mt7915_set_stream_vht_txbf_caps(phy);
mt7915_set_stream_he_caps(phy);
}
static void
mt7915_mac_init_band(struct mt7915_dev *dev, u8 band)
{
u32 mask, set;
mt76_rmw_field(dev, MT_TMAC_CTCR0(band),
MT_TMAC_CTCR0_INS_DDLMT_REFTIME, 0x3f);
mt76_set(dev, MT_TMAC_CTCR0(band),
MT_TMAC_CTCR0_INS_DDLMT_VHT_SMPDU_EN |
MT_TMAC_CTCR0_INS_DDLMT_EN);
mask = MT_MDP_RCFR0_MCU_RX_MGMT |
MT_MDP_RCFR0_MCU_RX_CTL_NON_BAR |
MT_MDP_RCFR0_MCU_RX_CTL_BAR;
set = FIELD_PREP(MT_MDP_RCFR0_MCU_RX_MGMT, MT_MDP_TO_HIF) |
FIELD_PREP(MT_MDP_RCFR0_MCU_RX_CTL_NON_BAR, MT_MDP_TO_HIF) |
FIELD_PREP(MT_MDP_RCFR0_MCU_RX_CTL_BAR, MT_MDP_TO_HIF);
mt76_rmw(dev, MT_MDP_BNRCFR0(band), mask, set);
mask = MT_MDP_RCFR1_MCU_RX_BYPASS |
MT_MDP_RCFR1_RX_DROPPED_UCAST |
MT_MDP_RCFR1_RX_DROPPED_MCAST;
set = FIELD_PREP(MT_MDP_RCFR1_MCU_RX_BYPASS, MT_MDP_TO_HIF) |
FIELD_PREP(MT_MDP_RCFR1_RX_DROPPED_UCAST, MT_MDP_TO_HIF) |
FIELD_PREP(MT_MDP_RCFR1_RX_DROPPED_MCAST, MT_MDP_TO_HIF);
mt76_rmw(dev, MT_MDP_BNRCFR1(band), mask, set);
mt76_set(dev, MT_WF_RMAC_MIB_AIRTIME0(band), MT_WF_RMAC_MIB_RXTIME_EN);
mt76_rmw_field(dev, MT_DMA_DCR0(band), MT_DMA_DCR0_MAX_RX_LEN, 1536);
/* disable rx rate report by default due to hw issues */
mt76_clear(dev, MT_DMA_DCR0(band), MT_DMA_DCR0_RXD_G5_EN);
}
static void mt7915_mac_init(struct mt7915_dev *dev)
{
int i;
mt76_rmw_field(dev, MT_MDP_DCR1, MT_MDP_DCR1_MAX_RX_LEN, 1536);
/* enable hardware de-agg */
mt76_set(dev, MT_MDP_DCR0, MT_MDP_DCR0_DAMSDU_EN);
for (i = 0; i < MT7915_WTBL_SIZE; i++)
mt7915_mac_wtbl_update(dev, i,
MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
for (i = 0; i < 2; i++)
mt7915_mac_init_band(dev, i);
}
static int mt7915_txbf_init(struct mt7915_dev *dev)
{
int ret;
if (dev->dbdc_support) {
ret = mt7915_mcu_set_txbf(dev, MT_BF_MODULE_UPDATE);
if (ret)
return ret;
}
/* trigger sounding packets */
ret = mt7915_mcu_set_txbf(dev, MT_BF_SOUNDING_ON);
if (ret)
return ret;
/* enable eBF */
return mt7915_mcu_set_txbf(dev, MT_BF_TYPE_UPDATE);
}
static int mt7915_register_ext_phy(struct mt7915_dev *dev)
{
struct mt7915_phy *phy = mt7915_ext_phy(dev);
struct mt76_phy *mphy;
int ret;
if (!dev->dbdc_support)
return 0;
if (phy)
return 0;
mphy = mt76_alloc_phy(&dev->mt76, sizeof(*phy), &mt7915_ops);
if (!mphy)
return -ENOMEM;
phy = mphy->priv;
phy->dev = dev;
phy->mt76 = mphy;
mphy->chainmask = dev->chainmask & ~dev->mphy.chainmask;
mphy->antenna_mask = BIT(hweight8(mphy->chainmask)) - 1;
INIT_DELAYED_WORK(&mphy->mac_work, mt7915_mac_work);
mt7915_eeprom_parse_band_config(phy);
mt7915_init_wiphy(mphy->hw);
memcpy(mphy->macaddr, dev->mt76.eeprom.data + MT_EE_MAC_ADDR2,
ETH_ALEN);
mt76_eeprom_override(mphy);
ret = mt7915_init_tx_queues(phy, MT7915_TXQ_BAND1,
MT7915_TX_RING_SIZE);
if (ret)
goto error;
ret = mt76_register_phy(mphy, true, mt76_rates,
ARRAY_SIZE(mt76_rates));
if (ret)
goto error;
ret = mt7915_thermal_init(phy);
if (ret)
goto error;
return 0;
error:
ieee80211_free_hw(mphy->hw);
return ret;
}
static void mt7915_init_work(struct work_struct *work)
{
struct mt7915_dev *dev = container_of(work, struct mt7915_dev,
init_work);
mt7915_mcu_set_eeprom(dev);
mt7915_mac_init(dev);
mt7915_init_txpower(dev, &dev->mphy.sband_2g.sband);
mt7915_init_txpower(dev, &dev->mphy.sband_5g.sband);
mt7915_txbf_init(dev);
}
static void mt7915_wfsys_reset(struct mt7915_dev *dev)
{
u32 val = MT_TOP_PWR_KEY | MT_TOP_PWR_SW_PWR_ON | MT_TOP_PWR_PWR_ON;
#define MT_MCU_DUMMY_RANDOM GENMASK(15, 0)
#define MT_MCU_DUMMY_DEFAULT GENMASK(31, 16)
mt76_wr(dev, MT_MCU_WFDMA0_DUMMY_CR, MT_MCU_DUMMY_RANDOM);
/* change to software control */
val |= MT_TOP_PWR_SW_RST;
mt76_wr(dev, MT_TOP_PWR_CTRL, val);
/* reset wfsys */
val &= ~MT_TOP_PWR_SW_RST;
mt76_wr(dev, MT_TOP_PWR_CTRL, val);
/* release wfsys then mcu re-excutes romcode */
val |= MT_TOP_PWR_SW_RST;
mt76_wr(dev, MT_TOP_PWR_CTRL, val);
/* switch to hw control */
val &= ~MT_TOP_PWR_SW_RST;
val |= MT_TOP_PWR_HW_CTRL;
mt76_wr(dev, MT_TOP_PWR_CTRL, val);
/* check whether mcu resets to default */
if (!mt76_poll_msec(dev, MT_MCU_WFDMA0_DUMMY_CR, MT_MCU_DUMMY_DEFAULT,
MT_MCU_DUMMY_DEFAULT, 1000)) {
dev_err(dev->mt76.dev, "wifi subsystem reset failure\n");
return;
}
/* wfsys reset won't clear host registers */
mt76_clear(dev, MT_TOP_MISC, MT_TOP_MISC_FW_STATE);
msleep(100);
}
static int mt7915_init_hardware(struct mt7915_dev *dev)
{
int ret, idx;
mt76_wr(dev, MT_INT_SOURCE_CSR, ~0);
INIT_WORK(&dev->init_work, mt7915_init_work);
dev->dbdc_support = !!(mt76_rr(dev, MT_HW_BOUND) & BIT(5));
/* If MCU was already running, it is likely in a bad state */
if (mt76_get_field(dev, MT_TOP_MISC, MT_TOP_MISC_FW_STATE) >
FW_STATE_FW_DOWNLOAD)
mt7915_wfsys_reset(dev);
ret = mt7915_dma_init(dev);
if (ret)
return ret;
set_bit(MT76_STATE_INITIALIZED, &dev->mphy.state);
/*
* force firmware operation mode into normal state,
* which should be set before firmware download stage.
*/
mt76_wr(dev, MT_SWDEF_MODE, MT_SWDEF_NORMAL_MODE);
ret = mt7915_mcu_init(dev);
if (ret) {
/* Reset and try again */
mt7915_wfsys_reset(dev);
ret = mt7915_mcu_init(dev);
if (ret)
return ret;
}
ret = mt7915_eeprom_init(dev);
if (ret < 0)
return ret;
if (dev->flash_mode) {
ret = mt7915_mcu_apply_group_cal(dev);
if (ret)
return ret;
}
/* Beacon and mgmt frames should occupy wcid 0 */
idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7915_WTBL_STA);
if (idx)
return -ENOSPC;
dev->mt76.global_wcid.idx = idx;
dev->mt76.global_wcid.hw_key_idx = -1;
dev->mt76.global_wcid.tx_info |= MT_WCID_TX_INFO_SET;
rcu_assign_pointer(dev->mt76.wcid[idx], &dev->mt76.global_wcid);
return 0;
}
void mt7915_set_stream_vht_txbf_caps(struct mt7915_phy *phy)
{
int nss;
u32 *cap;
if (!phy->mt76->cap.has_5ghz)
return;
nss = hweight8(phy->mt76->chainmask);
cap = &phy->mt76->sband_5g.sband.vht_cap.cap;
*cap |= IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |
IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE |
(3 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT);
*cap &= ~(IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK |
IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE |
IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE);
if (nss < 2)
return;
*cap |= IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE |
IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE |
FIELD_PREP(IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK,
nss - 1);
}
static void
mt7915_set_stream_he_txbf_caps(struct ieee80211_sta_he_cap *he_cap,
int vif, int nss)
{
struct ieee80211_he_cap_elem *elem = &he_cap->he_cap_elem;
struct ieee80211_he_mcs_nss_supp *mcs = &he_cap->he_mcs_nss_supp;
u8 c;
#ifdef CONFIG_MAC80211_MESH
if (vif == NL80211_IFTYPE_MESH_POINT)
return;
#endif
elem->phy_cap_info[3] &= ~IEEE80211_HE_PHY_CAP3_SU_BEAMFORMER;
elem->phy_cap_info[4] &= ~IEEE80211_HE_PHY_CAP4_MU_BEAMFORMER;
c = IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK |
IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_MASK;
elem->phy_cap_info[5] &= ~c;
c = IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMER_FB |
IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMER_FB;
elem->phy_cap_info[6] &= ~c;
elem->phy_cap_info[7] &= ~IEEE80211_HE_PHY_CAP7_MAX_NC_MASK;
c = IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US |
IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO |
IEEE80211_HE_PHY_CAP2_UL_MU_PARTIAL_MU_MIMO;
elem->phy_cap_info[2] |= c;
c = IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE |
IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_4 |
IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_4;
elem->phy_cap_info[4] |= c;
/* do not support NG16 due to spec D4.0 changes subcarrier idx */
c = IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_42_SU |
IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_75_MU;
if (vif == NL80211_IFTYPE_STATION)
c |= IEEE80211_HE_PHY_CAP6_PARTIAL_BANDWIDTH_DL_MUMIMO;
elem->phy_cap_info[6] |= c;
if (nss < 2)
return;
/* the maximum cap is 4 x 3, (Nr, Nc) = (3, 2) */
elem->phy_cap_info[7] |= min_t(int, nss - 1, 2) << 3;
if (vif != NL80211_IFTYPE_AP)
return;
elem->phy_cap_info[3] |= IEEE80211_HE_PHY_CAP3_SU_BEAMFORMER;
elem->phy_cap_info[4] |= IEEE80211_HE_PHY_CAP4_MU_BEAMFORMER;
/* num_snd_dim */
c = (nss - 1) | (max_t(int, le16_to_cpu(mcs->tx_mcs_160), 1) << 3);
elem->phy_cap_info[5] |= c;
c = IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMER_FB |
IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMER_FB;
elem->phy_cap_info[6] |= c;
}
static void
mt7915_gen_ppe_thresh(u8 *he_ppet, int nss)
{
u8 i, ppet_bits, ppet_size, ru_bit_mask = 0x7; /* HE80 */
u8 ppet16_ppet8_ru3_ru0[] = {0x1c, 0xc7, 0x71};
he_ppet[0] = FIELD_PREP(IEEE80211_PPE_THRES_NSS_MASK, nss - 1) |
FIELD_PREP(IEEE80211_PPE_THRES_RU_INDEX_BITMASK_MASK,
ru_bit_mask);
ppet_bits = IEEE80211_PPE_THRES_INFO_PPET_SIZE *
nss * hweight8(ru_bit_mask) * 2;
ppet_size = DIV_ROUND_UP(ppet_bits, 8);
for (i = 0; i < ppet_size - 1; i++)
he_ppet[i + 1] = ppet16_ppet8_ru3_ru0[i % 3];
he_ppet[i + 1] = ppet16_ppet8_ru3_ru0[i % 3] &
(0xff >> (8 - (ppet_bits - 1) % 8));
}
static int
mt7915_init_he_caps(struct mt7915_phy *phy, enum nl80211_band band,
struct ieee80211_sband_iftype_data *data)
{
int i, idx = 0, nss = hweight8(phy->mt76->chainmask);
u16 mcs_map = 0;
for (i = 0; i < 8; i++) {
if (i < nss)
mcs_map |= (IEEE80211_HE_MCS_SUPPORT_0_11 << (i * 2));
else
mcs_map |= (IEEE80211_HE_MCS_NOT_SUPPORTED << (i * 2));
}
for (i = 0; i < NUM_NL80211_IFTYPES; i++) {
struct ieee80211_sta_he_cap *he_cap = &data[idx].he_cap;
struct ieee80211_he_cap_elem *he_cap_elem =
&he_cap->he_cap_elem;
struct ieee80211_he_mcs_nss_supp *he_mcs =
&he_cap->he_mcs_nss_supp;
switch (i) {
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_AP:
#ifdef CONFIG_MAC80211_MESH
case NL80211_IFTYPE_MESH_POINT:
#endif
break;
default:
continue;
}
data[idx].types_mask = BIT(i);
he_cap->has_he = true;
he_cap_elem->mac_cap_info[0] =
IEEE80211_HE_MAC_CAP0_HTC_HE;
he_cap_elem->mac_cap_info[3] =
IEEE80211_HE_MAC_CAP3_OMI_CONTROL |
IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_RESERVED;
he_cap_elem->mac_cap_info[4] =
IEEE80211_HE_MAC_CAP4_AMDSU_IN_AMPDU;
if (band == NL80211_BAND_2GHZ)
he_cap_elem->phy_cap_info[0] =
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G;
else if (band == NL80211_BAND_5GHZ)
he_cap_elem->phy_cap_info[0] =
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G |
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G |
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G;
he_cap_elem->phy_cap_info[1] =
IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD;
he_cap_elem->phy_cap_info[2] =
IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ |
IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ;
switch (i) {
case NL80211_IFTYPE_AP:
he_cap_elem->mac_cap_info[2] |=
IEEE80211_HE_MAC_CAP2_BSR;
he_cap_elem->mac_cap_info[4] |=
IEEE80211_HE_MAC_CAP4_BQR;
he_cap_elem->mac_cap_info[5] |=
IEEE80211_HE_MAC_CAP5_OM_CTRL_UL_MU_DATA_DIS_RX;
he_cap_elem->phy_cap_info[3] |=
IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_QPSK |
IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_QPSK;
he_cap_elem->phy_cap_info[6] |=
IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT;
break;
case NL80211_IFTYPE_STATION:
he_cap_elem->mac_cap_info[1] |=
IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US;
if (band == NL80211_BAND_2GHZ)
he_cap_elem->phy_cap_info[0] |=
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_2G;
else if (band == NL80211_BAND_5GHZ)
he_cap_elem->phy_cap_info[0] |=
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_5G;
he_cap_elem->phy_cap_info[1] |=
IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A |
IEEE80211_HE_PHY_CAP1_HE_LTF_AND_GI_FOR_HE_PPDUS_0_8US;
he_cap_elem->phy_cap_info[3] |=
IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_QPSK |
IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_QPSK;
he_cap_elem->phy_cap_info[6] |=
IEEE80211_HE_PHY_CAP6_TRIG_CQI_FB |
IEEE80211_HE_PHY_CAP6_PARTIAL_BW_EXT_RANGE |
IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT;
he_cap_elem->phy_cap_info[7] |=
IEEE80211_HE_PHY_CAP7_POWER_BOOST_FACTOR_AR |
IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI;
he_cap_elem->phy_cap_info[8] |=
IEEE80211_HE_PHY_CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G |
IEEE80211_HE_PHY_CAP8_20MHZ_IN_160MHZ_HE_PPDU |
IEEE80211_HE_PHY_CAP8_80MHZ_IN_160MHZ_HE_PPDU |
IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_484;
he_cap_elem->phy_cap_info[9] |=
IEEE80211_HE_PHY_CAP9_LONGER_THAN_16_SIGB_OFDM_SYM |
IEEE80211_HE_PHY_CAP9_NON_TRIGGERED_CQI_FEEDBACK |
IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU |
IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU |
IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_COMP_SIGB |
IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB;
break;
}
he_mcs->rx_mcs_80 = cpu_to_le16(mcs_map);
he_mcs->tx_mcs_80 = cpu_to_le16(mcs_map);
he_mcs->rx_mcs_160 = cpu_to_le16(mcs_map);
he_mcs->tx_mcs_160 = cpu_to_le16(mcs_map);
he_mcs->rx_mcs_80p80 = cpu_to_le16(mcs_map);
he_mcs->tx_mcs_80p80 = cpu_to_le16(mcs_map);
mt7915_set_stream_he_txbf_caps(he_cap, i, nss);
memset(he_cap->ppe_thres, 0, sizeof(he_cap->ppe_thres));
if (he_cap_elem->phy_cap_info[6] &
IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT) {
mt7915_gen_ppe_thresh(he_cap->ppe_thres, nss);
} else {
he_cap_elem->phy_cap_info[9] |=
IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_16US;
}
idx++;
}
return idx;
}
void mt7915_set_stream_he_caps(struct mt7915_phy *phy)
{
struct ieee80211_sband_iftype_data *data;
struct ieee80211_supported_band *band;
int n;
if (phy->mt76->cap.has_2ghz) {
data = phy->iftype[NL80211_BAND_2GHZ];
n = mt7915_init_he_caps(phy, NL80211_BAND_2GHZ, data);
band = &phy->mt76->sband_2g.sband;
band->iftype_data = data;
band->n_iftype_data = n;
}
if (phy->mt76->cap.has_5ghz) {
data = phy->iftype[NL80211_BAND_5GHZ];
n = mt7915_init_he_caps(phy, NL80211_BAND_5GHZ, data);
band = &phy->mt76->sband_5g.sband;
band->iftype_data = data;
band->n_iftype_data = n;
}
}
static void mt7915_unregister_ext_phy(struct mt7915_dev *dev)
{
struct mt7915_phy *phy = mt7915_ext_phy(dev);
struct mt76_phy *mphy = dev->mt76.phy2;
if (!phy)
return;
mt7915_unregister_thermal(phy);
mt76_unregister_phy(mphy);
ieee80211_free_hw(mphy->hw);
}
int mt7915_register_device(struct mt7915_dev *dev)
{
struct ieee80211_hw *hw = mt76_hw(dev);
int ret;
dev->phy.dev = dev;
dev->phy.mt76 = &dev->mt76.phy;
dev->mt76.phy.priv = &dev->phy;
INIT_WORK(&dev->rc_work, mt7915_mac_sta_rc_work);
INIT_DELAYED_WORK(&dev->mphy.mac_work, mt7915_mac_work);
INIT_LIST_HEAD(&dev->sta_rc_list);
INIT_LIST_HEAD(&dev->sta_poll_list);
spin_lock_init(&dev->sta_poll_lock);
init_waitqueue_head(&dev->reset_wait);
INIT_WORK(&dev->reset_work, mt7915_mac_reset_work);
ret = mt7915_init_hardware(dev);
if (ret)
return ret;
mt7915_init_wiphy(hw);
if (!dev->dbdc_support)
dev->mphy.sband_5g.sband.vht_cap.cap |=
IEEE80211_VHT_CAP_SHORT_GI_160 |
IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
dev->mphy.hw->wiphy->available_antennas_rx = dev->mphy.chainmask;
dev->mphy.hw->wiphy->available_antennas_tx = dev->mphy.chainmask;
dev->phy.dfs_state = -1;
#ifdef CONFIG_NL80211_TESTMODE
dev->mt76.test_ops = &mt7915_testmode_ops;
#endif
ret = mt76_register_device(&dev->mt76, true, mt76_rates,
ARRAY_SIZE(mt76_rates));
if (ret)
return ret;
ret = mt7915_thermal_init(&dev->phy);
if (ret)
return ret;
ieee80211_queue_work(mt76_hw(dev), &dev->init_work);
ret = mt7915_register_ext_phy(dev);
if (ret)
return ret;
return mt7915_init_debugfs(dev);
}
void mt7915_unregister_device(struct mt7915_dev *dev)
{
mt7915_unregister_ext_phy(dev);
mt7915_unregister_thermal(&dev->phy);
mt76_unregister_device(&dev->mt76);
mt7915_mcu_exit(dev);
mt7915_tx_token_put(dev);
mt7915_dma_cleanup(dev);
tasklet_disable(&dev->irq_tasklet);
mt76_free_device(&dev->mt76);
}