// SPDX-License-Identifier: ISC
/* Copyright (C) 2019 MediaTek Inc.
*
* Author: Roy Luo <royluo@google.com>
* Ryder Lee <ryder.lee@mediatek.com>
* Felix Fietkau <nbd@nbd.name>
* Lorenzo Bianconi <lorenzo@kernel.org>
*/
#include <linux/etherdevice.h>
#include <linux/module.h>
#include "mt7615.h"
#include "mcu.h"
static bool mt7615_dev_running(struct mt7615_dev *dev)
{
struct mt7615_phy *phy;
if (test_bit(MT76_STATE_RUNNING, &dev->mphy.state))
return true;
phy = mt7615_ext_phy(dev);
return phy && test_bit(MT76_STATE_RUNNING, &phy->mt76->state);
}
static void mt7615_free_pending_tx_skbs(struct mt7615_dev *dev,
struct mt7615_sta *msta)
{
int i;
spin_lock_bh(&dev->pm.txq_lock);
for (i = 0; i < IEEE80211_NUM_ACS; i++) {
if (msta && dev->pm.tx_q[i].msta != msta)
continue;
dev_kfree_skb(dev->pm.tx_q[i].skb);
dev->pm.tx_q[i].skb = NULL;
}
spin_unlock_bh(&dev->pm.txq_lock);
}
static int mt7615_start(struct ieee80211_hw *hw)
{
struct mt7615_dev *dev = mt7615_hw_dev(hw);
struct mt7615_phy *phy = mt7615_hw_phy(hw);
bool running;
if (!mt7615_wait_for_mcu_init(dev))
return -EIO;
mt7615_mutex_acquire(dev);
running = mt7615_dev_running(dev);
if (!running) {
mt7615_mcu_set_pm(dev, 0, 0);
mt7615_mcu_set_mac_enable(dev, 0, true);
mt7615_mac_enable_nf(dev, 0);
}
if (phy != &dev->phy) {
mt7615_mcu_set_pm(dev, 1, 0);
mt7615_mcu_set_mac_enable(dev, 1, true);
mt7615_mac_enable_nf(dev, 1);
}
mt7615_mcu_set_channel_domain(phy);
mt7615_mcu_set_chan_info(phy, MCU_EXT_CMD_SET_RX_PATH);
set_bit(MT76_STATE_RUNNING, &phy->mt76->state);
ieee80211_queue_delayed_work(hw, &phy->mac_work,
MT7615_WATCHDOG_TIME);
if (!running)
mt7615_mac_reset_counters(dev);
mt7615_mutex_release(dev);
return 0;
}
static void mt7615_stop(struct ieee80211_hw *hw)
{
struct mt7615_dev *dev = mt7615_hw_dev(hw);
struct mt7615_phy *phy = mt7615_hw_phy(hw);
cancel_delayed_work_sync(&phy->mac_work);
del_timer_sync(&phy->roc_timer);