root/drivers/thunderbolt/lc.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. tb_lc_read_uuid
  2. read_lc_desc
  3. find_port_lc_cap
  4. tb_lc_configure_lane
  5. tb_lc_configure_link
  6. tb_lc_unconfigure_link
  7. tb_lc_set_sleep

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * Thunderbolt link controller support
   4  *
   5  * Copyright (C) 2019, Intel Corporation
   6  * Author: Mika Westerberg <mika.westerberg@linux.intel.com>
   7  */
   8 
   9 #include "tb.h"
  10 
  11 /**
  12  * tb_lc_read_uuid() - Read switch UUID from link controller common register
  13  * @sw: Switch whose UUID is read
  14  * @uuid: UUID is placed here
  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         /* Start of port LC registers */
  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         /* Resolve correct lane */
  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  * tb_lc_configure_link() - Let LC know about configured link
  87  * @sw: Switch that is being added
  88  *
  89  * Informs LC of both parent switch and @sw that there is established
  90  * link between the two.
  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         /* Configure parent link toward this switch */
 104         ret = tb_lc_configure_lane(down, true);
 105         if (ret)
 106                 return ret;
 107 
 108         /* Configure upstream link from this switch to the parent */
 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  * tb_lc_unconfigure_link() - Let LC know about unconfigured link
 118  * @sw: Switch to unconfigure
 119  *
 120  * Informs LC of both parent switch and @sw that the link between the
 121  * two does not exist anymore.
 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  * tb_lc_set_sleep() - Inform LC that the switch is going to sleep
 139  * @sw: Switch to set sleep
 140  *
 141  * Let the switch link controllers know that the switch is going to
 142  * sleep.
 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         /* Figure out number of link controllers */
 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         /* For each link controller set sleep bit */
 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 }

/* [<][>][^][v][top][bottom][index][help] */