Merge tag 'thunderbolt-for-v5.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel...
[sfrench/cifs-2.6.git] / drivers / thunderbolt / switch.c
index 2a95b4ce06c0b9c765e0d39475c5ba0b09991a70..e73cd296db7ef5497368b71935c147c09d3a0701 100644 (file)
@@ -626,28 +626,6 @@ int tb_port_add_nfc_credits(struct tb_port *port, int credits)
                             TB_CFG_PORT, ADP_CS_4, 1);
 }
 
-/**
- * tb_port_set_initial_credits() - Set initial port link credits allocated
- * @port: Port to set the initial credits
- * @credits: Number of credits to to allocate
- *
- * Set initial credits value to be used for ingress shared buffering.
- */
-int tb_port_set_initial_credits(struct tb_port *port, u32 credits)
-{
-       u32 data;
-       int ret;
-
-       ret = tb_port_read(port, &data, TB_CFG_PORT, ADP_CS_5, 1);
-       if (ret)
-               return ret;
-
-       data &= ~ADP_CS_5_LCA_MASK;
-       data |= (credits << ADP_CS_5_LCA_SHIFT) & ADP_CS_5_LCA_MASK;
-
-       return tb_port_write(port, &data, TB_CFG_PORT, ADP_CS_5, 1);
-}
-
 /**
  * tb_port_clear_counter() - clear a counter in TB_CFG_COUNTER
  * @port: Port whose counters to clear
@@ -1331,7 +1309,7 @@ int tb_switch_reset(struct tb_switch *sw)
                              TB_CFG_SWITCH, 2, 2);
        if (res.err)
                return res.err;
-       res = tb_cfg_reset(sw->tb->ctl, tb_route(sw), TB_CFG_DEFAULT_TIMEOUT);
+       res = tb_cfg_reset(sw->tb->ctl, tb_route(sw));
        if (res.err > 0)
                return -EIO;
        return res.err;
@@ -1762,6 +1740,18 @@ static struct attribute *switch_attrs[] = {
        NULL,
 };
 
+static bool has_port(const struct tb_switch *sw, enum tb_port_type type)
+{
+       const struct tb_port *port;
+
+       tb_switch_for_each_port(sw, port) {
+               if (!port->disabled && port->config.type == type)
+                       return true;
+       }
+
+       return false;
+}
+
 static umode_t switch_attr_is_visible(struct kobject *kobj,
                                      struct attribute *attr, int n)
 {
@@ -1770,7 +1760,8 @@ static umode_t switch_attr_is_visible(struct kobject *kobj,
 
        if (attr == &dev_attr_authorized.attr) {
                if (sw->tb->security_level == TB_SECURITY_NOPCIE ||
-                   sw->tb->security_level == TB_SECURITY_DPONLY)
+                   sw->tb->security_level == TB_SECURITY_DPONLY ||
+                   !has_port(sw, TB_TYPE_PCIE_UP))
                        return 0;
        } else if (attr == &dev_attr_device.attr) {
                if (!sw->device)
@@ -1849,6 +1840,39 @@ static void tb_switch_release(struct device *dev)
        kfree(sw);
 }
 
+static int tb_switch_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+       struct tb_switch *sw = tb_to_switch(dev);
+       const char *type;
+
+       if (sw->config.thunderbolt_version == USB4_VERSION_1_0) {
+               if (add_uevent_var(env, "USB4_VERSION=1.0"))
+                       return -ENOMEM;
+       }
+
+       if (!tb_route(sw)) {
+               type = "host";
+       } else {
+               const struct tb_port *port;
+               bool hub = false;
+
+               /* Device is hub if it has any downstream ports */
+               tb_switch_for_each_port(sw, port) {
+                       if (!port->disabled && !tb_is_upstream_port(port) &&
+                            tb_port_is_null(port)) {
+                               hub = true;
+                               break;
+                       }
+               }
+
+               type = hub ? "hub" : "device";
+       }
+
+       if (add_uevent_var(env, "USB4_TYPE=%s", type))
+               return -ENOMEM;
+       return 0;
+}
+
 /*
  * Currently only need to provide the callbacks. Everything else is handled
  * in the connection manager.
@@ -1882,6 +1906,7 @@ static const struct dev_pm_ops tb_switch_pm_ops = {
 struct device_type tb_switch_type = {
        .name = "thunderbolt_device",
        .release = tb_switch_release,
+       .uevent = tb_switch_uevent,
        .pm = &tb_switch_pm_ops,
 };
 
@@ -2542,6 +2567,8 @@ int tb_switch_add(struct tb_switch *sw)
                }
                tb_sw_dbg(sw, "uid: %#llx\n", sw->uid);
 
+               tb_check_quirks(sw);
+
                ret = tb_switch_set_uuid(sw);
                if (ret) {
                        dev_err(&sw->dev, "failed to set UUID\n");