brintos

brintos / linux-shallow public Read only

0
0
Text · 7.1 KiB · 5150879 Raw
324 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * USB4 port device4 *5 * Copyright (C) 2021, Intel Corporation6 * 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 if (port->xdomain)57		link = port->xdomain->link_usb4 ? "usb4" : "tbt";58	else59		link = "none";60 61	mutex_unlock(&tb->lock);62 63	return sysfs_emit(buf, "%s\n", link);64}65static DEVICE_ATTR_RO(link);66 67static struct attribute *common_attrs[] = {68	&dev_attr_link.attr,69	NULL70};71 72static const struct attribute_group common_group = {73	.attrs = common_attrs,74};75 76static int usb4_port_offline(struct usb4_port *usb4)77{78	struct tb_port *port = usb4->port;79	int ret;80 81	ret = tb_acpi_power_on_retimers(port);82	if (ret)83		return ret;84 85	ret = usb4_port_router_offline(port);86	if (ret) {87		tb_acpi_power_off_retimers(port);88		return ret;89	}90 91	ret = tb_retimer_scan(port, false);92	if (ret) {93		usb4_port_router_online(port);94		tb_acpi_power_off_retimers(port);95	}96 97	return ret;98}99 100static void usb4_port_online(struct usb4_port *usb4)101{102	struct tb_port *port = usb4->port;103 104	usb4_port_router_online(port);105	tb_acpi_power_off_retimers(port);106}107 108static ssize_t offline_show(struct device *dev,109	struct device_attribute *attr, char *buf)110{111	struct usb4_port *usb4 = tb_to_usb4_port_device(dev);112 113	return sysfs_emit(buf, "%d\n", usb4->offline);114}115 116static ssize_t offline_store(struct device *dev,117	struct device_attribute *attr, const char *buf, size_t count)118{119	struct usb4_port *usb4 = tb_to_usb4_port_device(dev);120	struct tb_port *port = usb4->port;121	struct tb *tb = port->sw->tb;122	bool val;123	int ret;124 125	ret = kstrtobool(buf, &val);126	if (ret)127		return ret;128 129	pm_runtime_get_sync(&usb4->dev);130 131	if (mutex_lock_interruptible(&tb->lock)) {132		ret = -ERESTARTSYS;133		goto out_rpm;134	}135 136	if (val == usb4->offline)137		goto out_unlock;138 139	/* Offline mode works only for ports that are not connected */140	if (tb_port_has_remote(port)) {141		ret = -EBUSY;142		goto out_unlock;143	}144 145	if (val) {146		ret = usb4_port_offline(usb4);147		if (ret)148			goto out_unlock;149	} else {150		usb4_port_online(usb4);151		tb_retimer_remove_all(port);152	}153 154	usb4->offline = val;155	tb_port_dbg(port, "%s offline mode\n", val ? "enter" : "exit");156 157out_unlock:158	mutex_unlock(&tb->lock);159out_rpm:160	pm_runtime_mark_last_busy(&usb4->dev);161	pm_runtime_put_autosuspend(&usb4->dev);162 163	return ret ? ret : count;164}165static DEVICE_ATTR_RW(offline);166 167static ssize_t rescan_store(struct device *dev,168	struct device_attribute *attr, const char *buf, size_t count)169{170	struct usb4_port *usb4 = tb_to_usb4_port_device(dev);171	struct tb_port *port = usb4->port;172	struct tb *tb = port->sw->tb;173	bool val;174	int ret;175 176	ret = kstrtobool(buf, &val);177	if (ret)178		return ret;179 180	if (!val)181		return count;182 183	pm_runtime_get_sync(&usb4->dev);184 185	if (mutex_lock_interruptible(&tb->lock)) {186		ret = -ERESTARTSYS;187		goto out_rpm;188	}189 190	/* Must be in offline mode already */191	if (!usb4->offline) {192		ret = -EINVAL;193		goto out_unlock;194	}195 196	tb_retimer_remove_all(port);197	ret = tb_retimer_scan(port, true);198 199out_unlock:200	mutex_unlock(&tb->lock);201out_rpm:202	pm_runtime_mark_last_busy(&usb4->dev);203	pm_runtime_put_autosuspend(&usb4->dev);204 205	return ret ? ret : count;206}207static DEVICE_ATTR_WO(rescan);208 209static struct attribute *service_attrs[] = {210	&dev_attr_offline.attr,211	&dev_attr_rescan.attr,212	NULL213};214 215static umode_t service_attr_is_visible(struct kobject *kobj,216				       struct attribute *attr, int n)217{218	struct device *dev = kobj_to_dev(kobj);219	struct usb4_port *usb4 = tb_to_usb4_port_device(dev);220 221	/*222	 * Always need some platform help to cycle the modes so that223	 * retimers can be accessed through the sideband.224	 */225	return usb4->can_offline ? attr->mode : 0;226}227 228static const struct attribute_group service_group = {229	.attrs = service_attrs,230	.is_visible = service_attr_is_visible,231};232 233static const struct attribute_group *usb4_port_device_groups[] = {234	&common_group,235	&service_group,236	NULL237};238 239static void usb4_port_device_release(struct device *dev)240{241	struct usb4_port *usb4 = container_of(dev, struct usb4_port, dev);242 243	kfree(usb4);244}245 246const struct device_type usb4_port_device_type = {247	.name = "usb4_port",248	.groups = usb4_port_device_groups,249	.release = usb4_port_device_release,250};251 252/**253 * usb4_port_device_add() - Add USB4 port device254 * @port: Lane 0 adapter port to add the USB4 port255 *256 * Creates and registers a USB4 port device for @port. Returns the new257 * USB4 port device pointer or ERR_PTR() in case of error.258 */259struct usb4_port *usb4_port_device_add(struct tb_port *port)260{261	struct usb4_port *usb4;262	int ret;263 264	usb4 = kzalloc(sizeof(*usb4), GFP_KERNEL);265	if (!usb4)266		return ERR_PTR(-ENOMEM);267 268	usb4->port = port;269	usb4->dev.type = &usb4_port_device_type;270	usb4->dev.parent = &port->sw->dev;271	dev_set_name(&usb4->dev, "usb4_port%d", port->port);272 273	ret = device_register(&usb4->dev);274	if (ret) {275		put_device(&usb4->dev);276		return ERR_PTR(ret);277	}278 279	if (dev_fwnode(&usb4->dev)) {280		ret = component_add(&usb4->dev, &connector_ops);281		if (ret) {282			dev_err(&usb4->dev, "failed to add component\n");283			device_unregister(&usb4->dev);284		}285	}286 287	if (!tb_is_upstream_port(port))288		device_set_wakeup_capable(&usb4->dev, true);289 290	pm_runtime_no_callbacks(&usb4->dev);291	pm_runtime_set_active(&usb4->dev);292	pm_runtime_enable(&usb4->dev);293	pm_runtime_set_autosuspend_delay(&usb4->dev, TB_AUTOSUSPEND_DELAY);294	pm_runtime_mark_last_busy(&usb4->dev);295	pm_runtime_use_autosuspend(&usb4->dev);296 297	return usb4;298}299 300/**301 * usb4_port_device_remove() - Removes USB4 port device302 * @usb4: USB4 port device303 *304 * Unregisters the USB4 port device from the system. The device will be305 * released when the last reference is dropped.306 */307void usb4_port_device_remove(struct usb4_port *usb4)308{309	if (dev_fwnode(&usb4->dev))310		component_del(&usb4->dev, &connector_ops);311	device_unregister(&usb4->dev);312}313 314/**315 * usb4_port_device_resume() - Resumes USB4 port device316 * @usb4: USB4 port device317 *318 * Used to resume USB4 port device after sleep state.319 */320int usb4_port_device_resume(struct usb4_port *usb4)321{322	return usb4->offline ? usb4_port_offline(usb4) : 0;323}324