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

bus_type.c (5273B)


      1// SPDX-License-Identifier: GPL-2.0
      2// Copyright(c) 2015-17 Intel Corporation.
      3
      4#include <linux/module.h>
      5#include <linux/mod_devicetable.h>
      6#include <linux/pm_domain.h>
      7#include <linux/soundwire/sdw.h>
      8#include <linux/soundwire/sdw_type.h>
      9#include "bus.h"
     10#include "sysfs_local.h"
     11
     12/**
     13 * sdw_get_device_id - find the matching SoundWire device id
     14 * @slave: SoundWire Slave Device
     15 * @drv: SoundWire Slave Driver
     16 *
     17 * The match is done by comparing the mfg_id and part_id from the
     18 * struct sdw_device_id.
     19 */
     20static const struct sdw_device_id *
     21sdw_get_device_id(struct sdw_slave *slave, struct sdw_driver *drv)
     22{
     23	const struct sdw_device_id *id;
     24
     25	for (id = drv->id_table; id && id->mfg_id; id++)
     26		if (slave->id.mfg_id == id->mfg_id &&
     27		    slave->id.part_id == id->part_id  &&
     28		    (!id->sdw_version ||
     29		     slave->id.sdw_version == id->sdw_version) &&
     30		    (!id->class_id ||
     31		     slave->id.class_id == id->class_id))
     32			return id;
     33
     34	return NULL;
     35}
     36
     37static int sdw_bus_match(struct device *dev, struct device_driver *ddrv)
     38{
     39	struct sdw_slave *slave;
     40	struct sdw_driver *drv;
     41	int ret = 0;
     42
     43	if (is_sdw_slave(dev)) {
     44		slave = dev_to_sdw_dev(dev);
     45		drv = drv_to_sdw_driver(ddrv);
     46
     47		ret = !!sdw_get_device_id(slave, drv);
     48	}
     49	return ret;
     50}
     51
     52int sdw_slave_modalias(const struct sdw_slave *slave, char *buf, size_t size)
     53{
     54	/* modalias is sdw:m<mfg_id>p<part_id>v<version>c<class_id> */
     55
     56	return snprintf(buf, size, "sdw:m%04Xp%04Xv%02Xc%02X\n",
     57			slave->id.mfg_id, slave->id.part_id,
     58			slave->id.sdw_version, slave->id.class_id);
     59}
     60
     61int sdw_slave_uevent(struct device *dev, struct kobj_uevent_env *env)
     62{
     63	struct sdw_slave *slave = dev_to_sdw_dev(dev);
     64	char modalias[32];
     65
     66	sdw_slave_modalias(slave, modalias, sizeof(modalias));
     67
     68	if (add_uevent_var(env, "MODALIAS=%s", modalias))
     69		return -ENOMEM;
     70
     71	return 0;
     72}
     73
     74struct bus_type sdw_bus_type = {
     75	.name = "soundwire",
     76	.match = sdw_bus_match,
     77};
     78EXPORT_SYMBOL_GPL(sdw_bus_type);
     79
     80static int sdw_drv_probe(struct device *dev)
     81{
     82	struct sdw_slave *slave = dev_to_sdw_dev(dev);
     83	struct sdw_driver *drv = drv_to_sdw_driver(dev->driver);
     84	const struct sdw_device_id *id;
     85	const char *name;
     86	int ret;
     87
     88	/*
     89	 * fw description is mandatory to bind
     90	 */
     91	if (!dev->fwnode)
     92		return -ENODEV;
     93
     94	if (!IS_ENABLED(CONFIG_ACPI) && !dev->of_node)
     95		return -ENODEV;
     96
     97	id = sdw_get_device_id(slave, drv);
     98	if (!id)
     99		return -ENODEV;
    100
    101	slave->ops = drv->ops;
    102
    103	/*
    104	 * attach to power domain but don't turn on (last arg)
    105	 */
    106	ret = dev_pm_domain_attach(dev, false);
    107	if (ret)
    108		return ret;
    109
    110	ret = drv->probe(slave, id);
    111	if (ret) {
    112		name = drv->name;
    113		if (!name)
    114			name = drv->driver.name;
    115		dev_err(dev, "Probe of %s failed: %d\n", name, ret);
    116		dev_pm_domain_detach(dev, false);
    117		return ret;
    118	}
    119
    120	/* device is probed so let's read the properties now */
    121	if (slave->ops && slave->ops->read_prop)
    122		slave->ops->read_prop(slave);
    123
    124	/* init the sysfs as we have properties now */
    125	ret = sdw_slave_sysfs_init(slave);
    126	if (ret < 0)
    127		dev_warn(dev, "Slave sysfs init failed:%d\n", ret);
    128
    129	/*
    130	 * Check for valid clk_stop_timeout, use DisCo worst case value of
    131	 * 300ms
    132	 *
    133	 * TODO: check the timeouts and driver removal case
    134	 */
    135	if (slave->prop.clk_stop_timeout == 0)
    136		slave->prop.clk_stop_timeout = 300;
    137
    138	slave->bus->clk_stop_timeout = max_t(u32, slave->bus->clk_stop_timeout,
    139					     slave->prop.clk_stop_timeout);
    140
    141	slave->probed = true;
    142	complete(&slave->probe_complete);
    143
    144	dev_dbg(dev, "probe complete\n");
    145
    146	return 0;
    147}
    148
    149static int sdw_drv_remove(struct device *dev)
    150{
    151	struct sdw_slave *slave = dev_to_sdw_dev(dev);
    152	struct sdw_driver *drv = drv_to_sdw_driver(dev->driver);
    153	int ret = 0;
    154
    155	if (drv->remove)
    156		ret = drv->remove(slave);
    157
    158	dev_pm_domain_detach(dev, false);
    159
    160	return ret;
    161}
    162
    163static void sdw_drv_shutdown(struct device *dev)
    164{
    165	struct sdw_slave *slave = dev_to_sdw_dev(dev);
    166	struct sdw_driver *drv = drv_to_sdw_driver(dev->driver);
    167
    168	if (drv->shutdown)
    169		drv->shutdown(slave);
    170}
    171
    172/**
    173 * __sdw_register_driver() - register a SoundWire Slave driver
    174 * @drv: driver to register
    175 * @owner: owning module/driver
    176 *
    177 * Return: zero on success, else a negative error code.
    178 */
    179int __sdw_register_driver(struct sdw_driver *drv, struct module *owner)
    180{
    181	const char *name;
    182
    183	drv->driver.bus = &sdw_bus_type;
    184
    185	if (!drv->probe) {
    186		name = drv->name;
    187		if (!name)
    188			name = drv->driver.name;
    189
    190		pr_err("driver %s didn't provide SDW probe routine\n", name);
    191		return -EINVAL;
    192	}
    193
    194	drv->driver.owner = owner;
    195	drv->driver.probe = sdw_drv_probe;
    196
    197	if (drv->remove)
    198		drv->driver.remove = sdw_drv_remove;
    199
    200	if (drv->shutdown)
    201		drv->driver.shutdown = sdw_drv_shutdown;
    202
    203	return driver_register(&drv->driver);
    204}
    205EXPORT_SYMBOL_GPL(__sdw_register_driver);
    206
    207/**
    208 * sdw_unregister_driver() - unregisters the SoundWire Slave driver
    209 * @drv: driver to unregister
    210 */
    211void sdw_unregister_driver(struct sdw_driver *drv)
    212{
    213	driver_unregister(&drv->driver);
    214}
    215EXPORT_SYMBOL_GPL(sdw_unregister_driver);
    216
    217static int __init sdw_bus_init(void)
    218{
    219	sdw_debugfs_init();
    220	return bus_register(&sdw_bus_type);
    221}
    222
    223static void __exit sdw_bus_exit(void)
    224{
    225	sdw_debugfs_exit();
    226	bus_unregister(&sdw_bus_type);
    227}
    228
    229postcore_initcall(sdw_bus_init);
    230module_exit(sdw_bus_exit);
    231
    232MODULE_DESCRIPTION("SoundWire bus");
    233MODULE_LICENSE("GPL v2");