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

class.c (9913B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * USB Role Switch Support
      4 *
      5 * Copyright (C) 2018 Intel Corporation
      6 * Author: Heikki Krogerus <heikki.krogerus@linux.intel.com>
      7 *         Hans de Goede <hdegoede@redhat.com>
      8 */
      9
     10#include <linux/usb/role.h>
     11#include <linux/property.h>
     12#include <linux/device.h>
     13#include <linux/module.h>
     14#include <linux/mutex.h>
     15#include <linux/slab.h>
     16
     17static struct class *role_class;
     18
     19struct usb_role_switch {
     20	struct device dev;
     21	struct mutex lock; /* device lock*/
     22	enum usb_role role;
     23
     24	/* From descriptor */
     25	struct device *usb2_port;
     26	struct device *usb3_port;
     27	struct device *udc;
     28	usb_role_switch_set_t set;
     29	usb_role_switch_get_t get;
     30	bool allow_userspace_control;
     31};
     32
     33#define to_role_switch(d)	container_of(d, struct usb_role_switch, dev)
     34
     35/**
     36 * usb_role_switch_set_role - Set USB role for a switch
     37 * @sw: USB role switch
     38 * @role: USB role to be switched to
     39 *
     40 * Set USB role @role for @sw.
     41 */
     42int usb_role_switch_set_role(struct usb_role_switch *sw, enum usb_role role)
     43{
     44	int ret;
     45
     46	if (IS_ERR_OR_NULL(sw))
     47		return 0;
     48
     49	mutex_lock(&sw->lock);
     50
     51	ret = sw->set(sw, role);
     52	if (!ret) {
     53		sw->role = role;
     54		kobject_uevent(&sw->dev.kobj, KOBJ_CHANGE);
     55	}
     56
     57	mutex_unlock(&sw->lock);
     58
     59	return ret;
     60}
     61EXPORT_SYMBOL_GPL(usb_role_switch_set_role);
     62
     63/**
     64 * usb_role_switch_get_role - Get the USB role for a switch
     65 * @sw: USB role switch
     66 *
     67 * Depending on the role-switch-driver this function returns either a cached
     68 * value of the last set role, or reads back the actual value from the hardware.
     69 */
     70enum usb_role usb_role_switch_get_role(struct usb_role_switch *sw)
     71{
     72	enum usb_role role;
     73
     74	if (IS_ERR_OR_NULL(sw))
     75		return USB_ROLE_NONE;
     76
     77	mutex_lock(&sw->lock);
     78
     79	if (sw->get)
     80		role = sw->get(sw);
     81	else
     82		role = sw->role;
     83
     84	mutex_unlock(&sw->lock);
     85
     86	return role;
     87}
     88EXPORT_SYMBOL_GPL(usb_role_switch_get_role);
     89
     90static void *usb_role_switch_match(struct fwnode_handle *fwnode, const char *id,
     91				   void *data)
     92{
     93	struct device *dev;
     94
     95	if (id && !fwnode_property_present(fwnode, id))
     96		return NULL;
     97
     98	dev = class_find_device_by_fwnode(role_class, fwnode);
     99
    100	return dev ? to_role_switch(dev) : ERR_PTR(-EPROBE_DEFER);
    101}
    102
    103static struct usb_role_switch *
    104usb_role_switch_is_parent(struct fwnode_handle *fwnode)
    105{
    106	struct fwnode_handle *parent = fwnode_get_parent(fwnode);
    107	struct device *dev;
    108
    109	if (!parent || !fwnode_property_present(parent, "usb-role-switch"))
    110		return NULL;
    111
    112	dev = class_find_device_by_fwnode(role_class, parent);
    113	return dev ? to_role_switch(dev) : ERR_PTR(-EPROBE_DEFER);
    114}
    115
    116/**
    117 * usb_role_switch_get - Find USB role switch linked with the caller
    118 * @dev: The caller device
    119 *
    120 * Finds and returns role switch linked with @dev. The reference count for the
    121 * found switch is incremented.
    122 */
    123struct usb_role_switch *usb_role_switch_get(struct device *dev)
    124{
    125	struct usb_role_switch *sw;
    126
    127	sw = usb_role_switch_is_parent(dev_fwnode(dev));
    128	if (!sw)
    129		sw = device_connection_find_match(dev, "usb-role-switch", NULL,
    130						  usb_role_switch_match);
    131
    132	if (!IS_ERR_OR_NULL(sw))
    133		WARN_ON(!try_module_get(sw->dev.parent->driver->owner));
    134
    135	return sw;
    136}
    137EXPORT_SYMBOL_GPL(usb_role_switch_get);
    138
    139/**
    140 * fwnode_usb_role_switch_get - Find USB role switch linked with the caller
    141 * @fwnode: The caller device node
    142 *
    143 * This is similar to the usb_role_switch_get() function above, but it searches
    144 * the switch using fwnode instead of device entry.
    145 */
    146struct usb_role_switch *fwnode_usb_role_switch_get(struct fwnode_handle *fwnode)
    147{
    148	struct usb_role_switch *sw;
    149
    150	sw = usb_role_switch_is_parent(fwnode);
    151	if (!sw)
    152		sw = fwnode_connection_find_match(fwnode, "usb-role-switch",
    153						  NULL, usb_role_switch_match);
    154	if (!IS_ERR_OR_NULL(sw))
    155		WARN_ON(!try_module_get(sw->dev.parent->driver->owner));
    156
    157	return sw;
    158}
    159EXPORT_SYMBOL_GPL(fwnode_usb_role_switch_get);
    160
    161/**
    162 * usb_role_switch_put - Release handle to a switch
    163 * @sw: USB Role Switch
    164 *
    165 * Decrement reference count for @sw.
    166 */
    167void usb_role_switch_put(struct usb_role_switch *sw)
    168{
    169	if (!IS_ERR_OR_NULL(sw)) {
    170		module_put(sw->dev.parent->driver->owner);
    171		put_device(&sw->dev);
    172	}
    173}
    174EXPORT_SYMBOL_GPL(usb_role_switch_put);
    175
    176/**
    177 * usb_role_switch_find_by_fwnode - Find USB role switch with its fwnode
    178 * @fwnode: fwnode of the USB Role Switch
    179 *
    180 * Finds and returns role switch with @fwnode. The reference count for the
    181 * found switch is incremented.
    182 */
    183struct usb_role_switch *
    184usb_role_switch_find_by_fwnode(const struct fwnode_handle *fwnode)
    185{
    186	struct device *dev;
    187
    188	if (!fwnode)
    189		return NULL;
    190
    191	dev = class_find_device_by_fwnode(role_class, fwnode);
    192	if (dev)
    193		WARN_ON(!try_module_get(dev->parent->driver->owner));
    194
    195	return dev ? to_role_switch(dev) : NULL;
    196}
    197EXPORT_SYMBOL_GPL(usb_role_switch_find_by_fwnode);
    198
    199static umode_t
    200usb_role_switch_is_visible(struct kobject *kobj, struct attribute *attr, int n)
    201{
    202	struct device *dev = kobj_to_dev(kobj);
    203	struct usb_role_switch *sw = to_role_switch(dev);
    204
    205	if (sw->allow_userspace_control)
    206		return attr->mode;
    207
    208	return 0;
    209}
    210
    211static const char * const usb_roles[] = {
    212	[USB_ROLE_NONE]		= "none",
    213	[USB_ROLE_HOST]		= "host",
    214	[USB_ROLE_DEVICE]	= "device",
    215};
    216
    217const char *usb_role_string(enum usb_role role)
    218{
    219	if (role < 0 || role >= ARRAY_SIZE(usb_roles))
    220		return "unknown";
    221
    222	return usb_roles[role];
    223}
    224EXPORT_SYMBOL_GPL(usb_role_string);
    225
    226static ssize_t
    227role_show(struct device *dev, struct device_attribute *attr, char *buf)
    228{
    229	struct usb_role_switch *sw = to_role_switch(dev);
    230	enum usb_role role = usb_role_switch_get_role(sw);
    231
    232	return sprintf(buf, "%s\n", usb_roles[role]);
    233}
    234
    235static ssize_t role_store(struct device *dev, struct device_attribute *attr,
    236			  const char *buf, size_t size)
    237{
    238	struct usb_role_switch *sw = to_role_switch(dev);
    239	int ret;
    240
    241	ret = sysfs_match_string(usb_roles, buf);
    242	if (ret < 0) {
    243		bool res;
    244
    245		/* Extra check if the user wants to disable the switch */
    246		ret = kstrtobool(buf, &res);
    247		if (ret || res)
    248			return -EINVAL;
    249	}
    250
    251	ret = usb_role_switch_set_role(sw, ret);
    252	if (ret)
    253		return ret;
    254
    255	return size;
    256}
    257static DEVICE_ATTR_RW(role);
    258
    259static struct attribute *usb_role_switch_attrs[] = {
    260	&dev_attr_role.attr,
    261	NULL,
    262};
    263
    264static const struct attribute_group usb_role_switch_group = {
    265	.is_visible = usb_role_switch_is_visible,
    266	.attrs = usb_role_switch_attrs,
    267};
    268
    269static const struct attribute_group *usb_role_switch_groups[] = {
    270	&usb_role_switch_group,
    271	NULL,
    272};
    273
    274static int
    275usb_role_switch_uevent(struct device *dev, struct kobj_uevent_env *env)
    276{
    277	int ret;
    278
    279	ret = add_uevent_var(env, "USB_ROLE_SWITCH=%s", dev_name(dev));
    280	if (ret)
    281		dev_err(dev, "failed to add uevent USB_ROLE_SWITCH\n");
    282
    283	return ret;
    284}
    285
    286static void usb_role_switch_release(struct device *dev)
    287{
    288	struct usb_role_switch *sw = to_role_switch(dev);
    289
    290	kfree(sw);
    291}
    292
    293static const struct device_type usb_role_dev_type = {
    294	.name = "usb_role_switch",
    295	.groups = usb_role_switch_groups,
    296	.uevent = usb_role_switch_uevent,
    297	.release = usb_role_switch_release,
    298};
    299
    300/**
    301 * usb_role_switch_register - Register USB Role Switch
    302 * @parent: Parent device for the switch
    303 * @desc: Description of the switch
    304 *
    305 * USB Role Switch is a device capable or choosing the role for USB connector.
    306 * On platforms where the USB controller is dual-role capable, the controller
    307 * driver will need to register the switch. On platforms where the USB host and
    308 * USB device controllers behind the connector are separate, there will be a
    309 * mux, and the driver for that mux will need to register the switch.
    310 *
    311 * Returns handle to a new role switch or ERR_PTR. The content of @desc is
    312 * copied.
    313 */
    314struct usb_role_switch *
    315usb_role_switch_register(struct device *parent,
    316			 const struct usb_role_switch_desc *desc)
    317{
    318	struct usb_role_switch *sw;
    319	int ret;
    320
    321	if (!desc || !desc->set)
    322		return ERR_PTR(-EINVAL);
    323
    324	sw = kzalloc(sizeof(*sw), GFP_KERNEL);
    325	if (!sw)
    326		return ERR_PTR(-ENOMEM);
    327
    328	mutex_init(&sw->lock);
    329
    330	sw->allow_userspace_control = desc->allow_userspace_control;
    331	sw->usb2_port = desc->usb2_port;
    332	sw->usb3_port = desc->usb3_port;
    333	sw->udc = desc->udc;
    334	sw->set = desc->set;
    335	sw->get = desc->get;
    336
    337	sw->dev.parent = parent;
    338	sw->dev.fwnode = desc->fwnode;
    339	sw->dev.class = role_class;
    340	sw->dev.type = &usb_role_dev_type;
    341	dev_set_drvdata(&sw->dev, desc->driver_data);
    342	dev_set_name(&sw->dev, "%s-role-switch",
    343		     desc->name ? desc->name : dev_name(parent));
    344
    345	ret = device_register(&sw->dev);
    346	if (ret) {
    347		put_device(&sw->dev);
    348		return ERR_PTR(ret);
    349	}
    350
    351	/* TODO: Symlinks for the host port and the device controller. */
    352
    353	return sw;
    354}
    355EXPORT_SYMBOL_GPL(usb_role_switch_register);
    356
    357/**
    358 * usb_role_switch_unregister - Unregsiter USB Role Switch
    359 * @sw: USB Role Switch
    360 *
    361 * Unregister switch that was registered with usb_role_switch_register().
    362 */
    363void usb_role_switch_unregister(struct usb_role_switch *sw)
    364{
    365	if (!IS_ERR_OR_NULL(sw))
    366		device_unregister(&sw->dev);
    367}
    368EXPORT_SYMBOL_GPL(usb_role_switch_unregister);
    369
    370/**
    371 * usb_role_switch_set_drvdata - Assign private data pointer to a switch
    372 * @sw: USB Role Switch
    373 * @data: Private data pointer
    374 */
    375void usb_role_switch_set_drvdata(struct usb_role_switch *sw, void *data)
    376{
    377	dev_set_drvdata(&sw->dev, data);
    378}
    379EXPORT_SYMBOL_GPL(usb_role_switch_set_drvdata);
    380
    381/**
    382 * usb_role_switch_get_drvdata - Get the private data pointer of a switch
    383 * @sw: USB Role Switch
    384 */
    385void *usb_role_switch_get_drvdata(struct usb_role_switch *sw)
    386{
    387	return dev_get_drvdata(&sw->dev);
    388}
    389EXPORT_SYMBOL_GPL(usb_role_switch_get_drvdata);
    390
    391static int __init usb_roles_init(void)
    392{
    393	role_class = class_create(THIS_MODULE, "usb_role");
    394	return PTR_ERR_OR_ZERO(role_class);
    395}
    396subsys_initcall(usb_roles_init);
    397
    398static void __exit usb_roles_exit(void)
    399{
    400	class_destroy(role_class);
    401}
    402module_exit(usb_roles_exit);
    403
    404MODULE_AUTHOR("Heikki Krogerus <heikki.krogerus@linux.intel.com>");
    405MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
    406MODULE_LICENSE("GPL v2");
    407MODULE_DESCRIPTION("USB Role Class");