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

rave-sp-eeprom.c (9605B)


      1// SPDX-License-Identifier: GPL-2.0+
      2
      3/*
      4 * EEPROM driver for RAVE SP
      5 *
      6 * Copyright (C) 2018 Zodiac Inflight Innovations
      7 *
      8 */
      9#include <linux/kernel.h>
     10#include <linux/mfd/rave-sp.h>
     11#include <linux/module.h>
     12#include <linux/nvmem-provider.h>
     13#include <linux/of_device.h>
     14#include <linux/platform_device.h>
     15#include <linux/sizes.h>
     16
     17/**
     18 * enum rave_sp_eeprom_access_type - Supported types of EEPROM access
     19 *
     20 * @RAVE_SP_EEPROM_WRITE:	EEPROM write
     21 * @RAVE_SP_EEPROM_READ:	EEPROM read
     22 */
     23enum rave_sp_eeprom_access_type {
     24	RAVE_SP_EEPROM_WRITE = 0,
     25	RAVE_SP_EEPROM_READ  = 1,
     26};
     27
     28/**
     29 * enum rave_sp_eeprom_header_size - EEPROM command header sizes
     30 *
     31 * @RAVE_SP_EEPROM_HEADER_SMALL: EEPROM header size for "small" devices (< 8K)
     32 * @RAVE_SP_EEPROM_HEADER_BIG:	 EEPROM header size for "big" devices (> 8K)
     33 */
     34enum rave_sp_eeprom_header_size {
     35	RAVE_SP_EEPROM_HEADER_SMALL = 4U,
     36	RAVE_SP_EEPROM_HEADER_BIG   = 5U,
     37};
     38#define RAVE_SP_EEPROM_HEADER_MAX	RAVE_SP_EEPROM_HEADER_BIG
     39
     40#define	RAVE_SP_EEPROM_PAGE_SIZE	32U
     41
     42/**
     43 * struct rave_sp_eeprom_page - RAVE SP EEPROM page
     44 *
     45 * @type:	Access type (see enum rave_sp_eeprom_access_type)
     46 * @success:	Success flag (Success = 1, Failure = 0)
     47 * @data:	Read data
     48
     49 * Note this structure corresponds to RSP_*_EEPROM payload from RAVE
     50 * SP ICD
     51 */
     52struct rave_sp_eeprom_page {
     53	u8  type;
     54	u8  success;
     55	u8  data[RAVE_SP_EEPROM_PAGE_SIZE];
     56} __packed;
     57
     58/**
     59 * struct rave_sp_eeprom - RAVE SP EEPROM device
     60 *
     61 * @sp:			Pointer to parent RAVE SP device
     62 * @mutex:		Lock protecting access to EEPROM
     63 * @address:		EEPROM device address
     64 * @header_size:	Size of EEPROM command header for this device
     65 * @dev:		Pointer to corresponding struct device used for logging
     66 */
     67struct rave_sp_eeprom {
     68	struct rave_sp *sp;
     69	struct mutex mutex;
     70	u8 address;
     71	unsigned int header_size;
     72	struct device *dev;
     73};
     74
     75/**
     76 * rave_sp_eeprom_io - Low-level part of EEPROM page access
     77 *
     78 * @eeprom:	EEPROM device to write to
     79 * @type:	EEPROM access type (read or write)
     80 * @idx:	number of the EEPROM page
     81 * @page:	Data to write or buffer to store result (via page->data)
     82 *
     83 * This function does all of the low-level work required to perform a
     84 * EEPROM access. This includes formatting correct command payload,
     85 * sending it and checking received results.
     86 *
     87 * Returns zero in case of success or negative error code in
     88 * case of failure.
     89 */
     90static int rave_sp_eeprom_io(struct rave_sp_eeprom *eeprom,
     91			     enum rave_sp_eeprom_access_type type,
     92			     u16 idx,
     93			     struct rave_sp_eeprom_page *page)
     94{
     95	const bool is_write = type == RAVE_SP_EEPROM_WRITE;
     96	const unsigned int data_size = is_write ? sizeof(page->data) : 0;
     97	const unsigned int cmd_size = eeprom->header_size + data_size;
     98	const unsigned int rsp_size =
     99		is_write ? sizeof(*page) - sizeof(page->data) : sizeof(*page);
    100	unsigned int offset = 0;
    101	u8 cmd[RAVE_SP_EEPROM_HEADER_MAX + sizeof(page->data)];
    102	int ret;
    103
    104	if (WARN_ON(cmd_size > sizeof(cmd)))
    105		return -EINVAL;
    106
    107	cmd[offset++] = eeprom->address;
    108	cmd[offset++] = 0;
    109	cmd[offset++] = type;
    110	cmd[offset++] = idx;
    111
    112	/*
    113	 * If there's still room in this command's header it means we
    114	 * are talkin to EEPROM that uses 16-bit page numbers and we
    115	 * have to specify index's MSB in payload as well.
    116	 */
    117	if (offset < eeprom->header_size)
    118		cmd[offset++] = idx >> 8;
    119	/*
    120	 * Copy our data to write to command buffer first. In case of
    121	 * a read data_size should be zero and memcpy would become a
    122	 * no-op
    123	 */
    124	memcpy(&cmd[offset], page->data, data_size);
    125
    126	ret = rave_sp_exec(eeprom->sp, cmd, cmd_size, page, rsp_size);
    127	if (ret)
    128		return ret;
    129
    130	if (page->type != type)
    131		return -EPROTO;
    132
    133	if (!page->success)
    134		return -EIO;
    135
    136	return 0;
    137}
    138
    139/**
    140 * rave_sp_eeprom_page_access - Access single EEPROM page
    141 *
    142 * @eeprom:	EEPROM device to access
    143 * @type:	Access type to perform (read or write)
    144 * @offset:	Offset within EEPROM to access
    145 * @data:	Data buffer
    146 * @data_len:	Size of the data buffer
    147 *
    148 * This function performs a generic access to a single page or a
    149 * portion thereof. Requested access MUST NOT cross the EEPROM page
    150 * boundary.
    151 *
    152 * Returns zero in case of success or negative error code in
    153 * case of failure.
    154 */
    155static int
    156rave_sp_eeprom_page_access(struct rave_sp_eeprom *eeprom,
    157			   enum rave_sp_eeprom_access_type type,
    158			   unsigned int offset, u8 *data,
    159			   size_t data_len)
    160{
    161	const unsigned int page_offset = offset % RAVE_SP_EEPROM_PAGE_SIZE;
    162	const unsigned int page_nr     = offset / RAVE_SP_EEPROM_PAGE_SIZE;
    163	struct rave_sp_eeprom_page page;
    164	int ret;
    165
    166	/*
    167	 * This function will not work if data access we've been asked
    168	 * to do is crossing EEPROM page boundary. Normally this
    169	 * should never happen and getting here would indicate a bug
    170	 * in the code.
    171	 */
    172	if (WARN_ON(data_len > sizeof(page.data) - page_offset))
    173		return -EINVAL;
    174
    175	if (type == RAVE_SP_EEPROM_WRITE) {
    176		/*
    177		 * If doing a partial write we need to do a read first
    178		 * to fill the rest of the page with correct data.
    179		 */
    180		if (data_len < RAVE_SP_EEPROM_PAGE_SIZE) {
    181			ret = rave_sp_eeprom_io(eeprom, RAVE_SP_EEPROM_READ,
    182						page_nr, &page);
    183			if (ret)
    184				return ret;
    185		}
    186
    187		memcpy(&page.data[page_offset], data, data_len);
    188	}
    189
    190	ret = rave_sp_eeprom_io(eeprom, type, page_nr, &page);
    191	if (ret)
    192		return ret;
    193
    194	/*
    195	 * Since we receive the result of the read via 'page.data'
    196	 * buffer we need to copy that to 'data'
    197	 */
    198	if (type == RAVE_SP_EEPROM_READ)
    199		memcpy(data, &page.data[page_offset], data_len);
    200
    201	return 0;
    202}
    203
    204/**
    205 * rave_sp_eeprom_access - Access EEPROM data
    206 *
    207 * @eeprom:	EEPROM device to access
    208 * @type:	Access type to perform (read or write)
    209 * @offset:	Offset within EEPROM to access
    210 * @data:	Data buffer
    211 * @data_len:	Size of the data buffer
    212 *
    213 * This function performs a generic access (either read or write) at
    214 * arbitrary offset (not necessary page aligned) of arbitrary length
    215 * (is not constrained by EEPROM page size).
    216 *
    217 * Returns zero in case of success or negative error code in case of
    218 * failure.
    219 */
    220static int rave_sp_eeprom_access(struct rave_sp_eeprom *eeprom,
    221				 enum rave_sp_eeprom_access_type type,
    222				 unsigned int offset, u8 *data,
    223				 unsigned int data_len)
    224{
    225	unsigned int residue;
    226	unsigned int chunk;
    227	unsigned int head;
    228	int ret;
    229
    230	mutex_lock(&eeprom->mutex);
    231
    232	head    = offset % RAVE_SP_EEPROM_PAGE_SIZE;
    233	residue = data_len;
    234
    235	do {
    236		/*
    237		 * First iteration, if we are doing an access that is
    238		 * not 32-byte aligned, we need to access only data up
    239		 * to a page boundary to avoid corssing it in
    240		 * rave_sp_eeprom_page_access()
    241		 */
    242		if (unlikely(head)) {
    243			chunk = RAVE_SP_EEPROM_PAGE_SIZE - head;
    244			/*
    245			 * This can only happen once per
    246			 * rave_sp_eeprom_access() call, so we set
    247			 * head to zero to process all the other
    248			 * iterations normally.
    249			 */
    250			head  = 0;
    251		} else {
    252			chunk = RAVE_SP_EEPROM_PAGE_SIZE;
    253		}
    254
    255		/*
    256		 * We should never read more that 'residue' bytes
    257		 */
    258		chunk = min(chunk, residue);
    259		ret = rave_sp_eeprom_page_access(eeprom, type, offset,
    260						 data, chunk);
    261		if (ret)
    262			goto out;
    263
    264		residue -= chunk;
    265		offset  += chunk;
    266		data    += chunk;
    267	} while (residue);
    268out:
    269	mutex_unlock(&eeprom->mutex);
    270	return ret;
    271}
    272
    273static int rave_sp_eeprom_reg_read(void *eeprom, unsigned int offset,
    274				   void *val, size_t bytes)
    275{
    276	return rave_sp_eeprom_access(eeprom, RAVE_SP_EEPROM_READ,
    277				     offset, val, bytes);
    278}
    279
    280static int rave_sp_eeprom_reg_write(void *eeprom, unsigned int offset,
    281				    void *val, size_t bytes)
    282{
    283	return rave_sp_eeprom_access(eeprom, RAVE_SP_EEPROM_WRITE,
    284				     offset, val, bytes);
    285}
    286
    287static int rave_sp_eeprom_probe(struct platform_device *pdev)
    288{
    289	struct device *dev = &pdev->dev;
    290	struct rave_sp *sp = dev_get_drvdata(dev->parent);
    291	struct device_node *np = dev->of_node;
    292	struct nvmem_config config = { 0 };
    293	struct rave_sp_eeprom *eeprom;
    294	struct nvmem_device *nvmem;
    295	u32 reg[2], size;
    296
    297	if (of_property_read_u32_array(np, "reg", reg, ARRAY_SIZE(reg))) {
    298		dev_err(dev, "Failed to parse \"reg\" property\n");
    299		return -EINVAL;
    300	}
    301
    302	size = reg[1];
    303	/*
    304	 * Per ICD, we have no more than 2 bytes to specify EEPROM
    305	 * page.
    306	 */
    307	if (size > U16_MAX * RAVE_SP_EEPROM_PAGE_SIZE) {
    308		dev_err(dev, "Specified size is too big\n");
    309		return -EINVAL;
    310	}
    311
    312	eeprom = devm_kzalloc(dev, sizeof(*eeprom), GFP_KERNEL);
    313	if (!eeprom)
    314		return -ENOMEM;
    315
    316	eeprom->address = reg[0];
    317	eeprom->sp      = sp;
    318	eeprom->dev     = dev;
    319
    320	if (size > SZ_8K)
    321		eeprom->header_size = RAVE_SP_EEPROM_HEADER_BIG;
    322	else
    323		eeprom->header_size = RAVE_SP_EEPROM_HEADER_SMALL;
    324
    325	mutex_init(&eeprom->mutex);
    326
    327	config.id		= -1;
    328	of_property_read_string(np, "zii,eeprom-name", &config.name);
    329	config.priv		= eeprom;
    330	config.dev		= dev;
    331	config.size		= size;
    332	config.reg_read		= rave_sp_eeprom_reg_read;
    333	config.reg_write	= rave_sp_eeprom_reg_write;
    334	config.word_size	= 1;
    335	config.stride		= 1;
    336
    337	nvmem = devm_nvmem_register(dev, &config);
    338
    339	return PTR_ERR_OR_ZERO(nvmem);
    340}
    341
    342static const struct of_device_id rave_sp_eeprom_of_match[] = {
    343	{ .compatible = "zii,rave-sp-eeprom" },
    344	{}
    345};
    346MODULE_DEVICE_TABLE(of, rave_sp_eeprom_of_match);
    347
    348static struct platform_driver rave_sp_eeprom_driver = {
    349	.probe = rave_sp_eeprom_probe,
    350	.driver	= {
    351		.name = KBUILD_MODNAME,
    352		.of_match_table = rave_sp_eeprom_of_match,
    353	},
    354};
    355module_platform_driver(rave_sp_eeprom_driver);
    356
    357MODULE_LICENSE("GPL");
    358MODULE_AUTHOR("Andrey Vostrikov <andrey.vostrikov@cogentembedded.com>");
    359MODULE_AUTHOR("Nikita Yushchenko <nikita.yoush@cogentembedded.com>");
    360MODULE_AUTHOR("Andrey Smirnov <andrew.smirnov@gmail.com>");
    361MODULE_DESCRIPTION("RAVE SP EEPROM driver");