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: stable@vger.kernel.org Tested-by: Ron Lee <ron.lee@intel.com> Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com> Link: https://lore.kernel.org/r/20230116142216.1141605-7-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Родитель
0522b9a165
Коммит
cd702d18c8
|
@ -37,6 +37,71 @@ bool usb_acpi_power_manageable(struct usb_device *hdev, int index)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(usb_acpi_power_manageable);
|
||||
|
||||
#define UUID_USB_CONTROLLER_DSM "ce2ee385-00e6-48cb-9f05-2edb927c4899"
|
||||
#define USB_DSM_DISABLE_U1_U2_FOR_PORT 5
|
||||
|
||||
/**
|
||||
* usb_acpi_port_lpm_incapable - check if lpm should be disabled for a port.
|
||||
* @hdev: USB device belonging to the usb hub
|
||||
* @index: zero based port index
|
||||
*
|
||||
* Some USB3 ports may not support USB3 link power management U1/U2 states
|
||||
* due to different retimer setup. ACPI provides _DSM method which returns 0x01
|
||||
* if U1 and U2 states should be disabled. Evaluate _DSM with:
|
||||
* Arg0: UUID = ce2ee385-00e6-48cb-9f05-2edb927c4899
|
||||
* Arg1: Revision ID = 0
|
||||
* Arg2: Function Index = 5
|
||||
* Arg3: (empty)
|
||||
*
|
||||
* Return 1 if USB3 port is LPM incapable, negative on error, otherwise 0
|
||||
*/
|
||||
|
||||
int usb_acpi_port_lpm_incapable(struct usb_device *hdev, int index)
|
||||
{
|
||||
union acpi_object *obj;
|
||||
acpi_handle port_handle;
|
||||
int port1 = index + 1;
|
||||
guid_t guid;
|
||||
int ret;
|
||||
|
||||
ret = guid_parse(UUID_USB_CONTROLLER_DSM, &guid);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
port_handle = usb_get_hub_port_acpi_handle(hdev, port1);
|
||||
if (!port_handle) {
|
||||
dev_dbg(&hdev->dev, "port-%d no acpi handle\n", port1);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!acpi_check_dsm(port_handle, &guid, 0,
|
||||
BIT(USB_DSM_DISABLE_U1_U2_FOR_PORT))) {
|
||||
dev_dbg(&hdev->dev, "port-%d no _DSM function %d\n",
|
||||
port1, USB_DSM_DISABLE_U1_U2_FOR_PORT);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
obj = acpi_evaluate_dsm(port_handle, &guid, 0,
|
||||
USB_DSM_DISABLE_U1_U2_FOR_PORT, NULL);
|
||||
|
||||
if (!obj)
|
||||
return -ENODEV;
|
||||
|
||||
if (obj->type != ACPI_TYPE_INTEGER) {
|
||||
dev_dbg(&hdev->dev, "evaluate port-%d _DSM failed\n", port1);
|
||||
ACPI_FREE(obj);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (obj->integer.value == 0x01)
|
||||
ret = 1;
|
||||
|
||||
ACPI_FREE(obj);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_acpi_port_lpm_incapable);
|
||||
|
||||
/**
|
||||
* usb_acpi_set_power_state - control usb port's power via acpi power
|
||||
* resource
|
||||
|
|
|
@ -774,11 +774,14 @@ extern struct device *usb_intf_get_dma_device(struct usb_interface *intf);
|
|||
extern int usb_acpi_set_power_state(struct usb_device *hdev, int index,
|
||||
bool enable);
|
||||
extern bool usb_acpi_power_manageable(struct usb_device *hdev, int index);
|
||||
extern int usb_acpi_port_lpm_incapable(struct usb_device *hdev, int index);
|
||||
#else
|
||||
static inline int usb_acpi_set_power_state(struct usb_device *hdev, int index,
|
||||
bool enable) { return 0; }
|
||||
static inline bool usb_acpi_power_manageable(struct usb_device *hdev, int index)
|
||||
{ return true; }
|
||||
static inline int usb_acpi_port_lpm_incapable(struct usb_device *hdev, int index)
|
||||
{ return 0; }
|
||||
#endif
|
||||
|
||||
/* USB autosuspend and autoresume */
|
||||
|
|
Загрузка…
Ссылка в новой задаче