Skip to content

Commit b2911a5

Browse files
committed
thunderbolt: Enable wakes from system suspend
In order for the router and the whole domain to wake up from system suspend states we need to enable wakes for the connected routers. For device routers we enable wakes from PCIe and USB 3.x. This allows devices such as keyboards connected to USB 3.x hub that is tunneled to wake the system up as expected. For all routers we enabled wake on USB4 for each connected ports. This is used to propagate the wake from router to another. Do the same for legacy routers through link controller vendor specific registers as documented in USB4 spec chapter 13. While there correct kernel-doc of usb4_switch_set_sleep() -- it does not enable wakes instead there is a separate function (usb4_switch_set_wake()) that does. Signed-off-by: Mika Westerberg <[email protected]>
1 parent 341d451 commit b2911a5

File tree

7 files changed

+231
-3
lines changed

7 files changed

+231
-3
lines changed

drivers/thunderbolt/domain.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,8 @@ int tb_domain_add(struct tb *tb)
455455
/* This starts event processing */
456456
mutex_unlock(&tb->lock);
457457

458+
device_init_wakeup(&tb->dev, true);
459+
458460
pm_runtime_no_callbacks(&tb->dev);
459461
pm_runtime_set_active(&tb->dev);
460462
pm_runtime_enable(&tb->dev);

drivers/thunderbolt/lc.c

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,73 @@ void tb_lc_unconfigure_xdomain(struct tb_port *port)
158158
tb_lc_set_xdomain_configured(port, false);
159159
}
160160

161+
static int tb_lc_set_wake_one(struct tb_switch *sw, unsigned int offset,
162+
unsigned int flags)
163+
{
164+
u32 ctrl;
165+
int ret;
166+
167+
/*
168+
* Enable wake on PCIe and USB4 (wake coming from another
169+
* router).
170+
*/
171+
ret = tb_sw_read(sw, &ctrl, TB_CFG_SWITCH,
172+
offset + TB_LC_SX_CTRL, 1);
173+
if (ret)
174+
return ret;
175+
176+
ctrl &= ~(TB_LC_SX_CTRL_WOC | TB_LC_SX_CTRL_WOD | TB_LC_SX_CTRL_WOP |
177+
TB_LC_SX_CTRL_WOU4);
178+
179+
if (flags & TB_WAKE_ON_CONNECT)
180+
ctrl |= TB_LC_SX_CTRL_WOC | TB_LC_SX_CTRL_WOD;
181+
if (flags & TB_WAKE_ON_USB4)
182+
ctrl |= TB_LC_SX_CTRL_WOU4;
183+
if (flags & TB_WAKE_ON_PCIE)
184+
ctrl |= TB_LC_SX_CTRL_WOP;
185+
186+
return tb_sw_write(sw, &ctrl, TB_CFG_SWITCH, offset + TB_LC_SX_CTRL, 1);
187+
}
188+
189+
/**
190+
* tb_lc_set_wake() - Enable/disable wake
191+
* @sw: Switch whose wakes to configure
192+
* @flags: Wakeup flags (%0 to disable)
193+
*
194+
* For each LC sets wake bits accordingly.
195+
*/
196+
int tb_lc_set_wake(struct tb_switch *sw, unsigned int flags)
197+
{
198+
int start, size, nlc, ret, i;
199+
u32 desc;
200+
201+
if (sw->generation < 2)
202+
return 0;
203+
204+
if (!tb_route(sw))
205+
return 0;
206+
207+
ret = read_lc_desc(sw, &desc);
208+
if (ret)
209+
return ret;
210+
211+
/* Figure out number of link controllers */
212+
nlc = desc & TB_LC_DESC_NLC_MASK;
213+
start = (desc & TB_LC_DESC_SIZE_MASK) >> TB_LC_DESC_SIZE_SHIFT;
214+
size = (desc & TB_LC_DESC_PORT_SIZE_MASK) >> TB_LC_DESC_PORT_SIZE_SHIFT;
215+
216+
/* For each link controller set sleep bit */
217+
for (i = 0; i < nlc; i++) {
218+
unsigned int offset = sw->cap_lc + start + i * size;
219+
220+
ret = tb_lc_set_wake_one(sw, offset, flags);
221+
if (ret)
222+
return ret;
223+
}
224+
225+
return 0;
226+
}
227+
161228
/**
162229
* tb_lc_set_sleep() - Inform LC that the switch is going to sleep
163230
* @sw: Switch to set sleep

drivers/thunderbolt/nhi.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1157,6 +1157,8 @@ static int nhi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
11571157
}
11581158
pci_set_drvdata(pdev, tb);
11591159

1160+
device_wakeup_enable(&pdev->dev);
1161+
11601162
pm_runtime_allow(&pdev->dev);
11611163
pm_runtime_set_autosuspend_delay(&pdev->dev, TB_AUTOSUSPEND_DELAY);
11621164
pm_runtime_use_autosuspend(&pdev->dev);

drivers/thunderbolt/switch.c

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2035,7 +2035,7 @@ int tb_switch_configure(struct tb_switch *sw)
20352035
route = tb_route(sw);
20362036

20372037
tb_dbg(tb, "%s Switch at %#llx (depth: %d, up port: %d)\n",
2038-
sw->config.enabled ? "restoring " : "initializing", route,
2038+
sw->config.enabled ? "restoring" : "initializing", route,
20392039
tb_route_length(route), sw->config.upstream_port_number);
20402040

20412041
sw->config.enabled = 1;
@@ -2501,6 +2501,13 @@ int tb_switch_add(struct tb_switch *sw)
25012501
return ret;
25022502
}
25032503

2504+
/*
2505+
* Thunderbolt routers do not generate wakeups themselves but
2506+
* they forward wakeups from tunneled protocols, so enable it
2507+
* here.
2508+
*/
2509+
device_init_wakeup(&sw->dev, true);
2510+
25042511
pm_runtime_set_active(&sw->dev);
25052512
if (sw->rpm) {
25062513
pm_runtime_set_autosuspend_delay(&sw->dev, TB_AUTOSUSPEND_DELAY);
@@ -2578,6 +2585,18 @@ void tb_sw_set_unplugged(struct tb_switch *sw)
25782585
}
25792586
}
25802587

2588+
static int tb_switch_set_wake(struct tb_switch *sw, unsigned int flags)
2589+
{
2590+
if (flags)
2591+
tb_sw_dbg(sw, "enabling wakeup: %#x\n", flags);
2592+
else
2593+
tb_sw_dbg(sw, "disabling wakeup\n");
2594+
2595+
if (tb_switch_is_usb4(sw))
2596+
return usb4_switch_set_wake(sw, flags);
2597+
return tb_lc_set_wake(sw, flags);
2598+
}
2599+
25812600
int tb_switch_resume(struct tb_switch *sw)
25822601
{
25832602
struct tb_port *port;
@@ -2623,6 +2642,9 @@ int tb_switch_resume(struct tb_switch *sw)
26232642
if (err)
26242643
return err;
26252644

2645+
/* Disable wakes */
2646+
tb_switch_set_wake(sw, 0);
2647+
26262648
err = tb_switch_tmu_init(sw);
26272649
if (err)
26282650
return err;
@@ -2658,6 +2680,7 @@ int tb_switch_resume(struct tb_switch *sw)
26582680

26592681
void tb_switch_suspend(struct tb_switch *sw)
26602682
{
2683+
unsigned int flags = 0;
26612684
struct tb_port *port;
26622685
int err;
26632686

@@ -2670,6 +2693,11 @@ void tb_switch_suspend(struct tb_switch *sw)
26702693
tb_switch_suspend(port->remote->sw);
26712694
}
26722695

2696+
if (device_may_wakeup(&sw->dev))
2697+
flags = TB_WAKE_ON_USB4 | TB_WAKE_ON_USB3 | TB_WAKE_ON_PCIE;
2698+
2699+
tb_switch_set_wake(sw, flags);
2700+
26732701
if (tb_switch_is_usb4(sw))
26742702
usb4_switch_set_sleep(sw);
26752703
else

drivers/thunderbolt/tb.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,13 @@ struct tb_path {
333333
*/
334334
#define TB_PATH_MAX_HOPS (7 * 2)
335335

336+
/* Possible wake types */
337+
#define TB_WAKE_ON_CONNECT BIT(0)
338+
#define TB_WAKE_ON_DISCONNECT BIT(1)
339+
#define TB_WAKE_ON_USB4 BIT(2)
340+
#define TB_WAKE_ON_USB3 BIT(3)
341+
#define TB_WAKE_ON_PCIE BIT(4)
342+
336343
/**
337344
* struct tb_cm_ops - Connection manager specific operations vector
338345
* @driver_ready: Called right after control channel is started. Used by
@@ -852,6 +859,7 @@ int tb_lc_configure_port(struct tb_port *port);
852859
void tb_lc_unconfigure_port(struct tb_port *port);
853860
int tb_lc_configure_xdomain(struct tb_port *port);
854861
void tb_lc_unconfigure_xdomain(struct tb_port *port);
862+
int tb_lc_set_wake(struct tb_switch *sw, unsigned int flags);
855863
int tb_lc_set_sleep(struct tb_switch *sw);
856864
bool tb_lc_lane_bonding_possible(struct tb_switch *sw);
857865
bool tb_lc_dp_sink_query(struct tb_switch *sw, struct tb_port *in);
@@ -907,6 +915,7 @@ int usb4_switch_read_uid(struct tb_switch *sw, u64 *uid);
907915
int usb4_switch_drom_read(struct tb_switch *sw, unsigned int address, void *buf,
908916
size_t size);
909917
bool usb4_switch_lane_bonding_possible(struct tb_switch *sw);
918+
int usb4_switch_set_wake(struct tb_switch *sw, unsigned int flags);
910919
int usb4_switch_set_sleep(struct tb_switch *sw);
911920
int usb4_switch_nvm_sector_size(struct tb_switch *sw);
912921
int usb4_switch_nvm_read(struct tb_switch *sw, unsigned int address, void *buf,

drivers/thunderbolt/tb_regs.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,8 @@ struct tb_regs_switch_header {
178178
#define ROUTER_CS_4 0x04
179179
#define ROUTER_CS_5 0x05
180180
#define ROUTER_CS_5_SLP BIT(0)
181+
#define ROUTER_CS_5_WOP BIT(1)
182+
#define ROUTER_CS_5_WOU BIT(2)
181183
#define ROUTER_CS_5_C3S BIT(23)
182184
#define ROUTER_CS_5_PTO BIT(24)
183185
#define ROUTER_CS_5_UTO BIT(25)
@@ -186,6 +188,8 @@ struct tb_regs_switch_header {
186188
#define ROUTER_CS_6 0x06
187189
#define ROUTER_CS_6_SLPR BIT(0)
188190
#define ROUTER_CS_6_TNS BIT(1)
191+
#define ROUTER_CS_6_WOPS BIT(2)
192+
#define ROUTER_CS_6_WOUS BIT(3)
189193
#define ROUTER_CS_6_HCI BIT(18)
190194
#define ROUTER_CS_6_CR BIT(25)
191195
#define ROUTER_CS_7 0x07
@@ -302,9 +306,13 @@ struct tb_regs_port_header {
302306
#define PORT_CS_18 0x12
303307
#define PORT_CS_18_BE BIT(8)
304308
#define PORT_CS_18_TCM BIT(9)
309+
#define PORT_CS_18_WOU4S BIT(18)
305310
#define PORT_CS_19 0x13
306311
#define PORT_CS_19_PC BIT(3)
307312
#define PORT_CS_19_PID BIT(4)
313+
#define PORT_CS_19_WOC BIT(16)
314+
#define PORT_CS_19_WOD BIT(17)
315+
#define PORT_CS_19_WOU4 BIT(18)
308316

309317
/* Display Port adapter registers */
310318
#define ADP_DP_CS_0 0x00
@@ -418,6 +426,10 @@ struct tb_regs_hop {
418426
#define TB_LC_PORT_ATTR_BE BIT(12)
419427

420428
#define TB_LC_SX_CTRL 0x96
429+
#define TB_LC_SX_CTRL_WOC BIT(1)
430+
#define TB_LC_SX_CTRL_WOD BIT(2)
431+
#define TB_LC_SX_CTRL_WOU4 BIT(5)
432+
#define TB_LC_SX_CTRL_WOP BIT(6)
421433
#define TB_LC_SX_CTRL_L1C BIT(16)
422434
#define TB_LC_SX_CTRL_L1D BIT(17)
423435
#define TB_LC_SX_CTRL_L2C BIT(20)

drivers/thunderbolt/usb4.c

Lines changed: 110 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,46 @@ static int usb4_switch_op(struct tb_switch *sw, u16 opcode, u8 *status)
196196
return 0;
197197
}
198198

199+
static void usb4_switch_check_wakes(struct tb_switch *sw)
200+
{
201+
struct tb_port *port;
202+
bool wakeup = false;
203+
u32 val;
204+
205+
if (!device_may_wakeup(&sw->dev))
206+
return;
207+
208+
if (tb_route(sw)) {
209+
if (tb_sw_read(sw, &val, TB_CFG_SWITCH, ROUTER_CS_6, 1))
210+
return;
211+
212+
tb_sw_dbg(sw, "PCIe wake: %s, USB3 wake: %s\n",
213+
(val & ROUTER_CS_6_WOPS) ? "yes" : "no",
214+
(val & ROUTER_CS_6_WOUS) ? "yes" : "no");
215+
216+
wakeup = val & (ROUTER_CS_6_WOPS | ROUTER_CS_6_WOUS);
217+
}
218+
219+
/* Check for any connected downstream ports for USB4 wake */
220+
tb_switch_for_each_port(sw, port) {
221+
if (!tb_port_has_remote(port))
222+
continue;
223+
224+
if (tb_port_read(port, &val, TB_CFG_PORT,
225+
port->cap_usb4 + PORT_CS_18, 1))
226+
break;
227+
228+
tb_port_dbg(port, "USB4 wake: %s\n",
229+
(val & PORT_CS_18_WOU4S) ? "yes" : "no");
230+
231+
if (val & PORT_CS_18_WOU4S)
232+
wakeup = true;
233+
}
234+
235+
if (wakeup)
236+
pm_wakeup_event(&sw->dev, 0);
237+
}
238+
199239
static bool link_is_usb4(struct tb_port *port)
200240
{
201241
u32 val;
@@ -229,6 +269,8 @@ int usb4_switch_setup(struct tb_switch *sw)
229269
u32 val = 0;
230270
int ret;
231271

272+
usb4_switch_check_wakes(sw);
273+
232274
if (!tb_route(sw))
233275
return 0;
234276

@@ -359,12 +401,78 @@ bool usb4_switch_lane_bonding_possible(struct tb_switch *sw)
359401
return !!(val & PORT_CS_18_BE);
360402
}
361403

404+
/**
405+
* usb4_switch_set_wake() - Enabled/disable wake
406+
* @sw: USB4 router
407+
* @flags: Wakeup flags (%0 to disable)
408+
*
409+
* Enables/disables router to wake up from sleep.
410+
*/
411+
int usb4_switch_set_wake(struct tb_switch *sw, unsigned int flags)
412+
{
413+
struct tb_port *port;
414+
u64 route = tb_route(sw);
415+
u32 val;
416+
int ret;
417+
418+
/*
419+
* Enable wakes coming from all USB4 downstream ports (from
420+
* child routers). For device routers do this also for the
421+
* upstream USB4 port.
422+
*/
423+
tb_switch_for_each_port(sw, port) {
424+
if (!route && tb_is_upstream_port(port))
425+
continue;
426+
427+
ret = tb_port_read(port, &val, TB_CFG_PORT,
428+
port->cap_usb4 + PORT_CS_19, 1);
429+
if (ret)
430+
return ret;
431+
432+
val &= ~(PORT_CS_19_WOC | PORT_CS_19_WOD | PORT_CS_19_WOU4);
433+
434+
if (flags & TB_WAKE_ON_CONNECT)
435+
val |= PORT_CS_19_WOC;
436+
if (flags & TB_WAKE_ON_DISCONNECT)
437+
val |= PORT_CS_19_WOD;
438+
if (flags & TB_WAKE_ON_USB4)
439+
val |= PORT_CS_19_WOU4;
440+
441+
ret = tb_port_write(port, &val, TB_CFG_PORT,
442+
port->cap_usb4 + PORT_CS_19, 1);
443+
if (ret)
444+
return ret;
445+
}
446+
447+
/*
448+
* Enable wakes from PCIe and USB 3.x on this router. Only
449+
* needed for device routers.
450+
*/
451+
if (route) {
452+
ret = tb_sw_read(sw, &val, TB_CFG_SWITCH, ROUTER_CS_5, 1);
453+
if (ret)
454+
return ret;
455+
456+
val &= ~(ROUTER_CS_5_WOP | ROUTER_CS_5_WOU);
457+
if (flags & TB_WAKE_ON_USB3)
458+
val |= ROUTER_CS_5_WOU;
459+
if (flags & TB_WAKE_ON_PCIE)
460+
val |= ROUTER_CS_5_WOP;
461+
462+
ret = tb_sw_write(sw, &val, TB_CFG_SWITCH, ROUTER_CS_5, 1);
463+
if (ret)
464+
return ret;
465+
}
466+
467+
return 0;
468+
}
469+
362470
/**
363471
* usb4_switch_set_sleep() - Prepare the router to enter sleep
364472
* @sw: USB4 router
365473
*
366-
* Enables wakes and sets sleep bit for the router. Returns when the
367-
* router sleep ready bit has been asserted.
474+
* Sets sleep bit for the router. Returns when the router sleep ready
475+
* bit has been asserted.
368476
*/
369477
int usb4_switch_set_sleep(struct tb_switch *sw)
370478
{

0 commit comments

Comments
 (0)