summaryrefslogtreecommitdiff
path: root/drivers/thunderbolt/switch.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/thunderbolt/switch.c')
-rw-r--r--drivers/thunderbolt/switch.c61
1 files changed, 60 insertions, 1 deletions
diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c
index da54ace4dd2f..25758671ddf4 100644
--- a/drivers/thunderbolt/switch.c
+++ b/drivers/thunderbolt/switch.c
@@ -716,6 +716,13 @@ static int tb_switch_set_authorized(struct tb_switch *sw, unsigned int val)
if (sw->authorized)
goto unlock;
+ /*
+ * Make sure there is no PCIe rescan ongoing when a new PCIe
+ * tunnel is created. Otherwise the PCIe rescan code might find
+ * the new tunnel too early.
+ */
+ pci_lock_rescan_remove();
+
switch (val) {
/* Approve switch */
case 1:
@@ -735,6 +742,8 @@ static int tb_switch_set_authorized(struct tb_switch *sw, unsigned int val)
break;
}
+ pci_unlock_rescan_remove();
+
if (!ret) {
sw->authorized = val;
/* Notify status change to the userspace */
@@ -766,6 +775,15 @@ static ssize_t authorized_store(struct device *dev,
}
static DEVICE_ATTR_RW(authorized);
+static ssize_t boot_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct tb_switch *sw = tb_to_switch(dev);
+
+ return sprintf(buf, "%u\n", sw->boot);
+}
+static DEVICE_ATTR_RO(boot);
+
static ssize_t device_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
@@ -942,6 +960,7 @@ static DEVICE_ATTR_RO(unique_id);
static struct attribute *switch_attrs[] = {
&dev_attr_authorized.attr,
+ &dev_attr_boot.attr,
&dev_attr_device.attr,
&dev_attr_device_name.attr,
&dev_attr_key.attr,
@@ -970,6 +989,10 @@ static umode_t switch_attr_is_visible(struct kobject *kobj,
if (sw->dma_port)
return attr->mode;
return 0;
+ } else if (attr == &dev_attr_boot.attr) {
+ if (tb_route(sw))
+ return attr->mode;
+ return 0;
}
return sw->safe_mode ? 0 : attr->mode;
@@ -1028,6 +1051,9 @@ static int tb_switch_get_generation(struct tb_switch *sw)
case PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_4C_BRIDGE:
case PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_C_2C_BRIDGE:
case PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_C_4C_BRIDGE:
+ case PCI_DEVICE_ID_INTEL_TITAN_RIDGE_2C_BRIDGE:
+ case PCI_DEVICE_ID_INTEL_TITAN_RIDGE_4C_BRIDGE:
+ case PCI_DEVICE_ID_INTEL_TITAN_RIDGE_DD_BRIDGE:
return 3;
default:
@@ -1470,6 +1496,7 @@ struct tb_sw_lookup {
u8 link;
u8 depth;
const uuid_t *uuid;
+ u64 route;
};
static int tb_switch_match(struct device *dev, void *data)
@@ -1485,6 +1512,11 @@ static int tb_switch_match(struct device *dev, void *data)
if (lookup->uuid)
return !memcmp(sw->uuid, lookup->uuid, sizeof(*lookup->uuid));
+ if (lookup->route) {
+ return sw->config.route_lo == lower_32_bits(lookup->route) &&
+ sw->config.route_hi == upper_32_bits(lookup->route);
+ }
+
/* Root switch is matched only by depth */
if (!lookup->depth)
return !sw->depth;
@@ -1519,7 +1551,7 @@ struct tb_switch *tb_switch_find_by_link_depth(struct tb *tb, u8 link, u8 depth)
}
/**
- * tb_switch_find_by_link_depth() - Find switch by UUID
+ * tb_switch_find_by_uuid() - Find switch by UUID
* @tb: Domain the switch belongs
* @uuid: UUID to look for
*
@@ -1542,6 +1574,33 @@ struct tb_switch *tb_switch_find_by_uuid(struct tb *tb, const uuid_t *uuid)
return NULL;
}
+/**
+ * tb_switch_find_by_route() - Find switch by route string
+ * @tb: Domain the switch belongs
+ * @route: Route string to look for
+ *
+ * Returned switch has reference count increased so the caller needs to
+ * call tb_switch_put() when done with the switch.
+ */
+struct tb_switch *tb_switch_find_by_route(struct tb *tb, u64 route)
+{
+ struct tb_sw_lookup lookup;
+ struct device *dev;
+
+ if (!route)
+ return tb_switch_get(tb->root_switch);
+
+ memset(&lookup, 0, sizeof(lookup));
+ lookup.tb = tb;
+ lookup.route = route;
+
+ dev = bus_find_device(&tb_bus_type, NULL, &lookup, tb_switch_match);
+ if (dev)
+ return tb_to_switch(dev);
+
+ return NULL;
+}
+
void tb_switch_exit(void)
{
ida_destroy(&nvm_ida);