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

sysfs_slave_dpn.c (7389B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2// Copyright(c) 2015-2020 Intel Corporation.
      3
      4#include <linux/device.h>
      5#include <linux/mod_devicetable.h>
      6#include <linux/slab.h>
      7#include <linux/sysfs.h>
      8#include <linux/soundwire/sdw.h>
      9#include <linux/soundwire/sdw_type.h>
     10#include "bus.h"
     11#include "sysfs_local.h"
     12
     13struct dpn_attribute {
     14	struct device_attribute	dev_attr;
     15	int N;
     16	int dir;
     17	const char *format_string;
     18};
     19
     20/*
     21 * Since we can't use ARRAY_SIZE, hard-code number of dpN attributes.
     22 * This needs to be updated when adding new attributes - an error will be
     23 * flagged on a mismatch.
     24 */
     25#define SDW_DPN_ATTRIBUTES 15
     26
     27#define sdw_dpn_attribute_alloc(field)					\
     28static int field##_attribute_alloc(struct device *dev,			\
     29				struct attribute **res,			\
     30				int N, int dir,				\
     31				const char *format_string)		\
     32{									\
     33	struct dpn_attribute *dpn_attr;					\
     34									\
     35	dpn_attr = devm_kzalloc(dev, sizeof(*dpn_attr), GFP_KERNEL);	\
     36	if (!dpn_attr)							\
     37		return -ENOMEM;						\
     38	dpn_attr->N = N;						\
     39	dpn_attr->dir = dir;						\
     40	sysfs_attr_init(&dpn_attr->dev_attr.attr);			\
     41	dpn_attr->format_string = format_string;			\
     42	dpn_attr->dev_attr.attr.name = __stringify(field);		\
     43	dpn_attr->dev_attr.attr.mode = 0444;				\
     44	dpn_attr->dev_attr.show = field##_show;				\
     45									\
     46	*res = &dpn_attr->dev_attr.attr;				\
     47									\
     48	return 0;							\
     49}
     50
     51#define sdw_dpn_attr(field)						\
     52									\
     53static ssize_t field##_dpn_show(struct sdw_slave *slave,		\
     54				int N,					\
     55				int dir,				\
     56				const char *format_string,		\
     57				char *buf)				\
     58{									\
     59	struct sdw_dpn_prop *dpn;					\
     60	unsigned long mask;						\
     61	int bit;							\
     62	int i;								\
     63									\
     64	if (dir) {							\
     65		dpn = slave->prop.src_dpn_prop;				\
     66		mask = slave->prop.source_ports;			\
     67	} else {							\
     68		dpn = slave->prop.sink_dpn_prop;			\
     69		mask = slave->prop.sink_ports;				\
     70	}								\
     71									\
     72	i = 0;								\
     73	for_each_set_bit(bit, &mask, 32) {				\
     74		if (bit == N) {						\
     75			return sprintf(buf, format_string,		\
     76				       dpn[i].field);			\
     77		}							\
     78		i++;							\
     79	}								\
     80	return -EINVAL;							\
     81}									\
     82									\
     83static ssize_t field##_show(struct device *dev,				\
     84			    struct device_attribute *attr,		\
     85			    char *buf)					\
     86{									\
     87	struct sdw_slave *slave = dev_to_sdw_dev(dev);			\
     88	struct dpn_attribute *dpn_attr =				\
     89		container_of(attr, struct dpn_attribute, dev_attr);	\
     90									\
     91	return field##_dpn_show(slave,					\
     92				dpn_attr->N, dpn_attr->dir,		\
     93				dpn_attr->format_string,		\
     94				buf);					\
     95}									\
     96sdw_dpn_attribute_alloc(field)
     97
     98sdw_dpn_attr(imp_def_interrupts);
     99sdw_dpn_attr(max_word);
    100sdw_dpn_attr(min_word);
    101sdw_dpn_attr(type);
    102sdw_dpn_attr(max_grouping);
    103sdw_dpn_attr(simple_ch_prep_sm);
    104sdw_dpn_attr(ch_prep_timeout);
    105sdw_dpn_attr(max_ch);
    106sdw_dpn_attr(min_ch);
    107sdw_dpn_attr(max_async_buffer);
    108sdw_dpn_attr(block_pack_mode);
    109sdw_dpn_attr(port_encoding);
    110
    111#define sdw_dpn_array_attr(field)					\
    112									\
    113static ssize_t field##_dpn_show(struct sdw_slave *slave,		\
    114				int N,					\
    115				int dir,				\
    116				const char *format_string,		\
    117				char *buf)				\
    118{									\
    119	struct sdw_dpn_prop *dpn;					\
    120	unsigned long mask;						\
    121	ssize_t size = 0;						\
    122	int bit;							\
    123	int i;								\
    124	int j;								\
    125									\
    126	if (dir) {							\
    127		dpn = slave->prop.src_dpn_prop;				\
    128		mask = slave->prop.source_ports;			\
    129	} else {							\
    130		dpn = slave->prop.sink_dpn_prop;			\
    131		mask = slave->prop.sink_ports;				\
    132	}								\
    133									\
    134	i = 0;								\
    135	for_each_set_bit(bit, &mask, 32) {				\
    136		if (bit == N) {						\
    137			for (j = 0; j < dpn[i].num_##field; j++)	\
    138				size += sprintf(buf + size,		\
    139						format_string,		\
    140						dpn[i].field[j]);	\
    141			size += sprintf(buf + size, "\n");		\
    142			return size;					\
    143		}							\
    144		i++;							\
    145	}								\
    146	return -EINVAL;							\
    147}									\
    148static ssize_t field##_show(struct device *dev,				\
    149			    struct device_attribute *attr,		\
    150			    char *buf)					\
    151{									\
    152	struct sdw_slave *slave = dev_to_sdw_dev(dev);			\
    153	struct dpn_attribute *dpn_attr =				\
    154		container_of(attr, struct dpn_attribute, dev_attr);	\
    155									\
    156	return field##_dpn_show(slave,					\
    157				dpn_attr->N, dpn_attr->dir,		\
    158				dpn_attr->format_string,		\
    159				buf);					\
    160}									\
    161sdw_dpn_attribute_alloc(field)
    162
    163sdw_dpn_array_attr(words);
    164sdw_dpn_array_attr(ch_combinations);
    165sdw_dpn_array_attr(channels);
    166
    167static int add_all_attributes(struct device *dev, int N, int dir)
    168{
    169	struct attribute **dpn_attrs;
    170	struct attribute_group *dpn_group;
    171	int i = 0;
    172	int ret;
    173
    174	/* allocate attributes, last one is NULL */
    175	dpn_attrs = devm_kcalloc(dev, SDW_DPN_ATTRIBUTES + 1,
    176				 sizeof(struct attribute *),
    177				 GFP_KERNEL);
    178	if (!dpn_attrs)
    179		return -ENOMEM;
    180
    181	ret = max_word_attribute_alloc(dev, &dpn_attrs[i++],
    182				       N, dir, "%d\n");
    183	if (ret < 0)
    184		return ret;
    185
    186	ret = min_word_attribute_alloc(dev, &dpn_attrs[i++],
    187				       N, dir, "%d\n");
    188	if (ret < 0)
    189		return ret;
    190
    191	ret = words_attribute_alloc(dev, &dpn_attrs[i++],
    192				    N, dir, "%d\n");
    193	if (ret < 0)
    194		return ret;
    195
    196	ret = type_attribute_alloc(dev, &dpn_attrs[i++],
    197				   N, dir, "%d\n");
    198	if (ret < 0)
    199		return ret;
    200
    201	ret = max_grouping_attribute_alloc(dev, &dpn_attrs[i++],
    202					   N, dir, "%d\n");
    203	if (ret < 0)
    204		return ret;
    205
    206	ret = simple_ch_prep_sm_attribute_alloc(dev, &dpn_attrs[i++],
    207						N, dir, "%d\n");
    208	if (ret < 0)
    209		return ret;
    210
    211	ret = ch_prep_timeout_attribute_alloc(dev, &dpn_attrs[i++],
    212					      N, dir, "%d\n");
    213	if (ret < 0)
    214		return ret;
    215
    216	ret = imp_def_interrupts_attribute_alloc(dev, &dpn_attrs[i++],
    217						 N, dir, "0x%x\n");
    218	if (ret < 0)
    219		return ret;
    220
    221	ret = min_ch_attribute_alloc(dev, &dpn_attrs[i++],
    222				     N, dir, "%d\n");
    223	if (ret < 0)
    224		return ret;
    225
    226	ret = max_ch_attribute_alloc(dev, &dpn_attrs[i++],
    227				     N, dir, "%d\n");
    228	if (ret < 0)
    229		return ret;
    230
    231	ret = channels_attribute_alloc(dev, &dpn_attrs[i++],
    232				       N, dir, "%d\n");
    233	if (ret < 0)
    234		return ret;
    235
    236	ret = ch_combinations_attribute_alloc(dev, &dpn_attrs[i++],
    237					      N, dir, "%d\n");
    238	if (ret < 0)
    239		return ret;
    240
    241	ret = max_async_buffer_attribute_alloc(dev, &dpn_attrs[i++],
    242					       N, dir, "%d\n");
    243	if (ret < 0)
    244		return ret;
    245
    246	ret = block_pack_mode_attribute_alloc(dev, &dpn_attrs[i++],
    247					      N, dir, "%d\n");
    248	if (ret < 0)
    249		return ret;
    250
    251	ret = port_encoding_attribute_alloc(dev, &dpn_attrs[i++],
    252					    N, dir, "%d\n");
    253	if (ret < 0)
    254		return ret;
    255
    256	/* paranoia check for editing mistakes */
    257	if (i != SDW_DPN_ATTRIBUTES) {
    258		dev_err(dev, "mismatch in attributes, allocated %d got %d\n",
    259			SDW_DPN_ATTRIBUTES, i);
    260		return -EINVAL;
    261	}
    262
    263	dpn_group = devm_kzalloc(dev, sizeof(*dpn_group), GFP_KERNEL);
    264	if (!dpn_group)
    265		return -ENOMEM;
    266
    267	dpn_group->attrs = dpn_attrs;
    268	dpn_group->name = devm_kasprintf(dev, GFP_KERNEL, "dp%d_%s",
    269					 N, dir ? "src" : "sink");
    270	if (!dpn_group->name)
    271		return -ENOMEM;
    272
    273	ret = devm_device_add_group(dev, dpn_group);
    274	if (ret < 0)
    275		return ret;
    276
    277	return 0;
    278}
    279
    280int sdw_slave_sysfs_dpn_init(struct sdw_slave *slave)
    281{
    282	unsigned long mask;
    283	int ret;
    284	int i;
    285
    286	mask = slave->prop.source_ports;
    287	for_each_set_bit(i, &mask, 32) {
    288		ret = add_all_attributes(&slave->dev, i, 1);
    289		if (ret < 0)
    290			return ret;
    291	}
    292
    293	mask = slave->prop.sink_ports;
    294	for_each_set_bit(i, &mask, 32) {
    295		ret = add_all_attributes(&slave->dev, i, 0);
    296		if (ret < 0)
    297			return ret;
    298	}
    299
    300	return 0;
    301}