thunderbolt: Add support for PCIe tunneling disabled (SL5)
[linux-2.6-microblaze.git] / drivers / thunderbolt / switch.c
index a8572f4..b63fecc 100644 (file)
@@ -525,6 +525,8 @@ int tb_port_state(struct tb_port *port)
 
 /**
  * tb_wait_for_port() - wait for a port to become ready
+ * @port: Port to wait
+ * @wait_if_unplugged: Wait also when port is unplugged
  *
  * Wait up to 1 second for a port to reach state TB_PORT_UP. If
  * wait_if_unplugged is set then we also wait if the port is in state
@@ -589,6 +591,8 @@ int tb_wait_for_port(struct tb_port *port, bool wait_if_unplugged)
 
 /**
  * tb_port_add_nfc_credits() - add/remove non flow controlled credits to port
+ * @port: Port to add/remove NFC credits
+ * @credits: Credits to add/remove
  *
  * Change the number of NFC credits allocated to @port by @credits. To remove
  * NFC credits pass a negative amount of credits.
@@ -646,6 +650,8 @@ int tb_port_set_initial_credits(struct tb_port *port, u32 credits)
 
 /**
  * tb_port_clear_counter() - clear a counter in TB_CFG_COUNTER
+ * @port: Port whose counters to clear
+ * @counter: Counter index to clear
  *
  * Return: Returns 0 on success or an error code on failure.
  */
@@ -718,7 +724,7 @@ int tb_port_disable(struct tb_port *port)
        return __tb_port_enable(port, false);
 }
 
-/**
+/*
  * tb_init_port() - initialize a port
  *
  * This is a helper method for tb_switch_alloc. Does not check or initialize
@@ -1065,6 +1071,17 @@ void tb_port_lane_bonding_disable(struct tb_port *port)
        tb_port_set_link_width(port, 1);
 }
 
+static int tb_port_start_lane_initialization(struct tb_port *port)
+{
+       int ret;
+
+       if (tb_switch_is_usb4(port->sw))
+               return 0;
+
+       ret = tb_lc_start_lane_initialization(port);
+       return ret == -EINVAL ? 0 : ret;
+}
+
 /**
  * tb_port_is_enabled() - Is the adapter port enabled
  * @port: Port to check
@@ -1302,7 +1319,7 @@ static void tb_dump_switch(const struct tb *tb, const struct tb_switch *sw)
 }
 
 /**
- * reset_switch() - reconfigure route, enable and send TB_CFG_PKG_RESET
+ * tb_switch_reset() - reconfigure route, enable and send TB_CFG_PKG_RESET
  * @sw: Switch to reset
  *
  * Return: Returns 0 on success or an error code on failure.
@@ -1326,7 +1343,7 @@ int tb_switch_reset(struct tb_switch *sw)
        return res.err;
 }
 
-/**
+/*
  * tb_plug_events_active() - enable/disable plug events on a switch
  *
  * Also configures a sane plug_events_delay of 255ms.
@@ -1376,6 +1393,30 @@ static ssize_t authorized_show(struct device *dev,
        return sprintf(buf, "%u\n", sw->authorized);
 }
 
+static int disapprove_switch(struct device *dev, void *not_used)
+{
+       struct tb_switch *sw;
+
+       sw = tb_to_switch(dev);
+       if (sw && sw->authorized) {
+               int ret;
+
+               /* First children */
+               ret = device_for_each_child_reverse(&sw->dev, NULL, disapprove_switch);
+               if (ret)
+                       return ret;
+
+               ret = tb_domain_disapprove_switch(sw->tb, sw);
+               if (ret)
+                       return ret;
+
+               sw->authorized = 0;
+               kobject_uevent(&sw->dev.kobj, KOBJ_CHANGE);
+       }
+
+       return 0;
+}
+
 static int tb_switch_set_authorized(struct tb_switch *sw, unsigned int val)
 {
        int ret = -EINVAL;
@@ -1383,10 +1424,18 @@ static int tb_switch_set_authorized(struct tb_switch *sw, unsigned int val)
        if (!mutex_trylock(&sw->tb->lock))
                return restart_syscall();
 
-       if (sw->authorized)
+       if (!!sw->authorized == !!val)
                goto unlock;
 
        switch (val) {
+       /* Disapprove switch */
+       case 0:
+               if (tb_route(sw)) {
+                       ret = disapprove_switch(&sw->dev, NULL);
+                       goto unlock;
+               }
+               break;
+
        /* Approve switch */
        case 1:
                if (sw->key)
@@ -1725,7 +1774,11 @@ static umode_t switch_attr_is_visible(struct kobject *kobj,
        struct device *dev = kobj_to_dev(kobj);
        struct tb_switch *sw = tb_to_switch(dev);
 
-       if (attr == &dev_attr_device.attr) {
+       if (attr == &dev_attr_authorized.attr) {
+               if (sw->tb->security_level == TB_SECURITY_NOPCIE ||
+                   sw->tb->security_level == TB_SECURITY_DPONLY)
+                       return 0;
+       } else if (attr == &dev_attr_device.attr) {
                if (!sw->device)
                        return 0;
        } else if (attr == &dev_attr_device_name.attr) {
@@ -1771,7 +1824,7 @@ static umode_t switch_attr_is_visible(struct kobject *kobj,
        return sw->safe_mode ? 0 : attr->mode;
 }
 
-static struct attribute_group switch_group = {
+static const struct attribute_group switch_group = {
        .is_visible = switch_attr_is_visible,
        .attrs = switch_attrs,
 };
@@ -2606,6 +2659,7 @@ void tb_switch_remove(struct tb_switch *sw)
 
 /**
  * tb_sw_set_unplugged() - set is_unplugged on switch and downstream switches
+ * @sw: Router to mark unplugged
  */
 void tb_sw_set_unplugged(struct tb_switch *sw)
 {
@@ -2694,8 +2748,22 @@ int tb_switch_resume(struct tb_switch *sw)
 
        /* check for surviving downstream switches */
        tb_switch_for_each_port(sw, port) {
-               if (!tb_port_has_remote(port) && !port->xdomain)
+               if (!tb_port_has_remote(port) && !port->xdomain) {
+                       /*
+                        * For disconnected downstream lane adapters
+                        * start lane initialization now so we detect
+                        * future connects.
+                        */
+                       if (!tb_is_upstream_port(port) && tb_port_is_null(port))
+                               tb_port_start_lane_initialization(port);
                        continue;
+               } else if (port->xdomain) {
+                       /*
+                        * Start lane initialization for XDomain so the
+                        * link gets re-established.
+                        */
+                       tb_port_start_lane_initialization(port);
+               }
 
                if (tb_wait_for_port(port, true) <= 0) {
                        tb_port_warn(port,