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

master.c (4954B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2// Copyright(c) 2019-2020 Intel Corporation.
      3
      4#include <linux/device.h>
      5#include <linux/acpi.h>
      6#include <linux/pm_runtime.h>
      7#include <linux/soundwire/sdw.h>
      8#include <linux/soundwire/sdw_type.h>
      9#include "bus.h"
     10
     11/*
     12 * The 3s value for autosuspend will only be used if there are no
     13 * devices physically attached on a bus segment. In practice enabling
     14 * the bus operation will result in children devices become active and
     15 * the master device will only suspend when all its children are no
     16 * longer active.
     17 */
     18#define SDW_MASTER_SUSPEND_DELAY_MS 3000
     19
     20/*
     21 * The sysfs for properties reflects the MIPI description as given
     22 * in the MIPI DisCo spec
     23 *
     24 * Base file is:
     25 *	sdw-master-N
     26 *      |---- revision
     27 *      |---- clk_stop_modes
     28 *      |---- max_clk_freq
     29 *      |---- clk_freq
     30 *      |---- clk_gears
     31 *      |---- default_row
     32 *      |---- default_col
     33 *      |---- dynamic_shape
     34 *      |---- err_threshold
     35 */
     36
     37#define sdw_master_attr(field, format_string)				\
     38static ssize_t field##_show(struct device *dev,				\
     39			    struct device_attribute *attr,		\
     40			    char *buf)					\
     41{									\
     42	struct sdw_master_device *md = dev_to_sdw_master_device(dev);	\
     43	return sprintf(buf, format_string, md->bus->prop.field);	\
     44}									\
     45static DEVICE_ATTR_RO(field)
     46
     47sdw_master_attr(revision, "0x%x\n");
     48sdw_master_attr(clk_stop_modes, "0x%x\n");
     49sdw_master_attr(max_clk_freq, "%d\n");
     50sdw_master_attr(default_row, "%d\n");
     51sdw_master_attr(default_col, "%d\n");
     52sdw_master_attr(default_frame_rate, "%d\n");
     53sdw_master_attr(dynamic_frame, "%d\n");
     54sdw_master_attr(err_threshold, "%d\n");
     55
     56static ssize_t clock_frequencies_show(struct device *dev,
     57				      struct device_attribute *attr, char *buf)
     58{
     59	struct sdw_master_device *md = dev_to_sdw_master_device(dev);
     60	ssize_t size = 0;
     61	int i;
     62
     63	for (i = 0; i < md->bus->prop.num_clk_freq; i++)
     64		size += sprintf(buf + size, "%8d ",
     65				md->bus->prop.clk_freq[i]);
     66	size += sprintf(buf + size, "\n");
     67
     68	return size;
     69}
     70static DEVICE_ATTR_RO(clock_frequencies);
     71
     72static ssize_t clock_gears_show(struct device *dev,
     73				struct device_attribute *attr, char *buf)
     74{
     75	struct sdw_master_device *md = dev_to_sdw_master_device(dev);
     76	ssize_t size = 0;
     77	int i;
     78
     79	for (i = 0; i < md->bus->prop.num_clk_gears; i++)
     80		size += sprintf(buf + size, "%8d ",
     81				md->bus->prop.clk_gears[i]);
     82	size += sprintf(buf + size, "\n");
     83
     84	return size;
     85}
     86static DEVICE_ATTR_RO(clock_gears);
     87
     88static struct attribute *master_node_attrs[] = {
     89	&dev_attr_revision.attr,
     90	&dev_attr_clk_stop_modes.attr,
     91	&dev_attr_max_clk_freq.attr,
     92	&dev_attr_default_row.attr,
     93	&dev_attr_default_col.attr,
     94	&dev_attr_default_frame_rate.attr,
     95	&dev_attr_dynamic_frame.attr,
     96	&dev_attr_err_threshold.attr,
     97	&dev_attr_clock_frequencies.attr,
     98	&dev_attr_clock_gears.attr,
     99	NULL,
    100};
    101ATTRIBUTE_GROUPS(master_node);
    102
    103static void sdw_master_device_release(struct device *dev)
    104{
    105	struct sdw_master_device *md = dev_to_sdw_master_device(dev);
    106
    107	kfree(md);
    108}
    109
    110static const struct dev_pm_ops master_dev_pm = {
    111	SET_RUNTIME_PM_OPS(pm_generic_runtime_suspend,
    112			   pm_generic_runtime_resume, NULL)
    113};
    114
    115struct device_type sdw_master_type = {
    116	.name =		"soundwire_master",
    117	.release =	sdw_master_device_release,
    118	.pm = &master_dev_pm,
    119};
    120
    121/**
    122 * sdw_master_device_add() - create a Linux Master Device representation.
    123 * @bus: SDW bus instance
    124 * @parent: parent device
    125 * @fwnode: firmware node handle
    126 */
    127int sdw_master_device_add(struct sdw_bus *bus, struct device *parent,
    128			  struct fwnode_handle *fwnode)
    129{
    130	struct sdw_master_device *md;
    131	int ret;
    132
    133	if (!parent)
    134		return -EINVAL;
    135
    136	md = kzalloc(sizeof(*md), GFP_KERNEL);
    137	if (!md)
    138		return -ENOMEM;
    139
    140	md->dev.bus = &sdw_bus_type;
    141	md->dev.type = &sdw_master_type;
    142	md->dev.parent = parent;
    143	md->dev.groups = master_node_groups;
    144	md->dev.of_node = parent->of_node;
    145	md->dev.fwnode = fwnode;
    146	md->dev.dma_mask = parent->dma_mask;
    147
    148	dev_set_name(&md->dev, "sdw-master-%d", bus->id);
    149
    150	ret = device_register(&md->dev);
    151	if (ret) {
    152		dev_err(parent, "Failed to add master: ret %d\n", ret);
    153		/*
    154		 * On err, don't free but drop ref as this will be freed
    155		 * when release method is invoked.
    156		 */
    157		put_device(&md->dev);
    158		goto device_register_err;
    159	}
    160
    161	/* add shortcuts to improve code readability/compactness */
    162	md->bus = bus;
    163	bus->dev = &md->dev;
    164	bus->md = md;
    165
    166	pm_runtime_set_autosuspend_delay(&bus->md->dev, SDW_MASTER_SUSPEND_DELAY_MS);
    167	pm_runtime_use_autosuspend(&bus->md->dev);
    168	pm_runtime_mark_last_busy(&bus->md->dev);
    169	pm_runtime_set_active(&bus->md->dev);
    170	pm_runtime_enable(&bus->md->dev);
    171	pm_runtime_idle(&bus->md->dev);
    172device_register_err:
    173	return ret;
    174}
    175
    176/**
    177 * sdw_master_device_del() - delete a Linux Master Device representation.
    178 * @bus: bus handle
    179 *
    180 * This function is the dual of sdw_master_device_add()
    181 */
    182int sdw_master_device_del(struct sdw_bus *bus)
    183{
    184	pm_runtime_disable(&bus->md->dev);
    185	device_unregister(bus->dev);
    186
    187	return 0;
    188}