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

slave.c (5932B)


      1// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
      2// Copyright(c) 2015-17 Intel Corporation.
      3
      4#include <linux/acpi.h>
      5#include <linux/of.h>
      6#include <linux/soundwire/sdw.h>
      7#include <linux/soundwire/sdw_type.h>
      8#include "bus.h"
      9#include "sysfs_local.h"
     10
     11static void sdw_slave_release(struct device *dev)
     12{
     13	struct sdw_slave *slave = dev_to_sdw_dev(dev);
     14
     15	kfree(slave);
     16}
     17
     18struct device_type sdw_slave_type = {
     19	.name =		"sdw_slave",
     20	.release =	sdw_slave_release,
     21	.uevent =	sdw_slave_uevent,
     22};
     23
     24int sdw_slave_add(struct sdw_bus *bus,
     25		  struct sdw_slave_id *id, struct fwnode_handle *fwnode)
     26{
     27	struct sdw_slave *slave;
     28	int ret;
     29	int i;
     30
     31	slave = kzalloc(sizeof(*slave), GFP_KERNEL);
     32	if (!slave)
     33		return -ENOMEM;
     34
     35	/* Initialize data structure */
     36	memcpy(&slave->id, id, sizeof(*id));
     37	slave->dev.parent = bus->dev;
     38	slave->dev.fwnode = fwnode;
     39
     40	if (id->unique_id == SDW_IGNORED_UNIQUE_ID) {
     41		/* name shall be sdw:link:mfg:part:class */
     42		dev_set_name(&slave->dev, "sdw:%01x:%04x:%04x:%02x",
     43			     bus->link_id, id->mfg_id, id->part_id,
     44			     id->class_id);
     45	} else {
     46		/* name shall be sdw:link:mfg:part:class:unique */
     47		dev_set_name(&slave->dev, "sdw:%01x:%04x:%04x:%02x:%01x",
     48			     bus->link_id, id->mfg_id, id->part_id,
     49			     id->class_id, id->unique_id);
     50	}
     51
     52	slave->dev.bus = &sdw_bus_type;
     53	slave->dev.of_node = of_node_get(to_of_node(fwnode));
     54	slave->dev.type = &sdw_slave_type;
     55	slave->dev.groups = sdw_slave_status_attr_groups;
     56	slave->bus = bus;
     57	slave->status = SDW_SLAVE_UNATTACHED;
     58	init_completion(&slave->enumeration_complete);
     59	init_completion(&slave->initialization_complete);
     60	slave->dev_num = 0;
     61	init_completion(&slave->probe_complete);
     62	slave->probed = false;
     63	slave->first_interrupt_done = false;
     64
     65	for (i = 0; i < SDW_MAX_PORTS; i++)
     66		init_completion(&slave->port_ready[i]);
     67
     68	mutex_lock(&bus->bus_lock);
     69	list_add_tail(&slave->node, &bus->slaves);
     70	mutex_unlock(&bus->bus_lock);
     71
     72	ret = device_register(&slave->dev);
     73	if (ret) {
     74		dev_err(bus->dev, "Failed to add slave: ret %d\n", ret);
     75
     76		/*
     77		 * On err, don't free but drop ref as this will be freed
     78		 * when release method is invoked.
     79		 */
     80		mutex_lock(&bus->bus_lock);
     81		list_del(&slave->node);
     82		mutex_unlock(&bus->bus_lock);
     83		put_device(&slave->dev);
     84
     85		return ret;
     86	}
     87	sdw_slave_debugfs_init(slave);
     88
     89	return ret;
     90}
     91EXPORT_SYMBOL(sdw_slave_add);
     92
     93#if IS_ENABLED(CONFIG_ACPI)
     94
     95static bool find_slave(struct sdw_bus *bus,
     96		       struct acpi_device *adev,
     97		       struct sdw_slave_id *id)
     98{
     99	u64 addr;
    100	unsigned int link_id;
    101	acpi_status status;
    102
    103	status = acpi_evaluate_integer(adev->handle,
    104				       METHOD_NAME__ADR, NULL, &addr);
    105
    106	if (ACPI_FAILURE(status)) {
    107		dev_err(bus->dev, "_ADR resolution failed: %x\n",
    108			status);
    109		return false;
    110	}
    111
    112	if (bus->ops->override_adr)
    113		addr = bus->ops->override_adr(bus, addr);
    114
    115	if (!addr)
    116		return false;
    117
    118	/* Extract link id from ADR, Bit 51 to 48 (included) */
    119	link_id = SDW_DISCO_LINK_ID(addr);
    120
    121	/* Check for link_id match */
    122	if (link_id != bus->link_id)
    123		return false;
    124
    125	sdw_extract_slave_id(bus, addr, id);
    126
    127	return true;
    128}
    129
    130/*
    131 * sdw_acpi_find_slaves() - Find Slave devices in Master ACPI node
    132 * @bus: SDW bus instance
    133 *
    134 * Scans Master ACPI node for SDW child Slave devices and registers it.
    135 */
    136int sdw_acpi_find_slaves(struct sdw_bus *bus)
    137{
    138	struct acpi_device *adev, *parent;
    139	struct acpi_device *adev2, *parent2;
    140
    141	parent = ACPI_COMPANION(bus->dev);
    142	if (!parent) {
    143		dev_err(bus->dev, "Can't find parent for acpi bind\n");
    144		return -ENODEV;
    145	}
    146
    147	list_for_each_entry(adev, &parent->children, node) {
    148		struct sdw_slave_id id;
    149		struct sdw_slave_id id2;
    150		bool ignore_unique_id = true;
    151
    152		if (!find_slave(bus, adev, &id))
    153			continue;
    154
    155		/* brute-force O(N^2) search for duplicates */
    156		parent2 = parent;
    157		list_for_each_entry(adev2, &parent2->children, node) {
    158
    159			if (adev == adev2)
    160				continue;
    161
    162			if (!find_slave(bus, adev2, &id2))
    163				continue;
    164
    165			if (id.sdw_version != id2.sdw_version ||
    166			    id.mfg_id != id2.mfg_id ||
    167			    id.part_id != id2.part_id ||
    168			    id.class_id != id2.class_id)
    169				continue;
    170
    171			if (id.unique_id != id2.unique_id) {
    172				dev_dbg(bus->dev,
    173					"Valid unique IDs 0x%x 0x%x for Slave mfg_id 0x%04x, part_id 0x%04x\n",
    174					id.unique_id, id2.unique_id, id.mfg_id, id.part_id);
    175				ignore_unique_id = false;
    176			} else {
    177				dev_err(bus->dev,
    178					"Invalid unique IDs 0x%x 0x%x for Slave mfg_id 0x%04x, part_id 0x%04x\n",
    179					id.unique_id, id2.unique_id, id.mfg_id, id.part_id);
    180				return -ENODEV;
    181			}
    182		}
    183
    184		if (ignore_unique_id)
    185			id.unique_id = SDW_IGNORED_UNIQUE_ID;
    186
    187		/*
    188		 * don't error check for sdw_slave_add as we want to continue
    189		 * adding Slaves
    190		 */
    191		sdw_slave_add(bus, &id, acpi_fwnode_handle(adev));
    192	}
    193
    194	return 0;
    195}
    196
    197#endif
    198
    199/*
    200 * sdw_of_find_slaves() - Find Slave devices in master device tree node
    201 * @bus: SDW bus instance
    202 *
    203 * Scans Master DT node for SDW child Slave devices and registers it.
    204 */
    205int sdw_of_find_slaves(struct sdw_bus *bus)
    206{
    207	struct device *dev = bus->dev;
    208	struct device_node *node;
    209
    210	for_each_child_of_node(bus->dev->of_node, node) {
    211		int link_id, ret, len;
    212		unsigned int sdw_version;
    213		const char *compat = NULL;
    214		struct sdw_slave_id id;
    215		const __be32 *addr;
    216
    217		compat = of_get_property(node, "compatible", NULL);
    218		if (!compat)
    219			continue;
    220
    221		ret = sscanf(compat, "sdw%01x%04hx%04hx%02hhx", &sdw_version,
    222			     &id.mfg_id, &id.part_id, &id.class_id);
    223
    224		if (ret != 4) {
    225			dev_err(dev, "Invalid compatible string found %s\n",
    226				compat);
    227			continue;
    228		}
    229
    230		addr = of_get_property(node, "reg", &len);
    231		if (!addr || (len < 2 * sizeof(u32))) {
    232			dev_err(dev, "Invalid Link and Instance ID\n");
    233			continue;
    234		}
    235
    236		link_id = be32_to_cpup(addr++);
    237		id.unique_id = be32_to_cpup(addr);
    238		id.sdw_version = sdw_version;
    239
    240		/* Check for link_id match */
    241		if (link_id != bus->link_id)
    242			continue;
    243
    244		sdw_slave_add(bus, &id, of_fwnode_handle(node));
    245	}
    246
    247	return 0;
    248}