cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

sdio.c (7740B)


      1// SPDX-License-Identifier: ISC
      2/* Copyright (C) 2021 MediaTek Inc.
      3 *
      4 */
      5
      6#include <linux/kernel.h>
      7#include <linux/iopoll.h>
      8#include <linux/module.h>
      9
     10#include <linux/mmc/host.h>
     11#include <linux/mmc/sdio_ids.h>
     12#include <linux/mmc/sdio_func.h>
     13
     14#include "mt7921.h"
     15#include "../sdio.h"
     16#include "mac.h"
     17#include "mcu.h"
     18
     19static const struct sdio_device_id mt7921s_table[] = {
     20	{ SDIO_DEVICE(SDIO_VENDOR_ID_MEDIATEK, 0x7901) },
     21	{ }	/* Terminating entry */
     22};
     23
     24static void mt7921s_txrx_worker(struct mt76_worker *w)
     25{
     26	struct mt76_sdio *sdio = container_of(w, struct mt76_sdio,
     27					      txrx_worker);
     28	struct mt76_dev *mdev = container_of(sdio, struct mt76_dev, sdio);
     29	struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76);
     30
     31	if (!mt76_connac_pm_ref(&dev->mphy, &dev->pm)) {
     32		queue_work(mdev->wq, &dev->pm.wake_work);
     33		return;
     34	}
     35
     36	mt76s_txrx_worker(sdio);
     37	mt76_connac_pm_unref(&dev->mphy, &dev->pm);
     38}
     39
     40static void mt7921s_unregister_device(struct mt7921_dev *dev)
     41{
     42	struct mt76_connac_pm *pm = &dev->pm;
     43
     44	cancel_work_sync(&dev->init_work);
     45	mt76_unregister_device(&dev->mt76);
     46	cancel_delayed_work_sync(&pm->ps_work);
     47	cancel_work_sync(&pm->wake_work);
     48
     49	mt76s_deinit(&dev->mt76);
     50	mt7921s_wfsys_reset(dev);
     51	mt7921_mcu_exit(dev);
     52
     53	mt76_free_device(&dev->mt76);
     54}
     55
     56static int mt7921s_parse_intr(struct mt76_dev *dev, struct mt76s_intr *intr)
     57{
     58	struct mt76_sdio *sdio = &dev->sdio;
     59	struct mt7921_sdio_intr *irq_data = sdio->intr_data;
     60	int i, err;
     61
     62	sdio_claim_host(sdio->func);
     63	err = sdio_readsb(sdio->func, irq_data, MCR_WHISR, sizeof(*irq_data));
     64	sdio_release_host(sdio->func);
     65
     66	if (err < 0)
     67		return err;
     68
     69	if (irq_data->rx.num[0] > 16 ||
     70	    irq_data->rx.num[1] > 128)
     71		return -EINVAL;
     72
     73	intr->isr = irq_data->isr;
     74	intr->rec_mb = irq_data->rec_mb;
     75	intr->tx.wtqcr = irq_data->tx.wtqcr;
     76	intr->rx.num = irq_data->rx.num;
     77	for (i = 0; i < 2 ; i++) {
     78		if (!i)
     79			intr->rx.len[0] = irq_data->rx.len0;
     80		else
     81			intr->rx.len[1] = irq_data->rx.len1;
     82	}
     83
     84	return 0;
     85}
     86
     87static int mt7921s_probe(struct sdio_func *func,
     88			 const struct sdio_device_id *id)
     89{
     90	static const struct mt76_driver_ops drv_ops = {
     91		.txwi_size = MT_SDIO_TXD_SIZE,
     92		.survey_flags = SURVEY_INFO_TIME_TX |
     93				SURVEY_INFO_TIME_RX |
     94				SURVEY_INFO_TIME_BSS_RX,
     95		.tx_prepare_skb = mt7921_usb_sdio_tx_prepare_skb,
     96		.tx_complete_skb = mt7921_usb_sdio_tx_complete_skb,
     97		.tx_status_data = mt7921_usb_sdio_tx_status_data,
     98		.rx_skb = mt7921_queue_rx_skb,
     99		.sta_ps = mt7921_sta_ps,
    100		.sta_add = mt7921_mac_sta_add,
    101		.sta_assoc = mt7921_mac_sta_assoc,
    102		.sta_remove = mt7921_mac_sta_remove,
    103		.update_survey = mt7921_update_channel,
    104	};
    105	static const struct mt76_bus_ops mt7921s_ops = {
    106		.rr = mt76s_rr,
    107		.rmw = mt76s_rmw,
    108		.wr = mt76s_wr,
    109		.write_copy = mt76s_write_copy,
    110		.read_copy = mt76s_read_copy,
    111		.wr_rp = mt76s_wr_rp,
    112		.rd_rp = mt76s_rd_rp,
    113		.type = MT76_BUS_SDIO,
    114	};
    115	static const struct mt7921_hif_ops mt7921_sdio_ops = {
    116		.init_reset = mt7921s_init_reset,
    117		.reset = mt7921s_mac_reset,
    118		.mcu_init = mt7921s_mcu_init,
    119		.drv_own = mt7921s_mcu_drv_pmctrl,
    120		.fw_own = mt7921s_mcu_fw_pmctrl,
    121	};
    122
    123	struct mt7921_dev *dev;
    124	struct mt76_dev *mdev;
    125	int ret;
    126
    127	mdev = mt76_alloc_device(&func->dev, sizeof(*dev), &mt7921_ops,
    128				 &drv_ops);
    129	if (!mdev)
    130		return -ENOMEM;
    131
    132	dev = container_of(mdev, struct mt7921_dev, mt76);
    133	dev->hif_ops = &mt7921_sdio_ops;
    134
    135	sdio_set_drvdata(func, dev);
    136
    137	ret = mt76s_init(mdev, func, &mt7921s_ops);
    138	if (ret < 0)
    139		goto error;
    140
    141	ret = mt76s_hw_init(mdev, func, MT76_CONNAC2_SDIO);
    142	if (ret)
    143		goto error;
    144
    145	mdev->rev = (mt76_rr(dev, MT_HW_CHIPID) << 16) |
    146		    (mt76_rr(dev, MT_HW_REV) & 0xff);
    147	dev_dbg(mdev->dev, "ASIC revision: %04x\n", mdev->rev);
    148
    149	mdev->sdio.parse_irq = mt7921s_parse_intr;
    150	mdev->sdio.intr_data = devm_kmalloc(mdev->dev,
    151					    sizeof(struct mt7921_sdio_intr),
    152					    GFP_KERNEL);
    153	if (!mdev->sdio.intr_data) {
    154		ret = -ENOMEM;
    155		goto error;
    156	}
    157
    158	ret = mt76s_alloc_rx_queue(mdev, MT_RXQ_MAIN);
    159	if (ret)
    160		goto error;
    161
    162	ret = mt76s_alloc_rx_queue(mdev, MT_RXQ_MCU);
    163	if (ret)
    164		goto error;
    165
    166	ret = mt76s_alloc_tx(mdev);
    167	if (ret)
    168		goto error;
    169
    170	ret = mt76_worker_setup(mt76_hw(dev), &mdev->sdio.txrx_worker,
    171				mt7921s_txrx_worker, "sdio-txrx");
    172	if (ret)
    173		goto error;
    174
    175	sched_set_fifo_low(mdev->sdio.txrx_worker.task);
    176
    177	ret = mt7921_register_device(dev);
    178	if (ret)
    179		goto error;
    180
    181	return 0;
    182
    183error:
    184	mt76s_deinit(&dev->mt76);
    185	mt76_free_device(&dev->mt76);
    186
    187	return ret;
    188}
    189
    190static void mt7921s_remove(struct sdio_func *func)
    191{
    192	struct mt7921_dev *dev = sdio_get_drvdata(func);
    193
    194	mt7921s_unregister_device(dev);
    195}
    196
    197#ifdef CONFIG_PM
    198static int mt7921s_suspend(struct device *__dev)
    199{
    200	struct sdio_func *func = dev_to_sdio_func(__dev);
    201	struct mt7921_dev *dev = sdio_get_drvdata(func);
    202	struct mt76_connac_pm *pm = &dev->pm;
    203	struct mt76_dev *mdev = &dev->mt76;
    204	int err;
    205
    206	pm->suspended = true;
    207	set_bit(MT76_STATE_SUSPEND, &mdev->phy.state);
    208
    209	cancel_delayed_work_sync(&pm->ps_work);
    210	cancel_work_sync(&pm->wake_work);
    211
    212	err = mt7921_mcu_drv_pmctrl(dev);
    213	if (err < 0)
    214		goto restore_suspend;
    215
    216	/* always enable deep sleep during suspend to reduce
    217	 * power consumption
    218	 */
    219	mt76_connac_mcu_set_deep_sleep(mdev, true);
    220
    221	mt76_txq_schedule_all(&dev->mphy);
    222	mt76_worker_disable(&mdev->tx_worker);
    223	mt76_worker_disable(&mdev->sdio.status_worker);
    224	cancel_work_sync(&mdev->sdio.stat_work);
    225	clear_bit(MT76_READING_STATS, &dev->mphy.state);
    226	mt76_tx_status_check(mdev, true);
    227
    228	mt76_worker_schedule(&mdev->sdio.txrx_worker);
    229	wait_event_timeout(dev->mt76.sdio.wait,
    230			   mt76s_txqs_empty(&dev->mt76), 5 * HZ);
    231
    232	/* It is supposed that SDIO bus is idle at the point */
    233	err = mt76_connac_mcu_set_hif_suspend(mdev, true);
    234	if (err)
    235		goto restore_worker;
    236
    237	mt76_worker_disable(&mdev->sdio.txrx_worker);
    238	mt76_worker_disable(&mdev->sdio.net_worker);
    239
    240	err = mt7921_mcu_fw_pmctrl(dev);
    241	if (err)
    242		goto restore_txrx_worker;
    243
    244	sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
    245
    246	return 0;
    247
    248restore_txrx_worker:
    249	mt76_worker_enable(&mdev->sdio.net_worker);
    250	mt76_worker_enable(&mdev->sdio.txrx_worker);
    251	mt76_connac_mcu_set_hif_suspend(mdev, false);
    252
    253restore_worker:
    254	mt76_worker_enable(&mdev->tx_worker);
    255	mt76_worker_enable(&mdev->sdio.status_worker);
    256
    257	if (!pm->ds_enable)
    258		mt76_connac_mcu_set_deep_sleep(mdev, false);
    259
    260restore_suspend:
    261	clear_bit(MT76_STATE_SUSPEND, &mdev->phy.state);
    262	pm->suspended = false;
    263
    264	return err;
    265}
    266
    267static int mt7921s_resume(struct device *__dev)
    268{
    269	struct sdio_func *func = dev_to_sdio_func(__dev);
    270	struct mt7921_dev *dev = sdio_get_drvdata(func);
    271	struct mt76_connac_pm *pm = &dev->pm;
    272	struct mt76_dev *mdev = &dev->mt76;
    273	int err;
    274
    275	clear_bit(MT76_STATE_SUSPEND, &mdev->phy.state);
    276
    277	err = mt7921_mcu_drv_pmctrl(dev);
    278	if (err < 0)
    279		return err;
    280
    281	mt76_worker_enable(&mdev->tx_worker);
    282	mt76_worker_enable(&mdev->sdio.txrx_worker);
    283	mt76_worker_enable(&mdev->sdio.status_worker);
    284	mt76_worker_enable(&mdev->sdio.net_worker);
    285
    286	/* restore previous ds setting */
    287	if (!pm->ds_enable)
    288		mt76_connac_mcu_set_deep_sleep(mdev, false);
    289
    290	err = mt76_connac_mcu_set_hif_suspend(mdev, false);
    291	if (err)
    292		return err;
    293
    294	pm->suspended = false;
    295
    296	return err;
    297}
    298
    299static const struct dev_pm_ops mt7921s_pm_ops = {
    300	.suspend = mt7921s_suspend,
    301	.resume = mt7921s_resume,
    302};
    303#endif
    304
    305MODULE_DEVICE_TABLE(sdio, mt7921s_table);
    306MODULE_FIRMWARE(MT7921_FIRMWARE_WM);
    307MODULE_FIRMWARE(MT7921_ROM_PATCH);
    308
    309static struct sdio_driver mt7921s_driver = {
    310	.name		= KBUILD_MODNAME,
    311	.probe		= mt7921s_probe,
    312	.remove		= mt7921s_remove,
    313	.id_table	= mt7921s_table,
    314#ifdef CONFIG_PM
    315	.drv = {
    316		.pm = &mt7921s_pm_ops,
    317	}
    318#endif
    319};
    320module_sdio_driver(mt7921s_driver);
    321MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>");
    322MODULE_LICENSE("Dual BSD/GPL");