thunderbolt: Add tb_regs.h
[deliverable/linux.git] / drivers / thunderbolt / tb.c
1 /*
2 * Thunderbolt Cactus Ridge driver - bus logic (NHI independent)
3 *
4 * Copyright (c) 2014 Andreas Noever <andreas.noever@gmail.com>
5 */
6
7 #include <linux/slab.h>
8 #include <linux/errno.h>
9 #include <linux/delay.h>
10
11 #include "tb.h"
12 #include "tb_regs.h"
13
14 /* hotplug handling */
15
16 struct tb_hotplug_event {
17 struct work_struct work;
18 struct tb *tb;
19 u64 route;
20 u8 port;
21 bool unplug;
22 };
23
24 /**
25 * tb_handle_hotplug() - handle hotplug event
26 *
27 * Executes on tb->wq.
28 */
29 static void tb_handle_hotplug(struct work_struct *work)
30 {
31 struct tb_hotplug_event *ev = container_of(work, typeof(*ev), work);
32 struct tb *tb = ev->tb;
33 mutex_lock(&tb->lock);
34 if (!tb->hotplug_active)
35 goto out; /* during init, suspend or shutdown */
36
37 /* do nothing for now */
38 out:
39 mutex_unlock(&tb->lock);
40 kfree(ev);
41 }
42
43 /**
44 * tb_schedule_hotplug_handler() - callback function for the control channel
45 *
46 * Delegates to tb_handle_hotplug.
47 */
48 static void tb_schedule_hotplug_handler(void *data, u64 route, u8 port,
49 bool unplug)
50 {
51 struct tb *tb = data;
52 struct tb_hotplug_event *ev = kmalloc(sizeof(*ev), GFP_KERNEL);
53 if (!ev)
54 return;
55 INIT_WORK(&ev->work, tb_handle_hotplug);
56 ev->tb = tb;
57 ev->route = route;
58 ev->port = port;
59 ev->unplug = unplug;
60 queue_work(tb->wq, &ev->work);
61 }
62
63 /**
64 * thunderbolt_shutdown_and_free() - shutdown everything
65 *
66 * Free all switches and the config channel.
67 *
68 * Used in the error path of thunderbolt_alloc_and_start.
69 */
70 void thunderbolt_shutdown_and_free(struct tb *tb)
71 {
72 mutex_lock(&tb->lock);
73
74 if (tb->ctl) {
75 tb_ctl_stop(tb->ctl);
76 tb_ctl_free(tb->ctl);
77 }
78 tb->ctl = NULL;
79 tb->hotplug_active = false; /* signal tb_handle_hotplug to quit */
80
81 /* allow tb_handle_hotplug to acquire the lock */
82 mutex_unlock(&tb->lock);
83 if (tb->wq) {
84 flush_workqueue(tb->wq);
85 destroy_workqueue(tb->wq);
86 tb->wq = NULL;
87 }
88 mutex_destroy(&tb->lock);
89 kfree(tb);
90 }
91
92 /**
93 * thunderbolt_alloc_and_start() - setup the thunderbolt bus
94 *
95 * Allocates a tb_cfg control channel, initializes the root switch, enables
96 * plug events and activates pci devices.
97 *
98 * Return: Returns NULL on error.
99 */
100 struct tb *thunderbolt_alloc_and_start(struct tb_nhi *nhi)
101 {
102 struct tb *tb;
103
104 BUILD_BUG_ON(sizeof(struct tb_regs_switch_header) != 5 * 4);
105 BUILD_BUG_ON(sizeof(struct tb_regs_port_header) != 8 * 4);
106 BUILD_BUG_ON(sizeof(struct tb_regs_hop) != 2 * 4);
107
108 tb = kzalloc(sizeof(*tb), GFP_KERNEL);
109 if (!tb)
110 return NULL;
111
112 tb->nhi = nhi;
113 mutex_init(&tb->lock);
114 mutex_lock(&tb->lock);
115
116 tb->wq = alloc_ordered_workqueue("thunderbolt", 0);
117 if (!tb->wq)
118 goto err_locked;
119
120 tb->ctl = tb_ctl_alloc(tb->nhi, tb_schedule_hotplug_handler, tb);
121 if (!tb->ctl)
122 goto err_locked;
123 /*
124 * tb_schedule_hotplug_handler may be called as soon as the config
125 * channel is started. Thats why we have to hold the lock here.
126 */
127 tb_ctl_start(tb->ctl);
128
129 /* Allow tb_handle_hotplug to progress events */
130 tb->hotplug_active = true;
131 mutex_unlock(&tb->lock);
132 return tb;
133
134 err_locked:
135 mutex_unlock(&tb->lock);
136 thunderbolt_shutdown_and_free(tb);
137 return NULL;
138 }
139
This page took 0.044465 seconds and 5 git commands to generate.