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

w1_ds2433.c (7201B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 *	w1_ds2433.c - w1 family 23 (DS2433) driver
      4 *
      5 * Copyright (c) 2005 Ben Gardner <bgardner@wabtec.com>
      6 */
      7
      8#include <linux/kernel.h>
      9#include <linux/module.h>
     10#include <linux/moduleparam.h>
     11#include <linux/device.h>
     12#include <linux/types.h>
     13#include <linux/delay.h>
     14#include <linux/slab.h>
     15#ifdef CONFIG_W1_SLAVE_DS2433_CRC
     16#include <linux/crc16.h>
     17
     18#define CRC16_INIT		0
     19#define CRC16_VALID		0xb001
     20
     21#endif
     22
     23#include <linux/w1.h>
     24
     25#define W1_EEPROM_DS2433	0x23
     26
     27#define W1_EEPROM_SIZE		512
     28#define W1_PAGE_COUNT		16
     29#define W1_PAGE_SIZE		32
     30#define W1_PAGE_BITS		5
     31#define W1_PAGE_MASK		0x1F
     32
     33#define W1_F23_TIME		300
     34
     35#define W1_F23_READ_EEPROM	0xF0
     36#define W1_F23_WRITE_SCRATCH	0x0F
     37#define W1_F23_READ_SCRATCH	0xAA
     38#define W1_F23_COPY_SCRATCH	0x55
     39
     40struct w1_f23_data {
     41	u8	memory[W1_EEPROM_SIZE];
     42	u32	validcrc;
     43};
     44
     45/**
     46 * Check the file size bounds and adjusts count as needed.
     47 * This would not be needed if the file size didn't reset to 0 after a write.
     48 */
     49static inline size_t w1_f23_fix_count(loff_t off, size_t count, size_t size)
     50{
     51	if (off > size)
     52		return 0;
     53
     54	if ((off + count) > size)
     55		return (size - off);
     56
     57	return count;
     58}
     59
     60#ifdef CONFIG_W1_SLAVE_DS2433_CRC
     61static int w1_f23_refresh_block(struct w1_slave *sl, struct w1_f23_data *data,
     62				int block)
     63{
     64	u8	wrbuf[3];
     65	int	off = block * W1_PAGE_SIZE;
     66
     67	if (data->validcrc & (1 << block))
     68		return 0;
     69
     70	if (w1_reset_select_slave(sl)) {
     71		data->validcrc = 0;
     72		return -EIO;
     73	}
     74
     75	wrbuf[0] = W1_F23_READ_EEPROM;
     76	wrbuf[1] = off & 0xff;
     77	wrbuf[2] = off >> 8;
     78	w1_write_block(sl->master, wrbuf, 3);
     79	w1_read_block(sl->master, &data->memory[off], W1_PAGE_SIZE);
     80
     81	/* cache the block if the CRC is valid */
     82	if (crc16(CRC16_INIT, &data->memory[off], W1_PAGE_SIZE) == CRC16_VALID)
     83		data->validcrc |= (1 << block);
     84
     85	return 0;
     86}
     87#endif	/* CONFIG_W1_SLAVE_DS2433_CRC */
     88
     89static ssize_t eeprom_read(struct file *filp, struct kobject *kobj,
     90			   struct bin_attribute *bin_attr, char *buf,
     91			   loff_t off, size_t count)
     92{
     93	struct w1_slave *sl = kobj_to_w1_slave(kobj);
     94#ifdef CONFIG_W1_SLAVE_DS2433_CRC
     95	struct w1_f23_data *data = sl->family_data;
     96	int i, min_page, max_page;
     97#else
     98	u8 wrbuf[3];
     99#endif
    100
    101	if ((count = w1_f23_fix_count(off, count, W1_EEPROM_SIZE)) == 0)
    102		return 0;
    103
    104	mutex_lock(&sl->master->bus_mutex);
    105
    106#ifdef CONFIG_W1_SLAVE_DS2433_CRC
    107
    108	min_page = (off >> W1_PAGE_BITS);
    109	max_page = (off + count - 1) >> W1_PAGE_BITS;
    110	for (i = min_page; i <= max_page; i++) {
    111		if (w1_f23_refresh_block(sl, data, i)) {
    112			count = -EIO;
    113			goto out_up;
    114		}
    115	}
    116	memcpy(buf, &data->memory[off], count);
    117
    118#else 	/* CONFIG_W1_SLAVE_DS2433_CRC */
    119
    120	/* read directly from the EEPROM */
    121	if (w1_reset_select_slave(sl)) {
    122		count = -EIO;
    123		goto out_up;
    124	}
    125
    126	wrbuf[0] = W1_F23_READ_EEPROM;
    127	wrbuf[1] = off & 0xff;
    128	wrbuf[2] = off >> 8;
    129	w1_write_block(sl->master, wrbuf, 3);
    130	w1_read_block(sl->master, buf, count);
    131
    132#endif	/* CONFIG_W1_SLAVE_DS2433_CRC */
    133
    134out_up:
    135	mutex_unlock(&sl->master->bus_mutex);
    136
    137	return count;
    138}
    139
    140/**
    141 * Writes to the scratchpad and reads it back for verification.
    142 * Then copies the scratchpad to EEPROM.
    143 * The data must be on one page.
    144 * The master must be locked.
    145 *
    146 * @param sl	The slave structure
    147 * @param addr	Address for the write
    148 * @param len   length must be <= (W1_PAGE_SIZE - (addr & W1_PAGE_MASK))
    149 * @param data	The data to write
    150 * @return	0=Success -1=failure
    151 */
    152static int w1_f23_write(struct w1_slave *sl, int addr, int len, const u8 *data)
    153{
    154#ifdef CONFIG_W1_SLAVE_DS2433_CRC
    155	struct w1_f23_data *f23 = sl->family_data;
    156#endif
    157	u8 wrbuf[4];
    158	u8 rdbuf[W1_PAGE_SIZE + 3];
    159	u8 es = (addr + len - 1) & 0x1f;
    160
    161	/* Write the data to the scratchpad */
    162	if (w1_reset_select_slave(sl))
    163		return -1;
    164
    165	wrbuf[0] = W1_F23_WRITE_SCRATCH;
    166	wrbuf[1] = addr & 0xff;
    167	wrbuf[2] = addr >> 8;
    168
    169	w1_write_block(sl->master, wrbuf, 3);
    170	w1_write_block(sl->master, data, len);
    171
    172	/* Read the scratchpad and verify */
    173	if (w1_reset_select_slave(sl))
    174		return -1;
    175
    176	w1_write_8(sl->master, W1_F23_READ_SCRATCH);
    177	w1_read_block(sl->master, rdbuf, len + 3);
    178
    179	/* Compare what was read against the data written */
    180	if ((rdbuf[0] != wrbuf[1]) || (rdbuf[1] != wrbuf[2]) ||
    181	    (rdbuf[2] != es) || (memcmp(data, &rdbuf[3], len) != 0))
    182		return -1;
    183
    184	/* Copy the scratchpad to EEPROM */
    185	if (w1_reset_select_slave(sl))
    186		return -1;
    187
    188	wrbuf[0] = W1_F23_COPY_SCRATCH;
    189	wrbuf[3] = es;
    190	w1_write_block(sl->master, wrbuf, 4);
    191
    192	/* Sleep for 5 ms to wait for the write to complete */
    193	msleep(5);
    194
    195	/* Reset the bus to wake up the EEPROM (this may not be needed) */
    196	w1_reset_bus(sl->master);
    197#ifdef CONFIG_W1_SLAVE_DS2433_CRC
    198	f23->validcrc &= ~(1 << (addr >> W1_PAGE_BITS));
    199#endif
    200	return 0;
    201}
    202
    203static ssize_t eeprom_write(struct file *filp, struct kobject *kobj,
    204			    struct bin_attribute *bin_attr, char *buf,
    205			    loff_t off, size_t count)
    206{
    207	struct w1_slave *sl = kobj_to_w1_slave(kobj);
    208	int addr, len, idx;
    209
    210	if ((count = w1_f23_fix_count(off, count, W1_EEPROM_SIZE)) == 0)
    211		return 0;
    212
    213#ifdef CONFIG_W1_SLAVE_DS2433_CRC
    214	/* can only write full blocks in cached mode */
    215	if ((off & W1_PAGE_MASK) || (count & W1_PAGE_MASK)) {
    216		dev_err(&sl->dev, "invalid offset/count off=%d cnt=%zd\n",
    217			(int)off, count);
    218		return -EINVAL;
    219	}
    220
    221	/* make sure the block CRCs are valid */
    222	for (idx = 0; idx < count; idx += W1_PAGE_SIZE) {
    223		if (crc16(CRC16_INIT, &buf[idx], W1_PAGE_SIZE) != CRC16_VALID) {
    224			dev_err(&sl->dev, "bad CRC at offset %d\n", (int)off);
    225			return -EINVAL;
    226		}
    227	}
    228#endif	/* CONFIG_W1_SLAVE_DS2433_CRC */
    229
    230	mutex_lock(&sl->master->bus_mutex);
    231
    232	/* Can only write data to one page at a time */
    233	idx = 0;
    234	while (idx < count) {
    235		addr = off + idx;
    236		len = W1_PAGE_SIZE - (addr & W1_PAGE_MASK);
    237		if (len > (count - idx))
    238			len = count - idx;
    239
    240		if (w1_f23_write(sl, addr, len, &buf[idx]) < 0) {
    241			count = -EIO;
    242			goto out_up;
    243		}
    244		idx += len;
    245	}
    246
    247out_up:
    248	mutex_unlock(&sl->master->bus_mutex);
    249
    250	return count;
    251}
    252
    253static BIN_ATTR_RW(eeprom, W1_EEPROM_SIZE);
    254
    255static struct bin_attribute *w1_f23_bin_attributes[] = {
    256	&bin_attr_eeprom,
    257	NULL,
    258};
    259
    260static const struct attribute_group w1_f23_group = {
    261	.bin_attrs = w1_f23_bin_attributes,
    262};
    263
    264static const struct attribute_group *w1_f23_groups[] = {
    265	&w1_f23_group,
    266	NULL,
    267};
    268
    269static int w1_f23_add_slave(struct w1_slave *sl)
    270{
    271#ifdef CONFIG_W1_SLAVE_DS2433_CRC
    272	struct w1_f23_data *data;
    273
    274	data = kzalloc(sizeof(struct w1_f23_data), GFP_KERNEL);
    275	if (!data)
    276		return -ENOMEM;
    277	sl->family_data = data;
    278
    279#endif	/* CONFIG_W1_SLAVE_DS2433_CRC */
    280	return 0;
    281}
    282
    283static void w1_f23_remove_slave(struct w1_slave *sl)
    284{
    285#ifdef CONFIG_W1_SLAVE_DS2433_CRC
    286	kfree(sl->family_data);
    287	sl->family_data = NULL;
    288#endif	/* CONFIG_W1_SLAVE_DS2433_CRC */
    289}
    290
    291static const struct w1_family_ops w1_f23_fops = {
    292	.add_slave      = w1_f23_add_slave,
    293	.remove_slave   = w1_f23_remove_slave,
    294	.groups		= w1_f23_groups,
    295};
    296
    297static struct w1_family w1_family_23 = {
    298	.fid = W1_EEPROM_DS2433,
    299	.fops = &w1_f23_fops,
    300};
    301module_w1_family(w1_family_23);
    302
    303MODULE_AUTHOR("Ben Gardner <bgardner@wabtec.com>");
    304MODULE_DESCRIPTION("w1 family 23 driver for DS2433, 4kb EEPROM");
    305MODULE_LICENSE("GPL");
    306MODULE_ALIAS("w1-family-" __stringify(W1_EEPROM_DS2433));