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

hwio.c (8438B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Low-level I/O functions.
      4 *
      5 * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
      6 * Copyright (c) 2010, ST-Ericsson
      7 */
      8#include <linux/kernel.h>
      9#include <linux/delay.h>
     10#include <linux/slab.h>
     11#include <linux/align.h>
     12
     13#include "hwio.h"
     14#include "wfx.h"
     15#include "bus.h"
     16#include "traces.h"
     17
     18#define WFX_HIF_BUFFER_SIZE 0x2000
     19
     20static int wfx_read32(struct wfx_dev *wdev, int reg, u32 *val)
     21{
     22	int ret;
     23	__le32 *tmp = kmalloc(sizeof(u32), GFP_KERNEL);
     24
     25	*val = ~0; /* Never return undefined value */
     26	if (!tmp)
     27		return -ENOMEM;
     28	ret = wdev->hwbus_ops->copy_from_io(wdev->hwbus_priv, reg, tmp, sizeof(u32));
     29	if (ret >= 0)
     30		*val = le32_to_cpu(*tmp);
     31	kfree(tmp);
     32	if (ret)
     33		dev_err(wdev->dev, "%s: bus communication error: %d\n", __func__, ret);
     34	return ret;
     35}
     36
     37static int wfx_write32(struct wfx_dev *wdev, int reg, u32 val)
     38{
     39	int ret;
     40	__le32 *tmp = kmalloc(sizeof(u32), GFP_KERNEL);
     41
     42	if (!tmp)
     43		return -ENOMEM;
     44	*tmp = cpu_to_le32(val);
     45	ret = wdev->hwbus_ops->copy_to_io(wdev->hwbus_priv, reg, tmp, sizeof(u32));
     46	kfree(tmp);
     47	if (ret)
     48		dev_err(wdev->dev, "%s: bus communication error: %d\n", __func__, ret);
     49	return ret;
     50}
     51
     52static int wfx_read32_locked(struct wfx_dev *wdev, int reg, u32 *val)
     53{
     54	int ret;
     55
     56	wdev->hwbus_ops->lock(wdev->hwbus_priv);
     57	ret = wfx_read32(wdev, reg, val);
     58	_trace_io_read32(reg, *val);
     59	wdev->hwbus_ops->unlock(wdev->hwbus_priv);
     60	return ret;
     61}
     62
     63static int wfx_write32_locked(struct wfx_dev *wdev, int reg, u32 val)
     64{
     65	int ret;
     66
     67	wdev->hwbus_ops->lock(wdev->hwbus_priv);
     68	ret = wfx_write32(wdev, reg, val);
     69	_trace_io_write32(reg, val);
     70	wdev->hwbus_ops->unlock(wdev->hwbus_priv);
     71	return ret;
     72}
     73
     74static int wfx_write32_bits_locked(struct wfx_dev *wdev, int reg, u32 mask, u32 val)
     75{
     76	int ret;
     77	u32 val_r, val_w;
     78
     79	WARN_ON(~mask & val);
     80	val &= mask;
     81	wdev->hwbus_ops->lock(wdev->hwbus_priv);
     82	ret = wfx_read32(wdev, reg, &val_r);
     83	_trace_io_read32(reg, val_r);
     84	if (ret < 0)
     85		goto err;
     86	val_w = (val_r & ~mask) | val;
     87	if (val_w != val_r) {
     88		ret = wfx_write32(wdev, reg, val_w);
     89		_trace_io_write32(reg, val_w);
     90	}
     91err:
     92	wdev->hwbus_ops->unlock(wdev->hwbus_priv);
     93	return ret;
     94}
     95
     96static int wfx_indirect_read(struct wfx_dev *wdev, int reg, u32 addr, void *buf, size_t len)
     97{
     98	int ret;
     99	int i;
    100	u32 cfg;
    101	u32 prefetch;
    102
    103	WARN_ON(len >= WFX_HIF_BUFFER_SIZE);
    104	WARN_ON(reg != WFX_REG_AHB_DPORT && reg != WFX_REG_SRAM_DPORT);
    105
    106	if (reg == WFX_REG_AHB_DPORT)
    107		prefetch = CFG_PREFETCH_AHB;
    108	else if (reg == WFX_REG_SRAM_DPORT)
    109		prefetch = CFG_PREFETCH_SRAM;
    110	else
    111		return -ENODEV;
    112
    113	ret = wfx_write32(wdev, WFX_REG_BASE_ADDR, addr);
    114	if (ret < 0)
    115		goto err;
    116
    117	ret = wfx_read32(wdev, WFX_REG_CONFIG, &cfg);
    118	if (ret < 0)
    119		goto err;
    120
    121	ret = wfx_write32(wdev, WFX_REG_CONFIG, cfg | prefetch);
    122	if (ret < 0)
    123		goto err;
    124
    125	for (i = 0; i < 20; i++) {
    126		ret = wfx_read32(wdev, WFX_REG_CONFIG, &cfg);
    127		if (ret < 0)
    128			goto err;
    129		if (!(cfg & prefetch))
    130			break;
    131		usleep_range(200, 250);
    132	}
    133	if (i == 20) {
    134		ret = -ETIMEDOUT;
    135		goto err;
    136	}
    137
    138	ret = wdev->hwbus_ops->copy_from_io(wdev->hwbus_priv, reg, buf, len);
    139
    140err:
    141	if (ret < 0)
    142		memset(buf, 0xFF, len); /* Never return undefined value */
    143	return ret;
    144}
    145
    146static int wfx_indirect_write(struct wfx_dev *wdev, int reg, u32 addr,
    147			      const void *buf, size_t len)
    148{
    149	int ret;
    150
    151	WARN_ON(len >= WFX_HIF_BUFFER_SIZE);
    152	WARN_ON(reg != WFX_REG_AHB_DPORT && reg != WFX_REG_SRAM_DPORT);
    153	ret = wfx_write32(wdev, WFX_REG_BASE_ADDR, addr);
    154	if (ret < 0)
    155		return ret;
    156
    157	return wdev->hwbus_ops->copy_to_io(wdev->hwbus_priv, reg, buf, len);
    158}
    159
    160static int wfx_indirect_read_locked(struct wfx_dev *wdev, int reg, u32 addr,
    161				    void *buf, size_t len)
    162{
    163	int ret;
    164
    165	wdev->hwbus_ops->lock(wdev->hwbus_priv);
    166	ret = wfx_indirect_read(wdev, reg, addr, buf, len);
    167	_trace_io_ind_read(reg, addr, buf, len);
    168	wdev->hwbus_ops->unlock(wdev->hwbus_priv);
    169	return ret;
    170}
    171
    172static int wfx_indirect_write_locked(struct wfx_dev *wdev, int reg, u32 addr,
    173				     const void *buf, size_t len)
    174{
    175	int ret;
    176
    177	wdev->hwbus_ops->lock(wdev->hwbus_priv);
    178	ret = wfx_indirect_write(wdev, reg, addr, buf, len);
    179	_trace_io_ind_write(reg, addr, buf, len);
    180	wdev->hwbus_ops->unlock(wdev->hwbus_priv);
    181	return ret;
    182}
    183
    184static int wfx_indirect_read32_locked(struct wfx_dev *wdev, int reg, u32 addr, u32 *val)
    185{
    186	int ret;
    187	__le32 *tmp = kmalloc(sizeof(u32), GFP_KERNEL);
    188
    189	if (!tmp)
    190		return -ENOMEM;
    191	wdev->hwbus_ops->lock(wdev->hwbus_priv);
    192	ret = wfx_indirect_read(wdev, reg, addr, tmp, sizeof(u32));
    193	*val = le32_to_cpu(*tmp);
    194	_trace_io_ind_read32(reg, addr, *val);
    195	wdev->hwbus_ops->unlock(wdev->hwbus_priv);
    196	kfree(tmp);
    197	return ret;
    198}
    199
    200static int wfx_indirect_write32_locked(struct wfx_dev *wdev, int reg, u32 addr, u32 val)
    201{
    202	int ret;
    203	__le32 *tmp = kmalloc(sizeof(u32), GFP_KERNEL);
    204
    205	if (!tmp)
    206		return -ENOMEM;
    207	*tmp = cpu_to_le32(val);
    208	wdev->hwbus_ops->lock(wdev->hwbus_priv);
    209	ret = wfx_indirect_write(wdev, reg, addr, tmp, sizeof(u32));
    210	_trace_io_ind_write32(reg, addr, val);
    211	wdev->hwbus_ops->unlock(wdev->hwbus_priv);
    212	kfree(tmp);
    213	return ret;
    214}
    215
    216int wfx_data_read(struct wfx_dev *wdev, void *buf, size_t len)
    217{
    218	int ret;
    219
    220	WARN(!IS_ALIGNED((uintptr_t)buf, 4), "unaligned buffer");
    221	wdev->hwbus_ops->lock(wdev->hwbus_priv);
    222	ret = wdev->hwbus_ops->copy_from_io(wdev->hwbus_priv, WFX_REG_IN_OUT_QUEUE, buf, len);
    223	_trace_io_read(WFX_REG_IN_OUT_QUEUE, buf, len);
    224	wdev->hwbus_ops->unlock(wdev->hwbus_priv);
    225	if (ret)
    226		dev_err(wdev->dev, "%s: bus communication error: %d\n", __func__, ret);
    227	return ret;
    228}
    229
    230int wfx_data_write(struct wfx_dev *wdev, const void *buf, size_t len)
    231{
    232	int ret;
    233
    234	WARN(!IS_ALIGNED((uintptr_t)buf, 4), "unaligned buffer");
    235	wdev->hwbus_ops->lock(wdev->hwbus_priv);
    236	ret = wdev->hwbus_ops->copy_to_io(wdev->hwbus_priv, WFX_REG_IN_OUT_QUEUE, buf, len);
    237	_trace_io_write(WFX_REG_IN_OUT_QUEUE, buf, len);
    238	wdev->hwbus_ops->unlock(wdev->hwbus_priv);
    239	if (ret)
    240		dev_err(wdev->dev, "%s: bus communication error: %d\n", __func__, ret);
    241	return ret;
    242}
    243
    244int wfx_sram_buf_read(struct wfx_dev *wdev, u32 addr, void *buf, size_t len)
    245{
    246	return wfx_indirect_read_locked(wdev, WFX_REG_SRAM_DPORT, addr, buf, len);
    247}
    248
    249int wfx_ahb_buf_read(struct wfx_dev *wdev, u32 addr, void *buf, size_t len)
    250{
    251	return wfx_indirect_read_locked(wdev, WFX_REG_AHB_DPORT, addr, buf, len);
    252}
    253
    254int wfx_sram_buf_write(struct wfx_dev *wdev, u32 addr, const void *buf, size_t len)
    255{
    256	return wfx_indirect_write_locked(wdev, WFX_REG_SRAM_DPORT, addr, buf, len);
    257}
    258
    259int wfx_ahb_buf_write(struct wfx_dev *wdev, u32 addr, const void *buf, size_t len)
    260{
    261	return wfx_indirect_write_locked(wdev, WFX_REG_AHB_DPORT, addr, buf, len);
    262}
    263
    264int wfx_sram_reg_read(struct wfx_dev *wdev, u32 addr, u32 *val)
    265{
    266	return wfx_indirect_read32_locked(wdev, WFX_REG_SRAM_DPORT, addr, val);
    267}
    268
    269int wfx_ahb_reg_read(struct wfx_dev *wdev, u32 addr, u32 *val)
    270{
    271	return wfx_indirect_read32_locked(wdev, WFX_REG_AHB_DPORT, addr, val);
    272}
    273
    274int wfx_sram_reg_write(struct wfx_dev *wdev, u32 addr, u32 val)
    275{
    276	return wfx_indirect_write32_locked(wdev, WFX_REG_SRAM_DPORT, addr, val);
    277}
    278
    279int wfx_ahb_reg_write(struct wfx_dev *wdev, u32 addr, u32 val)
    280{
    281	return wfx_indirect_write32_locked(wdev, WFX_REG_AHB_DPORT, addr, val);
    282}
    283
    284int wfx_config_reg_read(struct wfx_dev *wdev, u32 *val)
    285{
    286	return wfx_read32_locked(wdev, WFX_REG_CONFIG, val);
    287}
    288
    289int wfx_config_reg_write(struct wfx_dev *wdev, u32 val)
    290{
    291	return wfx_write32_locked(wdev, WFX_REG_CONFIG, val);
    292}
    293
    294int wfx_config_reg_write_bits(struct wfx_dev *wdev, u32 mask, u32 val)
    295{
    296	return wfx_write32_bits_locked(wdev, WFX_REG_CONFIG, mask, val);
    297}
    298
    299int wfx_control_reg_read(struct wfx_dev *wdev, u32 *val)
    300{
    301	return wfx_read32_locked(wdev, WFX_REG_CONTROL, val);
    302}
    303
    304int wfx_control_reg_write(struct wfx_dev *wdev, u32 val)
    305{
    306	return wfx_write32_locked(wdev, WFX_REG_CONTROL, val);
    307}
    308
    309int wfx_control_reg_write_bits(struct wfx_dev *wdev, u32 mask, u32 val)
    310{
    311	return wfx_write32_bits_locked(wdev, WFX_REG_CONTROL, mask, val);
    312}
    313
    314int wfx_igpr_reg_read(struct wfx_dev *wdev, int index, u32 *val)
    315{
    316	int ret;
    317
    318	*val = ~0; /* Never return undefined value */
    319	ret = wfx_write32_locked(wdev, WFX_REG_SET_GEN_R_W, IGPR_RW | index << 24);
    320	if (ret)
    321		return ret;
    322	ret = wfx_read32_locked(wdev, WFX_REG_SET_GEN_R_W, val);
    323	if (ret)
    324		return ret;
    325	*val &= IGPR_VALUE;
    326	return ret;
    327}
    328
    329int wfx_igpr_reg_write(struct wfx_dev *wdev, int index, u32 val)
    330{
    331	return wfx_write32_locked(wdev, WFX_REG_SET_GEN_R_W, index << 24 | val);
    332}