summaryrefslogtreecommitdiff
path: root/drivers/thunderbolt/icm.c
diff options
context:
space:
mode:
authorMika Westerberg <mika.westerberg@linux.intel.com>2019-03-21 19:03:00 +0200
committerMika Westerberg <mika.westerberg@linux.intel.com>2019-11-02 12:13:31 +0300
commit91c0c12080d0f40ee7275485221b06b4e1e289e1 (patch)
tree70e4119a7d77b11586f811906af5c8ab66ae7adc /drivers/thunderbolt/icm.c
parentb5db76dba0642ea6f2391374f3b2b479014e5bf0 (diff)
thunderbolt: Add support for lane bonding
Lane bonding allows aggregating two 10/20 Gb/s (depending on the generation) lanes into a single 20/40 Gb/s bonded link. This allows sharing the full bandwidth more efficiently. In order to establish lane bonding we need to check that lane bonding is possible through link controller and that both ends of the link actually supports 2x widths. This also means that all the paths should be established through the primary port so update tb_path_alloc() to handle this as well. Lane bonding is supported starting from Falcon Ridge (2nd generation) controllers. We also expose the current speed and number of lanes under each device except the host router following similar attribute naming than USB bus. Expose speed and number of lanes for both directions to allow possibility of asymmetric link in the future. Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Diffstat (limited to 'drivers/thunderbolt/icm.c')
-rw-r--r--drivers/thunderbolt/icm.c12
1 files changed, 10 insertions, 2 deletions
diff --git a/drivers/thunderbolt/icm.c b/drivers/thunderbolt/icm.c
index d9caac77e08c..78480b782045 100644
--- a/drivers/thunderbolt/icm.c
+++ b/drivers/thunderbolt/icm.c
@@ -692,11 +692,11 @@ icm_fr_device_connected(struct tb *tb, const struct icm_pkg_header *hdr)
(const struct icm_fr_event_device_connected *)hdr;
enum tb_security_level security_level;
struct tb_switch *sw, *parent_sw;
+ bool boot, dual_lane, speed_gen3;
struct icm *icm = tb_priv(tb);
bool authorized = false;
struct tb_xdomain *xd;
u8 link, depth;
- bool boot;
u64 route;
int ret;
@@ -709,6 +709,8 @@ icm_fr_device_connected(struct tb *tb, const struct icm_pkg_header *hdr)
security_level = (pkg->hdr.flags & ICM_FLAGS_SLEVEL_MASK) >>
ICM_FLAGS_SLEVEL_SHIFT;
boot = pkg->link_info & ICM_LINK_INFO_BOOT;
+ dual_lane = pkg->hdr.flags & ICM_FLAGS_DUAL_LANE;
+ speed_gen3 = pkg->hdr.flags & ICM_FLAGS_SPEED_GEN3;
if (pkg->link_info & ICM_LINK_INFO_REJECTED) {
tb_info(tb, "switch at %u.%u was rejected by ICM firmware because topology limit exceeded\n",
@@ -817,6 +819,8 @@ icm_fr_device_connected(struct tb *tb, const struct icm_pkg_header *hdr)
sw->authorized = authorized;
sw->security_level = security_level;
sw->boot = boot;
+ sw->link_speed = speed_gen3 ? 20 : 10;
+ sw->link_width = dual_lane ? 2 : 1;
sw->rpm = intel_vss_is_rtd3(pkg->ep_name, sizeof(pkg->ep_name));
if (add_switch(parent_sw, sw))
@@ -1152,10 +1156,10 @@ __icm_tr_device_connected(struct tb *tb, const struct icm_pkg_header *hdr,
{
const struct icm_tr_event_device_connected *pkg =
(const struct icm_tr_event_device_connected *)hdr;
+ bool authorized, boot, dual_lane, speed_gen3;
enum tb_security_level security_level;
struct tb_switch *sw, *parent_sw;
struct tb_xdomain *xd;
- bool authorized, boot;
u64 route;
icm_postpone_rescan(tb);
@@ -1173,6 +1177,8 @@ __icm_tr_device_connected(struct tb *tb, const struct icm_pkg_header *hdr,
security_level = (pkg->hdr.flags & ICM_FLAGS_SLEVEL_MASK) >>
ICM_FLAGS_SLEVEL_SHIFT;
boot = pkg->link_info & ICM_LINK_INFO_BOOT;
+ dual_lane = pkg->hdr.flags & ICM_FLAGS_DUAL_LANE;
+ speed_gen3 = pkg->hdr.flags & ICM_FLAGS_SPEED_GEN3;
if (pkg->link_info & ICM_LINK_INFO_REJECTED) {
tb_info(tb, "switch at %llx was rejected by ICM firmware because topology limit exceeded\n",
@@ -1223,6 +1229,8 @@ __icm_tr_device_connected(struct tb *tb, const struct icm_pkg_header *hdr,
sw->authorized = authorized;
sw->security_level = security_level;
sw->boot = boot;
+ sw->link_speed = speed_gen3 ? 20 : 10;
+ sw->link_width = dual_lane ? 2 : 1;
sw->rpm = force_rtd3;
if (!sw->rpm)
sw->rpm = intel_vss_is_rtd3(pkg->ep_name,