This source file includes following definitions.
- tb_lc_read_uuid
- read_lc_desc
- find_port_lc_cap
- tb_lc_configure_lane
- tb_lc_configure_link
- tb_lc_unconfigure_link
- tb_lc_set_sleep
   1 
   2 
   3 
   4 
   5 
   6 
   7 
   8 
   9 #include "tb.h"
  10 
  11 
  12 
  13 
  14 
  15 
  16 int tb_lc_read_uuid(struct tb_switch *sw, u32 *uuid)
  17 {
  18         if (!sw->cap_lc)
  19                 return -EINVAL;
  20         return tb_sw_read(sw, uuid, TB_CFG_SWITCH, sw->cap_lc + TB_LC_FUSE, 4);
  21 }
  22 
  23 static int read_lc_desc(struct tb_switch *sw, u32 *desc)
  24 {
  25         if (!sw->cap_lc)
  26                 return -EINVAL;
  27         return tb_sw_read(sw, desc, TB_CFG_SWITCH, sw->cap_lc + TB_LC_DESC, 1);
  28 }
  29 
  30 static int find_port_lc_cap(struct tb_port *port)
  31 {
  32         struct tb_switch *sw = port->sw;
  33         int start, phys, ret, size;
  34         u32 desc;
  35 
  36         ret = read_lc_desc(sw, &desc);
  37         if (ret)
  38                 return ret;
  39 
  40         
  41         start = (desc & TB_LC_DESC_SIZE_MASK) >> TB_LC_DESC_SIZE_SHIFT;
  42         size = (desc & TB_LC_DESC_PORT_SIZE_MASK) >> TB_LC_DESC_PORT_SIZE_SHIFT;
  43         phys = tb_phy_port_from_link(port->port);
  44 
  45         return sw->cap_lc + start + phys * size;
  46 }
  47 
  48 static int tb_lc_configure_lane(struct tb_port *port, bool configure)
  49 {
  50         bool upstream = tb_is_upstream_port(port);
  51         struct tb_switch *sw = port->sw;
  52         u32 ctrl, lane;
  53         int cap, ret;
  54 
  55         if (sw->generation < 2)
  56                 return 0;
  57 
  58         cap = find_port_lc_cap(port);
  59         if (cap < 0)
  60                 return cap;
  61 
  62         ret = tb_sw_read(sw, &ctrl, TB_CFG_SWITCH, cap + TB_LC_SX_CTRL, 1);
  63         if (ret)
  64                 return ret;
  65 
  66         
  67         if (port->port % 2)
  68                 lane = TB_LC_SX_CTRL_L1C;
  69         else
  70                 lane = TB_LC_SX_CTRL_L2C;
  71 
  72         if (configure) {
  73                 ctrl |= lane;
  74                 if (upstream)
  75                         ctrl |= TB_LC_SX_CTRL_UPSTREAM;
  76         } else {
  77                 ctrl &= ~lane;
  78                 if (upstream)
  79                         ctrl &= ~TB_LC_SX_CTRL_UPSTREAM;
  80         }
  81 
  82         return tb_sw_write(sw, &ctrl, TB_CFG_SWITCH, cap + TB_LC_SX_CTRL, 1);
  83 }
  84 
  85 
  86 
  87 
  88 
  89 
  90 
  91 
  92 int tb_lc_configure_link(struct tb_switch *sw)
  93 {
  94         struct tb_port *up, *down;
  95         int ret;
  96 
  97         if (!sw->config.enabled || !tb_route(sw))
  98                 return 0;
  99 
 100         up = tb_upstream_port(sw);
 101         down = tb_port_at(tb_route(sw), tb_to_switch(sw->dev.parent));
 102 
 103         
 104         ret = tb_lc_configure_lane(down, true);
 105         if (ret)
 106                 return ret;
 107 
 108         
 109         ret = tb_lc_configure_lane(up, true);
 110         if (ret)
 111                 tb_lc_configure_lane(down, false);
 112 
 113         return ret;
 114 }
 115 
 116 
 117 
 118 
 119 
 120 
 121 
 122 
 123 void tb_lc_unconfigure_link(struct tb_switch *sw)
 124 {
 125         struct tb_port *up, *down;
 126 
 127         if (sw->is_unplugged || !sw->config.enabled || !tb_route(sw))
 128                 return;
 129 
 130         up = tb_upstream_port(sw);
 131         down = tb_port_at(tb_route(sw), tb_to_switch(sw->dev.parent));
 132 
 133         tb_lc_configure_lane(up, false);
 134         tb_lc_configure_lane(down, false);
 135 }
 136 
 137 
 138 
 139 
 140 
 141 
 142 
 143 
 144 int tb_lc_set_sleep(struct tb_switch *sw)
 145 {
 146         int start, size, nlc, ret, i;
 147         u32 desc;
 148 
 149         if (sw->generation < 2)
 150                 return 0;
 151 
 152         ret = read_lc_desc(sw, &desc);
 153         if (ret)
 154                 return ret;
 155 
 156         
 157         nlc = desc & TB_LC_DESC_NLC_MASK;
 158         start = (desc & TB_LC_DESC_SIZE_MASK) >> TB_LC_DESC_SIZE_SHIFT;
 159         size = (desc & TB_LC_DESC_PORT_SIZE_MASK) >> TB_LC_DESC_PORT_SIZE_SHIFT;
 160 
 161         
 162         for (i = 0; i < nlc; i++) {
 163                 unsigned int offset = sw->cap_lc + start + i * size;
 164                 u32 ctrl;
 165 
 166                 ret = tb_sw_read(sw, &ctrl, TB_CFG_SWITCH,
 167                                  offset + TB_LC_SX_CTRL, 1);
 168                 if (ret)
 169                         return ret;
 170 
 171                 ctrl |= TB_LC_SX_CTRL_SLP;
 172                 ret = tb_sw_write(sw, &ctrl, TB_CFG_SWITCH,
 173                                   offset + TB_LC_SX_CTRL, 1);
 174                 if (ret)
 175                         return ret;
 176         }
 177 
 178         return 0;
 179 }