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