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(kobj: &dev->kobj, target: &connector->kobj, name: "connector");
20 if (ret)
21 return ret;
22
23 ret = sysfs_create_link(kobj: &connector->kobj, target: &dev->kobj, name: dev_name(dev));
24 if (ret)
25 sysfs_remove_link(kobj: &dev->kobj, name: "connector");
26
27 return ret;
28}
29
30static void connector_unbind(struct device *dev, struct device *connector, void *data)
31{
32 sysfs_remove_link(kobj: &connector->kobj, name: dev_name(dev));
33 sysfs_remove_link(kobj: &dev->kobj, name: "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 else
59 link = "none";
60
61 mutex_unlock(lock: &tb->lock);
62
63 return sysfs_emit(buf, fmt: "%s\n", link);
64}
65static DEVICE_ATTR_RO(link);
66
67static struct attribute *common_attrs[] = {
68 &dev_attr_link.attr,
69 NULL
70};
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, add: 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, fmt: "%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(s: buf, res: &val);
126 if (ret)
127 return ret;
128
129 pm_runtime_get_sync(dev: &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(lock: &tb->lock);
159out_rpm:
160 pm_runtime_mark_last_busy(dev: &usb4->dev);
161 pm_runtime_put_autosuspend(dev: &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(s: buf, res: &val);
177 if (ret)
178 return ret;
179
180 if (!val)
181 return count;
182
183 pm_runtime_get_sync(dev: &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, add: true);
198
199out_unlock:
200 mutex_unlock(lock: &tb->lock);
201out_rpm:
202 pm_runtime_mark_last_busy(dev: &usb4->dev);
203 pm_runtime_put_autosuspend(dev: &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 NULL
213};
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 that
223 * 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 NULL
237};
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(objp: 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 device
254 * @port: Lane 0 adapter port to add the USB4 port
255 *
256 * Creates and registers a USB4 port device for @port. Returns the new
257 * 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(size: sizeof(*usb4), GFP_KERNEL);
265 if (!usb4)
266 return ERR_PTR(error: -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(dev: &usb4->dev, name: "usb4_port%d", port->port);
272
273 ret = device_register(dev: &usb4->dev);
274 if (ret) {
275 put_device(dev: &usb4->dev);
276 return ERR_PTR(error: 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(dev: &usb4->dev);
284 }
285 }
286
287 if (!tb_is_upstream_port(port))
288 device_set_wakeup_capable(dev: &usb4->dev, capable: true);
289
290 pm_runtime_no_callbacks(dev: &usb4->dev);
291 pm_runtime_set_active(dev: &usb4->dev);
292 pm_runtime_enable(dev: &usb4->dev);
293 pm_runtime_set_autosuspend_delay(dev: &usb4->dev, TB_AUTOSUSPEND_DELAY);
294 pm_runtime_mark_last_busy(dev: &usb4->dev);
295 pm_runtime_use_autosuspend(dev: &usb4->dev);
296
297 return usb4;
298}
299
300/**
301 * usb4_port_device_remove() - Removes USB4 port device
302 * @usb4: USB4 port device
303 *
304 * Unregisters the USB4 port device from the system. The device will be
305 * 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(dev: &usb4->dev);
312}
313
314/**
315 * usb4_port_device_resume() - Resumes USB4 port device
316 * @usb4: USB4 port device
317 *
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

source code of linux/drivers/thunderbolt/usb4_port.c