Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

thunderbolt: Add Thunderbolt/USB4 <-> USB3 match function

This function checks whether given USB4 port device matches with USB3.x
port device, using ACPI _DSD property.

It is designed to be used by component framework to match
USB4 ports with Type-C ports they are connected to.

Also, added USB4 config stub in case mapping function is not reachable.

Signed-off-by: Alan Borzeszkowski <alan.borzeszkowski@linux.intel.com>
Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>

authored by

Alan Borzeszkowski and committed by
Mika Westerberg
e80c2359 f93b5e24

+66 -8
+48 -8
drivers/thunderbolt/usb4_port.c
··· 105 105 tb_acpi_power_off_retimers(port); 106 106 } 107 107 108 + /** 109 + * usb4_usb3_port_match() - Matches USB4 port device with USB 3.x port device 110 + * @usb4_port_dev: USB4 port device 111 + * @usb3_port_fwnode: USB 3.x port firmware node 112 + * 113 + * Checks if USB 3.x port @usb3_port_fwnode is tunneled through USB4 port @usb4_port_dev. 114 + * Returns true if match is found, false otherwise. 115 + * 116 + * Function is designed to be used with component framework (component_match_add). 117 + */ 118 + bool usb4_usb3_port_match(struct device *usb4_port_dev, 119 + const struct fwnode_handle *usb3_port_fwnode) 120 + { 121 + struct fwnode_handle *nhi_fwnode __free(fwnode_handle) = NULL; 122 + struct usb4_port *usb4; 123 + struct tb_switch *sw; 124 + struct tb_nhi *nhi; 125 + u8 usb4_port_num; 126 + struct tb *tb; 127 + 128 + usb4 = tb_to_usb4_port_device(usb4_port_dev); 129 + if (!usb4) 130 + return false; 131 + 132 + sw = usb4->port->sw; 133 + tb = sw->tb; 134 + nhi = tb->nhi; 135 + 136 + nhi_fwnode = fwnode_find_reference(usb3_port_fwnode, "usb4-host-interface", 0); 137 + if (IS_ERR(nhi_fwnode)) 138 + return false; 139 + 140 + /* Check if USB3 fwnode references same NHI where USB4 port resides */ 141 + if (!device_match_fwnode(&nhi->pdev->dev, nhi_fwnode)) 142 + return false; 143 + 144 + if (fwnode_property_read_u8(usb3_port_fwnode, "usb4-port-number", &usb4_port_num)) 145 + return false; 146 + 147 + return usb4_port_index(sw, usb4->port) == usb4_port_num; 148 + } 149 + EXPORT_SYMBOL_GPL(usb4_usb3_port_match); 150 + 108 151 static ssize_t offline_show(struct device *dev, 109 152 struct device_attribute *attr, char *buf) 110 153 { ··· 319 276 return ERR_PTR(ret); 320 277 } 321 278 322 - if (dev_fwnode(&usb4->dev)) { 323 - ret = component_add(&usb4->dev, &connector_ops); 324 - if (ret) { 325 - dev_err(&usb4->dev, "failed to add component\n"); 326 - device_unregister(&usb4->dev); 327 - } 279 + ret = component_add(&usb4->dev, &connector_ops); 280 + if (ret) { 281 + dev_err(&usb4->dev, "failed to add component\n"); 282 + device_unregister(&usb4->dev); 328 283 } 329 284 330 285 if (!tb_is_upstream_port(port)) ··· 347 306 */ 348 307 void usb4_port_device_remove(struct usb4_port *usb4) 349 308 { 350 - if (dev_fwnode(&usb4->dev)) 351 - component_del(&usb4->dev, &connector_ops); 309 + component_del(&usb4->dev, &connector_ops); 352 310 device_unregister(&usb4->dev); 353 311 } 354 312
+18
include/linux/thunderbolt.h
··· 11 11 #ifndef THUNDERBOLT_H_ 12 12 #define THUNDERBOLT_H_ 13 13 14 + #include <linux/types.h> 15 + 16 + struct fwnode_handle; 17 + struct device; 18 + 19 + #if IS_REACHABLE(CONFIG_USB4) 20 + 14 21 #include <linux/device.h> 15 22 #include <linux/idr.h> 16 23 #include <linux/list.h> ··· 680 673 { 681 674 return &ring->nhi->pdev->dev; 682 675 } 676 + 677 + bool usb4_usb3_port_match(struct device *usb4_port_dev, 678 + const struct fwnode_handle *usb3_port_fwnode); 679 + 680 + #else /* CONFIG_USB4 */ 681 + static inline bool usb4_usb3_port_match(struct device *usb4_port_dev, 682 + const struct fwnode_handle *usb3_port_fwnode) 683 + { 684 + return false; 685 + } 686 + #endif /* CONFIG_USB4 */ 683 687 684 688 #endif /* THUNDERBOLT_H_ */