tmu.c (15037B)
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Thunderbolt Time Management Unit (TMU) support 4 * 5 * Copyright (C) 2019, Intel Corporation 6 * Authors: Mika Westerberg <mika.westerberg@linux.intel.com> 7 * Rajmohan Mani <rajmohan.mani@intel.com> 8 */ 9 10#include <linux/delay.h> 11 12#include "tb.h" 13 14static const char *tb_switch_tmu_mode_name(const struct tb_switch *sw) 15{ 16 bool root_switch = !tb_route(sw); 17 18 switch (sw->tmu.rate) { 19 case TB_SWITCH_TMU_RATE_OFF: 20 return "off"; 21 22 case TB_SWITCH_TMU_RATE_HIFI: 23 /* Root switch does not have upstream directionality */ 24 if (root_switch) 25 return "HiFi"; 26 if (sw->tmu.unidirectional) 27 return "uni-directional, HiFi"; 28 return "bi-directional, HiFi"; 29 30 case TB_SWITCH_TMU_RATE_NORMAL: 31 if (root_switch) 32 return "normal"; 33 return "uni-directional, normal"; 34 35 default: 36 return "unknown"; 37 } 38} 39 40static bool tb_switch_tmu_ucap_supported(struct tb_switch *sw) 41{ 42 int ret; 43 u32 val; 44 45 ret = tb_sw_read(sw, &val, TB_CFG_SWITCH, 46 sw->tmu.cap + TMU_RTR_CS_0, 1); 47 if (ret) 48 return false; 49 50 return !!(val & TMU_RTR_CS_0_UCAP); 51} 52 53static int tb_switch_tmu_rate_read(struct tb_switch *sw) 54{ 55 int ret; 56 u32 val; 57 58 ret = tb_sw_read(sw, &val, TB_CFG_SWITCH, 59 sw->tmu.cap + TMU_RTR_CS_3, 1); 60 if (ret) 61 return ret; 62 63 val >>= TMU_RTR_CS_3_TS_PACKET_INTERVAL_SHIFT; 64 return val; 65} 66 67static int tb_switch_tmu_rate_write(struct tb_switch *sw, int rate) 68{ 69 int ret; 70 u32 val; 71 72 ret = tb_sw_read(sw, &val, TB_CFG_SWITCH, 73 sw->tmu.cap + TMU_RTR_CS_3, 1); 74 if (ret) 75 return ret; 76 77 val &= ~TMU_RTR_CS_3_TS_PACKET_INTERVAL_MASK; 78 val |= rate << TMU_RTR_CS_3_TS_PACKET_INTERVAL_SHIFT; 79 80 return tb_sw_write(sw, &val, TB_CFG_SWITCH, 81 sw->tmu.cap + TMU_RTR_CS_3, 1); 82} 83 84static int tb_port_tmu_write(struct tb_port *port, u8 offset, u32 mask, 85 u32 value) 86{ 87 u32 data; 88 int ret; 89 90 ret = tb_port_read(port, &data, TB_CFG_PORT, port->cap_tmu + offset, 1); 91 if (ret) 92 return ret; 93 94 data &= ~mask; 95 data |= value; 96 97 return tb_port_write(port, &data, TB_CFG_PORT, 98 port->cap_tmu + offset, 1); 99} 100 101static int tb_port_tmu_set_unidirectional(struct tb_port *port, 102 bool unidirectional) 103{ 104 u32 val; 105 106 if (!port->sw->tmu.has_ucap) 107 return 0; 108 109 val = unidirectional ? TMU_ADP_CS_3_UDM : 0; 110 return tb_port_tmu_write(port, TMU_ADP_CS_3, TMU_ADP_CS_3_UDM, val); 111} 112 113static inline int tb_port_tmu_unidirectional_disable(struct tb_port *port) 114{ 115 return tb_port_tmu_set_unidirectional(port, false); 116} 117 118static inline int tb_port_tmu_unidirectional_enable(struct tb_port *port) 119{ 120 return tb_port_tmu_set_unidirectional(port, true); 121} 122 123static bool tb_port_tmu_is_unidirectional(struct tb_port *port) 124{ 125 int ret; 126 u32 val; 127 128 ret = tb_port_read(port, &val, TB_CFG_PORT, 129 port->cap_tmu + TMU_ADP_CS_3, 1); 130 if (ret) 131 return false; 132 133 return val & TMU_ADP_CS_3_UDM; 134} 135 136static int tb_port_tmu_time_sync(struct tb_port *port, bool time_sync) 137{ 138 u32 val = time_sync ? TMU_ADP_CS_6_DTS : 0; 139 140 return tb_port_tmu_write(port, TMU_ADP_CS_6, TMU_ADP_CS_6_DTS, val); 141} 142 143static int tb_port_tmu_time_sync_disable(struct tb_port *port) 144{ 145 return tb_port_tmu_time_sync(port, true); 146} 147 148static int tb_port_tmu_time_sync_enable(struct tb_port *port) 149{ 150 return tb_port_tmu_time_sync(port, false); 151} 152 153static int tb_switch_tmu_set_time_disruption(struct tb_switch *sw, bool set) 154{ 155 u32 val, offset, bit; 156 int ret; 157 158 if (tb_switch_is_usb4(sw)) { 159 offset = sw->tmu.cap + TMU_RTR_CS_0; 160 bit = TMU_RTR_CS_0_TD; 161 } else { 162 offset = sw->cap_vsec_tmu + TB_TIME_VSEC_3_CS_26; 163 bit = TB_TIME_VSEC_3_CS_26_TD; 164 } 165 166 ret = tb_sw_read(sw, &val, TB_CFG_SWITCH, offset, 1); 167 if (ret) 168 return ret; 169 170 if (set) 171 val |= bit; 172 else 173 val &= ~bit; 174 175 return tb_sw_write(sw, &val, TB_CFG_SWITCH, offset, 1); 176} 177 178/** 179 * tb_switch_tmu_init() - Initialize switch TMU structures 180 * @sw: Switch to initialized 181 * 182 * This function must be called before other TMU related functions to 183 * makes the internal structures are filled in correctly. Does not 184 * change any hardware configuration. 185 */ 186int tb_switch_tmu_init(struct tb_switch *sw) 187{ 188 struct tb_port *port; 189 int ret; 190 191 if (tb_switch_is_icm(sw)) 192 return 0; 193 194 ret = tb_switch_find_cap(sw, TB_SWITCH_CAP_TMU); 195 if (ret > 0) 196 sw->tmu.cap = ret; 197 198 tb_switch_for_each_port(sw, port) { 199 int cap; 200 201 cap = tb_port_find_cap(port, TB_PORT_CAP_TIME1); 202 if (cap > 0) 203 port->cap_tmu = cap; 204 } 205 206 ret = tb_switch_tmu_rate_read(sw); 207 if (ret < 0) 208 return ret; 209 210 sw->tmu.rate = ret; 211 212 sw->tmu.has_ucap = tb_switch_tmu_ucap_supported(sw); 213 if (sw->tmu.has_ucap) { 214 tb_sw_dbg(sw, "TMU: supports uni-directional mode\n"); 215 216 if (tb_route(sw)) { 217 struct tb_port *up = tb_upstream_port(sw); 218 219 sw->tmu.unidirectional = 220 tb_port_tmu_is_unidirectional(up); 221 } 222 } else { 223 sw->tmu.unidirectional = false; 224 } 225 226 tb_sw_dbg(sw, "TMU: current mode: %s\n", tb_switch_tmu_mode_name(sw)); 227 return 0; 228} 229 230/** 231 * tb_switch_tmu_post_time() - Update switch local time 232 * @sw: Switch whose time to update 233 * 234 * Updates switch local time using time posting procedure. 235 */ 236int tb_switch_tmu_post_time(struct tb_switch *sw) 237{ 238 unsigned int post_time_high_offset, post_time_high = 0; 239 unsigned int post_local_time_offset, post_time_offset; 240 struct tb_switch *root_switch = sw->tb->root_switch; 241 u64 hi, mid, lo, local_time, post_time; 242 int i, ret, retries = 100; 243 u32 gm_local_time[3]; 244 245 if (!tb_route(sw)) 246 return 0; 247 248 if (!tb_switch_is_usb4(sw)) 249 return 0; 250 251 /* Need to be able to read the grand master time */ 252 if (!root_switch->tmu.cap) 253 return 0; 254 255 ret = tb_sw_read(root_switch, gm_local_time, TB_CFG_SWITCH, 256 root_switch->tmu.cap + TMU_RTR_CS_1, 257 ARRAY_SIZE(gm_local_time)); 258 if (ret) 259 return ret; 260 261 for (i = 0; i < ARRAY_SIZE(gm_local_time); i++) 262 tb_sw_dbg(root_switch, "local_time[%d]=0x%08x\n", i, 263 gm_local_time[i]); 264 265 /* Convert to nanoseconds (drop fractional part) */ 266 hi = gm_local_time[2] & TMU_RTR_CS_3_LOCAL_TIME_NS_MASK; 267 mid = gm_local_time[1]; 268 lo = (gm_local_time[0] & TMU_RTR_CS_1_LOCAL_TIME_NS_MASK) >> 269 TMU_RTR_CS_1_LOCAL_TIME_NS_SHIFT; 270 local_time = hi << 48 | mid << 16 | lo; 271 272 /* Tell the switch that time sync is disrupted for a while */ 273 ret = tb_switch_tmu_set_time_disruption(sw, true); 274 if (ret) 275 return ret; 276 277 post_local_time_offset = sw->tmu.cap + TMU_RTR_CS_22; 278 post_time_offset = sw->tmu.cap + TMU_RTR_CS_24; 279 post_time_high_offset = sw->tmu.cap + TMU_RTR_CS_25; 280 281 /* 282 * Write the Grandmaster time to the Post Local Time registers 283 * of the new switch. 284 */ 285 ret = tb_sw_write(sw, &local_time, TB_CFG_SWITCH, 286 post_local_time_offset, 2); 287 if (ret) 288 goto out; 289 290 /* 291 * Have the new switch update its local time by: 292 * 1) writing 0x1 to the Post Time Low register and 0xffffffff to 293 * Post Time High register. 294 * 2) write 0 to Post Time High register and then wait for 295 * the completion of the post_time register becomes 0. 296 * This means the time has been converged properly. 297 */ 298 post_time = 0xffffffff00000001ULL; 299 300 ret = tb_sw_write(sw, &post_time, TB_CFG_SWITCH, post_time_offset, 2); 301 if (ret) 302 goto out; 303 304 ret = tb_sw_write(sw, &post_time_high, TB_CFG_SWITCH, 305 post_time_high_offset, 1); 306 if (ret) 307 goto out; 308 309 do { 310 usleep_range(5, 10); 311 ret = tb_sw_read(sw, &post_time, TB_CFG_SWITCH, 312 post_time_offset, 2); 313 if (ret) 314 goto out; 315 } while (--retries && post_time); 316 317 if (!retries) { 318 ret = -ETIMEDOUT; 319 goto out; 320 } 321 322 tb_sw_dbg(sw, "TMU: updated local time to %#llx\n", local_time); 323 324out: 325 tb_switch_tmu_set_time_disruption(sw, false); 326 return ret; 327} 328 329/** 330 * tb_switch_tmu_disable() - Disable TMU of a switch 331 * @sw: Switch whose TMU to disable 332 * 333 * Turns off TMU of @sw if it is enabled. If not enabled does nothing. 334 */ 335int tb_switch_tmu_disable(struct tb_switch *sw) 336{ 337 /* 338 * No need to disable TMU on devices that don't support CLx since 339 * on these devices e.g. Alpine Ridge and earlier, the TMU mode 340 * HiFi bi-directional is enabled by default and we don't change it. 341 */ 342 if (!tb_switch_is_clx_supported(sw)) 343 return 0; 344 345 /* Already disabled? */ 346 if (sw->tmu.rate == TB_SWITCH_TMU_RATE_OFF) 347 return 0; 348 349 350 if (tb_route(sw)) { 351 bool unidirectional = tb_switch_tmu_hifi_is_enabled(sw, true); 352 struct tb_switch *parent = tb_switch_parent(sw); 353 struct tb_port *down, *up; 354 int ret; 355 356 down = tb_port_at(tb_route(sw), parent); 357 up = tb_upstream_port(sw); 358 /* 359 * In case of uni-directional time sync, TMU handshake is 360 * initiated by upstream router. In case of bi-directional 361 * time sync, TMU handshake is initiated by downstream router. 362 * Therefore, we change the rate to off in the respective 363 * router. 364 */ 365 if (unidirectional) 366 tb_switch_tmu_rate_write(parent, TB_SWITCH_TMU_RATE_OFF); 367 else 368 tb_switch_tmu_rate_write(sw, TB_SWITCH_TMU_RATE_OFF); 369 370 tb_port_tmu_time_sync_disable(up); 371 ret = tb_port_tmu_time_sync_disable(down); 372 if (ret) 373 return ret; 374 375 if (unidirectional) { 376 /* The switch may be unplugged so ignore any errors */ 377 tb_port_tmu_unidirectional_disable(up); 378 ret = tb_port_tmu_unidirectional_disable(down); 379 if (ret) 380 return ret; 381 } 382 } else { 383 tb_switch_tmu_rate_write(sw, TB_SWITCH_TMU_RATE_OFF); 384 } 385 386 sw->tmu.unidirectional = false; 387 sw->tmu.rate = TB_SWITCH_TMU_RATE_OFF; 388 389 tb_sw_dbg(sw, "TMU: disabled\n"); 390 return 0; 391} 392 393static void __tb_switch_tmu_off(struct tb_switch *sw, bool unidirectional) 394{ 395 struct tb_switch *parent = tb_switch_parent(sw); 396 struct tb_port *down, *up; 397 398 down = tb_port_at(tb_route(sw), parent); 399 up = tb_upstream_port(sw); 400 /* 401 * In case of any failure in one of the steps when setting 402 * bi-directional or uni-directional TMU mode, get back to the TMU 403 * configurations in off mode. In case of additional failures in 404 * the functions below, ignore them since the caller shall already 405 * report a failure. 406 */ 407 tb_port_tmu_time_sync_disable(down); 408 tb_port_tmu_time_sync_disable(up); 409 if (unidirectional) 410 tb_switch_tmu_rate_write(parent, TB_SWITCH_TMU_RATE_OFF); 411 else 412 tb_switch_tmu_rate_write(sw, TB_SWITCH_TMU_RATE_OFF); 413 414 tb_port_tmu_unidirectional_disable(down); 415 tb_port_tmu_unidirectional_disable(up); 416} 417 418/* 419 * This function is called when the previous TMU mode was 420 * TB_SWITCH_TMU_RATE_OFF. 421 */ 422static int __tb_switch_tmu_enable_bidirectional(struct tb_switch *sw) 423{ 424 struct tb_switch *parent = tb_switch_parent(sw); 425 struct tb_port *up, *down; 426 int ret; 427 428 up = tb_upstream_port(sw); 429 down = tb_port_at(tb_route(sw), parent); 430 431 ret = tb_port_tmu_unidirectional_disable(up); 432 if (ret) 433 return ret; 434 435 ret = tb_port_tmu_unidirectional_disable(down); 436 if (ret) 437 goto out; 438 439 ret = tb_switch_tmu_rate_write(sw, TB_SWITCH_TMU_RATE_HIFI); 440 if (ret) 441 goto out; 442 443 ret = tb_port_tmu_time_sync_enable(up); 444 if (ret) 445 goto out; 446 447 ret = tb_port_tmu_time_sync_enable(down); 448 if (ret) 449 goto out; 450 451 return 0; 452 453out: 454 __tb_switch_tmu_off(sw, false); 455 return ret; 456} 457 458static int tb_switch_tmu_objection_mask(struct tb_switch *sw) 459{ 460 u32 val; 461 int ret; 462 463 ret = tb_sw_read(sw, &val, TB_CFG_SWITCH, 464 sw->cap_vsec_tmu + TB_TIME_VSEC_3_CS_9, 1); 465 if (ret) 466 return ret; 467 468 val &= ~TB_TIME_VSEC_3_CS_9_TMU_OBJ_MASK; 469 470 return tb_sw_write(sw, &val, TB_CFG_SWITCH, 471 sw->cap_vsec_tmu + TB_TIME_VSEC_3_CS_9, 1); 472} 473 474static int tb_switch_tmu_unidirectional_enable(struct tb_switch *sw) 475{ 476 struct tb_port *up = tb_upstream_port(sw); 477 478 return tb_port_tmu_write(up, TMU_ADP_CS_6, 479 TMU_ADP_CS_6_DISABLE_TMU_OBJ_MASK, 480 TMU_ADP_CS_6_DISABLE_TMU_OBJ_MASK); 481} 482 483/* 484 * This function is called when the previous TMU mode was 485 * TB_SWITCH_TMU_RATE_OFF. 486 */ 487static int __tb_switch_tmu_enable_unidirectional(struct tb_switch *sw) 488{ 489 struct tb_switch *parent = tb_switch_parent(sw); 490 struct tb_port *up, *down; 491 int ret; 492 493 up = tb_upstream_port(sw); 494 down = tb_port_at(tb_route(sw), parent); 495 ret = tb_switch_tmu_rate_write(parent, TB_SWITCH_TMU_RATE_HIFI); 496 if (ret) 497 return ret; 498 499 ret = tb_port_tmu_unidirectional_enable(up); 500 if (ret) 501 goto out; 502 503 ret = tb_port_tmu_time_sync_enable(up); 504 if (ret) 505 goto out; 506 507 ret = tb_port_tmu_unidirectional_enable(down); 508 if (ret) 509 goto out; 510 511 ret = tb_port_tmu_time_sync_enable(down); 512 if (ret) 513 goto out; 514 515 return 0; 516 517out: 518 __tb_switch_tmu_off(sw, true); 519 return ret; 520} 521 522static int tb_switch_tmu_hifi_enable(struct tb_switch *sw) 523{ 524 bool unidirectional = sw->tmu.unidirectional_request; 525 int ret; 526 527 if (unidirectional && !sw->tmu.has_ucap) 528 return -EOPNOTSUPP; 529 530 /* 531 * No need to enable TMU on devices that don't support CLx since on 532 * these devices e.g. Alpine Ridge and earlier, the TMU mode HiFi 533 * bi-directional is enabled by default. 534 */ 535 if (!tb_switch_is_clx_supported(sw)) 536 return 0; 537 538 if (tb_switch_tmu_hifi_is_enabled(sw, sw->tmu.unidirectional_request)) 539 return 0; 540 541 if (tb_switch_is_titan_ridge(sw) && unidirectional) { 542 /* Titan Ridge supports only CL0s */ 543 if (!tb_switch_is_cl0s_enabled(sw)) 544 return -EOPNOTSUPP; 545 546 ret = tb_switch_tmu_objection_mask(sw); 547 if (ret) 548 return ret; 549 550 ret = tb_switch_tmu_unidirectional_enable(sw); 551 if (ret) 552 return ret; 553 } 554 555 ret = tb_switch_tmu_set_time_disruption(sw, true); 556 if (ret) 557 return ret; 558 559 if (tb_route(sw)) { 560 /* The used mode changes are from OFF to HiFi-Uni/HiFi-BiDir */ 561 if (sw->tmu.rate == TB_SWITCH_TMU_RATE_OFF) { 562 if (unidirectional) 563 ret = __tb_switch_tmu_enable_unidirectional(sw); 564 else 565 ret = __tb_switch_tmu_enable_bidirectional(sw); 566 if (ret) 567 return ret; 568 } 569 sw->tmu.unidirectional = unidirectional; 570 } else { 571 /* 572 * Host router port configurations are written as 573 * part of configurations for downstream port of the parent 574 * of the child node - see above. 575 * Here only the host router' rate configuration is written. 576 */ 577 ret = tb_switch_tmu_rate_write(sw, TB_SWITCH_TMU_RATE_HIFI); 578 if (ret) 579 return ret; 580 } 581 582 sw->tmu.rate = TB_SWITCH_TMU_RATE_HIFI; 583 584 tb_sw_dbg(sw, "TMU: mode set to: %s\n", tb_switch_tmu_mode_name(sw)); 585 return tb_switch_tmu_set_time_disruption(sw, false); 586} 587 588/** 589 * tb_switch_tmu_enable() - Enable TMU on a router 590 * @sw: Router whose TMU to enable 591 * 592 * Enables TMU of a router to be in uni-directional or bi-directional HiFi mode. 593 * Calling tb_switch_tmu_configure() is required before calling this function, 594 * to select the mode HiFi and directionality (uni-directional/bi-directional). 595 * In both modes all tunneling should work. Uni-directional mode is required for 596 * CLx (Link Low-Power) to work. 597 */ 598int tb_switch_tmu_enable(struct tb_switch *sw) 599{ 600 if (sw->tmu.rate_request == TB_SWITCH_TMU_RATE_NORMAL) 601 return -EOPNOTSUPP; 602 603 return tb_switch_tmu_hifi_enable(sw); 604} 605 606/** 607 * tb_switch_tmu_configure() - Configure the TMU rate and directionality 608 * @sw: Router whose mode to change 609 * @rate: Rate to configure Off/LowRes/HiFi 610 * @unidirectional: If uni-directional (bi-directional otherwise) 611 * 612 * Selects the rate of the TMU and directionality (uni-directional or 613 * bi-directional). Must be called before tb_switch_tmu_enable(). 614 */ 615void tb_switch_tmu_configure(struct tb_switch *sw, 616 enum tb_switch_tmu_rate rate, bool unidirectional) 617{ 618 sw->tmu.unidirectional_request = unidirectional; 619 sw->tmu.rate_request = rate; 620}