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

mt76: mt7615: introduce remain_on_channel support



Introduce remain_on_channel support to mt7615 driver if the device is
running offload firmware

Co-developed-by: default avatarSean Wang <sean.wang@mediatek.com>
Signed-off-by: default avatarSean Wang <sean.wang@mediatek.com>
Signed-off-by: default avatarLorenzo Bianconi <lorenzo@kernel.org>
Signed-off-by: default avatarFelix Fietkau <nbd@nbd.name>
parent 50ce4c09
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -290,6 +290,7 @@ enum {
	MT76_STATE_POWER_OFF,
	MT76_STATE_PS,
	MT76_STATE_SUSPEND,
	MT76_STATE_ROC,
};

struct mt76_hw_cap {
+10 −0
Original line number Diff line number Diff line
@@ -139,8 +139,10 @@ void mt7615_check_offload_capability(struct mt7615_dev *dev)
		ieee80211_hw_set(hw, SUPPORTS_PS);
		ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS);

		wiphy->max_remain_on_channel_duration = 5000;
		wiphy->features |= NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR |
				   NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR |
				   WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
				   NL80211_FEATURE_P2P_GO_CTWIN |
				   NL80211_FEATURE_P2P_GO_OPPPS;
	} else {
@@ -149,6 +151,8 @@ void mt7615_check_offload_capability(struct mt7615_dev *dev)
		dev->ops->sched_scan_start = NULL;
		dev->ops->sched_scan_stop = NULL;
		dev->ops->set_rekey_data = NULL;
		dev->ops->remain_on_channel = NULL;
		dev->ops->cancel_remain_on_channel = NULL;

		wiphy->max_sched_scan_plan_interval = 0;
		wiphy->max_sched_scan_ie_len = 0;
@@ -373,6 +377,9 @@ int mt7615_register_ext_phy(struct mt7615_dev *dev)
	skb_queue_head_init(&phy->scan_event_list);

	INIT_WORK(&phy->ps_work, mt7615_ps_work);
	INIT_WORK(&phy->roc_work, mt7615_roc_work);
	timer_setup(&phy->roc_timer, mt7615_roc_timer, 0);
	init_waitqueue_head(&phy->roc_wait);

	mt7615_cap_dbdc_enable(dev);
	mphy = mt76_alloc_phy(&dev->mt76, sizeof(*phy), &mt7615_ops);
@@ -437,9 +444,12 @@ void mt7615_init_device(struct mt7615_dev *dev)
	INIT_LIST_HEAD(&dev->sta_poll_list);
	spin_lock_init(&dev->sta_poll_lock);
	init_waitqueue_head(&dev->reset_wait);
	init_waitqueue_head(&dev->phy.roc_wait);

	INIT_WORK(&dev->reset_work, mt7615_mac_reset_work);
	INIT_WORK(&dev->phy.ps_work, mt7615_ps_work);
	INIT_WORK(&dev->phy.roc_work, mt7615_roc_work);
	timer_setup(&dev->phy.roc_timer, mt7615_roc_timer, 0);

	mt7615_init_wiphy(hw);
	dev->mphy.sband_2g.sband.ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING;
+8 −2
Original line number Diff line number Diff line
@@ -175,7 +175,8 @@ mt7615_get_status_freq_info(struct mt7615_dev *dev, struct mt76_phy *mphy,
			    struct mt76_rx_status *status, u8 chfreq)
{
	if (!test_bit(MT76_HW_SCANNING, &mphy->state) &&
	    !test_bit(MT76_HW_SCHED_SCANNING, &mphy->state)) {
	    !test_bit(MT76_HW_SCHED_SCANNING, &mphy->state) &&
	    !test_bit(MT76_STATE_ROC, &mphy->state)) {
		status->freq = mphy->chandef.chan->center_freq;
		status->band = mphy->chandef.chan->band;
		return;
@@ -1849,8 +1850,13 @@ void mt7615_mac_reset_work(struct work_struct *work)
	set_bit(MT76_MCU_RESET, &dev->mphy.state);
	wake_up(&dev->mt76.mcu.wait);
	cancel_delayed_work_sync(&dev->phy.mac_work);
	if (phy2)
	del_timer_sync(&dev->phy.roc_timer);
	cancel_work_sync(&dev->phy.roc_work);
	if (phy2) {
		cancel_delayed_work_sync(&phy2->mac_work);
		del_timer_sync(&phy2->roc_timer);
		cancel_work_sync(&phy2->roc_work);
	}

	/* lock/unlock all queues to ensure that no tx is pending */
	mt76_txq_schedule_all(&dev->mphy);
+79 −0
Original line number Diff line number Diff line
@@ -72,6 +72,8 @@ static void mt7615_stop(struct ieee80211_hw *hw)

	cancel_delayed_work_sync(&phy->mac_work);
	cancel_work_sync(&phy->ps_work);
	del_timer_sync(&phy->roc_timer);
	cancel_work_sync(&phy->roc_work);

	mutex_lock(&dev->mt76.mutex);

@@ -791,6 +793,37 @@ mt7615_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)
	return 0;
}

static void mt7615_roc_iter(void *priv, u8 *mac,
			    struct ieee80211_vif *vif)
{
	struct mt7615_phy *phy = priv;

	mt7615_mcu_set_roc(phy, vif, NULL, 0);
}

void mt7615_roc_work(struct work_struct *work)
{
	struct mt7615_phy *phy;

	phy = (struct mt7615_phy *)container_of(work, struct mt7615_phy,
						roc_work);

	if (!test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state))
		return;

	ieee80211_iterate_active_interfaces(phy->mt76->hw,
					    IEEE80211_IFACE_ITER_RESUME_ALL,
					    mt7615_roc_iter, phy);
	ieee80211_remain_on_channel_expired(phy->mt76->hw);
}

void mt7615_roc_timer(struct timer_list *timer)
{
	struct mt7615_phy *phy = from_timer(phy, timer, roc_timer);

	ieee80211_queue_work(phy->mt76->hw, &phy->roc_work);
}

void mt7615_scan_work(struct work_struct *work)
{
	struct mt7615_phy *phy;
@@ -864,6 +897,50 @@ mt7615_stop_sched_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
	return mt7615_mcu_sched_scan_enable(mphy->priv, vif, false);
}

static int mt7615_remain_on_channel(struct ieee80211_hw *hw,
				    struct ieee80211_vif *vif,
				    struct ieee80211_channel *chan,
				    int duration,
				    enum ieee80211_roc_type type)
{
	struct mt7615_phy *phy = mt7615_hw_phy(hw);
	int err;

	if (test_and_set_bit(MT76_STATE_ROC, &phy->mt76->state))
		return 0;

	err = mt7615_mcu_set_roc(phy, vif, chan, duration);
	if (err < 0) {
		clear_bit(MT76_STATE_ROC, &phy->mt76->state);
		return err;
	}

	if (!wait_event_timeout(phy->roc_wait, phy->roc_grant, HZ)) {
		mt7615_mcu_set_roc(phy, vif, NULL, 0);
		clear_bit(MT76_STATE_ROC, &phy->mt76->state);

		return -ETIMEDOUT;
	}

	return 0;
}

static int mt7615_cancel_remain_on_channel(struct ieee80211_hw *hw,
					   struct ieee80211_vif *vif)
{
	struct mt7615_phy *phy = mt7615_hw_phy(hw);

	if (!test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state))
		return 0;

	del_timer_sync(&phy->roc_timer);
	cancel_work_sync(&phy->roc_work);

	mt7615_mcu_set_roc(phy, vif, NULL, 0);

	return 0;
}

#ifdef CONFIG_PM
static int mt7615_suspend(struct ieee80211_hw *hw,
			  struct cfg80211_wowlan *wowlan)
@@ -978,6 +1055,8 @@ const struct ieee80211_ops mt7615_ops = {
	.cancel_hw_scan = mt7615_cancel_hw_scan,
	.sched_scan_start = mt7615_start_sched_scan,
	.sched_scan_stop = mt7615_stop_sched_scan,
	.remain_on_channel = mt7615_remain_on_channel,
	.cancel_remain_on_channel = mt7615_cancel_remain_on_channel,
#ifdef CONFIG_PM
	.suspend = mt7615_suspend,
	.resume = mt7615_resume,
+51 −0
Original line number Diff line number Diff line
@@ -359,6 +359,33 @@ mt7615_mcu_scan_event(struct mt7615_dev *dev, struct sk_buff *skb)
				     MT7615_HW_SCAN_TIMEOUT);
}

static void
mt7615_mcu_roc_event(struct mt7615_dev *dev, struct sk_buff *skb)
{
	struct mt7615_roc_tlv *event;
	struct mt7615_phy *phy;
	struct mt76_phy *mphy;
	int duration;

	skb_pull(skb, sizeof(struct mt7615_mcu_rxd));
	event = (struct mt7615_roc_tlv *)skb->data;

	if (event->dbdc_band && dev->mt76.phy2)
		mphy = dev->mt76.phy2;
	else
		mphy = &dev->mt76.phy;

	ieee80211_ready_on_channel(mphy->hw);

	phy = (struct mt7615_phy *)mphy->priv;
	phy->roc_grant = true;
	wake_up(&phy->roc_wait);

	duration = le32_to_cpu(event->max_interval);
	mod_timer(&phy->roc_timer,
		  round_jiffies_up(jiffies + msecs_to_jiffies(duration)));
}

static void
mt7615_mcu_beacon_loss_iter(void *priv, u8 *mac, struct ieee80211_vif *vif)
{
@@ -426,6 +453,9 @@ mt7615_mcu_rx_unsolicited_event(struct mt7615_dev *dev, struct sk_buff *skb)
	case MCU_EVENT_BSS_BEACON_LOSS:
		mt7615_mcu_beacon_loss_event(dev, skb);
		break;
	case MCU_EVENT_ROC:
		mt7615_mcu_roc_event(dev, skb);
		break;
	case MCU_EVENT_SCHED_SCAN_DONE:
	case MCU_EVENT_SCAN_DONE:
		mt7615_mcu_scan_event(dev, skb);
@@ -451,6 +481,7 @@ void mt7615_mcu_rx_event(struct mt7615_dev *dev, struct sk_buff *skb)
	    rxd->eid == MCU_EVENT_SCHED_SCAN_DONE ||
	    rxd->eid == MCU_EVENT_BSS_ABSENCE ||
	    rxd->eid == MCU_EVENT_SCAN_DONE ||
	    rxd->eid == MCU_EVENT_ROC ||
	    !rxd->seq)
		mt7615_mcu_rx_unsolicited_event(dev, skb);
	else
@@ -3601,6 +3632,26 @@ int mt7615_mcu_update_gtk_rekey(struct ieee80211_hw *hw,
}
#endif /* CONFIG_PM */

int mt7615_mcu_set_roc(struct mt7615_phy *phy, struct ieee80211_vif *vif,
		       struct ieee80211_channel *chan, int duration)
{
	struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
	struct mt7615_dev *dev = phy->dev;
	struct mt7615_roc_tlv req = {
		.bss_idx = mvif->idx,
		.active = !chan,
		.max_interval = cpu_to_le32(duration),
		.primary_chan = chan ? chan->hw_value : 0,
		.band = chan ? chan->band : 0,
		.req_type = 2,
	};

	phy->roc_grant = false;

	return __mt76_mcu_send_msg(&dev->mt76, MCU_CMD_SET_ROC, &req,
				   sizeof(req), false);
}

int mt7615_mcu_set_p2p_oppps(struct ieee80211_hw *hw,
			     struct ieee80211_vif *vif)
{
Loading