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 
15 static 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 
30 static 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 
36 static const struct component_ops connector_ops = {
37 	.bind = connector_bind,
38 	.unbind = connector_unbind,
39 };
40 
41 static 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 }
63 static DEVICE_ATTR_RO(link);
64 
65 static struct attribute *common_attrs[] = {
66 	&dev_attr_link.attr,
67 	NULL
68 };
69 
70 static const struct attribute_group common_group = {
71 	.attrs = common_attrs,
72 };
73 
74 static 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 
98 static 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 
106 static 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 
114 static 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 
155 out_unlock:
156 	mutex_unlock(&tb->lock);
157 out_rpm:
158 	pm_runtime_mark_last_busy(&usb4->dev);
159 	pm_runtime_put_autosuspend(&usb4->dev);
160 
161 	return ret ? ret : count;
162 }
163 static DEVICE_ATTR_RW(offline);
164 
165 static 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 
197 out_unlock:
198 	mutex_unlock(&tb->lock);
199 out_rpm:
200 	pm_runtime_mark_last_busy(&usb4->dev);
201 	pm_runtime_put_autosuspend(&usb4->dev);
202 
203 	return ret ? ret : count;
204 }
205 static DEVICE_ATTR_WO(rescan);
206 
207 static struct attribute *service_attrs[] = {
208 	&dev_attr_offline.attr,
209 	&dev_attr_rescan.attr,
210 	NULL
211 };
212 
213 static 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 
226 static const struct attribute_group service_group = {
227 	.attrs = service_attrs,
228 	.is_visible = service_attr_is_visible,
229 };
230 
231 static const struct attribute_group *usb4_port_device_groups[] = {
232 	&common_group,
233 	&service_group,
234 	NULL
235 };
236 
237 static 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 
244 struct 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  */
257 struct 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  */
302 void 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  */
315 int usb4_port_device_resume(struct usb4_port *usb4)
316 {
317 	return usb4->offline ? usb4_port_offline(usb4) : 0;
318 }
319