diff options
Diffstat (limited to 'sys/contrib/dev/mediatek/mt76/mt7921/sdio_mac.c')
| -rw-r--r-- | sys/contrib/dev/mediatek/mt76/mt7921/sdio_mac.c | 58 | 
1 files changed, 58 insertions, 0 deletions
| diff --git a/sys/contrib/dev/mediatek/mt76/mt7921/sdio_mac.c b/sys/contrib/dev/mediatek/mt76/mt7921/sdio_mac.c index 1f77cf71ca70..a9eb6252a904 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7921/sdio_mac.c +++ b/sys/contrib/dev/mediatek/mt76/mt7921/sdio_mac.c @@ -6,6 +6,8 @@  #include "mt7921.h"  #include "../mt76_connac2_mac.h"  #include "../sdio.h" +#include <linux/mmc/host.h> +#include <linux/kallsyms.h>  static void mt7921s_enable_irq(struct mt76_dev *dev)  { @@ -35,6 +37,9 @@ int mt7921s_wfsys_reset(struct mt792x_dev *dev)  	struct mt76_sdio *sdio = &dev->mt76.sdio;  	u32 val, status; +	if (atomic_read(&dev->mt76.bus_hung)) +		return 0; +  	mt7921s_mcu_drv_pmctrl(dev);  	sdio_claim_host(sdio->func); @@ -91,11 +96,64 @@ int mt7921s_init_reset(struct mt792x_dev *dev)  	return 0;  } +static struct mt76_sdio *msdio; +static void mt7921s_card_reset(struct work_struct *work) +{ +	struct mmc_host *sdio_host = msdio->func->card->host; + +	sdio_claim_host(msdio->func); +	sdio_release_irq(msdio->func); +	sdio_release_host(msdio->func); + +	mmc_remove_host(sdio_host); +	msleep(50); +	mmc_add_host(sdio_host); +} + +static DECLARE_WORK(sdio_reset_work, mt7921s_card_reset); +static int mt7921s_check_bus(struct mt76_dev *dev) +{ +	struct mt76_sdio *sdio = &dev->sdio; +	int err; + +	sdio_claim_host(sdio->func); +	sdio_readl(dev->sdio.func, MCR_WHCR, &err); +	sdio_release_host(sdio->func); + +	return err; +} + +static int mt7921s_host_reset(struct mt792x_dev *dev) +{ +	struct mt76_dev *mdev = &dev->mt76; +	int err = -1; + +	if (!atomic_read(&mdev->bus_hung)) +		err = mt7921s_check_bus(&dev->mt76); + +	if (err) { +		atomic_set(&mdev->bus_hung, true); +		msdio = &dev->mt76.sdio; +		dev_err(mdev->dev, "SDIO bus problem detected(%d), resetting card!!\n", err); +		schedule_work(&sdio_reset_work); +		return err; +	} + +	atomic_set(&mdev->bus_hung, false); + +	return 0; +} +  int mt7921s_mac_reset(struct mt792x_dev *dev)  {  	int err;  	mt76_connac_free_pending_tx_skbs(&dev->pm, NULL); + +	mt7921s_host_reset(dev); +	if (atomic_read(&dev->mt76.bus_hung)) +		return 0; +  	mt76_txq_schedule_all(&dev->mphy);  	mt76_worker_disable(&dev->mt76.tx_worker);  	set_bit(MT76_MCU_RESET, &dev->mphy.state); | 
