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 (7828B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * wl12xx SDIO routines
      4 *
      5 * Copyright (C) 2005 Texas Instruments Incorporated
      6 * Copyright (C) 2008 Google Inc
      7 * Copyright (C) 2009 Bob Copeland (me@bobcopeland.com)
      8 */
      9#include <linux/interrupt.h>
     10#include <linux/module.h>
     11#include <linux/mod_devicetable.h>
     12#include <linux/mmc/sdio_func.h>
     13#include <linux/mmc/sdio_ids.h>
     14#include <linux/platform_device.h>
     15#include <linux/wl12xx.h>
     16#include <linux/irq.h>
     17#include <linux/pm_runtime.h>
     18#include <linux/of.h>
     19#include <linux/of_irq.h>
     20
     21#include "wl1251.h"
     22
     23struct wl1251_sdio {
     24	struct sdio_func *func;
     25	u32 elp_val;
     26};
     27
     28static struct sdio_func *wl_to_func(struct wl1251 *wl)
     29{
     30	struct wl1251_sdio *wl_sdio = wl->if_priv;
     31	return wl_sdio->func;
     32}
     33
     34static void wl1251_sdio_interrupt(struct sdio_func *func)
     35{
     36	struct wl1251 *wl = sdio_get_drvdata(func);
     37
     38	wl1251_debug(DEBUG_IRQ, "IRQ");
     39
     40	/* FIXME should be synchronous for sdio */
     41	ieee80211_queue_work(wl->hw, &wl->irq_work);
     42}
     43
     44static const struct sdio_device_id wl1251_devices[] = {
     45	{ SDIO_DEVICE(SDIO_VENDOR_ID_TI_WL1251, SDIO_DEVICE_ID_TI_WL1251) },
     46	{}
     47};
     48MODULE_DEVICE_TABLE(sdio, wl1251_devices);
     49
     50
     51static void wl1251_sdio_read(struct wl1251 *wl, int addr,
     52			     void *buf, size_t len)
     53{
     54	int ret;
     55	struct sdio_func *func = wl_to_func(wl);
     56
     57	sdio_claim_host(func);
     58	ret = sdio_memcpy_fromio(func, buf, addr, len);
     59	if (ret)
     60		wl1251_error("sdio read failed (%d)", ret);
     61	sdio_release_host(func);
     62}
     63
     64static void wl1251_sdio_write(struct wl1251 *wl, int addr,
     65			      void *buf, size_t len)
     66{
     67	int ret;
     68	struct sdio_func *func = wl_to_func(wl);
     69
     70	sdio_claim_host(func);
     71	ret = sdio_memcpy_toio(func, addr, buf, len);
     72	if (ret)
     73		wl1251_error("sdio write failed (%d)", ret);
     74	sdio_release_host(func);
     75}
     76
     77static void wl1251_sdio_read_elp(struct wl1251 *wl, int addr, u32 *val)
     78{
     79	int ret = 0;
     80	struct wl1251_sdio *wl_sdio = wl->if_priv;
     81	struct sdio_func *func = wl_sdio->func;
     82
     83	/*
     84	 * The hardware only supports RAW (read after write) access for
     85	 * reading, regular sdio_readb won't work here (it interprets
     86	 * the unused bits of CMD52 as write data even if we send read
     87	 * request).
     88	 */
     89	sdio_claim_host(func);
     90	*val = sdio_writeb_readb(func, wl_sdio->elp_val, addr, &ret);
     91	sdio_release_host(func);
     92
     93	if (ret)
     94		wl1251_error("sdio_readb failed (%d)", ret);
     95}
     96
     97static void wl1251_sdio_write_elp(struct wl1251 *wl, int addr, u32 val)
     98{
     99	int ret = 0;
    100	struct wl1251_sdio *wl_sdio = wl->if_priv;
    101	struct sdio_func *func = wl_sdio->func;
    102
    103	sdio_claim_host(func);
    104	sdio_writeb(func, val, addr, &ret);
    105	sdio_release_host(func);
    106
    107	if (ret)
    108		wl1251_error("sdio_writeb failed (%d)", ret);
    109	else
    110		wl_sdio->elp_val = val;
    111}
    112
    113static void wl1251_sdio_reset(struct wl1251 *wl)
    114{
    115}
    116
    117static void wl1251_sdio_enable_irq(struct wl1251 *wl)
    118{
    119	struct sdio_func *func = wl_to_func(wl);
    120
    121	sdio_claim_host(func);
    122	sdio_claim_irq(func, wl1251_sdio_interrupt);
    123	sdio_release_host(func);
    124}
    125
    126static void wl1251_sdio_disable_irq(struct wl1251 *wl)
    127{
    128	struct sdio_func *func = wl_to_func(wl);
    129
    130	sdio_claim_host(func);
    131	sdio_release_irq(func);
    132	sdio_release_host(func);
    133}
    134
    135/* Interrupts when using dedicated WLAN_IRQ pin */
    136static irqreturn_t wl1251_line_irq(int irq, void *cookie)
    137{
    138	struct wl1251 *wl = cookie;
    139
    140	ieee80211_queue_work(wl->hw, &wl->irq_work);
    141
    142	return IRQ_HANDLED;
    143}
    144
    145static void wl1251_enable_line_irq(struct wl1251 *wl)
    146{
    147	return enable_irq(wl->irq);
    148}
    149
    150static void wl1251_disable_line_irq(struct wl1251 *wl)
    151{
    152	return disable_irq(wl->irq);
    153}
    154
    155static int wl1251_sdio_set_power(struct wl1251 *wl, bool enable)
    156{
    157	struct sdio_func *func = wl_to_func(wl);
    158	int ret;
    159
    160	if (enable) {
    161		ret = pm_runtime_get_sync(&func->dev);
    162		if (ret < 0) {
    163			pm_runtime_put_sync(&func->dev);
    164			goto out;
    165		}
    166
    167		sdio_claim_host(func);
    168		sdio_enable_func(func);
    169		sdio_release_host(func);
    170	} else {
    171		sdio_claim_host(func);
    172		sdio_disable_func(func);
    173		sdio_release_host(func);
    174
    175		ret = pm_runtime_put_sync(&func->dev);
    176		if (ret < 0)
    177			goto out;
    178	}
    179
    180out:
    181	return ret;
    182}
    183
    184static struct wl1251_if_operations wl1251_sdio_ops = {
    185	.read = wl1251_sdio_read,
    186	.write = wl1251_sdio_write,
    187	.write_elp = wl1251_sdio_write_elp,
    188	.read_elp = wl1251_sdio_read_elp,
    189	.reset = wl1251_sdio_reset,
    190	.power = wl1251_sdio_set_power,
    191};
    192
    193static int wl1251_sdio_probe(struct sdio_func *func,
    194			     const struct sdio_device_id *id)
    195{
    196	int ret;
    197	struct wl1251 *wl;
    198	struct ieee80211_hw *hw;
    199	struct wl1251_sdio *wl_sdio;
    200	const struct wl1251_platform_data *wl1251_board_data;
    201	struct device_node *np = func->dev.of_node;
    202
    203	hw = wl1251_alloc_hw();
    204	if (IS_ERR(hw))
    205		return PTR_ERR(hw);
    206
    207	wl = hw->priv;
    208
    209	wl_sdio = kzalloc(sizeof(*wl_sdio), GFP_KERNEL);
    210	if (wl_sdio == NULL) {
    211		ret = -ENOMEM;
    212		goto out_free_hw;
    213	}
    214
    215	sdio_claim_host(func);
    216	ret = sdio_enable_func(func);
    217	if (ret)
    218		goto release;
    219
    220	sdio_set_block_size(func, 512);
    221	sdio_release_host(func);
    222
    223	SET_IEEE80211_DEV(hw, &func->dev);
    224	wl_sdio->func = func;
    225	wl->if_priv = wl_sdio;
    226	wl->if_ops = &wl1251_sdio_ops;
    227
    228	wl1251_board_data = wl1251_get_platform_data();
    229	if (!IS_ERR(wl1251_board_data)) {
    230		wl->irq = wl1251_board_data->irq;
    231		wl->use_eeprom = wl1251_board_data->use_eeprom;
    232	} else if (np) {
    233		wl->use_eeprom = of_property_read_bool(np, "ti,wl1251-has-eeprom");
    234		wl->irq = of_irq_get(np, 0);
    235		if (wl->irq == -EPROBE_DEFER) {
    236			ret = -EPROBE_DEFER;
    237			goto disable;
    238		}
    239	}
    240
    241	if (wl->irq) {
    242		irq_set_status_flags(wl->irq, IRQ_NOAUTOEN);
    243		ret = request_irq(wl->irq, wl1251_line_irq, 0, "wl1251", wl);
    244		if (ret < 0) {
    245			wl1251_error("request_irq() failed: %d", ret);
    246			goto disable;
    247		}
    248
    249		irq_set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING);
    250
    251		wl1251_sdio_ops.enable_irq = wl1251_enable_line_irq;
    252		wl1251_sdio_ops.disable_irq = wl1251_disable_line_irq;
    253
    254		wl1251_info("using dedicated interrupt line");
    255	} else {
    256		wl1251_sdio_ops.enable_irq = wl1251_sdio_enable_irq;
    257		wl1251_sdio_ops.disable_irq = wl1251_sdio_disable_irq;
    258
    259		wl1251_info("using SDIO interrupt");
    260	}
    261
    262	ret = wl1251_init_ieee80211(wl);
    263	if (ret)
    264		goto out_free_irq;
    265
    266	sdio_set_drvdata(func, wl);
    267
    268	/* Tell PM core that we don't need the card to be powered now */
    269	pm_runtime_put_noidle(&func->dev);
    270
    271	return ret;
    272
    273out_free_irq:
    274	if (wl->irq)
    275		free_irq(wl->irq, wl);
    276disable:
    277	sdio_claim_host(func);
    278	sdio_disable_func(func);
    279release:
    280	sdio_release_host(func);
    281	kfree(wl_sdio);
    282out_free_hw:
    283	wl1251_free_hw(wl);
    284	return ret;
    285}
    286
    287static void wl1251_sdio_remove(struct sdio_func *func)
    288{
    289	struct wl1251 *wl = sdio_get_drvdata(func);
    290	struct wl1251_sdio *wl_sdio = wl->if_priv;
    291
    292	/* Undo decrement done above in wl1251_probe */
    293	pm_runtime_get_noresume(&func->dev);
    294
    295	if (wl->irq)
    296		free_irq(wl->irq, wl);
    297	wl1251_free_hw(wl);
    298	kfree(wl_sdio);
    299
    300	sdio_claim_host(func);
    301	sdio_release_irq(func);
    302	sdio_disable_func(func);
    303	sdio_release_host(func);
    304}
    305
    306static int wl1251_suspend(struct device *dev)
    307{
    308	/*
    309	 * Tell MMC/SDIO core it's OK to power down the card
    310	 * (if it isn't already), but not to remove it completely.
    311	 */
    312	return 0;
    313}
    314
    315static int wl1251_resume(struct device *dev)
    316{
    317	return 0;
    318}
    319
    320static const struct dev_pm_ops wl1251_sdio_pm_ops = {
    321	.suspend        = wl1251_suspend,
    322	.resume         = wl1251_resume,
    323};
    324
    325static struct sdio_driver wl1251_sdio_driver = {
    326	.name		= "wl1251_sdio",
    327	.id_table	= wl1251_devices,
    328	.probe		= wl1251_sdio_probe,
    329	.remove		= wl1251_sdio_remove,
    330	.drv.pm		= &wl1251_sdio_pm_ops,
    331};
    332
    333static int __init wl1251_sdio_init(void)
    334{
    335	int err;
    336
    337	err = sdio_register_driver(&wl1251_sdio_driver);
    338	if (err)
    339		wl1251_error("failed to register sdio driver: %d", err);
    340	return err;
    341}
    342
    343static void __exit wl1251_sdio_exit(void)
    344{
    345	sdio_unregister_driver(&wl1251_sdio_driver);
    346	wl1251_notice("unloaded");
    347}
    348
    349module_init(wl1251_sdio_init);
    350module_exit(wl1251_sdio_exit);
    351
    352MODULE_LICENSE("GPL");
    353MODULE_AUTHOR("Kalle Valo <kvalo@adurom.com>");