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

core.c (8201B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Greybus "Core"
      4 *
      5 * Copyright 2014-2015 Google Inc.
      6 * Copyright 2014-2015 Linaro Ltd.
      7 */
      8
      9#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
     10
     11#define CREATE_TRACE_POINTS
     12#include <linux/greybus.h>
     13#include "greybus_trace.h"
     14
     15#define GB_BUNDLE_AUTOSUSPEND_MS	3000
     16
     17/* Allow greybus to be disabled at boot if needed */
     18static bool nogreybus;
     19#ifdef MODULE
     20module_param(nogreybus, bool, 0444);
     21#else
     22core_param(nogreybus, nogreybus, bool, 0444);
     23#endif
     24int greybus_disabled(void)
     25{
     26	return nogreybus;
     27}
     28EXPORT_SYMBOL_GPL(greybus_disabled);
     29
     30static bool greybus_match_one_id(struct gb_bundle *bundle,
     31				 const struct greybus_bundle_id *id)
     32{
     33	if ((id->match_flags & GREYBUS_ID_MATCH_VENDOR) &&
     34	    (id->vendor != bundle->intf->vendor_id))
     35		return false;
     36
     37	if ((id->match_flags & GREYBUS_ID_MATCH_PRODUCT) &&
     38	    (id->product != bundle->intf->product_id))
     39		return false;
     40
     41	if ((id->match_flags & GREYBUS_ID_MATCH_CLASS) &&
     42	    (id->class != bundle->class))
     43		return false;
     44
     45	return true;
     46}
     47
     48static const struct greybus_bundle_id *
     49greybus_match_id(struct gb_bundle *bundle, const struct greybus_bundle_id *id)
     50{
     51	if (!id)
     52		return NULL;
     53
     54	for (; id->vendor || id->product || id->class || id->driver_info;
     55									id++) {
     56		if (greybus_match_one_id(bundle, id))
     57			return id;
     58	}
     59
     60	return NULL;
     61}
     62
     63static int greybus_match_device(struct device *dev, struct device_driver *drv)
     64{
     65	struct greybus_driver *driver = to_greybus_driver(drv);
     66	struct gb_bundle *bundle;
     67	const struct greybus_bundle_id *id;
     68
     69	if (!is_gb_bundle(dev))
     70		return 0;
     71
     72	bundle = to_gb_bundle(dev);
     73
     74	id = greybus_match_id(bundle, driver->id_table);
     75	if (id)
     76		return 1;
     77	/* FIXME - Dynamic ids? */
     78	return 0;
     79}
     80
     81static int greybus_uevent(struct device *dev, struct kobj_uevent_env *env)
     82{
     83	struct gb_host_device *hd;
     84	struct gb_module *module = NULL;
     85	struct gb_interface *intf = NULL;
     86	struct gb_control *control = NULL;
     87	struct gb_bundle *bundle = NULL;
     88	struct gb_svc *svc = NULL;
     89
     90	if (is_gb_host_device(dev)) {
     91		hd = to_gb_host_device(dev);
     92	} else if (is_gb_module(dev)) {
     93		module = to_gb_module(dev);
     94		hd = module->hd;
     95	} else if (is_gb_interface(dev)) {
     96		intf = to_gb_interface(dev);
     97		module = intf->module;
     98		hd = intf->hd;
     99	} else if (is_gb_control(dev)) {
    100		control = to_gb_control(dev);
    101		intf = control->intf;
    102		module = intf->module;
    103		hd = intf->hd;
    104	} else if (is_gb_bundle(dev)) {
    105		bundle = to_gb_bundle(dev);
    106		intf = bundle->intf;
    107		module = intf->module;
    108		hd = intf->hd;
    109	} else if (is_gb_svc(dev)) {
    110		svc = to_gb_svc(dev);
    111		hd = svc->hd;
    112	} else {
    113		dev_WARN(dev, "uevent for unknown greybus device \"type\"!\n");
    114		return -EINVAL;
    115	}
    116
    117	if (add_uevent_var(env, "BUS=%u", hd->bus_id))
    118		return -ENOMEM;
    119
    120	if (module) {
    121		if (add_uevent_var(env, "MODULE=%u", module->module_id))
    122			return -ENOMEM;
    123	}
    124
    125	if (intf) {
    126		if (add_uevent_var(env, "INTERFACE=%u", intf->interface_id))
    127			return -ENOMEM;
    128		if (add_uevent_var(env, "GREYBUS_ID=%08x/%08x",
    129				   intf->vendor_id, intf->product_id))
    130			return -ENOMEM;
    131	}
    132
    133	if (bundle) {
    134		// FIXME
    135		// add a uevent that can "load" a bundle type
    136		// This is what we need to bind a driver to so use the info
    137		// in gmod here as well
    138
    139		if (add_uevent_var(env, "BUNDLE=%u", bundle->id))
    140			return -ENOMEM;
    141		if (add_uevent_var(env, "BUNDLE_CLASS=%02x", bundle->class))
    142			return -ENOMEM;
    143	}
    144
    145	return 0;
    146}
    147
    148static void greybus_shutdown(struct device *dev)
    149{
    150	if (is_gb_host_device(dev)) {
    151		struct gb_host_device *hd;
    152
    153		hd = to_gb_host_device(dev);
    154		gb_hd_shutdown(hd);
    155	}
    156}
    157
    158struct bus_type greybus_bus_type = {
    159	.name =		"greybus",
    160	.match =	greybus_match_device,
    161	.uevent =	greybus_uevent,
    162	.shutdown =	greybus_shutdown,
    163};
    164
    165static int greybus_probe(struct device *dev)
    166{
    167	struct greybus_driver *driver = to_greybus_driver(dev->driver);
    168	struct gb_bundle *bundle = to_gb_bundle(dev);
    169	const struct greybus_bundle_id *id;
    170	int retval;
    171
    172	/* match id */
    173	id = greybus_match_id(bundle, driver->id_table);
    174	if (!id)
    175		return -ENODEV;
    176
    177	retval = pm_runtime_get_sync(&bundle->intf->dev);
    178	if (retval < 0) {
    179		pm_runtime_put_noidle(&bundle->intf->dev);
    180		return retval;
    181	}
    182
    183	retval = gb_control_bundle_activate(bundle->intf->control, bundle->id);
    184	if (retval) {
    185		pm_runtime_put(&bundle->intf->dev);
    186		return retval;
    187	}
    188
    189	/*
    190	 * Unbound bundle devices are always deactivated. During probe, the
    191	 * Runtime PM is set to enabled and active and the usage count is
    192	 * incremented. If the driver supports runtime PM, it should call
    193	 * pm_runtime_put() in its probe routine and pm_runtime_get_sync()
    194	 * in remove routine.
    195	 */
    196	pm_runtime_set_autosuspend_delay(dev, GB_BUNDLE_AUTOSUSPEND_MS);
    197	pm_runtime_use_autosuspend(dev);
    198	pm_runtime_get_noresume(dev);
    199	pm_runtime_set_active(dev);
    200	pm_runtime_enable(dev);
    201
    202	retval = driver->probe(bundle, id);
    203	if (retval) {
    204		/*
    205		 * Catch buggy drivers that fail to destroy their connections.
    206		 */
    207		WARN_ON(!list_empty(&bundle->connections));
    208
    209		gb_control_bundle_deactivate(bundle->intf->control, bundle->id);
    210
    211		pm_runtime_disable(dev);
    212		pm_runtime_set_suspended(dev);
    213		pm_runtime_put_noidle(dev);
    214		pm_runtime_dont_use_autosuspend(dev);
    215		pm_runtime_put(&bundle->intf->dev);
    216
    217		return retval;
    218	}
    219
    220	pm_runtime_put(&bundle->intf->dev);
    221
    222	return 0;
    223}
    224
    225static int greybus_remove(struct device *dev)
    226{
    227	struct greybus_driver *driver = to_greybus_driver(dev->driver);
    228	struct gb_bundle *bundle = to_gb_bundle(dev);
    229	struct gb_connection *connection;
    230	int retval;
    231
    232	retval = pm_runtime_get_sync(dev);
    233	if (retval < 0)
    234		dev_err(dev, "failed to resume bundle: %d\n", retval);
    235
    236	/*
    237	 * Disable (non-offloaded) connections early in case the interface is
    238	 * already gone to avoid unceccessary operation timeouts during
    239	 * driver disconnect. Otherwise, only disable incoming requests.
    240	 */
    241	list_for_each_entry(connection, &bundle->connections, bundle_links) {
    242		if (gb_connection_is_offloaded(connection))
    243			continue;
    244
    245		if (bundle->intf->disconnected)
    246			gb_connection_disable_forced(connection);
    247		else
    248			gb_connection_disable_rx(connection);
    249	}
    250
    251	driver->disconnect(bundle);
    252
    253	/* Catch buggy drivers that fail to destroy their connections. */
    254	WARN_ON(!list_empty(&bundle->connections));
    255
    256	if (!bundle->intf->disconnected)
    257		gb_control_bundle_deactivate(bundle->intf->control, bundle->id);
    258
    259	pm_runtime_put_noidle(dev);
    260	pm_runtime_disable(dev);
    261	pm_runtime_set_suspended(dev);
    262	pm_runtime_dont_use_autosuspend(dev);
    263	pm_runtime_put_noidle(dev);
    264
    265	return 0;
    266}
    267
    268int greybus_register_driver(struct greybus_driver *driver, struct module *owner,
    269			    const char *mod_name)
    270{
    271	int retval;
    272
    273	if (greybus_disabled())
    274		return -ENODEV;
    275
    276	driver->driver.bus = &greybus_bus_type;
    277	driver->driver.name = driver->name;
    278	driver->driver.probe = greybus_probe;
    279	driver->driver.remove = greybus_remove;
    280	driver->driver.owner = owner;
    281	driver->driver.mod_name = mod_name;
    282
    283	retval = driver_register(&driver->driver);
    284	if (retval)
    285		return retval;
    286
    287	pr_info("registered new driver %s\n", driver->name);
    288	return 0;
    289}
    290EXPORT_SYMBOL_GPL(greybus_register_driver);
    291
    292void greybus_deregister_driver(struct greybus_driver *driver)
    293{
    294	driver_unregister(&driver->driver);
    295}
    296EXPORT_SYMBOL_GPL(greybus_deregister_driver);
    297
    298static int __init gb_init(void)
    299{
    300	int retval;
    301
    302	if (greybus_disabled())
    303		return -ENODEV;
    304
    305	BUILD_BUG_ON(CPORT_ID_MAX >= (long)CPORT_ID_BAD);
    306
    307	gb_debugfs_init();
    308
    309	retval = bus_register(&greybus_bus_type);
    310	if (retval) {
    311		pr_err("bus_register failed (%d)\n", retval);
    312		goto error_bus;
    313	}
    314
    315	retval = gb_hd_init();
    316	if (retval) {
    317		pr_err("gb_hd_init failed (%d)\n", retval);
    318		goto error_hd;
    319	}
    320
    321	retval = gb_operation_init();
    322	if (retval) {
    323		pr_err("gb_operation_init failed (%d)\n", retval);
    324		goto error_operation;
    325	}
    326	return 0;	/* Success */
    327
    328error_operation:
    329	gb_hd_exit();
    330error_hd:
    331	bus_unregister(&greybus_bus_type);
    332error_bus:
    333	gb_debugfs_cleanup();
    334
    335	return retval;
    336}
    337module_init(gb_init);
    338
    339static void __exit gb_exit(void)
    340{
    341	gb_operation_exit();
    342	gb_hd_exit();
    343	bus_unregister(&greybus_bus_type);
    344	gb_debugfs_cleanup();
    345	tracepoint_synchronize_unregister();
    346}
    347module_exit(gb_exit);
    348MODULE_LICENSE("GPL v2");
    349MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@linuxfoundation.org>");