xref: /OK3568_Linux_fs/kernel/drivers/thunderbolt/acpi.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * ACPI support
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2020, Intel Corporation
6*4882a593Smuzhiyun  * Author: Mika Westerberg <mika.westerberg@linux.intel.com>
7*4882a593Smuzhiyun  */
8*4882a593Smuzhiyun 
9*4882a593Smuzhiyun #include <linux/acpi.h>
10*4882a593Smuzhiyun #include <linux/pm_runtime.h>
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun #include "tb.h"
13*4882a593Smuzhiyun 
tb_acpi_add_link(acpi_handle handle,u32 level,void * data,void ** return_value)14*4882a593Smuzhiyun static acpi_status tb_acpi_add_link(acpi_handle handle, u32 level, void *data,
15*4882a593Smuzhiyun 				    void **return_value)
16*4882a593Smuzhiyun {
17*4882a593Smuzhiyun 	struct fwnode_reference_args args;
18*4882a593Smuzhiyun 	struct fwnode_handle *fwnode;
19*4882a593Smuzhiyun 	struct tb_nhi *nhi = data;
20*4882a593Smuzhiyun 	struct acpi_device *adev;
21*4882a593Smuzhiyun 	struct pci_dev *pdev;
22*4882a593Smuzhiyun 	struct device *dev;
23*4882a593Smuzhiyun 	int ret;
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun 	if (acpi_bus_get_device(handle, &adev))
26*4882a593Smuzhiyun 		return AE_OK;
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun 	fwnode = acpi_fwnode_handle(adev);
29*4882a593Smuzhiyun 	ret = fwnode_property_get_reference_args(fwnode, "usb4-host-interface",
30*4882a593Smuzhiyun 						 NULL, 0, 0, &args);
31*4882a593Smuzhiyun 	if (ret)
32*4882a593Smuzhiyun 		return AE_OK;
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun 	/* It needs to reference this NHI */
35*4882a593Smuzhiyun 	if (nhi->pdev->dev.fwnode != args.fwnode)
36*4882a593Smuzhiyun 		goto out_put;
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun 	/*
39*4882a593Smuzhiyun 	 * Try to find physical device walking upwards to the hierarcy.
40*4882a593Smuzhiyun 	 * We need to do this because the xHCI driver might not yet be
41*4882a593Smuzhiyun 	 * bound so the USB3 SuperSpeed ports are not yet created.
42*4882a593Smuzhiyun 	 */
43*4882a593Smuzhiyun 	dev = acpi_get_first_physical_node(adev);
44*4882a593Smuzhiyun 	while (!dev) {
45*4882a593Smuzhiyun 		adev = adev->parent;
46*4882a593Smuzhiyun 		if (!adev)
47*4882a593Smuzhiyun 			break;
48*4882a593Smuzhiyun 		dev = acpi_get_first_physical_node(adev);
49*4882a593Smuzhiyun 	}
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun 	if (!dev)
52*4882a593Smuzhiyun 		goto out_put;
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun 	/*
55*4882a593Smuzhiyun 	 * Check that the device is PCIe. This is because USB3
56*4882a593Smuzhiyun 	 * SuperSpeed ports have this property and they are not power
57*4882a593Smuzhiyun 	 * managed with the xHCI and the SuperSpeed hub so we create the
58*4882a593Smuzhiyun 	 * link from xHCI instead.
59*4882a593Smuzhiyun 	 */
60*4882a593Smuzhiyun 	while (dev && !dev_is_pci(dev))
61*4882a593Smuzhiyun 		dev = dev->parent;
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun 	if (!dev)
64*4882a593Smuzhiyun 		goto out_put;
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun 	/*
67*4882a593Smuzhiyun 	 * Check that this actually matches the type of device we
68*4882a593Smuzhiyun 	 * expect. It should either be xHCI or PCIe root/downstream
69*4882a593Smuzhiyun 	 * port.
70*4882a593Smuzhiyun 	 */
71*4882a593Smuzhiyun 	pdev = to_pci_dev(dev);
72*4882a593Smuzhiyun 	if (pdev->class == PCI_CLASS_SERIAL_USB_XHCI ||
73*4882a593Smuzhiyun 	    (pci_is_pcie(pdev) &&
74*4882a593Smuzhiyun 		(pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT ||
75*4882a593Smuzhiyun 		 pci_pcie_type(pdev) == PCI_EXP_TYPE_DOWNSTREAM))) {
76*4882a593Smuzhiyun 		const struct device_link *link;
77*4882a593Smuzhiyun 
78*4882a593Smuzhiyun 		/*
79*4882a593Smuzhiyun 		 * Make them both active first to make sure the NHI does
80*4882a593Smuzhiyun 		 * not runtime suspend before the consumer. The
81*4882a593Smuzhiyun 		 * pm_runtime_put() below then allows the consumer to
82*4882a593Smuzhiyun 		 * runtime suspend again (which then allows NHI runtime
83*4882a593Smuzhiyun 		 * suspend too now that the device link is established).
84*4882a593Smuzhiyun 		 */
85*4882a593Smuzhiyun 		pm_runtime_get_sync(&pdev->dev);
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun 		link = device_link_add(&pdev->dev, &nhi->pdev->dev,
88*4882a593Smuzhiyun 				       DL_FLAG_AUTOREMOVE_SUPPLIER |
89*4882a593Smuzhiyun 				       DL_FLAG_RPM_ACTIVE |
90*4882a593Smuzhiyun 				       DL_FLAG_PM_RUNTIME);
91*4882a593Smuzhiyun 		if (link) {
92*4882a593Smuzhiyun 			dev_dbg(&nhi->pdev->dev, "created link from %s\n",
93*4882a593Smuzhiyun 				dev_name(&pdev->dev));
94*4882a593Smuzhiyun 		} else {
95*4882a593Smuzhiyun 			dev_warn(&nhi->pdev->dev, "device link creation from %s failed\n",
96*4882a593Smuzhiyun 				 dev_name(&pdev->dev));
97*4882a593Smuzhiyun 		}
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun 		pm_runtime_put(&pdev->dev);
100*4882a593Smuzhiyun 	}
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun out_put:
103*4882a593Smuzhiyun 	fwnode_handle_put(args.fwnode);
104*4882a593Smuzhiyun 	return AE_OK;
105*4882a593Smuzhiyun }
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun /**
108*4882a593Smuzhiyun  * tb_acpi_add_links() - Add device links based on ACPI description
109*4882a593Smuzhiyun  * @nhi: Pointer to NHI
110*4882a593Smuzhiyun  *
111*4882a593Smuzhiyun  * Goes over ACPI namespace finding tunneled ports that reference to
112*4882a593Smuzhiyun  * @nhi ACPI node. For each reference a device link is added. The link
113*4882a593Smuzhiyun  * is automatically removed by the driver core.
114*4882a593Smuzhiyun  */
tb_acpi_add_links(struct tb_nhi * nhi)115*4882a593Smuzhiyun void tb_acpi_add_links(struct tb_nhi *nhi)
116*4882a593Smuzhiyun {
117*4882a593Smuzhiyun 	acpi_status status;
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun 	if (!has_acpi_companion(&nhi->pdev->dev))
120*4882a593Smuzhiyun 		return;
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun 	/*
123*4882a593Smuzhiyun 	 * Find all devices that have usb4-host-controller interface
124*4882a593Smuzhiyun 	 * property that references to this NHI.
125*4882a593Smuzhiyun 	 */
126*4882a593Smuzhiyun 	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, 32,
127*4882a593Smuzhiyun 				     tb_acpi_add_link, NULL, nhi, NULL);
128*4882a593Smuzhiyun 	if (ACPI_FAILURE(status))
129*4882a593Smuzhiyun 		dev_warn(&nhi->pdev->dev, "failed to enumerate tunneled ports\n");
130*4882a593Smuzhiyun }
131