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