Skip to content

Commit cd702d1

Browse files
matnymangregkh
authored andcommitted
usb: acpi: add helper to check port lpm capability using acpi _DSM
Add a helper to evaluate ACPI usb device specific method (_DSM) provided in case the USB3 port shouldn't enter U1 and U2 link states. This _DSM was added as port specific retimer configuration may lead to exit latencies growing beyond U1/U2 exit limits, and OS needs a way to find which ports can't support U1/U2 link power management states. This _DSM is also used by windows: Link: https://docs.microsoft.com/en-us/windows-hardware/drivers/bringup/usb-device-specific-method---dsm- Some patch issues found in testing resolved by Ron Lee Cc: [email protected] Tested-by: Ron Lee <[email protected]> Signed-off-by: Mathias Nyman <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 0522b9a commit cd702d1

File tree

2 files changed

+68
-0
lines changed

2 files changed

+68
-0
lines changed

drivers/usb/core/usb-acpi.c

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,71 @@ bool usb_acpi_power_manageable(struct usb_device *hdev, int index)
3737
}
3838
EXPORT_SYMBOL_GPL(usb_acpi_power_manageable);
3939

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, &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(port_handle, &guid, 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(port_handle, &guid, 0,
85+
USB_DSM_DISABLE_U1_U2_FOR_PORT, NULL);
86+
87+
if (!obj)
88+
return -ENODEV;
89+
90+
if (obj->type != ACPI_TYPE_INTEGER) {
91+
dev_dbg(&hdev->dev, "evaluate port-%d _DSM failed\n", port1);
92+
ACPI_FREE(obj);
93+
return -EINVAL;
94+
}
95+
96+
if (obj->integer.value == 0x01)
97+
ret = 1;
98+
99+
ACPI_FREE(obj);
100+
101+
return ret;
102+
}
103+
EXPORT_SYMBOL_GPL(usb_acpi_port_lpm_incapable);
104+
40105
/**
41106
* usb_acpi_set_power_state - control usb port's power via acpi power
42107
* resource

include/linux/usb.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -774,11 +774,14 @@ extern struct device *usb_intf_get_dma_device(struct usb_interface *intf);
774774
extern int usb_acpi_set_power_state(struct usb_device *hdev, int index,
775775
bool enable);
776776
extern bool usb_acpi_power_manageable(struct usb_device *hdev, int index);
777+
extern int usb_acpi_port_lpm_incapable(struct usb_device *hdev, int index);
777778
#else
778779
static inline int usb_acpi_set_power_state(struct usb_device *hdev, int index,
779780
bool enable) { return 0; }
780781
static inline bool usb_acpi_power_manageable(struct usb_device *hdev, int index)
781782
{ return true; }
783+
static inline int usb_acpi_port_lpm_incapable(struct usb_device *hdev, int index)
784+
{ return 0; }
782785
#endif
783786

784787
/* USB autosuspend and autoresume */

0 commit comments

Comments
 (0)