summaryrefslogtreecommitdiffstats
path: root/drivers/thunderbolt/tb.c
diff options
context:
space:
mode:
authorMika Westerberg <mika.westerberg@linux.intel.com>2017-06-06 08:25:00 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-06-09 05:42:41 -0400
commit9d3cce0b613689ee849a505ffac179af0ae9fff2 (patch)
treeabe7bda188831abb170c39ebfc4d0765c77f6b02 /drivers/thunderbolt/tb.c
parentc9843ebbb83a120094aa3a55bc0190d285e8384a (diff)
thunderbolt: Introduce thunderbolt bus and connection manager
Thunderbolt fabric consists of one or more switches. This fabric is called domain and it is controlled by an entity called connection manager. The connection manager can be either internal (driven by a firmware running on the host controller) or external (software driver). This driver currently implements support for the latter. In order to manage switches and their properties more easily we model this domain structure as a Linux bus. Each host controller adds a domain device to this bus, and these devices are named as domainN where N stands for index or id of the current domain. We then abstract connection manager specific operations into a new structure tb_cm_ops and convert the existing tb.c to fill those accordingly. This makes it easier to add support for the internal connection manager in subsequent patches. Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com> Reviewed-by: Yehezkel Bernat <yehezkel.bernat@intel.com> Reviewed-by: Michael Jamet <michael.jamet@intel.com> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Andreas Noever <andreas.noever@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/thunderbolt/tb.c')
-rw-r--r--drivers/thunderbolt/tb.c156
1 files changed, 69 insertions, 87 deletions
diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c
index 6b44076e1380..9f00a0f28d53 100644
--- a/drivers/thunderbolt/tb.c
+++ b/drivers/thunderbolt/tb.c
@@ -12,6 +12,18 @@
12#include "tb_regs.h" 12#include "tb_regs.h"
13#include "tunnel_pci.h" 13#include "tunnel_pci.h"
14 14
15/**
16 * struct tb_cm - Simple Thunderbolt connection manager
17 * @tunnel_list: List of active tunnels
18 * @hotplug_active: tb_handle_hotplug will stop progressing plug
19 * events and exit if this is not set (it needs to
20 * acquire the lock one more time). Used to drain wq
21 * after cfg has been paused.
22 */
23struct tb_cm {
24 struct list_head tunnel_list;
25 bool hotplug_active;
26};
15 27
16/* enumeration & hot plug handling */ 28/* enumeration & hot plug handling */
17 29
@@ -62,12 +74,14 @@ static void tb_scan_port(struct tb_port *port)
62 */ 74 */
63static void tb_free_invalid_tunnels(struct tb *tb) 75static void tb_free_invalid_tunnels(struct tb *tb)
64{ 76{
77 struct tb_cm *tcm = tb_priv(tb);
65 struct tb_pci_tunnel *tunnel; 78 struct tb_pci_tunnel *tunnel;
66 struct tb_pci_tunnel *n; 79 struct tb_pci_tunnel *n;
67 list_for_each_entry_safe(tunnel, n, &tb->tunnel_list, list) 80
68 { 81 list_for_each_entry_safe(tunnel, n, &tcm->tunnel_list, list) {
69 if (tb_pci_is_invalid(tunnel)) { 82 if (tb_pci_is_invalid(tunnel)) {
70 tb_pci_deactivate(tunnel); 83 tb_pci_deactivate(tunnel);
84 list_del(&tunnel->list);
71 tb_pci_free(tunnel); 85 tb_pci_free(tunnel);
72 } 86 }
73 } 87 }
@@ -149,6 +163,8 @@ static void tb_activate_pcie_devices(struct tb *tb)
149 struct tb_port *up_port; 163 struct tb_port *up_port;
150 struct tb_port *down_port; 164 struct tb_port *down_port;
151 struct tb_pci_tunnel *tunnel; 165 struct tb_pci_tunnel *tunnel;
166 struct tb_cm *tcm = tb_priv(tb);
167
152 /* scan for pcie devices at depth 1*/ 168 /* scan for pcie devices at depth 1*/
153 for (i = 1; i <= tb->root_switch->config.max_port_number; i++) { 169 for (i = 1; i <= tb->root_switch->config.max_port_number; i++) {
154 if (tb_is_upstream_port(&tb->root_switch->ports[i])) 170 if (tb_is_upstream_port(&tb->root_switch->ports[i]))
@@ -195,6 +211,7 @@ static void tb_activate_pcie_devices(struct tb *tb)
195 tb_pci_free(tunnel); 211 tb_pci_free(tunnel);
196 } 212 }
197 213
214 list_add(&tunnel->list, &tcm->tunnel_list);
198 } 215 }
199} 216}
200 217
@@ -217,10 +234,11 @@ static void tb_handle_hotplug(struct work_struct *work)
217{ 234{
218 struct tb_hotplug_event *ev = container_of(work, typeof(*ev), work); 235 struct tb_hotplug_event *ev = container_of(work, typeof(*ev), work);
219 struct tb *tb = ev->tb; 236 struct tb *tb = ev->tb;
237 struct tb_cm *tcm = tb_priv(tb);
220 struct tb_switch *sw; 238 struct tb_switch *sw;
221 struct tb_port *port; 239 struct tb_port *port;
222 mutex_lock(&tb->lock); 240 mutex_lock(&tb->lock);
223 if (!tb->hotplug_active) 241 if (!tcm->hotplug_active)
224 goto out; /* during init, suspend or shutdown */ 242 goto out; /* during init, suspend or shutdown */
225 243
226 sw = get_switch_at_route(tb->root_switch, ev->route); 244 sw = get_switch_at_route(tb->root_switch, ev->route);
@@ -296,22 +314,14 @@ static void tb_schedule_hotplug_handler(void *data, u64 route, u8 port,
296 queue_work(tb->wq, &ev->work); 314 queue_work(tb->wq, &ev->work);
297} 315}
298 316
299/** 317static void tb_stop(struct tb *tb)
300 * thunderbolt_shutdown_and_free() - shutdown everything
301 *
302 * Free all switches and the config channel.
303 *
304 * Used in the error path of thunderbolt_alloc_and_start.
305 */
306void thunderbolt_shutdown_and_free(struct tb *tb)
307{ 318{
319 struct tb_cm *tcm = tb_priv(tb);
308 struct tb_pci_tunnel *tunnel; 320 struct tb_pci_tunnel *tunnel;
309 struct tb_pci_tunnel *n; 321 struct tb_pci_tunnel *n;
310 322
311 mutex_lock(&tb->lock);
312
313 /* tunnels are only present after everything has been initialized */ 323 /* tunnels are only present after everything has been initialized */
314 list_for_each_entry_safe(tunnel, n, &tb->tunnel_list, list) { 324 list_for_each_entry_safe(tunnel, n, &tcm->tunnel_list, list) {
315 tb_pci_deactivate(tunnel); 325 tb_pci_deactivate(tunnel);
316 tb_pci_free(tunnel); 326 tb_pci_free(tunnel);
317 } 327 }
@@ -320,98 +330,44 @@ void thunderbolt_shutdown_and_free(struct tb *tb)
320 tb_switch_free(tb->root_switch); 330 tb_switch_free(tb->root_switch);
321 tb->root_switch = NULL; 331 tb->root_switch = NULL;
322 332
323 if (tb->ctl) { 333 tcm->hotplug_active = false; /* signal tb_handle_hotplug to quit */
324 tb_ctl_stop(tb->ctl);
325 tb_ctl_free(tb->ctl);
326 }
327 tb->ctl = NULL;
328 tb->hotplug_active = false; /* signal tb_handle_hotplug to quit */
329
330 /* allow tb_handle_hotplug to acquire the lock */
331 mutex_unlock(&tb->lock);
332 if (tb->wq) {
333 flush_workqueue(tb->wq);
334 destroy_workqueue(tb->wq);
335 tb->wq = NULL;
336 }
337 mutex_destroy(&tb->lock);
338 kfree(tb);
339} 334}
340 335
341/** 336static int tb_start(struct tb *tb)
342 * thunderbolt_alloc_and_start() - setup the thunderbolt bus
343 *
344 * Allocates a tb_cfg control channel, initializes the root switch, enables
345 * plug events and activates pci devices.
346 *
347 * Return: Returns NULL on error.
348 */
349struct tb *thunderbolt_alloc_and_start(struct tb_nhi *nhi)
350{ 337{
351 struct tb *tb; 338 struct tb_cm *tcm = tb_priv(tb);
352
353 BUILD_BUG_ON(sizeof(struct tb_regs_switch_header) != 5 * 4);
354 BUILD_BUG_ON(sizeof(struct tb_regs_port_header) != 8 * 4);
355 BUILD_BUG_ON(sizeof(struct tb_regs_hop) != 2 * 4);
356
357 tb = kzalloc(sizeof(*tb), GFP_KERNEL);
358 if (!tb)
359 return NULL;
360
361 tb->nhi = nhi;
362 mutex_init(&tb->lock);
363 mutex_lock(&tb->lock);
364 INIT_LIST_HEAD(&tb->tunnel_list);
365
366 tb->wq = alloc_ordered_workqueue("thunderbolt", 0);
367 if (!tb->wq)
368 goto err_locked;
369
370 tb->ctl = tb_ctl_alloc(tb->nhi, tb_schedule_hotplug_handler, tb);
371 if (!tb->ctl)
372 goto err_locked;
373 /*
374 * tb_schedule_hotplug_handler may be called as soon as the config
375 * channel is started. Thats why we have to hold the lock here.
376 */
377 tb_ctl_start(tb->ctl);
378 339
379 tb->root_switch = tb_switch_alloc(tb, 0); 340 tb->root_switch = tb_switch_alloc(tb, 0);
380 if (!tb->root_switch) 341 if (!tb->root_switch)
381 goto err_locked; 342 return -ENOMEM;
382 343
383 /* Full scan to discover devices added before the driver was loaded. */ 344 /* Full scan to discover devices added before the driver was loaded. */
384 tb_scan_switch(tb->root_switch); 345 tb_scan_switch(tb->root_switch);
385 tb_activate_pcie_devices(tb); 346 tb_activate_pcie_devices(tb);
386 347
387 /* Allow tb_handle_hotplug to progress events */ 348 /* Allow tb_handle_hotplug to progress events */
388 tb->hotplug_active = true; 349 tcm->hotplug_active = true;
389 mutex_unlock(&tb->lock); 350 return 0;
390 return tb;
391
392err_locked:
393 mutex_unlock(&tb->lock);
394 thunderbolt_shutdown_and_free(tb);
395 return NULL;
396} 351}
397 352
398void thunderbolt_suspend(struct tb *tb) 353static int tb_suspend_noirq(struct tb *tb)
399{ 354{
355 struct tb_cm *tcm = tb_priv(tb);
356
400 tb_info(tb, "suspending...\n"); 357 tb_info(tb, "suspending...\n");
401 mutex_lock(&tb->lock);
402 tb_switch_suspend(tb->root_switch); 358 tb_switch_suspend(tb->root_switch);
403 tb_ctl_stop(tb->ctl); 359 tcm->hotplug_active = false; /* signal tb_handle_hotplug to quit */
404 tb->hotplug_active = false; /* signal tb_handle_hotplug to quit */
405 mutex_unlock(&tb->lock);
406 tb_info(tb, "suspend finished\n"); 360 tb_info(tb, "suspend finished\n");
361
362 return 0;
407} 363}
408 364
409void thunderbolt_resume(struct tb *tb) 365static int tb_resume_noirq(struct tb *tb)
410{ 366{
367 struct tb_cm *tcm = tb_priv(tb);
411 struct tb_pci_tunnel *tunnel, *n; 368 struct tb_pci_tunnel *tunnel, *n;
369
412 tb_info(tb, "resuming...\n"); 370 tb_info(tb, "resuming...\n");
413 mutex_lock(&tb->lock);
414 tb_ctl_start(tb->ctl);
415 371
416 /* remove any pci devices the firmware might have setup */ 372 /* remove any pci devices the firmware might have setup */
417 tb_switch_reset(tb, 0); 373 tb_switch_reset(tb, 0);
@@ -419,9 +375,9 @@ void thunderbolt_resume(struct tb *tb)
419 tb_switch_resume(tb->root_switch); 375 tb_switch_resume(tb->root_switch);
420 tb_free_invalid_tunnels(tb); 376 tb_free_invalid_tunnels(tb);
421 tb_free_unplugged_children(tb->root_switch); 377 tb_free_unplugged_children(tb->root_switch);
422 list_for_each_entry_safe(tunnel, n, &tb->tunnel_list, list) 378 list_for_each_entry_safe(tunnel, n, &tcm->tunnel_list, list)
423 tb_pci_restart(tunnel); 379 tb_pci_restart(tunnel);
424 if (!list_empty(&tb->tunnel_list)) { 380 if (!list_empty(&tcm->tunnel_list)) {
425 /* 381 /*
426 * the pcie links need some time to get going. 382 * the pcie links need some time to get going.
427 * 100ms works for me... 383 * 100ms works for me...
@@ -430,7 +386,33 @@ void thunderbolt_resume(struct tb *tb)
430 msleep(100); 386 msleep(100);
431 } 387 }
432 /* Allow tb_handle_hotplug to progress events */ 388 /* Allow tb_handle_hotplug to progress events */
433 tb->hotplug_active = true; 389 tcm->hotplug_active = true;
434 mutex_unlock(&tb->lock);
435 tb_info(tb, "resume finished\n"); 390 tb_info(tb, "resume finished\n");
391
392 return 0;
393}
394
395static const struct tb_cm_ops tb_cm_ops = {
396 .start = tb_start,
397 .stop = tb_stop,
398 .suspend_noirq = tb_suspend_noirq,
399 .resume_noirq = tb_resume_noirq,
400 .hotplug = tb_schedule_hotplug_handler,
401};
402
403struct tb *tb_probe(struct tb_nhi *nhi)
404{
405 struct tb_cm *tcm;
406 struct tb *tb;
407
408 tb = tb_domain_alloc(nhi, sizeof(*tcm));
409 if (!tb)
410 return NULL;
411
412 tb->cm_ops = &tb_cm_ops;
413
414 tcm = tb_priv(tb);
415 INIT_LIST_HEAD(&tcm->tunnel_list);
416
417 return tb;
436} 418}