]>
Commit | Line | Data |
---|---|---|
cff3d0cc GKH |
1 | From ed18c5fa945768a9bec994e786edbbbc7695acf6 Mon Sep 17 00:00:00 2001 |
2 | From: Mathias Nyman <mathias.nyman@linux.intel.com> | |
3 | Date: Fri, 2 Jun 2017 16:36:26 +0300 | |
4 | Subject: usb: optimize acpi companion search for usb port devices | |
5 | ||
6 | From: Mathias Nyman <mathias.nyman@linux.intel.com> | |
7 | ||
8 | commit ed18c5fa945768a9bec994e786edbbbc7695acf6 upstream. | |
9 | ||
10 | This optimization significantly reduces xhci driver load time. | |
11 | ||
12 | In ACPI tables the acpi companion port devices are children of | |
13 | the hub device. The port devices are identified by their port number | |
14 | returned by the ACPI _ADR method. | |
15 | _ADR 0 is reserved for the root hub device. | |
16 | ||
17 | The current implementation to find a acpi companion port device | |
18 | loops through all acpi port devices under that parent hub, evaluating | |
19 | their _ADR method each time a new port device is added. | |
20 | ||
21 | for a xHC controller with 25 ports under its roothub it | |
22 | will end up invoking ACPI bytecode 625 times before all ports | |
23 | are ready, making it really slow. | |
24 | ||
25 | The _ADR values are already read and cached earler. So instead of | |
26 | running the bytecode again we can check the cached _ADR value first, | |
27 | and then fall back to the old way. | |
28 | ||
29 | As one of the more significant changes, the xhci load time on | |
30 | Intel kabylake reduced by 70%, (28ms) from | |
31 | initcall xhci_pci_init+0x0/0x49 returned 0 after 39537 usecs | |
32 | to | |
33 | initcall xhci_pci_init+0x0/0x49 returned 0 after 11270 usecs | |
34 | ||
35 | Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com> | |
36 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
37 | ||
38 | --- | |
39 | drivers/usb/core/usb-acpi.c | 26 +++++++++++++++++++++++--- | |
40 | 1 file changed, 23 insertions(+), 3 deletions(-) | |
41 | ||
42 | --- a/drivers/usb/core/usb-acpi.c | |
43 | +++ b/drivers/usb/core/usb-acpi.c | |
44 | @@ -127,6 +127,22 @@ out: | |
45 | */ | |
46 | #define USB_ACPI_LOCATION_VALID (1 << 31) | |
47 | ||
48 | +static struct acpi_device *usb_acpi_find_port(struct acpi_device *parent, | |
49 | + int raw) | |
50 | +{ | |
51 | + struct acpi_device *adev; | |
52 | + | |
53 | + if (!parent) | |
54 | + return NULL; | |
55 | + | |
56 | + list_for_each_entry(adev, &parent->children, node) { | |
57 | + if (acpi_device_adr(adev) == raw) | |
58 | + return adev; | |
59 | + } | |
60 | + | |
61 | + return acpi_find_child_device(parent, raw, false); | |
62 | +} | |
63 | + | |
64 | static struct acpi_device *usb_acpi_find_companion(struct device *dev) | |
65 | { | |
66 | struct usb_device *udev; | |
67 | @@ -174,8 +190,10 @@ static struct acpi_device *usb_acpi_find | |
68 | int raw; | |
69 | ||
70 | raw = usb_hcd_find_raw_port_number(hcd, port1); | |
71 | - adev = acpi_find_child_device(ACPI_COMPANION(&udev->dev), | |
72 | - raw, false); | |
73 | + | |
74 | + adev = usb_acpi_find_port(ACPI_COMPANION(&udev->dev), | |
75 | + raw); | |
76 | + | |
77 | if (!adev) | |
78 | return NULL; | |
79 | } else { | |
80 | @@ -186,7 +204,9 @@ static struct acpi_device *usb_acpi_find | |
81 | return NULL; | |
82 | ||
83 | acpi_bus_get_device(parent_handle, &adev); | |
84 | - adev = acpi_find_child_device(adev, port1, false); | |
85 | + | |
86 | + adev = usb_acpi_find_port(adev, port1); | |
87 | + | |
88 | if (!adev) | |
89 | return NULL; | |
90 | } |