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_ds2408.c (9305B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 *	w1_ds2408.c - w1 family 29 (DS2408) driver
      4 *
      5 * Copyright (c) 2010 Jean-Francois Dagenais <dagenaisj@sonatest.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
     16#include <linux/w1.h>
     17
     18#define W1_FAMILY_DS2408	0x29
     19
     20#define W1_F29_RETRIES		3
     21
     22#define W1_F29_REG_LOGIG_STATE             0x88 /* R */
     23#define W1_F29_REG_OUTPUT_LATCH_STATE      0x89 /* R */
     24#define W1_F29_REG_ACTIVITY_LATCH_STATE    0x8A /* R */
     25#define W1_F29_REG_COND_SEARCH_SELECT_MASK 0x8B /* RW */
     26#define W1_F29_REG_COND_SEARCH_POL_SELECT  0x8C /* RW */
     27#define W1_F29_REG_CONTROL_AND_STATUS      0x8D /* RW */
     28
     29#define W1_F29_FUNC_READ_PIO_REGS          0xF0
     30#define W1_F29_FUNC_CHANN_ACCESS_READ      0xF5
     31#define W1_F29_FUNC_CHANN_ACCESS_WRITE     0x5A
     32/* also used to write the control/status reg (0x8D): */
     33#define W1_F29_FUNC_WRITE_COND_SEARCH_REG  0xCC
     34#define W1_F29_FUNC_RESET_ACTIVITY_LATCHES 0xC3
     35
     36#define W1_F29_SUCCESS_CONFIRM_BYTE        0xAA
     37
     38static int _read_reg(struct w1_slave *sl, u8 address, unsigned char* buf)
     39{
     40	u8 wrbuf[3];
     41	dev_dbg(&sl->dev,
     42			"Reading with slave: %p, reg addr: %0#4x, buff addr: %p",
     43			sl, (unsigned int)address, buf);
     44
     45	if (!buf)
     46		return -EINVAL;
     47
     48	mutex_lock(&sl->master->bus_mutex);
     49	dev_dbg(&sl->dev, "mutex locked");
     50
     51	if (w1_reset_select_slave(sl)) {
     52		mutex_unlock(&sl->master->bus_mutex);
     53		return -EIO;
     54	}
     55
     56	wrbuf[0] = W1_F29_FUNC_READ_PIO_REGS;
     57	wrbuf[1] = address;
     58	wrbuf[2] = 0;
     59	w1_write_block(sl->master, wrbuf, 3);
     60	*buf = w1_read_8(sl->master);
     61
     62	mutex_unlock(&sl->master->bus_mutex);
     63	dev_dbg(&sl->dev, "mutex unlocked");
     64	return 1;
     65}
     66
     67static ssize_t state_read(struct file *filp, struct kobject *kobj,
     68			  struct bin_attribute *bin_attr, char *buf, loff_t off,
     69			  size_t count)
     70{
     71	dev_dbg(&kobj_to_w1_slave(kobj)->dev,
     72		"Reading %s kobj: %p, off: %0#10x, count: %zu, buff addr: %p",
     73		bin_attr->attr.name, kobj, (unsigned int)off, count, buf);
     74	if (count != 1 || off != 0)
     75		return -EFAULT;
     76	return _read_reg(kobj_to_w1_slave(kobj), W1_F29_REG_LOGIG_STATE, buf);
     77}
     78
     79static ssize_t output_read(struct file *filp, struct kobject *kobj,
     80			   struct bin_attribute *bin_attr, char *buf,
     81			   loff_t off, size_t count)
     82{
     83	dev_dbg(&kobj_to_w1_slave(kobj)->dev,
     84		"Reading %s kobj: %p, off: %0#10x, count: %zu, buff addr: %p",
     85		bin_attr->attr.name, kobj, (unsigned int)off, count, buf);
     86	if (count != 1 || off != 0)
     87		return -EFAULT;
     88	return _read_reg(kobj_to_w1_slave(kobj),
     89					 W1_F29_REG_OUTPUT_LATCH_STATE, buf);
     90}
     91
     92static ssize_t activity_read(struct file *filp, struct kobject *kobj,
     93			     struct bin_attribute *bin_attr, char *buf,
     94			     loff_t off, size_t count)
     95{
     96	dev_dbg(&kobj_to_w1_slave(kobj)->dev,
     97		"Reading %s kobj: %p, off: %0#10x, count: %zu, buff addr: %p",
     98		bin_attr->attr.name, kobj, (unsigned int)off, count, buf);
     99	if (count != 1 || off != 0)
    100		return -EFAULT;
    101	return _read_reg(kobj_to_w1_slave(kobj),
    102					 W1_F29_REG_ACTIVITY_LATCH_STATE, buf);
    103}
    104
    105static ssize_t cond_search_mask_read(struct file *filp, struct kobject *kobj,
    106				     struct bin_attribute *bin_attr, char *buf,
    107				     loff_t off, size_t count)
    108{
    109	dev_dbg(&kobj_to_w1_slave(kobj)->dev,
    110		"Reading %s kobj: %p, off: %0#10x, count: %zu, buff addr: %p",
    111		bin_attr->attr.name, kobj, (unsigned int)off, count, buf);
    112	if (count != 1 || off != 0)
    113		return -EFAULT;
    114	return _read_reg(kobj_to_w1_slave(kobj),
    115		W1_F29_REG_COND_SEARCH_SELECT_MASK, buf);
    116}
    117
    118static ssize_t cond_search_polarity_read(struct file *filp,
    119					 struct kobject *kobj,
    120					 struct bin_attribute *bin_attr,
    121					 char *buf, loff_t off, size_t count)
    122{
    123	if (count != 1 || off != 0)
    124		return -EFAULT;
    125	return _read_reg(kobj_to_w1_slave(kobj),
    126		W1_F29_REG_COND_SEARCH_POL_SELECT, buf);
    127}
    128
    129static ssize_t status_control_read(struct file *filp, struct kobject *kobj,
    130				   struct bin_attribute *bin_attr, char *buf,
    131				   loff_t off, size_t count)
    132{
    133	if (count != 1 || off != 0)
    134		return -EFAULT;
    135	return _read_reg(kobj_to_w1_slave(kobj),
    136		W1_F29_REG_CONTROL_AND_STATUS, buf);
    137}
    138
    139#ifdef CONFIG_W1_SLAVE_DS2408_READBACK
    140static bool optional_read_back_valid(struct w1_slave *sl, u8 expected)
    141{
    142	u8 w1_buf[3];
    143
    144	if (w1_reset_resume_command(sl->master))
    145		return false;
    146
    147	w1_buf[0] = W1_F29_FUNC_READ_PIO_REGS;
    148	w1_buf[1] = W1_F29_REG_OUTPUT_LATCH_STATE;
    149	w1_buf[2] = 0;
    150
    151	w1_write_block(sl->master, w1_buf, 3);
    152
    153	return (w1_read_8(sl->master) == expected);
    154}
    155#else
    156static bool optional_read_back_valid(struct w1_slave *sl, u8 expected)
    157{
    158	return true;
    159}
    160#endif
    161
    162static ssize_t output_write(struct file *filp, struct kobject *kobj,
    163			    struct bin_attribute *bin_attr, char *buf,
    164			    loff_t off, size_t count)
    165{
    166	struct w1_slave *sl = kobj_to_w1_slave(kobj);
    167	u8 w1_buf[3];
    168	unsigned int retries = W1_F29_RETRIES;
    169	ssize_t bytes_written = -EIO;
    170
    171	if (count != 1 || off != 0)
    172		return -EFAULT;
    173
    174	dev_dbg(&sl->dev, "locking mutex for write_output");
    175	mutex_lock(&sl->master->bus_mutex);
    176	dev_dbg(&sl->dev, "mutex locked");
    177
    178	if (w1_reset_select_slave(sl))
    179		goto out;
    180
    181	do {
    182		w1_buf[0] = W1_F29_FUNC_CHANN_ACCESS_WRITE;
    183		w1_buf[1] = *buf;
    184		w1_buf[2] = ~(*buf);
    185
    186		w1_write_block(sl->master, w1_buf, 3);
    187
    188		if (w1_read_8(sl->master) == W1_F29_SUCCESS_CONFIRM_BYTE &&
    189		    optional_read_back_valid(sl, *buf)) {
    190			bytes_written = 1;
    191			goto out;
    192		}
    193
    194		if (w1_reset_resume_command(sl->master))
    195			goto out; /* unrecoverable error */
    196		/* try again, the slave is ready for a command */
    197	} while (--retries);
    198
    199out:
    200	mutex_unlock(&sl->master->bus_mutex);
    201
    202	dev_dbg(&sl->dev, "%s, mutex unlocked retries:%d\n",
    203		(bytes_written > 0) ? "succeeded" : "error", retries);
    204
    205	return bytes_written;
    206}
    207
    208
    209/**
    210 * Writing to the activity file resets the activity latches.
    211 */
    212static ssize_t activity_write(struct file *filp, struct kobject *kobj,
    213			      struct bin_attribute *bin_attr, char *buf,
    214			      loff_t off, size_t count)
    215{
    216	struct w1_slave *sl = kobj_to_w1_slave(kobj);
    217	unsigned int retries = W1_F29_RETRIES;
    218
    219	if (count != 1 || off != 0)
    220		return -EFAULT;
    221
    222	mutex_lock(&sl->master->bus_mutex);
    223
    224	if (w1_reset_select_slave(sl))
    225		goto error;
    226
    227	while (retries--) {
    228		w1_write_8(sl->master, W1_F29_FUNC_RESET_ACTIVITY_LATCHES);
    229		if (w1_read_8(sl->master) == W1_F29_SUCCESS_CONFIRM_BYTE) {
    230			mutex_unlock(&sl->master->bus_mutex);
    231			return 1;
    232		}
    233		if (w1_reset_resume_command(sl->master))
    234			goto error;
    235	}
    236
    237error:
    238	mutex_unlock(&sl->master->bus_mutex);
    239	return -EIO;
    240}
    241
    242static ssize_t status_control_write(struct file *filp, struct kobject *kobj,
    243				    struct bin_attribute *bin_attr, char *buf,
    244				    loff_t off, size_t count)
    245{
    246	struct w1_slave *sl = kobj_to_w1_slave(kobj);
    247	u8 w1_buf[4];
    248	unsigned int retries = W1_F29_RETRIES;
    249
    250	if (count != 1 || off != 0)
    251		return -EFAULT;
    252
    253	mutex_lock(&sl->master->bus_mutex);
    254
    255	if (w1_reset_select_slave(sl))
    256		goto error;
    257
    258	while (retries--) {
    259		w1_buf[0] = W1_F29_FUNC_WRITE_COND_SEARCH_REG;
    260		w1_buf[1] = W1_F29_REG_CONTROL_AND_STATUS;
    261		w1_buf[2] = 0;
    262		w1_buf[3] = *buf;
    263
    264		w1_write_block(sl->master, w1_buf, 4);
    265		if (w1_reset_resume_command(sl->master))
    266			goto error;
    267
    268		w1_buf[0] = W1_F29_FUNC_READ_PIO_REGS;
    269		w1_buf[1] = W1_F29_REG_CONTROL_AND_STATUS;
    270		w1_buf[2] = 0;
    271
    272		w1_write_block(sl->master, w1_buf, 3);
    273		if (w1_read_8(sl->master) == *buf) {
    274			/* success! */
    275			mutex_unlock(&sl->master->bus_mutex);
    276			return 1;
    277		}
    278	}
    279error:
    280	mutex_unlock(&sl->master->bus_mutex);
    281
    282	return -EIO;
    283}
    284
    285/*
    286 * This is a special sequence we must do to ensure the P0 output is not stuck
    287 * in test mode. This is described in rev 2 of the ds2408's datasheet
    288 * (http://datasheets.maximintegrated.com/en/ds/DS2408.pdf) under
    289 * "APPLICATION INFORMATION/Power-up timing".
    290 */
    291static int w1_f29_disable_test_mode(struct w1_slave *sl)
    292{
    293	int res;
    294	u8 magic[10] = {0x96, };
    295	u64 rn = le64_to_cpu(*((u64*)&sl->reg_num));
    296
    297	memcpy(&magic[1], &rn, 8);
    298	magic[9] = 0x3C;
    299
    300	mutex_lock(&sl->master->bus_mutex);
    301
    302	res = w1_reset_bus(sl->master);
    303	if (res)
    304		goto out;
    305	w1_write_block(sl->master, magic, ARRAY_SIZE(magic));
    306
    307	res = w1_reset_bus(sl->master);
    308out:
    309	mutex_unlock(&sl->master->bus_mutex);
    310	return res;
    311}
    312
    313static BIN_ATTR_RO(state, 1);
    314static BIN_ATTR_RW(output, 1);
    315static BIN_ATTR_RW(activity, 1);
    316static BIN_ATTR_RO(cond_search_mask, 1);
    317static BIN_ATTR_RO(cond_search_polarity, 1);
    318static BIN_ATTR_RW(status_control, 1);
    319
    320static struct bin_attribute *w1_f29_bin_attrs[] = {
    321	&bin_attr_state,
    322	&bin_attr_output,
    323	&bin_attr_activity,
    324	&bin_attr_cond_search_mask,
    325	&bin_attr_cond_search_polarity,
    326	&bin_attr_status_control,
    327	NULL,
    328};
    329
    330static const struct attribute_group w1_f29_group = {
    331	.bin_attrs = w1_f29_bin_attrs,
    332};
    333
    334static const struct attribute_group *w1_f29_groups[] = {
    335	&w1_f29_group,
    336	NULL,
    337};
    338
    339static const struct w1_family_ops w1_f29_fops = {
    340	.add_slave      = w1_f29_disable_test_mode,
    341	.groups		= w1_f29_groups,
    342};
    343
    344static struct w1_family w1_family_29 = {
    345	.fid = W1_FAMILY_DS2408,
    346	.fops = &w1_f29_fops,
    347};
    348module_w1_family(w1_family_29);
    349
    350MODULE_AUTHOR("Jean-Francois Dagenais <dagenaisj@sonatest.com>");
    351MODULE_DESCRIPTION("w1 family 29 driver for DS2408 8 Pin IO");
    352MODULE_LICENSE("GPL");
    353MODULE_ALIAS("w1-family-" __stringify(W1_FAMILY_DS2408));