| 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 | /** | 
|---|
| 146 | * usb_acpi_add_usb4_devlink - add device link to USB4 Host Interface for tunneled USB3 devices | 
|---|
| 147 | * | 
|---|
| 148 | * @udev: Tunneled USB3 device connected to a roothub. | 
|---|
| 149 | * | 
|---|
| 150 | * Adds a device link between a tunneled USB3 device and the USB4 Host Interface | 
|---|
| 151 | * device to ensure correct runtime PM suspend and resume order. This function | 
|---|
| 152 | * should only be called for tunneled USB3 devices. | 
|---|
| 153 | * The USB4 Host Interface this tunneled device depends on is found from the roothub | 
|---|
| 154 | * port ACPI device specific data _DSD entry. | 
|---|
| 155 | * | 
|---|
| 156 | * Return: negative error code on failure, 0 otherwise | 
|---|
| 157 | */ | 
|---|
| 158 | static int usb_acpi_add_usb4_devlink(struct usb_device *udev) | 
|---|
| 159 | { | 
|---|
| 160 | struct device_link *link; | 
|---|
| 161 | struct usb_port *port_dev; | 
|---|
| 162 | struct usb_hub *hub; | 
|---|
| 163 |  | 
|---|
| 164 | if (!udev->parent || udev->parent->parent) | 
|---|
| 165 | return 0; | 
|---|
| 166 |  | 
|---|
| 167 | hub = usb_hub_to_struct_hub(hdev: udev->parent); | 
|---|
| 168 | if (!hub) | 
|---|
| 169 | return 0; | 
|---|
| 170 | port_dev = hub->ports[udev->portnum - 1]; | 
|---|
| 171 |  | 
|---|
| 172 | struct fwnode_handle *nhi_fwnode __free(fwnode_handle) = | 
|---|
| 173 | fwnode_find_reference(dev_fwnode(&port_dev->dev), name: "usb4-host-interface", index: 0); | 
|---|
| 174 |  | 
|---|
| 175 | if (IS_ERR(ptr: nhi_fwnode) || !nhi_fwnode->dev) | 
|---|
| 176 | return 0; | 
|---|
| 177 |  | 
|---|
| 178 | link = device_link_add(consumer: &port_dev->child->dev, supplier: nhi_fwnode->dev, | 
|---|
| 179 | DL_FLAG_STATELESS | | 
|---|
| 180 | DL_FLAG_RPM_ACTIVE | | 
|---|
| 181 | DL_FLAG_PM_RUNTIME); | 
|---|
| 182 | if (!link) { | 
|---|
| 183 | dev_err(&port_dev->dev, "Failed to created device link from %s to %s\n", | 
|---|
| 184 | dev_name(&port_dev->child->dev), dev_name(nhi_fwnode->dev)); | 
|---|
| 185 | return -EINVAL; | 
|---|
| 186 | } | 
|---|
| 187 |  | 
|---|
| 188 | dev_dbg(&port_dev->dev, "Created device link from %s to %s\n", | 
|---|
| 189 | dev_name(&port_dev->child->dev), dev_name(nhi_fwnode->dev)); | 
|---|
| 190 |  | 
|---|
| 191 | udev->usb4_link = link; | 
|---|
| 192 |  | 
|---|
| 193 | return 0; | 
|---|
| 194 | } | 
|---|
| 195 |  | 
|---|
| 196 | /* | 
|---|
| 197 | * Private to usb-acpi, all the core needs to know is that | 
|---|
| 198 | * port_dev->location is non-zero when it has been set by the firmware. | 
|---|
| 199 | */ | 
|---|
| 200 | #define USB_ACPI_LOCATION_VALID (1 << 31) | 
|---|
| 201 |  | 
|---|
| 202 | static void | 
|---|
| 203 | usb_acpi_get_connect_type(struct usb_port *port_dev, acpi_handle *handle) | 
|---|
| 204 | { | 
|---|
| 205 | enum usb_port_connect_type connect_type = USB_PORT_CONNECT_TYPE_UNKNOWN; | 
|---|
| 206 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | 
|---|
| 207 | union acpi_object *upc = NULL; | 
|---|
| 208 | struct acpi_pld_info *pld = NULL; | 
|---|
| 209 | acpi_status status; | 
|---|
| 210 |  | 
|---|
| 211 | /* | 
|---|
| 212 | * According to 9.14 in ACPI Spec 6.2. _PLD indicates whether usb port | 
|---|
| 213 | * is user visible and _UPC indicates whether it is connectable. If | 
|---|
| 214 | * the port was visible and connectable, it could be freely connected | 
|---|
| 215 | * and disconnected with USB devices. If no visible and connectable, | 
|---|
| 216 | * a usb device is directly hard-wired to the port. If no visible and | 
|---|
| 217 | * no connectable, the port would be not used. | 
|---|
| 218 | */ | 
|---|
| 219 |  | 
|---|
| 220 | if (acpi_get_physical_device_location(handle, pld: &pld) && pld) | 
|---|
| 221 | port_dev->location = USB_ACPI_LOCATION_VALID | | 
|---|
| 222 | pld->group_token << 8 | pld->group_position; | 
|---|
| 223 |  | 
|---|
| 224 | status = acpi_evaluate_object(object: handle, pathname: "_UPC", NULL, return_object_buffer: &buffer); | 
|---|
| 225 | if (ACPI_FAILURE(status)) | 
|---|
| 226 | goto out; | 
|---|
| 227 |  | 
|---|
| 228 | upc = buffer.pointer; | 
|---|
| 229 | if (!upc || (upc->type != ACPI_TYPE_PACKAGE) || upc->package.count != 4) | 
|---|
| 230 | goto out; | 
|---|
| 231 |  | 
|---|
| 232 | /* UPC states port is connectable */ | 
|---|
| 233 | if (upc->package.elements[0].integer.value) | 
|---|
| 234 | if (!pld) | 
|---|
| 235 | ; /* keep connect_type as unknown */ | 
|---|
| 236 | else if (pld->user_visible) | 
|---|
| 237 | connect_type = USB_PORT_CONNECT_TYPE_HOT_PLUG; | 
|---|
| 238 | else | 
|---|
| 239 | connect_type = USB_PORT_CONNECT_TYPE_HARD_WIRED; | 
|---|
| 240 | else | 
|---|
| 241 | connect_type = USB_PORT_NOT_USED; | 
|---|
| 242 | out: | 
|---|
| 243 | port_dev->connect_type = connect_type; | 
|---|
| 244 | kfree(objp: upc); | 
|---|
| 245 | ACPI_FREE(pld); | 
|---|
| 246 | } | 
|---|
| 247 |  | 
|---|
| 248 | static struct acpi_device * | 
|---|
| 249 | usb_acpi_get_companion_for_port(struct usb_port *port_dev) | 
|---|
| 250 | { | 
|---|
| 251 | struct usb_device *udev; | 
|---|
| 252 | struct acpi_device *adev; | 
|---|
| 253 | acpi_handle *parent_handle; | 
|---|
| 254 | int port1; | 
|---|
| 255 |  | 
|---|
| 256 | /* Get the struct usb_device point of port's hub */ | 
|---|
| 257 | udev = to_usb_device(port_dev->dev.parent->parent); | 
|---|
| 258 |  | 
|---|
| 259 | /* | 
|---|
| 260 | * The root hub ports' parent is the root hub. The non-root-hub | 
|---|
| 261 | * ports' parent is the parent hub port which the hub is | 
|---|
| 262 | * connected to. | 
|---|
| 263 | */ | 
|---|
| 264 | if (!udev->parent) { | 
|---|
| 265 | adev = ACPI_COMPANION(&udev->dev); | 
|---|
| 266 | port1 = usb_hcd_find_raw_port_number(hcd: bus_to_hcd(bus: udev->bus), | 
|---|
| 267 | port1: port_dev->portnum); | 
|---|
| 268 | } else { | 
|---|
| 269 | parent_handle = usb_get_hub_port_acpi_handle(hdev: udev->parent, | 
|---|
| 270 | port1: udev->portnum); | 
|---|
| 271 | if (!parent_handle) | 
|---|
| 272 | return NULL; | 
|---|
| 273 |  | 
|---|
| 274 | adev = acpi_fetch_acpi_dev(handle: parent_handle); | 
|---|
| 275 | port1 = port_dev->portnum; | 
|---|
| 276 | } | 
|---|
| 277 |  | 
|---|
| 278 | return acpi_find_child_by_adr(adev, adr: port1); | 
|---|
| 279 | } | 
|---|
| 280 |  | 
|---|
| 281 | static struct acpi_device * | 
|---|
| 282 | usb_acpi_find_companion_for_port(struct usb_port *port_dev) | 
|---|
| 283 | { | 
|---|
| 284 | struct acpi_device *adev; | 
|---|
| 285 |  | 
|---|
| 286 | adev = usb_acpi_get_companion_for_port(port_dev); | 
|---|
| 287 | if (!adev) | 
|---|
| 288 | return NULL; | 
|---|
| 289 |  | 
|---|
| 290 | usb_acpi_get_connect_type(port_dev, handle: adev->handle); | 
|---|
| 291 |  | 
|---|
| 292 | return adev; | 
|---|
| 293 | } | 
|---|
| 294 |  | 
|---|
| 295 | static struct acpi_device * | 
|---|
| 296 | usb_acpi_find_companion_for_device(struct usb_device *udev) | 
|---|
| 297 | { | 
|---|
| 298 | struct acpi_device *adev; | 
|---|
| 299 | struct usb_port *port_dev; | 
|---|
| 300 | struct usb_hub *hub; | 
|---|
| 301 |  | 
|---|
| 302 | if (!udev->parent) { | 
|---|
| 303 | /* | 
|---|
| 304 | * root hub is only child (_ADR=0) under its parent, the HC. | 
|---|
| 305 | * sysdev pointer is the HC as seen from firmware. | 
|---|
| 306 | */ | 
|---|
| 307 | adev = ACPI_COMPANION(udev->bus->sysdev); | 
|---|
| 308 | return acpi_find_child_device(parent: adev, address: 0, check_children: false); | 
|---|
| 309 | } | 
|---|
| 310 |  | 
|---|
| 311 | hub = usb_hub_to_struct_hub(hdev: udev->parent); | 
|---|
| 312 | if (!hub) | 
|---|
| 313 | return NULL; | 
|---|
| 314 |  | 
|---|
| 315 |  | 
|---|
| 316 | /* Tunneled USB3 devices depend on USB4 Host Interface, set device link to it */ | 
|---|
| 317 | if (udev->speed >= USB_SPEED_SUPER && | 
|---|
| 318 | udev->tunnel_mode != USB_LINK_NATIVE) | 
|---|
| 319 | usb_acpi_add_usb4_devlink(udev); | 
|---|
| 320 |  | 
|---|
| 321 | /* | 
|---|
| 322 | * This is an embedded USB device connected to a port and such | 
|---|
| 323 | * devices share port's ACPI companion. | 
|---|
| 324 | */ | 
|---|
| 325 | port_dev = hub->ports[udev->portnum - 1]; | 
|---|
| 326 | return usb_acpi_get_companion_for_port(port_dev); | 
|---|
| 327 | } | 
|---|
| 328 |  | 
|---|
| 329 | static struct acpi_device *usb_acpi_find_companion(struct device *dev) | 
|---|
| 330 | { | 
|---|
| 331 | /* | 
|---|
| 332 | * The USB hierarchy like following: | 
|---|
| 333 | * | 
|---|
| 334 | * Device (EHC1) | 
|---|
| 335 | *	Device (HUBN) | 
|---|
| 336 | *		Device (PR01) | 
|---|
| 337 | *			Device (PR11) | 
|---|
| 338 | *			Device (PR12) | 
|---|
| 339 | *				Device (FN12) | 
|---|
| 340 | *				Device (FN13) | 
|---|
| 341 | *			Device (PR13) | 
|---|
| 342 | *			... | 
|---|
| 343 | * where HUBN is root hub, and PRNN are USB ports and devices | 
|---|
| 344 | * connected to them, and FNNN are individualk functions for | 
|---|
| 345 | * connected composite USB devices. PRNN and FNNN may contain | 
|---|
| 346 | * _CRS and other methods describing sideband resources for | 
|---|
| 347 | * the connected device. | 
|---|
| 348 | * | 
|---|
| 349 | * On the kernel side both root hub and embedded USB devices are | 
|---|
| 350 | * represented as instances of usb_device structure, and ports | 
|---|
| 351 | * are represented as usb_port structures, so the whole process | 
|---|
| 352 | * is split into 2 parts: finding companions for devices and | 
|---|
| 353 | * finding companions for ports. | 
|---|
| 354 | * | 
|---|
| 355 | * Note that we do not handle individual functions of composite | 
|---|
| 356 | * devices yet, for that we would need to assign companions to | 
|---|
| 357 | * devices corresponding to USB interfaces. | 
|---|
| 358 | */ | 
|---|
| 359 | if (is_usb_device(dev)) | 
|---|
| 360 | return usb_acpi_find_companion_for_device(to_usb_device(dev)); | 
|---|
| 361 | else if (is_usb_port(dev)) | 
|---|
| 362 | return usb_acpi_find_companion_for_port(to_usb_port(dev)); | 
|---|
| 363 |  | 
|---|
| 364 | return NULL; | 
|---|
| 365 | } | 
|---|
| 366 |  | 
|---|
| 367 | static bool usb_acpi_bus_match(struct device *dev) | 
|---|
| 368 | { | 
|---|
| 369 | return is_usb_device(dev) || is_usb_port(dev); | 
|---|
| 370 | } | 
|---|
| 371 |  | 
|---|
| 372 | static struct acpi_bus_type usb_acpi_bus = { | 
|---|
| 373 | .name = "USB", | 
|---|
| 374 | .match = usb_acpi_bus_match, | 
|---|
| 375 | .find_companion = usb_acpi_find_companion, | 
|---|
| 376 | }; | 
|---|
| 377 |  | 
|---|
| 378 | int usb_acpi_register(void) | 
|---|
| 379 | { | 
|---|
| 380 | return register_acpi_bus_type(&usb_acpi_bus); | 
|---|
| 381 | } | 
|---|
| 382 |  | 
|---|
| 383 | void usb_acpi_unregister(void) | 
|---|
| 384 | { | 
|---|
| 385 | unregister_acpi_bus_type(&usb_acpi_bus); | 
|---|
| 386 | } | 
|---|
| 387 |  | 
|---|