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

usb4_port.c (7069B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * USB4 port device
      4 *
      5 * Copyright (C) 2021, Intel Corporation
      6 * Author: Mika Westerberg <mika.westerberg@linux.intel.com>
      7 */
      8
      9#include <linux/pm_runtime.h>
     10#include <linux/component.h>
     11#include <linux/property.h>
     12
     13#include "tb.h"
     14
     15static int connector_bind(struct device *dev, struct device *connector, void *data)
     16{
     17	int ret;
     18
     19	ret = sysfs_create_link(&dev->kobj, &connector->kobj, "connector");
     20	if (ret)
     21		return ret;
     22
     23	ret = sysfs_create_link(&connector->kobj, &dev->kobj, dev_name(dev));
     24	if (ret)
     25		sysfs_remove_link(&dev->kobj, "connector");
     26
     27	return ret;
     28}
     29
     30static void connector_unbind(struct device *dev, struct device *connector, void *data)
     31{
     32	sysfs_remove_link(&connector->kobj, dev_name(dev));
     33	sysfs_remove_link(&dev->kobj, "connector");
     34}
     35
     36static const struct component_ops connector_ops = {
     37	.bind = connector_bind,
     38	.unbind = connector_unbind,
     39};
     40
     41static ssize_t link_show(struct device *dev, struct device_attribute *attr,
     42			 char *buf)
     43{
     44	struct usb4_port *usb4 = tb_to_usb4_port_device(dev);
     45	struct tb_port *port = usb4->port;
     46	struct tb *tb = port->sw->tb;
     47	const char *link;
     48
     49	if (mutex_lock_interruptible(&tb->lock))
     50		return -ERESTARTSYS;
     51
     52	if (tb_is_upstream_port(port))
     53		link = port->sw->link_usb4 ? "usb4" : "tbt";
     54	else if (tb_port_has_remote(port))
     55		link = port->remote->sw->link_usb4 ? "usb4" : "tbt";
     56	else
     57		link = "none";
     58
     59	mutex_unlock(&tb->lock);
     60
     61	return sysfs_emit(buf, "%s\n", link);
     62}
     63static DEVICE_ATTR_RO(link);
     64
     65static struct attribute *common_attrs[] = {
     66	&dev_attr_link.attr,
     67	NULL
     68};
     69
     70static const struct attribute_group common_group = {
     71	.attrs = common_attrs,
     72};
     73
     74static int usb4_port_offline(struct usb4_port *usb4)
     75{
     76	struct tb_port *port = usb4->port;
     77	int ret;
     78
     79	ret = tb_acpi_power_on_retimers(port);
     80	if (ret)
     81		return ret;
     82
     83	ret = usb4_port_router_offline(port);
     84	if (ret) {
     85		tb_acpi_power_off_retimers(port);
     86		return ret;
     87	}
     88
     89	ret = tb_retimer_scan(port, false);
     90	if (ret) {
     91		usb4_port_router_online(port);
     92		tb_acpi_power_off_retimers(port);
     93	}
     94
     95	return ret;
     96}
     97
     98static void usb4_port_online(struct usb4_port *usb4)
     99{
    100	struct tb_port *port = usb4->port;
    101
    102	usb4_port_router_online(port);
    103	tb_acpi_power_off_retimers(port);
    104}
    105
    106static ssize_t offline_show(struct device *dev,
    107	struct device_attribute *attr, char *buf)
    108{
    109	struct usb4_port *usb4 = tb_to_usb4_port_device(dev);
    110
    111	return sysfs_emit(buf, "%d\n", usb4->offline);
    112}
    113
    114static ssize_t offline_store(struct device *dev,
    115	struct device_attribute *attr, const char *buf, size_t count)
    116{
    117	struct usb4_port *usb4 = tb_to_usb4_port_device(dev);
    118	struct tb_port *port = usb4->port;
    119	struct tb *tb = port->sw->tb;
    120	bool val;
    121	int ret;
    122
    123	ret = kstrtobool(buf, &val);
    124	if (ret)
    125		return ret;
    126
    127	pm_runtime_get_sync(&usb4->dev);
    128
    129	if (mutex_lock_interruptible(&tb->lock)) {
    130		ret = -ERESTARTSYS;
    131		goto out_rpm;
    132	}
    133
    134	if (val == usb4->offline)
    135		goto out_unlock;
    136
    137	/* Offline mode works only for ports that are not connected */
    138	if (tb_port_has_remote(port)) {
    139		ret = -EBUSY;
    140		goto out_unlock;
    141	}
    142
    143	if (val) {
    144		ret = usb4_port_offline(usb4);
    145		if (ret)
    146			goto out_unlock;
    147	} else {
    148		usb4_port_online(usb4);
    149		tb_retimer_remove_all(port);
    150	}
    151
    152	usb4->offline = val;
    153	tb_port_dbg(port, "%s offline mode\n", val ? "enter" : "exit");
    154
    155out_unlock:
    156	mutex_unlock(&tb->lock);
    157out_rpm:
    158	pm_runtime_mark_last_busy(&usb4->dev);
    159	pm_runtime_put_autosuspend(&usb4->dev);
    160
    161	return ret ? ret : count;
    162}
    163static DEVICE_ATTR_RW(offline);
    164
    165static ssize_t rescan_store(struct device *dev,
    166	struct device_attribute *attr, const char *buf, size_t count)
    167{
    168	struct usb4_port *usb4 = tb_to_usb4_port_device(dev);
    169	struct tb_port *port = usb4->port;
    170	struct tb *tb = port->sw->tb;
    171	bool val;
    172	int ret;
    173
    174	ret = kstrtobool(buf, &val);
    175	if (ret)
    176		return ret;
    177
    178	if (!val)
    179		return count;
    180
    181	pm_runtime_get_sync(&usb4->dev);
    182
    183	if (mutex_lock_interruptible(&tb->lock)) {
    184		ret = -ERESTARTSYS;
    185		goto out_rpm;
    186	}
    187
    188	/* Must be in offline mode already */
    189	if (!usb4->offline) {
    190		ret = -EINVAL;
    191		goto out_unlock;
    192	}
    193
    194	tb_retimer_remove_all(port);
    195	ret = tb_retimer_scan(port, true);
    196
    197out_unlock:
    198	mutex_unlock(&tb->lock);
    199out_rpm:
    200	pm_runtime_mark_last_busy(&usb4->dev);
    201	pm_runtime_put_autosuspend(&usb4->dev);
    202
    203	return ret ? ret : count;
    204}
    205static DEVICE_ATTR_WO(rescan);
    206
    207static struct attribute *service_attrs[] = {
    208	&dev_attr_offline.attr,
    209	&dev_attr_rescan.attr,
    210	NULL
    211};
    212
    213static umode_t service_attr_is_visible(struct kobject *kobj,
    214				       struct attribute *attr, int n)
    215{
    216	struct device *dev = kobj_to_dev(kobj);
    217	struct usb4_port *usb4 = tb_to_usb4_port_device(dev);
    218
    219	/*
    220	 * Always need some platform help to cycle the modes so that
    221	 * retimers can be accessed through the sideband.
    222	 */
    223	return usb4->can_offline ? attr->mode : 0;
    224}
    225
    226static const struct attribute_group service_group = {
    227	.attrs = service_attrs,
    228	.is_visible = service_attr_is_visible,
    229};
    230
    231static const struct attribute_group *usb4_port_device_groups[] = {
    232	&common_group,
    233	&service_group,
    234	NULL
    235};
    236
    237static void usb4_port_device_release(struct device *dev)
    238{
    239	struct usb4_port *usb4 = container_of(dev, struct usb4_port, dev);
    240
    241	kfree(usb4);
    242}
    243
    244struct device_type usb4_port_device_type = {
    245	.name = "usb4_port",
    246	.groups = usb4_port_device_groups,
    247	.release = usb4_port_device_release,
    248};
    249
    250/**
    251 * usb4_port_device_add() - Add USB4 port device
    252 * @port: Lane 0 adapter port to add the USB4 port
    253 *
    254 * Creates and registers a USB4 port device for @port. Returns the new
    255 * USB4 port device pointer or ERR_PTR() in case of error.
    256 */
    257struct usb4_port *usb4_port_device_add(struct tb_port *port)
    258{
    259	struct usb4_port *usb4;
    260	int ret;
    261
    262	usb4 = kzalloc(sizeof(*usb4), GFP_KERNEL);
    263	if (!usb4)
    264		return ERR_PTR(-ENOMEM);
    265
    266	usb4->port = port;
    267	usb4->dev.type = &usb4_port_device_type;
    268	usb4->dev.parent = &port->sw->dev;
    269	dev_set_name(&usb4->dev, "usb4_port%d", port->port);
    270
    271	ret = device_register(&usb4->dev);
    272	if (ret) {
    273		put_device(&usb4->dev);
    274		return ERR_PTR(ret);
    275	}
    276
    277	if (dev_fwnode(&usb4->dev)) {
    278		ret = component_add(&usb4->dev, &connector_ops);
    279		if (ret) {
    280			dev_err(&usb4->dev, "failed to add component\n");
    281			device_unregister(&usb4->dev);
    282		}
    283	}
    284
    285	pm_runtime_no_callbacks(&usb4->dev);
    286	pm_runtime_set_active(&usb4->dev);
    287	pm_runtime_enable(&usb4->dev);
    288	pm_runtime_set_autosuspend_delay(&usb4->dev, TB_AUTOSUSPEND_DELAY);
    289	pm_runtime_mark_last_busy(&usb4->dev);
    290	pm_runtime_use_autosuspend(&usb4->dev);
    291
    292	return usb4;
    293}
    294
    295/**
    296 * usb4_port_device_remove() - Removes USB4 port device
    297 * @usb4: USB4 port device
    298 *
    299 * Unregisters the USB4 port device from the system. The device will be
    300 * released when the last reference is dropped.
    301 */
    302void usb4_port_device_remove(struct usb4_port *usb4)
    303{
    304	if (dev_fwnode(&usb4->dev))
    305		component_del(&usb4->dev, &connector_ops);
    306	device_unregister(&usb4->dev);
    307}
    308
    309/**
    310 * usb4_port_device_resume() - Resumes USB4 port device
    311 * @usb4: USB4 port device
    312 *
    313 * Used to resume USB4 port device after sleep state.
    314 */
    315int usb4_port_device_resume(struct usb4_port *usb4)
    316{
    317	return usb4->offline ? usb4_port_offline(usb4) : 0;
    318}