1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * USB-ACPI glue code |
4 | * |
5 | * Copyright 2012 Red Hat <mjg@redhat.com> |
6 | */ |
7 | #include <linux/module.h> |
8 | #include <linux/usb.h> |
9 | #include <linux/device.h> |
10 | #include <linux/errno.h> |
11 | #include <linux/kernel.h> |
12 | #include <linux/acpi.h> |
13 | #include <linux/pci.h> |
14 | #include <linux/usb/hcd.h> |
15 | |
16 | #include "hub.h" |
17 | |
18 | /** |
19 | * usb_acpi_power_manageable - check whether usb port has |
20 | * acpi power resource. |
21 | * @hdev: USB device belonging to the usb hub |
22 | * @index: port index based zero |
23 | * |
24 | * Return true if the port has acpi power resource and false if no. |
25 | */ |
26 | bool usb_acpi_power_manageable(struct usb_device *hdev, int index) |
27 | { |
28 | acpi_handle port_handle; |
29 | int port1 = index + 1; |
30 | |
31 | port_handle = usb_get_hub_port_acpi_handle(hdev, |
32 | port1); |
33 | if (port_handle) |
34 | return acpi_bus_power_manageable(handle: port_handle); |
35 | else |
36 | return false; |
37 | } |
38 | EXPORT_SYMBOL_GPL(usb_acpi_power_manageable); |
39 | |
40 | #define UUID_USB_CONTROLLER_DSM "ce2ee385-00e6-48cb-9f05-2edb927c4899" |
41 | #define USB_DSM_DISABLE_U1_U2_FOR_PORT 5 |
42 | |
43 | /** |
44 | * usb_acpi_port_lpm_incapable - check if lpm should be disabled for a port. |
45 | * @hdev: USB device belonging to the usb hub |
46 | * @index: zero based port index |
47 | * |
48 | * Some USB3 ports may not support USB3 link power management U1/U2 states |
49 | * due to different retimer setup. ACPI provides _DSM method which returns 0x01 |
50 | * if U1 and U2 states should be disabled. Evaluate _DSM with: |
51 | * Arg0: UUID = ce2ee385-00e6-48cb-9f05-2edb927c4899 |
52 | * Arg1: Revision ID = 0 |
53 | * Arg2: Function Index = 5 |
54 | * Arg3: (empty) |
55 | * |
56 | * Return 1 if USB3 port is LPM incapable, negative on error, otherwise 0 |
57 | */ |
58 | |
59 | int usb_acpi_port_lpm_incapable(struct usb_device *hdev, int index) |
60 | { |
61 | union acpi_object *obj; |
62 | acpi_handle port_handle; |
63 | int port1 = index + 1; |
64 | guid_t guid; |
65 | int ret; |
66 | |
67 | ret = guid_parse(UUID_USB_CONTROLLER_DSM, u: &guid); |
68 | if (ret) |
69 | return ret; |
70 | |
71 | port_handle = usb_get_hub_port_acpi_handle(hdev, port1); |
72 | if (!port_handle) { |
73 | dev_dbg(&hdev->dev, "port-%d no acpi handle\n" , port1); |
74 | return -ENODEV; |
75 | } |
76 | |
77 | if (!acpi_check_dsm(handle: port_handle, guid: &guid, rev: 0, |
78 | BIT(USB_DSM_DISABLE_U1_U2_FOR_PORT))) { |
79 | dev_dbg(&hdev->dev, "port-%d no _DSM function %d\n" , |
80 | port1, USB_DSM_DISABLE_U1_U2_FOR_PORT); |
81 | return -ENODEV; |
82 | } |
83 | |
84 | obj = acpi_evaluate_dsm_typed(handle: port_handle, guid: &guid, rev: 0, |
85 | USB_DSM_DISABLE_U1_U2_FOR_PORT, NULL, |
86 | ACPI_TYPE_INTEGER); |
87 | if (!obj) { |
88 | dev_dbg(&hdev->dev, "evaluate port-%d _DSM failed\n" , port1); |
89 | return -EINVAL; |
90 | } |
91 | |
92 | if (obj->integer.value == 0x01) |
93 | ret = 1; |
94 | |
95 | ACPI_FREE(obj); |
96 | |
97 | return ret; |
98 | } |
99 | EXPORT_SYMBOL_GPL(usb_acpi_port_lpm_incapable); |
100 | |
101 | /** |
102 | * usb_acpi_set_power_state - control usb port's power via acpi power |
103 | * resource |
104 | * @hdev: USB device belonging to the usb hub |
105 | * @index: port index based zero |
106 | * @enable: power state expected to be set |
107 | * |
108 | * Notice to use usb_acpi_power_manageable() to check whether the usb port |
109 | * has acpi power resource before invoking this function. |
110 | * |
111 | * Returns 0 on success, else negative errno. |
112 | */ |
113 | int usb_acpi_set_power_state(struct usb_device *hdev, int index, bool enable) |
114 | { |
115 | struct usb_hub *hub = usb_hub_to_struct_hub(hdev); |
116 | struct usb_port *port_dev; |
117 | acpi_handle port_handle; |
118 | unsigned char state; |
119 | int port1 = index + 1; |
120 | int error = -EINVAL; |
121 | |
122 | if (!hub) |
123 | return -ENODEV; |
124 | port_dev = hub->ports[port1 - 1]; |
125 | |
126 | port_handle = (acpi_handle) usb_get_hub_port_acpi_handle(hdev, port1); |
127 | if (!port_handle) |
128 | return error; |
129 | |
130 | if (enable) |
131 | state = ACPI_STATE_D0; |
132 | else |
133 | state = ACPI_STATE_D3_COLD; |
134 | |
135 | error = acpi_bus_set_power(handle: port_handle, state); |
136 | if (!error) |
137 | dev_dbg(&port_dev->dev, "acpi: power was set to %d\n" , enable); |
138 | else |
139 | dev_dbg(&port_dev->dev, "acpi: power failed to be set\n" ); |
140 | |
141 | return error; |
142 | } |
143 | EXPORT_SYMBOL_GPL(usb_acpi_set_power_state); |
144 | |
145 | static enum usb_port_connect_type usb_acpi_get_connect_type(acpi_handle handle, |
146 | struct acpi_pld_info *pld) |
147 | { |
148 | enum usb_port_connect_type connect_type = USB_PORT_CONNECT_TYPE_UNKNOWN; |
149 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; |
150 | union acpi_object *upc = NULL; |
151 | acpi_status status; |
152 | |
153 | /* |
154 | * According to 9.14 in ACPI Spec 6.2. _PLD indicates whether usb port |
155 | * is user visible and _UPC indicates whether it is connectable. If |
156 | * the port was visible and connectable, it could be freely connected |
157 | * and disconnected with USB devices. If no visible and connectable, |
158 | * a usb device is directly hard-wired to the port. If no visible and |
159 | * no connectable, the port would be not used. |
160 | */ |
161 | status = acpi_evaluate_object(object: handle, pathname: "_UPC" , NULL, return_object_buffer: &buffer); |
162 | if (ACPI_FAILURE(status)) |
163 | goto out; |
164 | |
165 | upc = buffer.pointer; |
166 | if (!upc || (upc->type != ACPI_TYPE_PACKAGE) || upc->package.count != 4) |
167 | goto out; |
168 | |
169 | if (upc->package.elements[0].integer.value) |
170 | if (pld->user_visible) |
171 | connect_type = USB_PORT_CONNECT_TYPE_HOT_PLUG; |
172 | else |
173 | connect_type = USB_PORT_CONNECT_TYPE_HARD_WIRED; |
174 | else if (!pld->user_visible) |
175 | connect_type = USB_PORT_NOT_USED; |
176 | out: |
177 | kfree(objp: upc); |
178 | return connect_type; |
179 | } |
180 | |
181 | |
182 | /* |
183 | * Private to usb-acpi, all the core needs to know is that |
184 | * port_dev->location is non-zero when it has been set by the firmware. |
185 | */ |
186 | #define USB_ACPI_LOCATION_VALID (1 << 31) |
187 | |
188 | static struct acpi_device * |
189 | usb_acpi_get_companion_for_port(struct usb_port *port_dev) |
190 | { |
191 | struct usb_device *udev; |
192 | struct acpi_device *adev; |
193 | acpi_handle *parent_handle; |
194 | int port1; |
195 | |
196 | /* Get the struct usb_device point of port's hub */ |
197 | udev = to_usb_device(port_dev->dev.parent->parent); |
198 | |
199 | /* |
200 | * The root hub ports' parent is the root hub. The non-root-hub |
201 | * ports' parent is the parent hub port which the hub is |
202 | * connected to. |
203 | */ |
204 | if (!udev->parent) { |
205 | adev = ACPI_COMPANION(&udev->dev); |
206 | port1 = usb_hcd_find_raw_port_number(hcd: bus_to_hcd(bus: udev->bus), |
207 | port1: port_dev->portnum); |
208 | } else { |
209 | parent_handle = usb_get_hub_port_acpi_handle(hdev: udev->parent, |
210 | port1: udev->portnum); |
211 | if (!parent_handle) |
212 | return NULL; |
213 | |
214 | adev = acpi_fetch_acpi_dev(handle: parent_handle); |
215 | port1 = port_dev->portnum; |
216 | } |
217 | |
218 | return acpi_find_child_by_adr(adev, adr: port1); |
219 | } |
220 | |
221 | static struct acpi_device * |
222 | usb_acpi_find_companion_for_port(struct usb_port *port_dev) |
223 | { |
224 | struct acpi_device *adev; |
225 | struct acpi_pld_info *pld; |
226 | acpi_handle *handle; |
227 | acpi_status status; |
228 | |
229 | adev = usb_acpi_get_companion_for_port(port_dev); |
230 | if (!adev) |
231 | return NULL; |
232 | |
233 | handle = adev->handle; |
234 | status = acpi_get_physical_device_location(handle, pld: &pld); |
235 | if (ACPI_SUCCESS(status) && pld) { |
236 | port_dev->location = USB_ACPI_LOCATION_VALID |
237 | | pld->group_token << 8 | pld->group_position; |
238 | port_dev->connect_type = usb_acpi_get_connect_type(handle, pld); |
239 | ACPI_FREE(pld); |
240 | } |
241 | |
242 | return adev; |
243 | } |
244 | |
245 | static struct acpi_device * |
246 | usb_acpi_find_companion_for_device(struct usb_device *udev) |
247 | { |
248 | struct acpi_device *adev; |
249 | struct usb_port *port_dev; |
250 | struct usb_hub *hub; |
251 | |
252 | if (!udev->parent) { |
253 | /* |
254 | * root hub is only child (_ADR=0) under its parent, the HC. |
255 | * sysdev pointer is the HC as seen from firmware. |
256 | */ |
257 | adev = ACPI_COMPANION(udev->bus->sysdev); |
258 | return acpi_find_child_device(parent: adev, address: 0, check_children: false); |
259 | } |
260 | |
261 | hub = usb_hub_to_struct_hub(hdev: udev->parent); |
262 | if (!hub) |
263 | return NULL; |
264 | |
265 | /* |
266 | * This is an embedded USB device connected to a port and such |
267 | * devices share port's ACPI companion. |
268 | */ |
269 | port_dev = hub->ports[udev->portnum - 1]; |
270 | return usb_acpi_get_companion_for_port(port_dev); |
271 | } |
272 | |
273 | static struct acpi_device *usb_acpi_find_companion(struct device *dev) |
274 | { |
275 | /* |
276 | * The USB hierarchy like following: |
277 | * |
278 | * Device (EHC1) |
279 | * Device (HUBN) |
280 | * Device (PR01) |
281 | * Device (PR11) |
282 | * Device (PR12) |
283 | * Device (FN12) |
284 | * Device (FN13) |
285 | * Device (PR13) |
286 | * ... |
287 | * where HUBN is root hub, and PRNN are USB ports and devices |
288 | * connected to them, and FNNN are individualk functions for |
289 | * connected composite USB devices. PRNN and FNNN may contain |
290 | * _CRS and other methods describing sideband resources for |
291 | * the connected device. |
292 | * |
293 | * On the kernel side both root hub and embedded USB devices are |
294 | * represented as instances of usb_device structure, and ports |
295 | * are represented as usb_port structures, so the whole process |
296 | * is split into 2 parts: finding companions for devices and |
297 | * finding companions for ports. |
298 | * |
299 | * Note that we do not handle individual functions of composite |
300 | * devices yet, for that we would need to assign companions to |
301 | * devices corresponding to USB interfaces. |
302 | */ |
303 | if (is_usb_device(dev)) |
304 | return usb_acpi_find_companion_for_device(to_usb_device(dev)); |
305 | else if (is_usb_port(dev)) |
306 | return usb_acpi_find_companion_for_port(to_usb_port(dev)); |
307 | |
308 | return NULL; |
309 | } |
310 | |
311 | static bool usb_acpi_bus_match(struct device *dev) |
312 | { |
313 | return is_usb_device(dev) || is_usb_port(dev); |
314 | } |
315 | |
316 | static struct acpi_bus_type usb_acpi_bus = { |
317 | .name = "USB" , |
318 | .match = usb_acpi_bus_match, |
319 | .find_companion = usb_acpi_find_companion, |
320 | }; |
321 | |
322 | int usb_acpi_register(void) |
323 | { |
324 | return register_acpi_bus_type(&usb_acpi_bus); |
325 | } |
326 | |
327 | void usb_acpi_unregister(void) |
328 | { |
329 | unregister_acpi_bus_type(&usb_acpi_bus); |
330 | } |
331 | |