Blame view
drivers/greybus/connection.c
22.6 KB
eb50fd3a2 staging: greybus:... |
1 |
// SPDX-License-Identifier: GPL-2.0 |
c68adb2f2 greybus: introduc... |
2 3 4 5 |
/* * Greybus connections * * Copyright 2014 Google Inc. |
a46e96719 greybus: add Lina... |
6 |
* Copyright 2014 Linaro Ltd. |
c68adb2f2 greybus: introduc... |
7 |
*/ |
5a5bc354c greybus: operatio... |
8 |
#include <linux/workqueue.h> |
ec0ad8681 staging: greybus:... |
9 |
#include <linux/greybus.h> |
5a5bc354c greybus: operatio... |
10 |
|
79c8c6494 greybus: tracing:... |
11 |
#include "greybus_trace.h" |
c68adb2f2 greybus: introduc... |
12 |
|
aac0839ea greybus: connecti... |
13 |
#define GB_CONNECTION_CPORT_QUIESCE_TIMEOUT 1000 |
0e46fab7d greybus: connecti... |
14 |
static void gb_connection_kref_release(struct kref *kref); |
748e1230c greybus: fix some... |
15 |
static DEFINE_SPINLOCK(gb_connections_lock); |
210b508e4 greybus: connecti... |
16 |
static DEFINE_MUTEX(gb_connection_mutex); |
b53e0c9e8 greybus: connecti... |
17 |
/* Caller holds gb_connection_mutex. */ |
54131222e greybus: connecti... |
18 |
static bool gb_connection_cport_in_use(struct gb_interface *intf, u16 cport_id) |
f5c2be9e9 greybus: connecti... |
19 |
{ |
2537636ab greybus: hd: rena... |
20 |
struct gb_host_device *hd = intf->hd; |
f5c2be9e9 greybus: connecti... |
21 |
struct gb_connection *connection; |
0daf17b9e greybus: connecti... |
22 23 |
list_for_each_entry(connection, &hd->connections, hd_links) { if (connection->intf == intf && |
8478c35a8 staging: greybus:... |
24 |
connection->intf_cport_id == cport_id) |
54131222e greybus: connecti... |
25 |
return true; |
0daf17b9e greybus: connecti... |
26 |
} |
54131222e greybus: connecti... |
27 |
return false; |
f5c2be9e9 greybus: connecti... |
28 |
} |
0e46fab7d greybus: connecti... |
29 30 31 |
static void gb_connection_get(struct gb_connection *connection) { kref_get(&connection->kref); |
79c8c6494 greybus: tracing:... |
32 33 |
trace_gb_connection_get(connection); |
0e46fab7d greybus: connecti... |
34 35 36 37 |
} static void gb_connection_put(struct gb_connection *connection) { |
79c8c6494 greybus: tracing:... |
38 |
trace_gb_connection_put(connection); |
0e46fab7d greybus: connecti... |
39 40 41 42 43 44 |
kref_put(&connection->kref, gb_connection_kref_release); } /* * Returns a reference-counted pointer to the connection if found. */ |
8bd0ae6e7 greybus: connecti... |
45 |
static struct gb_connection * |
2537636ab greybus: hd: rena... |
46 |
gb_connection_hd_find(struct gb_host_device *hd, u16 cport_id) |
ee9ebe4d0 greybus: add bg_h... |
47 |
{ |
f5c2be9e9 greybus: connecti... |
48 |
struct gb_connection *connection; |
8f5eadb7e greybus: connecti... |
49 |
unsigned long flags; |
ee9ebe4d0 greybus: add bg_h... |
50 |
|
8f5eadb7e greybus: connecti... |
51 |
spin_lock_irqsave(&gb_connections_lock, flags); |
2c43ce496 greybus: use a si... |
52 |
list_for_each_entry(connection, &hd->connections, hd_links) |
0e46fab7d greybus: connecti... |
53 54 |
if (connection->hd_cport_id == cport_id) { gb_connection_get(connection); |
e86905b6c greybus: gb_hd_co... |
55 |
goto found; |
0e46fab7d greybus: connecti... |
56 |
} |
e86905b6c greybus: gb_hd_co... |
57 |
connection = NULL; |
f5c2be9e9 greybus: connecti... |
58 |
found: |
8f5eadb7e greybus: connecti... |
59 |
spin_unlock_irqrestore(&gb_connections_lock, flags); |
ee9ebe4d0 greybus: add bg_h... |
60 61 62 |
return connection; } |
de3557d92 greybus: rename g... |
63 64 |
/* * Callback from the host driver to let us know that data has been |
1db0a5ff3 greybus: bundle: ... |
65 |
* received on the bundle. |
de3557d92 greybus: rename g... |
66 |
*/ |
2537636ab greybus: hd: rena... |
67 |
void greybus_data_rcvd(struct gb_host_device *hd, u16 cport_id, |
8478c35a8 staging: greybus:... |
68 |
u8 *data, size_t length) |
374e6a269 greybus: kill off... |
69 70 |
{ struct gb_connection *connection; |
495787a79 greybus: tracing:... |
71 |
trace_gb_hd_in(hd); |
12eba9f8e greybus: connecti... |
72 |
connection = gb_connection_hd_find(hd, cport_id); |
374e6a269 greybus: kill off... |
73 |
if (!connection) { |
2adaefb14 greybus: hd: make... |
74 |
dev_err(&hd->dev, |
374e6a269 greybus: kill off... |
75 76 77 78 |
"nonexistent connection (%zu bytes dropped) ", length); return; } |
61089e89e greybus: rework r... |
79 |
gb_connection_recv(connection, data, length); |
0e46fab7d greybus: connecti... |
80 |
gb_connection_put(connection); |
374e6a269 greybus: kill off... |
81 |
} |
de3557d92 greybus: rename g... |
82 |
EXPORT_SYMBOL_GPL(greybus_data_rcvd); |
374e6a269 greybus: kill off... |
83 |
|
b750fa337 greybus: connecti... |
84 |
static void gb_connection_kref_release(struct kref *kref) |
f0f61b904 greybus: hook up ... |
85 |
{ |
b750fa337 greybus: connecti... |
86 |
struct gb_connection *connection; |
f0f61b904 greybus: hook up ... |
87 |
|
b750fa337 greybus: connecti... |
88 |
connection = container_of(kref, struct gb_connection, kref); |
c3681f6c9 greybus: connecti... |
89 |
|
79c8c6494 greybus: tracing:... |
90 |
trace_gb_connection_release(connection); |
f0f61b904 greybus: hook up ... |
91 92 |
kfree(connection); } |
729b260a6 greybus: connecti... |
93 94 95 96 97 98 99 100 101 102 103 104 |
static void gb_connection_init_name(struct gb_connection *connection) { u16 hd_cport_id = connection->hd_cport_id; u16 cport_id = 0; u8 intf_id = 0; if (connection->intf) { intf_id = connection->intf->interface_id; cport_id = connection->intf_cport_id; } snprintf(connection->name, sizeof(connection->name), |
8478c35a8 staging: greybus:... |
105 |
"%u/%u:%u", hd_cport_id, intf_id, cport_id); |
729b260a6 greybus: connecti... |
106 |
} |
177404bd2 greybus: use ida ... |
107 |
/* |
96c2af5c6 greybus: connecti... |
108 |
* _gb_connection_create() - create a Greybus connection |
2566fae6a greybus: connecti... |
109 110 111 112 113 |
* @hd: host device of the connection * @hd_cport_id: host-device cport id, or -1 for dynamic allocation * @intf: remote interface, or NULL for static connections * @bundle: remote-interface bundle (may be NULL) * @cport_id: remote-interface cport id, or 0 for static connections |
f7ee081e3 greybus: connecti... |
114 |
* @handler: request handler (may be NULL) |
cb033188d greybus: connecti... |
115 |
* @flags: connection flags |
2566fae6a greybus: connecti... |
116 117 |
* * Create a Greybus connection, representing the bidirectional link |
c68adb2f2 greybus: introduc... |
118 |
* between a CPort on a (local) Greybus host device and a CPort on |
2566fae6a greybus: connecti... |
119 |
* another Greybus interface. |
c68adb2f2 greybus: introduc... |
120 |
* |
e88afa581 greybus: introduc... |
121 122 123 |
* A connection also maintains the state of operations sent over the * connection. * |
210b508e4 greybus: connecti... |
124 125 126 |
* Serialised against concurrent create and destroy using the * gb_connection_mutex. * |
24e094d68 greybus: connecti... |
127 128 |
* Return: A pointer to the new connection if successful, or an ERR_PTR * otherwise. |
c68adb2f2 greybus: introduc... |
129 |
*/ |
2566fae6a greybus: connecti... |
130 |
static struct gb_connection * |
96c2af5c6 greybus: connecti... |
131 |
_gb_connection_create(struct gb_host_device *hd, int hd_cport_id, |
8478c35a8 staging: greybus:... |
132 133 134 135 |
struct gb_interface *intf, struct gb_bundle *bundle, int cport_id, gb_request_handler_t handler, unsigned long flags) |
c68adb2f2 greybus: introduc... |
136 137 |
{ struct gb_connection *connection; |
24e094d68 greybus: connecti... |
138 |
int ret; |
c68adb2f2 greybus: introduc... |
139 |
|
210b508e4 greybus: connecti... |
140 |
mutex_lock(&gb_connection_mutex); |
54131222e greybus: connecti... |
141 |
if (intf && gb_connection_cport_in_use(intf, cport_id)) { |
b53e0c9e8 greybus: connecti... |
142 143 |
dev_err(&intf->dev, "cport %u already in use ", cport_id); |
24e094d68 greybus: connecti... |
144 |
ret = -EBUSY; |
b53e0c9e8 greybus: connecti... |
145 146 |
goto err_unlock; } |
f2aae1c6e greybus: hd: gene... |
147 |
ret = gb_hd_cport_allocate(hd, hd_cport_id, flags); |
74a5d93ce greybus: hd: move... |
148 149 150 |
if (ret < 0) { dev_err(&hd->dev, "failed to allocate cport: %d ", ret); |
210b508e4 greybus: connecti... |
151 |
goto err_unlock; |
74a5d93ce greybus: hd: move... |
152 |
} |
24e094d68 greybus: connecti... |
153 |
hd_cport_id = ret; |
10f9fa133 greybus: connecti... |
154 |
|
c68adb2f2 greybus: introduc... |
155 |
connection = kzalloc(sizeof(*connection), GFP_KERNEL); |
24e094d68 greybus: connecti... |
156 157 |
if (!connection) { ret = -ENOMEM; |
74a5d93ce greybus: hd: move... |
158 |
goto err_hd_cport_release; |
24e094d68 greybus: connecti... |
159 |
} |
c68adb2f2 greybus: introduc... |
160 |
|
7c63a827d greybus: connecti... |
161 |
connection->hd_cport_id = hd_cport_id; |
f9b0366f1 greybus: connecti... |
162 |
connection->intf_cport_id = cport_id; |
f5c2be9e9 greybus: connecti... |
163 |
connection->hd = hd; |
2566fae6a greybus: connecti... |
164 |
connection->intf = intf; |
1db0a5ff3 greybus: bundle: ... |
165 |
connection->bundle = bundle; |
f7ee081e3 greybus: connecti... |
166 |
connection->handler = handler; |
cb033188d greybus: connecti... |
167 |
connection->flags = flags; |
0e9b41ab9 greybus: connecti... |
168 169 |
if (intf && (intf->quirks & GB_INTERFACE_QUIRK_NO_CPORT_FEATURES)) connection->flags |= GB_CONNECTION_FLAG_NO_FLOWCTRL; |
36561f23a greybus: define c... |
170 |
connection->state = GB_CONNECTION_STATE_DISABLED; |
ad1c449eb greybus: record c... |
171 |
|
4e2b1e46a greybus: connecti... |
172 |
atomic_set(&connection->op_cycle, 0); |
23268785b greybus: connecti... |
173 |
mutex_init(&connection->mutex); |
4e2b1e46a greybus: connecti... |
174 175 |
spin_lock_init(&connection->lock); INIT_LIST_HEAD(&connection->operations); |
5a5bc354c greybus: operatio... |
176 |
connection->wq = alloc_workqueue("%s:%d", WQ_UNBOUND, 1, |
582b3a139 greybus: connecti... |
177 |
dev_name(&hd->dev), hd_cport_id); |
24e094d68 greybus: connecti... |
178 179 |
if (!connection->wq) { ret = -ENOMEM; |
5a5bc354c greybus: operatio... |
180 |
goto err_free_connection; |
24e094d68 greybus: connecti... |
181 |
} |
5a5bc354c greybus: operatio... |
182 |
|
b750fa337 greybus: connecti... |
183 |
kref_init(&connection->kref); |
f0f61b904 greybus: hook up ... |
184 |
|
729b260a6 greybus: connecti... |
185 |
gb_connection_init_name(connection); |
0b1d26235 greybus: Revert "... |
186 |
spin_lock_irq(&gb_connections_lock); |
928f2abd5 greybus: Tear dow... |
187 |
list_add(&connection->hd_links, &hd->connections); |
75662e5ca greybus: connecti... |
188 189 190 191 192 |
if (bundle) list_add(&connection->bundle_links, &bundle->connections); else INIT_LIST_HEAD(&connection->bundle_links); |
0b1d26235 greybus: Revert "... |
193 |
spin_unlock_irq(&gb_connections_lock); |
748e1230c greybus: fix some... |
194 |
|
210b508e4 greybus: connecti... |
195 |
mutex_unlock(&gb_connection_mutex); |
79c8c6494 greybus: tracing:... |
196 |
trace_gb_connection_create(connection); |
c68adb2f2 greybus: introduc... |
197 |
return connection; |
10f9fa133 greybus: connecti... |
198 |
|
5a5bc354c greybus: operatio... |
199 200 |
err_free_connection: kfree(connection); |
74a5d93ce greybus: hd: move... |
201 202 |
err_hd_cport_release: gb_hd_cport_release(hd, hd_cport_id); |
210b508e4 greybus: connecti... |
203 204 |
err_unlock: mutex_unlock(&gb_connection_mutex); |
10f9fa133 greybus: connecti... |
205 |
|
24e094d68 greybus: connecti... |
206 |
return ERR_PTR(ret); |
c68adb2f2 greybus: introduc... |
207 |
} |
2566fae6a greybus: connecti... |
208 |
struct gb_connection * |
f7ee081e3 greybus: connecti... |
209 |
gb_connection_create_static(struct gb_host_device *hd, u16 hd_cport_id, |
8478c35a8 staging: greybus:... |
210 |
gb_request_handler_t handler) |
2566fae6a greybus: connecti... |
211 |
{ |
cb033188d greybus: connecti... |
212 |
return _gb_connection_create(hd, hd_cport_id, NULL, NULL, 0, handler, |
8478c35a8 staging: greybus:... |
213 |
GB_CONNECTION_FLAG_HIGH_PRIO); |
2566fae6a greybus: connecti... |
214 215 216 |
} struct gb_connection * |
59507e261 greybus: connecti... |
217 218 |
gb_connection_create_control(struct gb_interface *intf) { |
aca7aab39 greybus: connecti... |
219 |
return _gb_connection_create(intf->hd, -1, intf, NULL, 0, NULL, |
8478c35a8 staging: greybus:... |
220 221 |
GB_CONNECTION_FLAG_CONTROL | GB_CONNECTION_FLAG_HIGH_PRIO); |
59507e261 greybus: connecti... |
222 223 224 |
} struct gb_connection * |
f7ee081e3 greybus: connecti... |
225 |
gb_connection_create(struct gb_bundle *bundle, u16 cport_id, |
8478c35a8 staging: greybus:... |
226 |
gb_request_handler_t handler) |
2566fae6a greybus: connecti... |
227 |
{ |
8cff6c647 greybus: connecti... |
228 |
struct gb_interface *intf = bundle->intf; |
f7ee081e3 greybus: connecti... |
229 |
return _gb_connection_create(intf->hd, -1, intf, bundle, cport_id, |
8478c35a8 staging: greybus:... |
230 |
handler, 0); |
2566fae6a greybus: connecti... |
231 |
} |
96c2af5c6 greybus: connecti... |
232 |
EXPORT_SYMBOL_GPL(gb_connection_create); |
2566fae6a greybus: connecti... |
233 |
|
cb033188d greybus: connecti... |
234 235 |
struct gb_connection * gb_connection_create_flags(struct gb_bundle *bundle, u16 cport_id, |
8478c35a8 staging: greybus:... |
236 237 |
gb_request_handler_t handler, unsigned long flags) |
cb033188d greybus: connecti... |
238 239 |
{ struct gb_interface *intf = bundle->intf; |
1ba30c330 greybus: connecti... |
240 241 |
if (WARN_ON_ONCE(flags & GB_CONNECTION_FLAG_CORE_MASK)) flags &= ~GB_CONNECTION_FLAG_CORE_MASK; |
cb033188d greybus: connecti... |
242 |
return _gb_connection_create(intf->hd, -1, intf, bundle, cport_id, |
8478c35a8 staging: greybus:... |
243 |
handler, flags); |
cb033188d greybus: connecti... |
244 245 |
} EXPORT_SYMBOL_GPL(gb_connection_create_flags); |
781ac8662 greybus: connecti... |
246 247 |
struct gb_connection * gb_connection_create_offloaded(struct gb_bundle *bundle, u16 cport_id, |
8478c35a8 staging: greybus:... |
248 |
unsigned long flags) |
781ac8662 greybus: connecti... |
249 |
{ |
781ac8662 greybus: connecti... |
250 |
flags |= GB_CONNECTION_FLAG_OFFLOADED; |
1ba30c330 greybus: connecti... |
251 |
return gb_connection_create_flags(bundle, cport_id, NULL, flags); |
781ac8662 greybus: connecti... |
252 253 |
} EXPORT_SYMBOL_GPL(gb_connection_create_offloaded); |
d7ea30a57 greybus: hd: add ... |
254 255 |
static int gb_connection_hd_cport_enable(struct gb_connection *connection) { |
2537636ab greybus: hd: rena... |
256 |
struct gb_host_device *hd = connection->hd; |
d7ea30a57 greybus: hd: add ... |
257 258 259 260 |
int ret; if (!hd->driver->cport_enable) return 0; |
6910fa2dd greybus: hd: add ... |
261 |
ret = hd->driver->cport_enable(hd, connection->hd_cport_id, |
8478c35a8 staging: greybus:... |
262 |
connection->flags); |
d7ea30a57 greybus: hd: add ... |
263 |
if (ret) { |
62e046235 greybus: connecti... |
264 265 |
dev_err(&hd->dev, "%s: failed to enable host cport: %d ", |
8478c35a8 staging: greybus:... |
266 |
connection->name, ret); |
d7ea30a57 greybus: hd: add ... |
267 268 269 270 271 272 273 274 |
return ret; } return 0; } static void gb_connection_hd_cport_disable(struct gb_connection *connection) { |
2537636ab greybus: hd: rena... |
275 |
struct gb_host_device *hd = connection->hd; |
3cbe52c2e greybus: connecti... |
276 |
int ret; |
d7ea30a57 greybus: hd: add ... |
277 278 279 |
if (!hd->driver->cport_disable) return; |
3cbe52c2e greybus: connecti... |
280 281 |
ret = hd->driver->cport_disable(hd, connection->hd_cport_id); if (ret) { |
62e046235 greybus: connecti... |
282 283 |
dev_err(&hd->dev, "%s: failed to disable host cport: %d ", |
8478c35a8 staging: greybus:... |
284 |
connection->name, ret); |
3cbe52c2e greybus: connecti... |
285 |
} |
d7ea30a57 greybus: hd: add ... |
286 |
} |
aac0839ea greybus: connecti... |
287 288 289 290 291 292 293 294 295 296 297 298 |
static int gb_connection_hd_cport_connected(struct gb_connection *connection) { struct gb_host_device *hd = connection->hd; int ret; if (!hd->driver->cport_connected) return 0; ret = hd->driver->cport_connected(hd, connection->hd_cport_id); if (ret) { dev_err(&hd->dev, "%s: failed to set connected state: %d ", |
8478c35a8 staging: greybus:... |
299 |
connection->name, ret); |
aac0839ea greybus: connecti... |
300 301 302 303 304 |
return ret; } return 0; } |
800d6c8f4 greybus: connecti... |
305 306 307 308 309 310 311 312 313 314 315 316 |
static int gb_connection_hd_cport_flush(struct gb_connection *connection) { struct gb_host_device *hd = connection->hd; int ret; if (!hd->driver->cport_flush) return 0; ret = hd->driver->cport_flush(hd, connection->hd_cport_id); if (ret) { dev_err(&hd->dev, "%s: failed to flush host cport: %d ", |
8478c35a8 staging: greybus:... |
317 |
connection->name, ret); |
800d6c8f4 greybus: connecti... |
318 319 320 321 322 |
return ret; } return 0; } |
aac0839ea greybus: connecti... |
323 |
static int gb_connection_hd_cport_quiesce(struct gb_connection *connection) |
9ed5e1ba3 greybus: connecti... |
324 325 |
{ struct gb_host_device *hd = connection->hd; |
aac0839ea greybus: connecti... |
326 |
size_t peer_space; |
9ed5e1ba3 greybus: connecti... |
327 |
int ret; |
f05a88a39 staging: greybus:... |
328 329 |
if (!hd->driver->cport_quiesce) return 0; |
aac0839ea greybus: connecti... |
330 331 |
peer_space = sizeof(struct gb_operation_msg_hdr) + sizeof(struct gb_cport_shutdown_request); |
9ed5e1ba3 greybus: connecti... |
332 |
|
aac0839ea greybus: connecti... |
333 334 335 336 337 338 |
if (connection->mode_switch) peer_space += sizeof(struct gb_operation_msg_hdr); ret = hd->driver->cport_quiesce(hd, connection->hd_cport_id, peer_space, GB_CONNECTION_CPORT_QUIESCE_TIMEOUT); |
9ed5e1ba3 greybus: connecti... |
339 |
if (ret) { |
aac0839ea greybus: connecti... |
340 341 |
dev_err(&hd->dev, "%s: failed to quiesce host cport: %d ", |
8478c35a8 staging: greybus:... |
342 |
connection->name, ret); |
9ed5e1ba3 greybus: connecti... |
343 344 345 346 347 |
return ret; } return 0; } |
aac0839ea greybus: connecti... |
348 |
static int gb_connection_hd_cport_clear(struct gb_connection *connection) |
9ed5e1ba3 greybus: connecti... |
349 350 |
{ struct gb_host_device *hd = connection->hd; |
aac0839ea greybus: connecti... |
351 |
int ret; |
9ed5e1ba3 greybus: connecti... |
352 |
|
f05a88a39 staging: greybus:... |
353 354 |
if (!hd->driver->cport_clear) return 0; |
aac0839ea greybus: connecti... |
355 356 357 358 |
ret = hd->driver->cport_clear(hd, connection->hd_cport_id); if (ret) { dev_err(&hd->dev, "%s: failed to clear host cport: %d ", |
8478c35a8 staging: greybus:... |
359 |
connection->name, ret); |
aac0839ea greybus: connecti... |
360 361 |
return ret; } |
9ed5e1ba3 greybus: connecti... |
362 |
|
aac0839ea greybus: connecti... |
363 |
return 0; |
9ed5e1ba3 greybus: connecti... |
364 |
} |
c68adb2f2 greybus: introduc... |
365 |
/* |
a95c258c6 greybus: connecti... |
366 367 368 369 370 371 |
* Request the SVC to create a connection from AP's cport to interface's * cport. */ static int gb_connection_svc_connection_create(struct gb_connection *connection) { |
2537636ab greybus: hd: rena... |
372 |
struct gb_host_device *hd = connection->hd; |
1575ef18a greybus: svc: ski... |
373 |
struct gb_interface *intf; |
27f25c17a greybus: connecti... |
374 |
u8 cport_flags; |
a95c258c6 greybus: connecti... |
375 |
int ret; |
4ec1574ae greybus: connecti... |
376 |
if (gb_connection_is_static(connection)) |
00ad6975e greybus: connecti... |
377 |
return 0; |
a95c258c6 greybus: connecti... |
378 |
|
35822c04a greybus: connecti... |
379 |
intf = connection->intf; |
27f25c17a greybus: connecti... |
380 |
|
ec199ccdd greybus: interfac... |
381 |
/* |
0e9b41ab9 greybus: connecti... |
382 |
* Enable either E2EFC or CSD, unless no flow control is requested. |
ec199ccdd greybus: interfac... |
383 |
*/ |
27f25c17a greybus: connecti... |
384 |
cport_flags = GB_SVC_CPORT_FLAG_CSV_N; |
0e9b41ab9 greybus: connecti... |
385 |
if (gb_connection_flow_control_disabled(connection)) { |
27f25c17a greybus: connecti... |
386 |
cport_flags |= GB_SVC_CPORT_FLAG_CSD_N; |
64a6d1388 greybus: connecti... |
387 |
} else if (gb_connection_e2efc_enabled(connection)) { |
27f25c17a greybus: connecti... |
388 389 390 |
cport_flags |= GB_SVC_CPORT_FLAG_CSD_N | GB_SVC_CPORT_FLAG_E2EFC; } |
a95c258c6 greybus: connecti... |
391 |
ret = gb_svc_connection_create(hd->svc, |
8478c35a8 staging: greybus:... |
392 393 394 395 396 |
hd->svc->ap_intf_id, connection->hd_cport_id, intf->interface_id, connection->intf_cport_id, cport_flags); |
a95c258c6 greybus: connecti... |
397 |
if (ret) { |
4c4b50218 greybus: connecti... |
398 399 400 401 |
dev_err(&connection->hd->dev, "%s: failed to create svc connection: %d ", connection->name, ret); |
a95c258c6 greybus: connecti... |
402 403 |
return ret; } |
a95c258c6 greybus: connecti... |
404 405 |
return 0; } |
1b7a9cd5a greybus: connecti... |
406 407 408 |
static void gb_connection_svc_connection_destroy(struct gb_connection *connection) { |
4ec1574ae greybus: connecti... |
409 |
if (gb_connection_is_static(connection)) |
1b7a9cd5a greybus: connecti... |
410 411 412 |
return; gb_svc_connection_destroy(connection->hd->svc, |
66069fb06 greybus: svc: mov... |
413 |
connection->hd->svc->ap_intf_id, |
1b7a9cd5a greybus: connecti... |
414 |
connection->hd_cport_id, |
35822c04a greybus: connecti... |
415 |
connection->intf->interface_id, |
1b7a9cd5a greybus: connecti... |
416 417 |
connection->intf_cport_id); } |
9d7fc25b3 greybus: connecti... |
418 419 420 |
/* Inform Interface about active CPorts */ static int gb_connection_control_connected(struct gb_connection *connection) { |
9d7fc25b3 greybus: connecti... |
421 422 423 |
struct gb_control *control; u16 cport_id = connection->intf_cport_id; int ret; |
bc3be1705 greybus: connecti... |
424 |
if (gb_connection_is_static(connection)) |
9d7fc25b3 greybus: connecti... |
425 |
return 0; |
aca7aab39 greybus: connecti... |
426 |
if (gb_connection_is_control(connection)) |
bc3be1705 greybus: connecti... |
427 |
return 0; |
9d7fc25b3 greybus: connecti... |
428 |
|
aca7aab39 greybus: connecti... |
429 |
control = connection->intf->control; |
9d7fc25b3 greybus: connecti... |
430 431 |
ret = gb_control_connected_operation(control, cport_id); if (ret) { |
30482c1e6 greybus: connecti... |
432 433 434 |
dev_err(&connection->bundle->dev, "failed to connect cport: %d ", ret); |
9d7fc25b3 greybus: connecti... |
435 436 437 438 439 |
return ret; } return 0; } |
3de5acfaf greybus: connecti... |
440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 |
static void gb_connection_control_disconnecting(struct gb_connection *connection) { struct gb_control *control; u16 cport_id = connection->intf_cport_id; int ret; if (gb_connection_is_static(connection)) return; control = connection->intf->control; ret = gb_control_disconnecting_operation(control, cport_id); if (ret) { dev_err(&connection->hd->dev, |
8478c35a8 staging: greybus:... |
455 456 457 |
"%s: failed to send disconnecting: %d ", connection->name, ret); |
3de5acfaf greybus: connecti... |
458 459 |
} } |
72d748226 greybus: connecti... |
460 461 |
static void gb_connection_control_disconnected(struct gb_connection *connection) |
186906590 greybus: connecti... |
462 463 |
{ struct gb_control *control; |
72d748226 greybus: connecti... |
464 |
u16 cport_id = connection->intf_cport_id; |
186906590 greybus: connecti... |
465 |
int ret; |
bc3be1705 greybus: connecti... |
466 |
if (gb_connection_is_static(connection)) |
186906590 greybus: connecti... |
467 |
return; |
55742d2a0 greybus: interfac... |
468 469 470 471 472 473 474 475 476 477 478 479 480 |
control = connection->intf->control; if (gb_connection_is_control(connection)) { if (connection->mode_switch) { ret = gb_control_mode_switch_operation(control); if (ret) { /* * Allow mode switch to time out waiting for * mailbox event. */ return; } } |
bc3be1705 greybus: connecti... |
481 |
return; |
55742d2a0 greybus: interfac... |
482 |
} |
186906590 greybus: connecti... |
483 484 |
ret = gb_control_disconnected_operation(control, cport_id); |
72d748226 greybus: connecti... |
485 |
if (ret) { |
30482c1e6 greybus: connecti... |
486 487 488 |
dev_warn(&connection->bundle->dev, "failed to disconnect cport: %d ", ret); |
72d748226 greybus: connecti... |
489 |
} |
186906590 greybus: connecti... |
490 |
} |
aac0839ea greybus: connecti... |
491 |
static int gb_connection_shutdown_operation(struct gb_connection *connection, |
8478c35a8 staging: greybus:... |
492 |
u8 phase) |
3de5acfaf greybus: connecti... |
493 |
{ |
aac0839ea greybus: connecti... |
494 |
struct gb_cport_shutdown_request *req; |
3de5acfaf greybus: connecti... |
495 496 497 498 |
struct gb_operation *operation; int ret; operation = gb_operation_create_core(connection, |
8478c35a8 staging: greybus:... |
499 500 501 |
GB_REQUEST_TYPE_CPORT_SHUTDOWN, sizeof(*req), 0, 0, GFP_KERNEL); |
3de5acfaf greybus: connecti... |
502 503 |
if (!operation) return -ENOMEM; |
aac0839ea greybus: connecti... |
504 505 |
req = operation->request->payload; req->phase = phase; |
3de5acfaf greybus: connecti... |
506 507 508 509 510 511 |
ret = gb_operation_request_send_sync(operation); gb_operation_put(operation); return ret; } |
aac0839ea greybus: connecti... |
512 513 |
static int gb_connection_cport_shutdown(struct gb_connection *connection, u8 phase) |
3de5acfaf greybus: connecti... |
514 515 |
{ struct gb_host_device *hd = connection->hd; |
aac0839ea greybus: connecti... |
516 |
const struct gb_hd_driver *drv = hd->driver; |
3de5acfaf greybus: connecti... |
517 518 519 520 521 522 |
int ret; if (gb_connection_is_static(connection)) return 0; if (gb_connection_is_offloaded(connection)) { |
aac0839ea greybus: connecti... |
523 |
if (!drv->cport_shutdown) |
3de5acfaf greybus: connecti... |
524 |
return 0; |
aac0839ea greybus: connecti... |
525 |
ret = drv->cport_shutdown(hd, connection->hd_cport_id, phase, |
8478c35a8 staging: greybus:... |
526 |
GB_OPERATION_TIMEOUT_DEFAULT); |
3de5acfaf greybus: connecti... |
527 |
} else { |
aac0839ea greybus: connecti... |
528 |
ret = gb_connection_shutdown_operation(connection, phase); |
3de5acfaf greybus: connecti... |
529 530 531 |
} if (ret) { |
aac0839ea greybus: connecti... |
532 533 |
dev_err(&hd->dev, "%s: failed to send cport shutdown (phase %d): %d ", |
8478c35a8 staging: greybus:... |
534 |
connection->name, phase, ret); |
3de5acfaf greybus: connecti... |
535 536 537 538 539 |
return ret; } return 0; } |
aac0839ea greybus: connecti... |
540 541 542 543 544 545 546 547 548 549 550 |
static int gb_connection_cport_shutdown_phase_1(struct gb_connection *connection) { return gb_connection_cport_shutdown(connection, 1); } static int gb_connection_cport_shutdown_phase_2(struct gb_connection *connection) { return gb_connection_cport_shutdown(connection, 2); } |
2846d3ed2 greybus: connecti... |
551 |
/* |
520c6eae9 greybus: connecti... |
552 553 |
* Cancel all active operations on a connection. * |
3de5acfaf greybus: connecti... |
554 555 |
* Locking: Called with connection lock held and state set to DISABLED or * DISCONNECTING. |
520c6eae9 greybus: connecti... |
556 557 |
*/ static void gb_connection_cancel_operations(struct gb_connection *connection, |
8478c35a8 staging: greybus:... |
558 |
int errno) |
127c1fbd5 greybus: connecti... |
559 |
__must_hold(&connection->lock) |
520c6eae9 greybus: connecti... |
560 561 562 563 564 |
{ struct gb_operation *operation; while (!list_empty(&connection->operations)) { operation = list_last_entry(&connection->operations, |
8478c35a8 staging: greybus:... |
565 |
struct gb_operation, links); |
520c6eae9 greybus: connecti... |
566 |
gb_operation_get(operation); |
a29bac623 greybus: Revert "... |
567 |
spin_unlock_irq(&connection->lock); |
520c6eae9 greybus: connecti... |
568 569 570 571 572 573 574 |
if (gb_operation_is_incoming(operation)) gb_operation_cancel_incoming(operation, errno); else gb_operation_cancel(operation, errno); gb_operation_put(operation); |
a29bac623 greybus: Revert "... |
575 |
spin_lock_irq(&connection->lock); |
520c6eae9 greybus: connecti... |
576 577 |
} } |
beb6b7fed greybus: connecti... |
578 579 580 581 582 583 584 |
/* * Cancel all active incoming operations on a connection. * * Locking: Called with connection lock held and state set to ENABLED_TX. */ static void gb_connection_flush_incoming_operations(struct gb_connection *connection, |
8478c35a8 staging: greybus:... |
585 |
int errno) |
127c1fbd5 greybus: connecti... |
586 |
__must_hold(&connection->lock) |
beb6b7fed greybus: connecti... |
587 588 589 590 591 592 593 |
{ struct gb_operation *operation; bool incoming; while (!list_empty(&connection->operations)) { incoming = false; list_for_each_entry(operation, &connection->operations, |
8478c35a8 staging: greybus:... |
594 |
links) { |
beb6b7fed greybus: connecti... |
595 596 597 598 599 600 601 602 603 |
if (gb_operation_is_incoming(operation)) { gb_operation_get(operation); incoming = true; break; } } if (!incoming) break; |
a29bac623 greybus: Revert "... |
604 |
spin_unlock_irq(&connection->lock); |
beb6b7fed greybus: connecti... |
605 606 607 608 |
/* FIXME: flush, not cancel? */ gb_operation_cancel_incoming(operation, errno); gb_operation_put(operation); |
a29bac623 greybus: Revert "... |
609 |
spin_lock_irq(&connection->lock); |
beb6b7fed greybus: connecti... |
610 611 |
} } |
f7ee081e3 greybus: connecti... |
612 613 614 615 616 617 618 619 620 621 622 |
/* * _gb_connection_enable() - enable a connection * @connection: connection to enable * @rx: whether to enable incoming requests * * Connection-enable helper for DISABLED->ENABLED, DISABLED->ENABLED_TX, and * ENABLED_TX->ENABLED state transitions. * * Locking: Caller holds connection->mutex. */ static int _gb_connection_enable(struct gb_connection *connection, bool rx) |
574341c67 greybus: add devi... |
623 |
{ |
36561f23a greybus: define c... |
624 |
int ret; |
f7ee081e3 greybus: connecti... |
625 |
/* Handle ENABLED_TX -> ENABLED transitions. */ |
570dfa7c5 greybus: connecti... |
626 |
if (connection->state == GB_CONNECTION_STATE_ENABLED_TX) { |
f7ee081e3 greybus: connecti... |
627 628 |
if (!(connection->handler && rx)) return 0; |
570dfa7c5 greybus: connecti... |
629 |
|
a29bac623 greybus: Revert "... |
630 |
spin_lock_irq(&connection->lock); |
570dfa7c5 greybus: connecti... |
631 |
connection->state = GB_CONNECTION_STATE_ENABLED; |
a29bac623 greybus: Revert "... |
632 |
spin_unlock_irq(&connection->lock); |
570dfa7c5 greybus: connecti... |
633 |
|
f7ee081e3 greybus: connecti... |
634 |
return 0; |
570dfa7c5 greybus: connecti... |
635 |
} |
d7ea30a57 greybus: hd: add ... |
636 |
ret = gb_connection_hd_cport_enable(connection); |
a95c258c6 greybus: connecti... |
637 |
if (ret) |
f7ee081e3 greybus: connecti... |
638 |
return ret; |
a1163fae6 greybus: connecti... |
639 |
|
d7ea30a57 greybus: hd: add ... |
640 641 |
ret = gb_connection_svc_connection_create(connection); if (ret) |
aac0839ea greybus: connecti... |
642 |
goto err_hd_cport_clear; |
d7ea30a57 greybus: hd: add ... |
643 |
|
aac0839ea greybus: connecti... |
644 |
ret = gb_connection_hd_cport_connected(connection); |
00ad6975e greybus: connecti... |
645 646 |
if (ret) goto err_svc_connection_destroy; |
a29bac623 greybus: Revert "... |
647 |
spin_lock_irq(&connection->lock); |
f7ee081e3 greybus: connecti... |
648 |
if (connection->handler && rx) |
570dfa7c5 greybus: connecti... |
649 650 651 |
connection->state = GB_CONNECTION_STATE_ENABLED; else connection->state = GB_CONNECTION_STATE_ENABLED_TX; |
a29bac623 greybus: Revert "... |
652 |
spin_unlock_irq(&connection->lock); |
cad09a8f8 greybus: connecti... |
653 |
|
4d0bee112 greybus: connecti... |
654 655 |
ret = gb_connection_control_connected(connection); if (ret) |
3de5acfaf greybus: connecti... |
656 |
goto err_control_disconnecting; |
4d0bee112 greybus: connecti... |
657 |
|
3ea6a8156 greybus: connecti... |
658 |
return 0; |
36561f23a greybus: define c... |
659 |
|
3de5acfaf greybus: connecti... |
660 |
err_control_disconnecting: |
a29bac623 greybus: Revert "... |
661 |
spin_lock_irq(&connection->lock); |
3de5acfaf greybus: connecti... |
662 |
connection->state = GB_CONNECTION_STATE_DISCONNECTING; |
a29bac623 greybus: Revert "... |
663 664 |
gb_connection_cancel_operations(connection, -ESHUTDOWN); spin_unlock_irq(&connection->lock); |
8d7a712ca greybus: connecti... |
665 |
|
800d6c8f4 greybus: connecti... |
666 667 |
/* Transmit queue should already be empty. */ gb_connection_hd_cport_flush(connection); |
aac0839ea greybus: connecti... |
668 669 670 671 |
gb_connection_control_disconnecting(connection); gb_connection_cport_shutdown_phase_1(connection); gb_connection_hd_cport_quiesce(connection); gb_connection_cport_shutdown_phase_2(connection); |
3de5acfaf greybus: connecti... |
672 673 |
gb_connection_control_disconnected(connection); connection->state = GB_CONNECTION_STATE_DISABLED; |
00ad6975e greybus: connecti... |
674 |
err_svc_connection_destroy: |
3ea6a8156 greybus: connecti... |
675 |
gb_connection_svc_connection_destroy(connection); |
aac0839ea greybus: connecti... |
676 677 |
err_hd_cport_clear: gb_connection_hd_cport_clear(connection); |
3ea6a8156 greybus: connecti... |
678 |
gb_connection_hd_cport_disable(connection); |
f7ee081e3 greybus: connecti... |
679 680 681 682 683 684 685 686 687 688 689 690 691 692 |
return ret; } int gb_connection_enable(struct gb_connection *connection) { int ret = 0; mutex_lock(&connection->mutex); if (connection->state == GB_CONNECTION_STATE_ENABLED) goto out_unlock; ret = _gb_connection_enable(connection, true); |
79c8c6494 greybus: tracing:... |
693 694 |
if (!ret) trace_gb_connection_enable(connection); |
f7ee081e3 greybus: connecti... |
695 |
out_unlock: |
23268785b greybus: connecti... |
696 |
mutex_unlock(&connection->mutex); |
3ea6a8156 greybus: connecti... |
697 698 699 700 |
return ret; } EXPORT_SYMBOL_GPL(gb_connection_enable); |
186906590 greybus: connecti... |
701 |
|
f7ee081e3 greybus: connecti... |
702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 |
int gb_connection_enable_tx(struct gb_connection *connection) { int ret = 0; mutex_lock(&connection->mutex); if (connection->state == GB_CONNECTION_STATE_ENABLED) { ret = -EINVAL; goto out_unlock; } if (connection->state == GB_CONNECTION_STATE_ENABLED_TX) goto out_unlock; ret = _gb_connection_enable(connection, false); |
79c8c6494 greybus: tracing:... |
717 718 |
if (!ret) trace_gb_connection_enable(connection); |
f7ee081e3 greybus: connecti... |
719 720 721 722 723 724 |
out_unlock: mutex_unlock(&connection->mutex); return ret; } EXPORT_SYMBOL_GPL(gb_connection_enable_tx); |
beb6b7fed greybus: connecti... |
725 726 727 |
void gb_connection_disable_rx(struct gb_connection *connection) { mutex_lock(&connection->mutex); |
a29bac623 greybus: Revert "... |
728 |
spin_lock_irq(&connection->lock); |
beb6b7fed greybus: connecti... |
729 |
if (connection->state != GB_CONNECTION_STATE_ENABLED) { |
a29bac623 greybus: Revert "... |
730 |
spin_unlock_irq(&connection->lock); |
beb6b7fed greybus: connecti... |
731 732 733 |
goto out_unlock; } connection->state = GB_CONNECTION_STATE_ENABLED_TX; |
a29bac623 greybus: Revert "... |
734 735 |
gb_connection_flush_incoming_operations(connection, -ESHUTDOWN); spin_unlock_irq(&connection->lock); |
beb6b7fed greybus: connecti... |
736 |
|
79c8c6494 greybus: tracing:... |
737 |
trace_gb_connection_disable(connection); |
beb6b7fed greybus: connecti... |
738 739 740 |
out_unlock: mutex_unlock(&connection->mutex); } |
6d58e7144 greybus: connecti... |
741 |
EXPORT_SYMBOL_GPL(gb_connection_disable_rx); |
beb6b7fed greybus: connecti... |
742 |
|
55742d2a0 greybus: interfac... |
743 744 745 746 747 748 749 750 |
void gb_connection_mode_switch_prepare(struct gb_connection *connection) { connection->mode_switch = true; } void gb_connection_mode_switch_complete(struct gb_connection *connection) { gb_connection_svc_connection_destroy(connection); |
aac0839ea greybus: connecti... |
751 |
gb_connection_hd_cport_clear(connection); |
55742d2a0 greybus: interfac... |
752 |
gb_connection_hd_cport_disable(connection); |
aac0839ea greybus: connecti... |
753 |
|
55742d2a0 greybus: interfac... |
754 755 |
connection->mode_switch = false; } |
3ea6a8156 greybus: connecti... |
756 757 |
void gb_connection_disable(struct gb_connection *connection) { |
23268785b greybus: connecti... |
758 |
mutex_lock(&connection->mutex); |
81fba2496 greybus: connecti... |
759 |
if (connection->state == GB_CONNECTION_STATE_DISABLED) |
23268785b greybus: connecti... |
760 |
goto out_unlock; |
81fba2496 greybus: connecti... |
761 |
|
0698be028 greybus: connecti... |
762 |
trace_gb_connection_disable(connection); |
a29bac623 greybus: Revert "... |
763 |
spin_lock_irq(&connection->lock); |
3de5acfaf greybus: connecti... |
764 |
connection->state = GB_CONNECTION_STATE_DISCONNECTING; |
a29bac623 greybus: Revert "... |
765 766 |
gb_connection_cancel_operations(connection, -ESHUTDOWN); spin_unlock_irq(&connection->lock); |
81fba2496 greybus: connecti... |
767 |
|
800d6c8f4 greybus: connecti... |
768 |
gb_connection_hd_cport_flush(connection); |
aac0839ea greybus: connecti... |
769 770 771 772 |
gb_connection_control_disconnecting(connection); gb_connection_cport_shutdown_phase_1(connection); gb_connection_hd_cport_quiesce(connection); gb_connection_cport_shutdown_phase_2(connection); |
3de5acfaf greybus: connecti... |
773 774 775 |
gb_connection_control_disconnected(connection); connection->state = GB_CONNECTION_STATE_DISABLED; |
55742d2a0 greybus: interfac... |
776 777 778 |
/* control-connection tear down is deferred when mode switching */ if (!connection->mode_switch) { gb_connection_svc_connection_destroy(connection); |
aac0839ea greybus: connecti... |
779 |
gb_connection_hd_cport_clear(connection); |
55742d2a0 greybus: interfac... |
780 781 |
gb_connection_hd_cport_disable(connection); } |
23268785b greybus: connecti... |
782 783 784 |
out_unlock: mutex_unlock(&connection->mutex); |
3ea6a8156 greybus: connecti... |
785 786 |
} EXPORT_SYMBOL_GPL(gb_connection_disable); |
7aefe7918 greybus: core: av... |
787 788 789 790 791 792 793 |
/* Disable a connection without communicating with the remote end. */ void gb_connection_disable_forced(struct gb_connection *connection) { mutex_lock(&connection->mutex); if (connection->state == GB_CONNECTION_STATE_DISABLED) goto out_unlock; |
0698be028 greybus: connecti... |
794 |
trace_gb_connection_disable(connection); |
a29bac623 greybus: Revert "... |
795 |
spin_lock_irq(&connection->lock); |
7aefe7918 greybus: core: av... |
796 |
connection->state = GB_CONNECTION_STATE_DISABLED; |
a29bac623 greybus: Revert "... |
797 798 |
gb_connection_cancel_operations(connection, -ESHUTDOWN); spin_unlock_irq(&connection->lock); |
7aefe7918 greybus: core: av... |
799 |
|
800d6c8f4 greybus: connecti... |
800 |
gb_connection_hd_cport_flush(connection); |
aac0839ea greybus: connecti... |
801 |
|
7aefe7918 greybus: core: av... |
802 |
gb_connection_svc_connection_destroy(connection); |
aac0839ea greybus: connecti... |
803 |
gb_connection_hd_cport_clear(connection); |
7aefe7918 greybus: core: av... |
804 |
|
aac0839ea greybus: connecti... |
805 |
gb_connection_hd_cport_disable(connection); |
7aefe7918 greybus: core: av... |
806 807 808 809 |
out_unlock: mutex_unlock(&connection->mutex); } EXPORT_SYMBOL_GPL(gb_connection_disable_forced); |
c3681f6c9 greybus: connecti... |
810 |
/* Caller must have disabled the connection before destroying it. */ |
fda2381bd greybus: connecti... |
811 812 |
void gb_connection_destroy(struct gb_connection *connection) { |
2edbf5ffb greybus: connecti... |
813 |
if (!connection) |
fda2381bd greybus: connecti... |
814 |
return; |
814ae531d greybus: connecti... |
815 816 |
if (WARN_ON(connection->state != GB_CONNECTION_STATE_DISABLED)) gb_connection_disable(connection); |
210b508e4 greybus: connecti... |
817 |
mutex_lock(&gb_connection_mutex); |
0b1d26235 greybus: Revert "... |
818 |
spin_lock_irq(&gb_connections_lock); |
fda2381bd greybus: connecti... |
819 820 |
list_del(&connection->bundle_links); list_del(&connection->hd_links); |
0b1d26235 greybus: Revert "... |
821 |
spin_unlock_irq(&gb_connections_lock); |
fda2381bd greybus: connecti... |
822 |
|
c3681f6c9 greybus: connecti... |
823 |
destroy_workqueue(connection->wq); |
74a5d93ce greybus: hd: move... |
824 |
gb_hd_cport_release(connection->hd, connection->hd_cport_id); |
fda2381bd greybus: connecti... |
825 |
connection->hd_cport_id = CPORT_ID_BAD; |
210b508e4 greybus: connecti... |
826 |
mutex_unlock(&gb_connection_mutex); |
0e46fab7d greybus: connecti... |
827 |
gb_connection_put(connection); |
fda2381bd greybus: connecti... |
828 |
} |
98fdf5a03 greybus: core: de... |
829 |
EXPORT_SYMBOL_GPL(gb_connection_destroy); |
fda2381bd greybus: connecti... |
830 |
|
e7e2efc43 greybus: connecti... |
831 832 |
void gb_connection_latency_tag_enable(struct gb_connection *connection) { |
2537636ab greybus: hd: rena... |
833 |
struct gb_host_device *hd = connection->hd; |
e7e2efc43 greybus: connecti... |
834 835 836 837 838 839 840 |
int ret; if (!hd->driver->latency_tag_enable) return; ret = hd->driver->latency_tag_enable(hd, connection->hd_cport_id); if (ret) { |
4c4b50218 greybus: connecti... |
841 842 843 844 |
dev_err(&connection->hd->dev, "%s: failed to enable latency tag: %d ", connection->name, ret); |
e7e2efc43 greybus: connecti... |
845 846 847 848 849 850 |
} } EXPORT_SYMBOL_GPL(gb_connection_latency_tag_enable); void gb_connection_latency_tag_disable(struct gb_connection *connection) { |
2537636ab greybus: hd: rena... |
851 |
struct gb_host_device *hd = connection->hd; |
e7e2efc43 greybus: connecti... |
852 853 854 855 856 857 858 |
int ret; if (!hd->driver->latency_tag_disable) return; ret = hd->driver->latency_tag_disable(hd, connection->hd_cport_id); if (ret) { |
4c4b50218 greybus: connecti... |
859 860 861 862 |
dev_err(&connection->hd->dev, "%s: failed to disable latency tag: %d ", connection->name, ret); |
e7e2efc43 greybus: connecti... |
863 864 865 |
} } EXPORT_SYMBOL_GPL(gb_connection_latency_tag_disable); |