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

gbphy.c (8499B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Greybus Bridged-Phy Bus driver
      4 *
      5 * Copyright 2014 Google Inc.
      6 * Copyright 2014 Linaro Ltd.
      7 */
      8
      9#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
     10
     11#include <linux/types.h>
     12#include <linux/module.h>
     13#include <linux/kernel.h>
     14#include <linux/slab.h>
     15#include <linux/device.h>
     16#include <linux/greybus.h>
     17
     18#include "gbphy.h"
     19
     20#define GB_GBPHY_AUTOSUSPEND_MS	3000
     21
     22struct gbphy_host {
     23	struct gb_bundle *bundle;
     24	struct list_head devices;
     25};
     26
     27static DEFINE_IDA(gbphy_id);
     28
     29static ssize_t protocol_id_show(struct device *dev,
     30				struct device_attribute *attr, char *buf)
     31{
     32	struct gbphy_device *gbphy_dev = to_gbphy_dev(dev);
     33
     34	return sprintf(buf, "0x%02x\n", gbphy_dev->cport_desc->protocol_id);
     35}
     36static DEVICE_ATTR_RO(protocol_id);
     37
     38static struct attribute *gbphy_dev_attrs[] = {
     39	&dev_attr_protocol_id.attr,
     40	NULL,
     41};
     42
     43ATTRIBUTE_GROUPS(gbphy_dev);
     44
     45static void gbphy_dev_release(struct device *dev)
     46{
     47	struct gbphy_device *gbphy_dev = to_gbphy_dev(dev);
     48
     49	ida_simple_remove(&gbphy_id, gbphy_dev->id);
     50	kfree(gbphy_dev);
     51}
     52
     53#ifdef CONFIG_PM
     54static int gb_gbphy_idle(struct device *dev)
     55{
     56	pm_runtime_mark_last_busy(dev);
     57	pm_request_autosuspend(dev);
     58	return 0;
     59}
     60#endif
     61
     62static const struct dev_pm_ops gb_gbphy_pm_ops = {
     63	SET_RUNTIME_PM_OPS(pm_generic_runtime_suspend,
     64			   pm_generic_runtime_resume,
     65			   gb_gbphy_idle)
     66};
     67
     68static const struct device_type greybus_gbphy_dev_type = {
     69	.name	 =	"gbphy_device",
     70	.release =	gbphy_dev_release,
     71	.pm	=	&gb_gbphy_pm_ops,
     72};
     73
     74static int gbphy_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
     75{
     76	struct gbphy_device *gbphy_dev = to_gbphy_dev(dev);
     77	struct greybus_descriptor_cport *cport_desc = gbphy_dev->cport_desc;
     78	struct gb_bundle *bundle = gbphy_dev->bundle;
     79	struct gb_interface *intf = bundle->intf;
     80	struct gb_module *module = intf->module;
     81	struct gb_host_device *hd = intf->hd;
     82
     83	if (add_uevent_var(env, "BUS=%u", hd->bus_id))
     84		return -ENOMEM;
     85	if (add_uevent_var(env, "MODULE=%u", module->module_id))
     86		return -ENOMEM;
     87	if (add_uevent_var(env, "INTERFACE=%u", intf->interface_id))
     88		return -ENOMEM;
     89	if (add_uevent_var(env, "GREYBUS_ID=%08x/%08x",
     90			   intf->vendor_id, intf->product_id))
     91		return -ENOMEM;
     92	if (add_uevent_var(env, "BUNDLE=%u", gbphy_dev->bundle->id))
     93		return -ENOMEM;
     94	if (add_uevent_var(env, "BUNDLE_CLASS=%02x", bundle->class))
     95		return -ENOMEM;
     96	if (add_uevent_var(env, "GBPHY=%u", gbphy_dev->id))
     97		return -ENOMEM;
     98	if (add_uevent_var(env, "PROTOCOL_ID=%02x", cport_desc->protocol_id))
     99		return -ENOMEM;
    100
    101	return 0;
    102}
    103
    104static const struct gbphy_device_id *
    105gbphy_dev_match_id(struct gbphy_device *gbphy_dev,
    106		   struct gbphy_driver *gbphy_drv)
    107{
    108	const struct gbphy_device_id *id = gbphy_drv->id_table;
    109
    110	if (!id)
    111		return NULL;
    112
    113	for (; id->protocol_id; id++)
    114		if (id->protocol_id == gbphy_dev->cport_desc->protocol_id)
    115			return id;
    116
    117	return NULL;
    118}
    119
    120static int gbphy_dev_match(struct device *dev, struct device_driver *drv)
    121{
    122	struct gbphy_driver *gbphy_drv = to_gbphy_driver(drv);
    123	struct gbphy_device *gbphy_dev = to_gbphy_dev(dev);
    124	const struct gbphy_device_id *id;
    125
    126	id = gbphy_dev_match_id(gbphy_dev, gbphy_drv);
    127	if (id)
    128		return 1;
    129
    130	return 0;
    131}
    132
    133static int gbphy_dev_probe(struct device *dev)
    134{
    135	struct gbphy_driver *gbphy_drv = to_gbphy_driver(dev->driver);
    136	struct gbphy_device *gbphy_dev = to_gbphy_dev(dev);
    137	const struct gbphy_device_id *id;
    138	int ret;
    139
    140	id = gbphy_dev_match_id(gbphy_dev, gbphy_drv);
    141	if (!id)
    142		return -ENODEV;
    143
    144	/* for old kernels we need get_sync to resume parent devices */
    145	ret = gb_pm_runtime_get_sync(gbphy_dev->bundle);
    146	if (ret < 0)
    147		return ret;
    148
    149	pm_runtime_set_autosuspend_delay(dev, GB_GBPHY_AUTOSUSPEND_MS);
    150	pm_runtime_use_autosuspend(dev);
    151	pm_runtime_get_noresume(dev);
    152	pm_runtime_set_active(dev);
    153	pm_runtime_enable(dev);
    154
    155	/*
    156	 * Drivers should call put on the gbphy dev before returning
    157	 * from probe if they support runtime pm.
    158	 */
    159	ret = gbphy_drv->probe(gbphy_dev, id);
    160	if (ret) {
    161		pm_runtime_disable(dev);
    162		pm_runtime_set_suspended(dev);
    163		pm_runtime_put_noidle(dev);
    164		pm_runtime_dont_use_autosuspend(dev);
    165	}
    166
    167	gb_pm_runtime_put_autosuspend(gbphy_dev->bundle);
    168
    169	return ret;
    170}
    171
    172static void gbphy_dev_remove(struct device *dev)
    173{
    174	struct gbphy_driver *gbphy_drv = to_gbphy_driver(dev->driver);
    175	struct gbphy_device *gbphy_dev = to_gbphy_dev(dev);
    176
    177	gbphy_drv->remove(gbphy_dev);
    178
    179	pm_runtime_disable(dev);
    180	pm_runtime_set_suspended(dev);
    181	pm_runtime_put_noidle(dev);
    182	pm_runtime_dont_use_autosuspend(dev);
    183}
    184
    185static struct bus_type gbphy_bus_type = {
    186	.name =		"gbphy",
    187	.match =	gbphy_dev_match,
    188	.probe =	gbphy_dev_probe,
    189	.remove =	gbphy_dev_remove,
    190	.uevent =	gbphy_dev_uevent,
    191};
    192
    193int gb_gbphy_register_driver(struct gbphy_driver *driver,
    194			     struct module *owner, const char *mod_name)
    195{
    196	int retval;
    197
    198	if (greybus_disabled())
    199		return -ENODEV;
    200
    201	driver->driver.bus = &gbphy_bus_type;
    202	driver->driver.name = driver->name;
    203	driver->driver.owner = owner;
    204	driver->driver.mod_name = mod_name;
    205
    206	retval = driver_register(&driver->driver);
    207	if (retval)
    208		return retval;
    209
    210	pr_info("registered new driver %s\n", driver->name);
    211	return 0;
    212}
    213EXPORT_SYMBOL_GPL(gb_gbphy_register_driver);
    214
    215void gb_gbphy_deregister_driver(struct gbphy_driver *driver)
    216{
    217	driver_unregister(&driver->driver);
    218}
    219EXPORT_SYMBOL_GPL(gb_gbphy_deregister_driver);
    220
    221static struct gbphy_device *gb_gbphy_create_dev(struct gb_bundle *bundle,
    222						struct greybus_descriptor_cport *cport_desc)
    223{
    224	struct gbphy_device *gbphy_dev;
    225	int retval;
    226	int id;
    227
    228	id = ida_simple_get(&gbphy_id, 1, 0, GFP_KERNEL);
    229	if (id < 0)
    230		return ERR_PTR(id);
    231
    232	gbphy_dev = kzalloc(sizeof(*gbphy_dev), GFP_KERNEL);
    233	if (!gbphy_dev) {
    234		ida_simple_remove(&gbphy_id, id);
    235		return ERR_PTR(-ENOMEM);
    236	}
    237
    238	gbphy_dev->id = id;
    239	gbphy_dev->bundle = bundle;
    240	gbphy_dev->cport_desc = cport_desc;
    241	gbphy_dev->dev.parent = &bundle->dev;
    242	gbphy_dev->dev.bus = &gbphy_bus_type;
    243	gbphy_dev->dev.type = &greybus_gbphy_dev_type;
    244	gbphy_dev->dev.groups = gbphy_dev_groups;
    245	gbphy_dev->dev.dma_mask = bundle->dev.dma_mask;
    246	dev_set_name(&gbphy_dev->dev, "gbphy%d", id);
    247
    248	retval = device_register(&gbphy_dev->dev);
    249	if (retval) {
    250		put_device(&gbphy_dev->dev);
    251		return ERR_PTR(retval);
    252	}
    253
    254	return gbphy_dev;
    255}
    256
    257static void gb_gbphy_disconnect(struct gb_bundle *bundle)
    258{
    259	struct gbphy_host *gbphy_host = greybus_get_drvdata(bundle);
    260	struct gbphy_device *gbphy_dev, *temp;
    261	int ret;
    262
    263	ret = gb_pm_runtime_get_sync(bundle);
    264	if (ret < 0)
    265		gb_pm_runtime_get_noresume(bundle);
    266
    267	list_for_each_entry_safe(gbphy_dev, temp, &gbphy_host->devices, list) {
    268		list_del(&gbphy_dev->list);
    269		device_unregister(&gbphy_dev->dev);
    270	}
    271
    272	kfree(gbphy_host);
    273}
    274
    275static int gb_gbphy_probe(struct gb_bundle *bundle,
    276			  const struct greybus_bundle_id *id)
    277{
    278	struct gbphy_host *gbphy_host;
    279	struct gbphy_device *gbphy_dev;
    280	int i;
    281
    282	if (bundle->num_cports == 0)
    283		return -ENODEV;
    284
    285	gbphy_host = kzalloc(sizeof(*gbphy_host), GFP_KERNEL);
    286	if (!gbphy_host)
    287		return -ENOMEM;
    288
    289	gbphy_host->bundle = bundle;
    290	INIT_LIST_HEAD(&gbphy_host->devices);
    291	greybus_set_drvdata(bundle, gbphy_host);
    292
    293	/*
    294	 * Create a bunch of children devices, one per cport, and bind the
    295	 * bridged phy drivers to them.
    296	 */
    297	for (i = 0; i < bundle->num_cports; ++i) {
    298		gbphy_dev = gb_gbphy_create_dev(bundle, &bundle->cport_desc[i]);
    299		if (IS_ERR(gbphy_dev)) {
    300			gb_gbphy_disconnect(bundle);
    301			return PTR_ERR(gbphy_dev);
    302		}
    303		list_add(&gbphy_dev->list, &gbphy_host->devices);
    304	}
    305
    306	gb_pm_runtime_put_autosuspend(bundle);
    307
    308	return 0;
    309}
    310
    311static const struct greybus_bundle_id gb_gbphy_id_table[] = {
    312	{ GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_BRIDGED_PHY) },
    313	{ },
    314};
    315MODULE_DEVICE_TABLE(greybus, gb_gbphy_id_table);
    316
    317static struct greybus_driver gb_gbphy_driver = {
    318	.name		= "gbphy",
    319	.probe		= gb_gbphy_probe,
    320	.disconnect	= gb_gbphy_disconnect,
    321	.id_table	= gb_gbphy_id_table,
    322};
    323
    324static int __init gbphy_init(void)
    325{
    326	int retval;
    327
    328	retval = bus_register(&gbphy_bus_type);
    329	if (retval) {
    330		pr_err("gbphy bus register failed (%d)\n", retval);
    331		return retval;
    332	}
    333
    334	retval = greybus_register(&gb_gbphy_driver);
    335	if (retval) {
    336		pr_err("error registering greybus driver\n");
    337		goto error_gbphy;
    338	}
    339
    340	return 0;
    341
    342error_gbphy:
    343	bus_unregister(&gbphy_bus_type);
    344	ida_destroy(&gbphy_id);
    345	return retval;
    346}
    347module_init(gbphy_init);
    348
    349static void __exit gbphy_exit(void)
    350{
    351	greybus_deregister(&gb_gbphy_driver);
    352	bus_unregister(&gbphy_bus_type);
    353	ida_destroy(&gbphy_id);
    354}
    355module_exit(gbphy_exit);
    356
    357MODULE_LICENSE("GPL v2");