Commit d67a6646 authored by Lorenzo Bianconi's avatar Lorenzo Bianconi Committed by Felix Fietkau
Browse files

mt76: mt7615: add hw dfs pattern detector support



Add hw radar detection support to mt7615 driver in order to
unlock dfs channels on 5GHz band

Signed-off-by: default avatarLorenzo Bianconi <lorenzo@kernel.org>
Signed-off-by: default avatarFelix Fietkau <nbd@nbd.name>
parent 3ea83705
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -76,7 +76,7 @@ void mt7615_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
		mt7615_mac_tx_free(dev, skb);
		break;
	case PKT_TYPE_RX_EVENT:
		mt76_mcu_rx_event(&dev->mt76, skb);
		mt7615_mcu_rx_event(dev, skb);
		break;
	case PKT_TYPE_NORMAL:
		if (!mt7615_mac_fill_rx(dev, skb)) {
+17 −0
Original line number Diff line number Diff line
@@ -163,6 +163,8 @@ static int mt7615_init_debugfs(struct mt7615_dev *dev)
	if (!dir)
		return -ENOMEM;

	debugfs_create_u32("dfs_hw_pattern", 0400, dir, &dev->hw_pattern);

	return 0;
}

@@ -214,8 +216,22 @@ mt7615_regd_notifier(struct wiphy *wiphy,
{
	struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
	struct mt7615_dev *dev = hw->priv;
	struct cfg80211_chan_def *chandef = &dev->mt76.chandef;

	if (request->dfs_region == dev->mt76.region)
		return;

	dev->mt76.region = request->dfs_region;

	if (!(chandef->chan->flags & IEEE80211_CHAN_RADAR))
		return;

	mt7615_dfs_stop_radar_detector(dev);
	if (request->dfs_region == NL80211_DFS_UNSET)
		mt7615_mcu_rdd_cmd(dev, RDD_CAC_END, MT_HW_RDD0,
				   MT_RX_SEL0, 0);
	else
		mt7615_dfs_start_radar_detector(dev);
}

int mt7615_register_device(struct mt7615_dev *dev)
@@ -254,6 +270,7 @@ int mt7615_register_device(struct mt7615_dev *dev)
			IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
	dev->mt76.chainmask = 0x404;
	dev->mt76.antenna_mask = 0xf;
	dev->dfs_state = -1;

	wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
#ifdef CONFIG_MAC80211_MESH
+88 −0
Original line number Diff line number Diff line
@@ -746,3 +746,91 @@ void mt7615_mac_work(struct work_struct *work)
	ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mt76.mac_work,
				     MT7615_WATCHDOG_TIME);
}

int mt7615_dfs_stop_radar_detector(struct mt7615_dev *dev)
{
	struct cfg80211_chan_def *chandef = &dev->mt76.chandef;
	int err;

	err = mt7615_mcu_rdd_cmd(dev, RDD_STOP, MT_HW_RDD0,
				 MT_RX_SEL0, 0);
	if (err < 0)
		return err;

	if (chandef->width == NL80211_CHAN_WIDTH_160 ||
	    chandef->width == NL80211_CHAN_WIDTH_80P80)
		err = mt7615_mcu_rdd_cmd(dev, RDD_STOP, MT_HW_RDD1,
					 MT_RX_SEL0, 0);
	return err;
}

static int mt7615_dfs_start_rdd(struct mt7615_dev *dev, int chain)
{
	int err;

	err = mt7615_mcu_rdd_cmd(dev, RDD_START, chain, MT_RX_SEL0, 0);
	if (err < 0)
		return err;

	return mt7615_mcu_rdd_cmd(dev, RDD_DET_MODE, chain,
				  MT_RX_SEL0, 1);
}

int mt7615_dfs_start_radar_detector(struct mt7615_dev *dev)
{
	struct cfg80211_chan_def *chandef = &dev->mt76.chandef;
	int err;

	/* start CAC */
	err = mt7615_mcu_rdd_cmd(dev, RDD_CAC_START, MT_HW_RDD0,
				 MT_RX_SEL0, 0);
	if (err < 0)
		return err;

	/* TODO: DBDC support */

	err = mt7615_dfs_start_rdd(dev, MT_HW_RDD0);
	if (err < 0)
		return err;

	if (chandef->width == NL80211_CHAN_WIDTH_160 ||
	    chandef->width == NL80211_CHAN_WIDTH_80P80) {
		err = mt7615_dfs_start_rdd(dev, MT_HW_RDD1);
		if (err < 0)
			return err;
	}

	return 0;
}

int mt7615_dfs_init_radar_detector(struct mt7615_dev *dev)
{
	struct cfg80211_chan_def *chandef = &dev->mt76.chandef;
	int err;

	if (dev->mt76.region == NL80211_DFS_UNSET)
		return 0;

	if (test_bit(MT76_SCANNING, &dev->mt76.state))
		return 0;

	if (dev->dfs_state == chandef->chan->dfs_state)
		return 0;

	dev->dfs_state = chandef->chan->dfs_state;

	if (chandef->chan->flags & IEEE80211_CHAN_RADAR) {
		if (chandef->chan->dfs_state != NL80211_DFS_AVAILABLE)
			return mt7615_dfs_start_radar_detector(dev);
		else
			return mt7615_mcu_rdd_cmd(dev, RDD_CAC_END, MT_HW_RDD0,
						  MT_RX_SEL0, 0);
	} else {
		err = mt7615_mcu_rdd_cmd(dev, RDD_NORMAL_START,
					 MT_HW_RDD0, MT_RX_SEL0, 0);
		if (err < 0)
			return err;

		return mt7615_dfs_stop_radar_detector(dev);
	}
}
+6 −0
Original line number Diff line number Diff line
@@ -137,12 +137,18 @@ static int mt7615_set_channel(struct mt7615_dev *dev)
	cancel_delayed_work_sync(&dev->mt76.mac_work);
	set_bit(MT76_RESET, &dev->mt76.state);

	mt7615_dfs_check_channel(dev);

	mt76_set_channel(&dev->mt76);

	ret = mt7615_mcu_set_channel(dev);
	if (ret)
		return ret;

	ret = mt7615_dfs_init_radar_detector(dev);
	if (ret < 0)
		return ret;

	clear_bit(MT76_RESET, &dev->mt76.state);

	mt76_txq_schedule_all(&dev->mt76);
+65 −0
Original line number Diff line number Diff line
@@ -159,6 +159,50 @@ mt7615_mcu_msg_send(struct mt76_dev *mdev, int cmd, const void *data,
	return ret;
}

static void
mt7615_mcu_rx_ext_event(struct mt7615_dev *dev, struct sk_buff *skb)
{
	struct mt7615_mcu_rxd *rxd = (struct mt7615_mcu_rxd *)skb->data;

	switch (rxd->ext_eid) {
	case MCU_EXT_EVENT_RDD_REPORT:
		ieee80211_radar_detected(dev->mt76.hw);
		dev->hw_pattern++;
		break;
	default:
		break;
	}
}

static void
mt7615_mcu_rx_unsolicited_event(struct mt7615_dev *dev, struct sk_buff *skb)
{
	struct mt7615_mcu_rxd *rxd = (struct mt7615_mcu_rxd *)skb->data;

	switch (rxd->eid) {
	case MCU_EVENT_EXT:
		mt7615_mcu_rx_ext_event(dev, skb);
		break;
	default:
		break;
	}
	dev_kfree_skb(skb);
}

void mt7615_mcu_rx_event(struct mt7615_dev *dev, struct sk_buff *skb)
{
	struct mt7615_mcu_rxd *rxd = (struct mt7615_mcu_rxd *)skb->data;

	if (rxd->ext_eid == MCU_EXT_EVENT_THERMAL_PROTECT ||
	    rxd->ext_eid == MCU_EXT_EVENT_FW_LOG_2_HOST ||
	    rxd->ext_eid == MCU_EXT_EVENT_ASSERT_DUMP ||
	    rxd->ext_eid == MCU_EXT_EVENT_PS_SYNC ||
	    !rxd->seq)
		mt7615_mcu_rx_unsolicited_event(dev, skb);
	else
		mt76_mcu_rx_event(&dev->mt76, skb);
}

static int mt7615_mcu_init_download(struct mt7615_dev *dev, u32 addr,
				    u32 len, u32 mode)
{
@@ -1213,6 +1257,27 @@ int mt7615_mcu_set_tx_power(struct mt7615_dev *dev)
	return ret;
}

int mt7615_mcu_rdd_cmd(struct mt7615_dev *dev,
		       enum mt7615_rdd_cmd cmd, u8 index,
		       u8 rx_sel, u8 val)
{
	struct {
		u8 ctrl;
		u8 rdd_idx;
		u8 rdd_rx_sel;
		u8 val;
		u8 rsv[4];
	} req = {
		.ctrl = cmd,
		.rdd_idx = index,
		.rdd_rx_sel = rx_sel,
		.val = val,
	};

	return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_RDD_CTRL,
				   &req, sizeof(req), true);
}

int mt7615_mcu_set_channel(struct mt7615_dev *dev)
{
	struct cfg80211_chan_def *chdef = &dev->mt76.chandef;
Loading