Skip to content

Commit

Permalink
mt76: mt7615: rework rx phy index handling
Browse files Browse the repository at this point in the history
Overwriting the RMAC_CHFREQ register is not reliable enough, as the firmware
could potentially write it again.
Since there is no PHY index indication in the rx info, we need to use another
way:

If both PHYs are using different channels, find the PHY where chfreq matches
the register value.

The only corner case remaining is when both PHYs are using the same channel.
In that case, the per-packet noise value on the primary PHY will have
information belonging to the chains of the secondary PHY from the previous
received packet of that PHY. The secondary PHY will set noise to 0 for extra
chains.

Signed-off-by: Felix Fietkau <nbd@nbd.name>
  • Loading branch information
nbd168 committed Feb 13, 2020
1 parent 1881241 commit fa14e7f
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 50 deletions.
111 changes: 68 additions & 43 deletions mt7615/mac.c
Expand Up @@ -169,36 +169,32 @@ int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb)
struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
struct mt76_phy *mphy = &dev->mt76.phy;
struct mt7615_phy *phy = &dev->phy;
struct mt7615_phy *phy2 = dev->mt76.phy2 ? dev->mt76.phy2->priv : NULL;
struct ieee80211_supported_band *sband;
struct ieee80211_hdr *hdr;
__le32 *rxd = (__le32 *)skb->data;
u32 rxd0 = le32_to_cpu(rxd[0]);
u32 rxd1 = le32_to_cpu(rxd[1]);
u32 rxd2 = le32_to_cpu(rxd[2]);
__le32 rxd12 = rxd[12];
bool unicast, remove_pad, insert_ccmp_hdr = false;
int phy_idx;
int i, idx;
u8 chfreq;

memset(status, 0, sizeof(*status));

chfreq = FIELD_GET(MT_RXD1_NORMAL_CH_FREQ, rxd1);
if (!(chfreq & MT_CHFREQ_VALID))
return -EINVAL;

if (chfreq & MT_CHFREQ_DBDC_IDX) {
mphy = dev->mt76.phy2;
if (!mphy)
return -EINVAL;

phy = mphy->priv;
status->ext_phy = true;
}

if ((chfreq & MT_CHFREQ_SEQ) != phy->chfreq_seq)
return -EINVAL;

if (!test_bit(MT76_STATE_RUNNING, &mphy->state))
return -EINVAL;
if (!phy2)
phy_idx = 0;
else if (phy2->chfreq == phy->chfreq)
phy_idx = -1;
else if (phy->chfreq == chfreq)
phy_idx = 0;
else if (phy2->chfreq == chfreq)
phy_idx = 1;
else
phy_idx = -1;

unicast = (rxd1 & MT_RXD1_NORMAL_ADDR_TYPE) == MT_RXD1_NORMAL_U2M;
idx = FIELD_GET(MT_RXD2_NORMAL_WLAN_IDX, rxd2);
Expand All @@ -214,13 +210,6 @@ int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb)
spin_unlock_bh(&dev->sta_poll_lock);
}

status->freq = mphy->chandef.chan->center_freq;
status->band = mphy->chandef.chan->band;
if (status->band == NL80211_BAND_5GHZ)
sband = &mphy->sband_5g.sband;
else
sband = &mphy->sband_2g.sband;

if (rxd2 & MT_RXD2_NORMAL_FCS_ERR)
status->flag |= RX_FLAG_FAILED_FCS_CRC;

Expand All @@ -234,28 +223,11 @@ int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb)
status->flag |= RX_FLAG_MMIC_STRIPPED | RX_FLAG_MIC_STRIPPED;
}

if (!(rxd2 & (MT_RXD2_NORMAL_NON_AMPDU_SUB |
MT_RXD2_NORMAL_NON_AMPDU))) {
status->flag |= RX_FLAG_AMPDU_DETAILS;

/* all subframes of an A-MPDU have the same timestamp */
if (phy->rx_ampdu_ts != rxd[12]) {
if (!++phy->ampdu_ref)
phy->ampdu_ref++;
}
phy->rx_ampdu_ts = rxd[12];

status->ampdu_ref = phy->ampdu_ref;
}

remove_pad = rxd1 & MT_RXD1_NORMAL_HDR_OFFSET;

if (rxd2 & MT_RXD2_NORMAL_MAX_LEN_ERROR)
return -EINVAL;

if (!sband->channels)
return -EINVAL;

rxd += 4;
if (rxd0 & MT_RXD0_NORMAL_GROUP_4) {
rxd += 4;
Expand Down Expand Up @@ -287,6 +259,59 @@ int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb)
return -EINVAL;
}

if (rxd0 & MT_RXD0_NORMAL_GROUP_3) {
u32 rxdg5 = le32_to_cpu(rxd[5]);

/*
* If both PHYs are on the same channel and we don't have a WCID,
* we need to figure out which PHY this packet was received on.
* On the primary PHY, the noise value for the chains belonging to the
* second PHY will be set to the noise value of the last packet from
* that PHY.
*/
if (phy_idx < 0) {
int first_chain = ffs(phy2->chainmask) - 1;

phy_idx = ((rxdg5 >> (first_chain * 8)) & 0xff) == 0;
}
}

if (phy_idx == 1 && phy2) {
mphy = dev->mt76.phy2;
phy = phy2;
status->ext_phy = true;
}

if (chfreq != phy->chfreq)
return -EINVAL;

status->freq = mphy->chandef.chan->center_freq;
status->band = mphy->chandef.chan->band;
if (status->band == NL80211_BAND_5GHZ)
sband = &mphy->sband_5g.sband;
else
sband = &mphy->sband_2g.sband;

if (!test_bit(MT76_STATE_RUNNING, &mphy->state))
return -EINVAL;

if (!sband->channels)
return -EINVAL;

if (!(rxd2 & (MT_RXD2_NORMAL_NON_AMPDU_SUB |
MT_RXD2_NORMAL_NON_AMPDU))) {
status->flag |= RX_FLAG_AMPDU_DETAILS;

/* all subframes of an A-MPDU have the same timestamp */
if (phy->rx_ampdu_ts != rxd12) {
if (!++phy->ampdu_ref)
phy->ampdu_ref++;
}
phy->rx_ampdu_ts = rxd12;

status->ampdu_ref = phy->ampdu_ref;
}

if (rxd0 & MT_RXD0_NORMAL_GROUP_3) {
u32 rxdg0 = le32_to_cpu(rxd[0]);
u32 rxdg1 = le32_to_cpu(rxd[1]);
Expand Down Expand Up @@ -340,14 +365,14 @@ int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb)

status->enc_flags |= RX_ENC_FLAG_STBC_MASK * stbc;

status->chains = dev->mphy.antenna_mask;
status->chains = mphy->antenna_mask;
status->chain_signal[0] = to_rssi(MT_RXV4_RCPI0, rxdg3);
status->chain_signal[1] = to_rssi(MT_RXV4_RCPI1, rxdg3);
status->chain_signal[2] = to_rssi(MT_RXV4_RCPI2, rxdg3);
status->chain_signal[3] = to_rssi(MT_RXV4_RCPI3, rxdg3);
status->signal = status->chain_signal[0];

for (i = 1; i < hweight8(dev->mphy.antenna_mask); i++) {
for (i = 1; i < hweight8(mphy->antenna_mask); i++) {
if (!(status->chains & BIT(i)))
continue;

Expand Down
5 changes: 5 additions & 0 deletions mt7615/mac.h
Expand Up @@ -103,6 +103,11 @@ enum rx_pkt_type {
#define MT_RXV4_RCPI1 GENMASK(15, 8)
#define MT_RXV4_RCPI0 GENMASK(7, 0)

#define MT_RXV6_NF3 GENMASK(31, 24)
#define MT_RXV6_NF2 GENMASK(23, 16)
#define MT_RXV6_NF1 GENMASK(15, 8)
#define MT_RXV6_NF0 GENMASK(7, 0)

enum tx_header_format {
MT_HDR_FORMAT_802_3,
MT_HDR_FORMAT_CMD,
Expand Down
7 changes: 1 addition & 6 deletions mt7615/main.c
Expand Up @@ -229,26 +229,21 @@ static int mt7615_set_channel(struct mt7615_phy *phy)
mutex_lock(&dev->mt76.mutex);
set_bit(MT76_RESET, &phy->mt76->state);

phy->chfreq_seq = (phy->chfreq_seq + 1) & MT_CHFREQ_SEQ;
phy->dfs_state = -1;
mt76_set_channel(phy->mt76);

ret = mt7615_mcu_set_chan_info(phy, MCU_EXT_CMD_CHANNEL_SWITCH);
if (ret)
goto out;

mt76_wr(dev, MT_CHFREQ(ext_phy),
MT_CHFREQ_VALID |
(ext_phy * MT_CHFREQ_DBDC_IDX) |
phy->chfreq_seq);

mt7615_mac_set_timing(phy);
ret = mt7615_dfs_init_radar_detector(phy);
mt7615_mac_cca_stats_reset(phy);
mt7615_mcu_set_sku_en(phy, true);

mt7615_mac_reset_counters(dev);
phy->noise = 0;
phy->chfreq = mt76_rr(dev, MT_CHFREQ(ext_phy));

out:
clear_bit(MT76_RESET, &phy->mt76->state);
Expand Down
2 changes: 1 addition & 1 deletion mt7615/mt7615.h
Expand Up @@ -134,7 +134,7 @@ struct mt7615_phy {
s16 coverage_class;
u8 slottime;

u8 chfreq_seq;
u8 chfreq;
u8 rdd_state;
int dfs_state;

Expand Down

0 comments on commit fa14e7f

Please sign in to comment.