Skip to content

Commit 6d392d8

Browse files
westerirafaeljw
authored andcommitted
ACPI: Run USB4 _OSC() first with query bit set
The platform can deny certain tunneling from the OS and it does that by clearing the control bits it does not want the OS to get and returning with OSC_CAPABILITIES_MASK_ERROR bit set. Currently we do not handle this properly so if this happens, for example when the platform denies PCIe tunneling, we just fail the whole negotiation and revert back to what the Thunderbolt driver is doing to figure out whether the controller is running firmware connection manager or not. However, we should honor what the platform returns. For this reason run the USB4 _OSC() first with query bit set, and then use the returned control double word (that may contain some of the bits cleared by the platform) and run it second time with query bit clear. While there, remove an extra space from the assignment of the control double word. Reported-by: NaamaX Shachar <naamax.shachar@intel.com> Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
1 parent 98b1cc8 commit 6d392d8

File tree

1 file changed

+29
-3
lines changed

1 file changed

+29
-3
lines changed

drivers/acpi/bus.c

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,7 @@ static void acpi_bus_decode_usb_osc(const char *msg, u32 bits)
408408
static u8 sb_usb_uuid_str[] = "23A0D13A-26AB-486C-9C5F-0FFA525A575A";
409409
static void acpi_bus_osc_negotiate_usb_control(void)
410410
{
411-
u32 capbuf[3];
411+
u32 capbuf[3], *capbuf_ret;
412412
struct acpi_osc_context context = {
413413
.uuid_str = sb_usb_uuid_str,
414414
.rev = 1,
@@ -428,7 +428,12 @@ static void acpi_bus_osc_negotiate_usb_control(void)
428428
control = OSC_USB_USB3_TUNNELING | OSC_USB_DP_TUNNELING |
429429
OSC_USB_PCIE_TUNNELING | OSC_USB_XDOMAIN;
430430

431-
capbuf[OSC_QUERY_DWORD] = 0;
431+
/*
432+
* Run _OSC first with query bit set, trying to get control over
433+
* all tunneling. The platform can then clear out bits in the
434+
* control dword that it does not want to grant to the OS.
435+
*/
436+
capbuf[OSC_QUERY_DWORD] = OSC_QUERY_ENABLE;
432437
capbuf[OSC_SUPPORT_DWORD] = 0;
433438
capbuf[OSC_CONTROL_DWORD] = control;
434439

@@ -441,8 +446,29 @@ static void acpi_bus_osc_negotiate_usb_control(void)
441446
goto out_free;
442447
}
443448

449+
/*
450+
* Run _OSC again now with query bit clear and the control dword
451+
* matching what the platform granted (which may not have all
452+
* the control bits set).
453+
*/
454+
capbuf_ret = context.ret.pointer;
455+
456+
capbuf[OSC_QUERY_DWORD] = 0;
457+
capbuf[OSC_CONTROL_DWORD] = capbuf_ret[OSC_CONTROL_DWORD];
458+
459+
kfree(context.ret.pointer);
460+
461+
status = acpi_run_osc(handle, &context);
462+
if (ACPI_FAILURE(status))
463+
return;
464+
465+
if (context.ret.length != sizeof(capbuf)) {
466+
pr_info("USB4 _OSC: returned invalid length buffer\n");
467+
goto out_free;
468+
}
469+
444470
osc_sb_native_usb4_control =
445-
control & acpi_osc_ctx_get_pci_control(&context);
471+
control & acpi_osc_ctx_get_pci_control(&context);
446472

447473
acpi_bus_decode_usb_osc("USB4 _OSC: OS supports", control);
448474
acpi_bus_decode_usb_osc("USB4 _OSC: OS controls",

0 commit comments

Comments
 (0)