Alex Elder | c68adb2 | 2014-10-01 21:54:14 -0500 | [diff] [blame] | 1 | /* |
| 2 | * Greybus connections |
| 3 | * |
| 4 | * Copyright 2014 Google Inc. |
Alex Elder | a46e967 | 2014-12-12 12:08:42 -0600 | [diff] [blame] | 5 | * Copyright 2014 Linaro Ltd. |
Alex Elder | c68adb2 | 2014-10-01 21:54:14 -0500 | [diff] [blame] | 6 | * |
| 7 | * Released under the GPLv2 only. |
| 8 | */ |
| 9 | |
Johan Hovold | 5a5bc35 | 2015-07-23 10:50:02 +0200 | [diff] [blame] | 10 | #include <linux/workqueue.h> |
| 11 | |
Alex Elder | c68adb2 | 2014-10-01 21:54:14 -0500 | [diff] [blame] | 12 | #include "greybus.h" |
| 13 | |
Johan Hovold | 2d54e4d | 2015-12-07 15:05:30 +0100 | [diff] [blame] | 14 | |
Johan Hovold | 0e46fab | 2016-01-19 12:51:25 +0100 | [diff] [blame] | 15 | static void gb_connection_kref_release(struct kref *kref); |
| 16 | |
| 17 | |
Alex Elder | 748e123 | 2014-10-03 14:14:22 -0500 | [diff] [blame] | 18 | static DEFINE_SPINLOCK(gb_connections_lock); |
Johan Hovold | 210b508 | 2016-01-19 12:51:26 +0100 | [diff] [blame] | 19 | static DEFINE_MUTEX(gb_connection_mutex); |
| 20 | |
Alex Elder | 748e123 | 2014-10-03 14:14:22 -0500 | [diff] [blame] | 21 | |
Johan Hovold | b53e0c9 | 2016-01-19 12:51:27 +0100 | [diff] [blame] | 22 | /* Caller holds gb_connection_mutex. */ |
Alex Elder | f5c2be9 | 2015-06-09 17:42:58 -0500 | [diff] [blame] | 23 | static struct gb_connection * |
Viresh Kumar | c3a1617 | 2015-07-01 12:13:56 +0530 | [diff] [blame] | 24 | gb_connection_intf_find(struct gb_interface *intf, u16 cport_id) |
Alex Elder | f5c2be9 | 2015-06-09 17:42:58 -0500 | [diff] [blame] | 25 | { |
Johan Hovold | 2537636 | 2015-11-03 18:03:23 +0100 | [diff] [blame] | 26 | struct gb_host_device *hd = intf->hd; |
Alex Elder | f5c2be9 | 2015-06-09 17:42:58 -0500 | [diff] [blame] | 27 | struct gb_connection *connection; |
| 28 | |
Johan Hovold | 0daf17b | 2015-11-25 15:59:12 +0100 | [diff] [blame] | 29 | list_for_each_entry(connection, &hd->connections, hd_links) { |
| 30 | if (connection->intf == intf && |
Viresh Kumar | c3a1617 | 2015-07-01 12:13:56 +0530 | [diff] [blame] | 31 | connection->intf_cport_id == cport_id) |
Alex Elder | f5c2be9 | 2015-06-09 17:42:58 -0500 | [diff] [blame] | 32 | return connection; |
Johan Hovold | 0daf17b | 2015-11-25 15:59:12 +0100 | [diff] [blame] | 33 | } |
| 34 | |
Alex Elder | f5c2be9 | 2015-06-09 17:42:58 -0500 | [diff] [blame] | 35 | return NULL; |
| 36 | } |
| 37 | |
Johan Hovold | 0e46fab | 2016-01-19 12:51:25 +0100 | [diff] [blame] | 38 | static void gb_connection_get(struct gb_connection *connection) |
| 39 | { |
| 40 | kref_get(&connection->kref); |
| 41 | } |
| 42 | |
| 43 | static void gb_connection_put(struct gb_connection *connection) |
| 44 | { |
| 45 | kref_put(&connection->kref, gb_connection_kref_release); |
| 46 | } |
| 47 | |
| 48 | /* |
| 49 | * Returns a reference-counted pointer to the connection if found. |
| 50 | */ |
Alex Elder | 8bd0ae6 | 2015-06-08 12:05:11 -0500 | [diff] [blame] | 51 | static struct gb_connection * |
Johan Hovold | 2537636 | 2015-11-03 18:03:23 +0100 | [diff] [blame] | 52 | gb_connection_hd_find(struct gb_host_device *hd, u16 cport_id) |
Alex Elder | ee9ebe4 | 2014-10-06 06:53:08 -0500 | [diff] [blame] | 53 | { |
Alex Elder | f5c2be9 | 2015-06-09 17:42:58 -0500 | [diff] [blame] | 54 | struct gb_connection *connection; |
Johan Hovold | 8f5eadb | 2015-03-02 09:55:26 +0100 | [diff] [blame] | 55 | unsigned long flags; |
Alex Elder | ee9ebe4 | 2014-10-06 06:53:08 -0500 | [diff] [blame] | 56 | |
Johan Hovold | 8f5eadb | 2015-03-02 09:55:26 +0100 | [diff] [blame] | 57 | spin_lock_irqsave(&gb_connections_lock, flags); |
Alex Elder | 2c43ce4 | 2014-11-17 08:08:44 -0600 | [diff] [blame] | 58 | list_for_each_entry(connection, &hd->connections, hd_links) |
Johan Hovold | 0e46fab | 2016-01-19 12:51:25 +0100 | [diff] [blame] | 59 | if (connection->hd_cport_id == cport_id) { |
| 60 | gb_connection_get(connection); |
Marti Bolivar | e86905b | 2014-10-06 13:26:02 -0400 | [diff] [blame] | 61 | goto found; |
Johan Hovold | 0e46fab | 2016-01-19 12:51:25 +0100 | [diff] [blame] | 62 | } |
Marti Bolivar | e86905b | 2014-10-06 13:26:02 -0400 | [diff] [blame] | 63 | connection = NULL; |
Alex Elder | f5c2be9 | 2015-06-09 17:42:58 -0500 | [diff] [blame] | 64 | found: |
Johan Hovold | 8f5eadb | 2015-03-02 09:55:26 +0100 | [diff] [blame] | 65 | spin_unlock_irqrestore(&gb_connections_lock, flags); |
Alex Elder | ee9ebe4 | 2014-10-06 06:53:08 -0500 | [diff] [blame] | 66 | |
| 67 | return connection; |
| 68 | } |
| 69 | |
Alex Elder | de3557d | 2014-11-20 16:09:18 -0600 | [diff] [blame] | 70 | /* |
| 71 | * Callback from the host driver to let us know that data has been |
Greg Kroah-Hartman | 1db0a5f | 2014-12-12 17:10:17 -0500 | [diff] [blame] | 72 | * received on the bundle. |
Alex Elder | de3557d | 2014-11-20 16:09:18 -0600 | [diff] [blame] | 73 | */ |
Johan Hovold | 2537636 | 2015-11-03 18:03:23 +0100 | [diff] [blame] | 74 | void greybus_data_rcvd(struct gb_host_device *hd, u16 cport_id, |
Alex Elder | 374e6a2 | 2014-11-17 18:08:37 -0600 | [diff] [blame] | 75 | u8 *data, size_t length) |
| 76 | { |
| 77 | struct gb_connection *connection; |
| 78 | |
Viresh Kumar | 12eba9f | 2015-05-20 16:48:00 +0530 | [diff] [blame] | 79 | connection = gb_connection_hd_find(hd, cport_id); |
Alex Elder | 374e6a2 | 2014-11-17 18:08:37 -0600 | [diff] [blame] | 80 | if (!connection) { |
Johan Hovold | 2adaefb | 2015-11-25 15:59:02 +0100 | [diff] [blame] | 81 | dev_err(&hd->dev, |
Alex Elder | 374e6a2 | 2014-11-17 18:08:37 -0600 | [diff] [blame] | 82 | "nonexistent connection (%zu bytes dropped)\n", length); |
| 83 | return; |
| 84 | } |
Alex Elder | 61089e8 | 2014-11-18 13:26:50 -0600 | [diff] [blame] | 85 | gb_connection_recv(connection, data, length); |
Johan Hovold | 0e46fab | 2016-01-19 12:51:25 +0100 | [diff] [blame] | 86 | gb_connection_put(connection); |
Alex Elder | 374e6a2 | 2014-11-17 18:08:37 -0600 | [diff] [blame] | 87 | } |
Alex Elder | de3557d | 2014-11-20 16:09:18 -0600 | [diff] [blame] | 88 | EXPORT_SYMBOL_GPL(greybus_data_rcvd); |
Alex Elder | 374e6a2 | 2014-11-17 18:08:37 -0600 | [diff] [blame] | 89 | |
Greg Kroah-Hartman | b750fa3 | 2015-10-16 16:56:38 -0700 | [diff] [blame] | 90 | static void gb_connection_kref_release(struct kref *kref) |
Greg Kroah-Hartman | f0f61b9 | 2014-10-24 17:34:46 +0800 | [diff] [blame] | 91 | { |
Greg Kroah-Hartman | b750fa3 | 2015-10-16 16:56:38 -0700 | [diff] [blame] | 92 | struct gb_connection *connection; |
Greg Kroah-Hartman | f0f61b9 | 2014-10-24 17:34:46 +0800 | [diff] [blame] | 93 | |
Greg Kroah-Hartman | b750fa3 | 2015-10-16 16:56:38 -0700 | [diff] [blame] | 94 | connection = container_of(kref, struct gb_connection, kref); |
Johan Hovold | c3681f6 | 2016-01-19 12:51:23 +0100 | [diff] [blame] | 95 | |
Greg Kroah-Hartman | f0f61b9 | 2014-10-24 17:34:46 +0800 | [diff] [blame] | 96 | kfree(connection); |
| 97 | } |
| 98 | |
Johan Hovold | 729b260 | 2015-11-25 15:59:14 +0100 | [diff] [blame] | 99 | static void gb_connection_init_name(struct gb_connection *connection) |
| 100 | { |
| 101 | u16 hd_cport_id = connection->hd_cport_id; |
| 102 | u16 cport_id = 0; |
| 103 | u8 intf_id = 0; |
| 104 | |
| 105 | if (connection->intf) { |
| 106 | intf_id = connection->intf->interface_id; |
| 107 | cport_id = connection->intf_cport_id; |
| 108 | } |
| 109 | |
| 110 | snprintf(connection->name, sizeof(connection->name), |
Viresh Kumar | 2f3db92 | 2015-12-04 21:30:09 +0530 | [diff] [blame] | 111 | "%u/%u:%u", hd_cport_id, intf_id, cport_id); |
Johan Hovold | 729b260 | 2015-11-25 15:59:14 +0100 | [diff] [blame] | 112 | } |
| 113 | |
Alex Elder | 177404b | 2014-10-03 14:14:24 -0500 | [diff] [blame] | 114 | /* |
Johan Hovold | 96c2af5 | 2016-01-21 17:34:15 +0100 | [diff] [blame] | 115 | * _gb_connection_create() - create a Greybus connection |
Johan Hovold | 2566fae | 2015-11-25 15:59:11 +0100 | [diff] [blame] | 116 | * @hd: host device of the connection |
| 117 | * @hd_cport_id: host-device cport id, or -1 for dynamic allocation |
| 118 | * @intf: remote interface, or NULL for static connections |
| 119 | * @bundle: remote-interface bundle (may be NULL) |
| 120 | * @cport_id: remote-interface cport id, or 0 for static connections |
Johan Hovold | f7ee081 | 2016-01-21 17:34:21 +0100 | [diff] [blame] | 121 | * @handler: request handler (may be NULL) |
Johan Hovold | 2566fae | 2015-11-25 15:59:11 +0100 | [diff] [blame] | 122 | * |
| 123 | * Create a Greybus connection, representing the bidirectional link |
Alex Elder | c68adb2 | 2014-10-01 21:54:14 -0500 | [diff] [blame] | 124 | * between a CPort on a (local) Greybus host device and a CPort on |
Johan Hovold | 2566fae | 2015-11-25 15:59:11 +0100 | [diff] [blame] | 125 | * another Greybus interface. |
Alex Elder | c68adb2 | 2014-10-01 21:54:14 -0500 | [diff] [blame] | 126 | * |
Alex Elder | e88afa5 | 2014-10-01 21:54:15 -0500 | [diff] [blame] | 127 | * A connection also maintains the state of operations sent over the |
| 128 | * connection. |
| 129 | * |
Johan Hovold | 210b508 | 2016-01-19 12:51:26 +0100 | [diff] [blame] | 130 | * Serialised against concurrent create and destroy using the |
| 131 | * gb_connection_mutex. |
| 132 | * |
Johan Hovold | 24e094d | 2016-01-21 17:34:16 +0100 | [diff] [blame] | 133 | * Return: A pointer to the new connection if successful, or an ERR_PTR |
| 134 | * otherwise. |
Alex Elder | c68adb2 | 2014-10-01 21:54:14 -0500 | [diff] [blame] | 135 | */ |
Johan Hovold | 2566fae | 2015-11-25 15:59:11 +0100 | [diff] [blame] | 136 | static struct gb_connection * |
Johan Hovold | 96c2af5 | 2016-01-21 17:34:15 +0100 | [diff] [blame] | 137 | _gb_connection_create(struct gb_host_device *hd, int hd_cport_id, |
Johan Hovold | 2566fae | 2015-11-25 15:59:11 +0100 | [diff] [blame] | 138 | struct gb_interface *intf, |
Johan Hovold | f7ee081 | 2016-01-21 17:34:21 +0100 | [diff] [blame] | 139 | struct gb_bundle *bundle, int cport_id, |
| 140 | gb_request_handler_t handler) |
Alex Elder | c68adb2 | 2014-10-01 21:54:14 -0500 | [diff] [blame] | 141 | { |
| 142 | struct gb_connection *connection; |
Alex Elder | f9b0366 | 2015-06-12 10:21:08 -0500 | [diff] [blame] | 143 | struct ida *id_map = &hd->cport_id_map; |
Johan Hovold | 2566fae | 2015-11-25 15:59:11 +0100 | [diff] [blame] | 144 | int ida_start, ida_end; |
Johan Hovold | 24e094d | 2016-01-21 17:34:16 +0100 | [diff] [blame] | 145 | int ret; |
Alex Elder | c68adb2 | 2014-10-01 21:54:14 -0500 | [diff] [blame] | 146 | |
Johan Hovold | 2566fae | 2015-11-25 15:59:11 +0100 | [diff] [blame] | 147 | if (hd_cport_id < 0) { |
| 148 | ida_start = 0; |
| 149 | ida_end = hd->num_cports; |
| 150 | } else if (hd_cport_id < hd->num_cports) { |
| 151 | ida_start = hd_cport_id; |
| 152 | ida_end = hd_cport_id + 1; |
| 153 | } else { |
| 154 | dev_err(&hd->dev, "cport %d not available\n", hd_cport_id); |
Johan Hovold | 24e094d | 2016-01-21 17:34:16 +0100 | [diff] [blame] | 155 | return ERR_PTR(-EINVAL); |
Johan Hovold | 2566fae | 2015-11-25 15:59:11 +0100 | [diff] [blame] | 156 | } |
| 157 | |
Johan Hovold | 210b508 | 2016-01-19 12:51:26 +0100 | [diff] [blame] | 158 | mutex_lock(&gb_connection_mutex); |
| 159 | |
Johan Hovold | b53e0c9 | 2016-01-19 12:51:27 +0100 | [diff] [blame] | 160 | if (intf && gb_connection_intf_find(intf, cport_id)) { |
| 161 | dev_err(&intf->dev, "cport %u already in use\n", cport_id); |
Johan Hovold | 24e094d | 2016-01-21 17:34:16 +0100 | [diff] [blame] | 162 | ret = -EBUSY; |
Johan Hovold | b53e0c9 | 2016-01-19 12:51:27 +0100 | [diff] [blame] | 163 | goto err_unlock; |
| 164 | } |
| 165 | |
Johan Hovold | 24e094d | 2016-01-21 17:34:16 +0100 | [diff] [blame] | 166 | ret = ida_simple_get(id_map, ida_start, ida_end, GFP_KERNEL); |
| 167 | if (ret < 0) |
Johan Hovold | 210b508 | 2016-01-19 12:51:26 +0100 | [diff] [blame] | 168 | goto err_unlock; |
Johan Hovold | 24e094d | 2016-01-21 17:34:16 +0100 | [diff] [blame] | 169 | hd_cport_id = ret; |
Alex Elder | c68adb2 | 2014-10-01 21:54:14 -0500 | [diff] [blame] | 170 | |
Johan Hovold | 10f9fa1 | 2015-07-23 10:50:01 +0200 | [diff] [blame] | 171 | connection = kzalloc(sizeof(*connection), GFP_KERNEL); |
Johan Hovold | 24e094d | 2016-01-21 17:34:16 +0100 | [diff] [blame] | 172 | if (!connection) { |
| 173 | ret = -ENOMEM; |
Johan Hovold | 10f9fa1 | 2015-07-23 10:50:01 +0200 | [diff] [blame] | 174 | goto err_remove_ida; |
Johan Hovold | 24e094d | 2016-01-21 17:34:16 +0100 | [diff] [blame] | 175 | } |
Johan Hovold | 10f9fa1 | 2015-07-23 10:50:01 +0200 | [diff] [blame] | 176 | |
Johan Hovold | 7c63a82 | 2015-07-23 10:50:00 +0200 | [diff] [blame] | 177 | connection->hd_cport_id = hd_cport_id; |
Alex Elder | f9b0366 | 2015-06-12 10:21:08 -0500 | [diff] [blame] | 178 | connection->intf_cport_id = cport_id; |
| 179 | connection->hd = hd; |
Johan Hovold | 2566fae | 2015-11-25 15:59:11 +0100 | [diff] [blame] | 180 | connection->intf = intf; |
Greg Kroah-Hartman | 1db0a5f | 2014-12-12 17:10:17 -0500 | [diff] [blame] | 181 | connection->bundle = bundle; |
Johan Hovold | f7ee081 | 2016-01-21 17:34:21 +0100 | [diff] [blame] | 182 | connection->handler = handler; |
Alex Elder | 36561f2 | 2014-10-22 02:04:30 -0500 | [diff] [blame] | 183 | connection->state = GB_CONNECTION_STATE_DISABLED; |
Alex Elder | ad1c449 | 2014-10-02 12:30:06 -0500 | [diff] [blame] | 184 | |
Johan Hovold | 4e2b1e4 | 2015-07-22 17:49:19 +0200 | [diff] [blame] | 185 | atomic_set(&connection->op_cycle, 0); |
Johan Hovold | 2326878 | 2016-01-19 12:51:06 +0100 | [diff] [blame] | 186 | mutex_init(&connection->mutex); |
Johan Hovold | 4e2b1e4 | 2015-07-22 17:49:19 +0200 | [diff] [blame] | 187 | spin_lock_init(&connection->lock); |
| 188 | INIT_LIST_HEAD(&connection->operations); |
| 189 | |
Johan Hovold | 5a5bc35 | 2015-07-23 10:50:02 +0200 | [diff] [blame] | 190 | connection->wq = alloc_workqueue("%s:%d", WQ_UNBOUND, 1, |
Johan Hovold | 582b3a1 | 2015-11-25 15:59:03 +0100 | [diff] [blame] | 191 | dev_name(&hd->dev), hd_cport_id); |
Johan Hovold | 24e094d | 2016-01-21 17:34:16 +0100 | [diff] [blame] | 192 | if (!connection->wq) { |
| 193 | ret = -ENOMEM; |
Johan Hovold | 5a5bc35 | 2015-07-23 10:50:02 +0200 | [diff] [blame] | 194 | goto err_free_connection; |
Johan Hovold | 24e094d | 2016-01-21 17:34:16 +0100 | [diff] [blame] | 195 | } |
Johan Hovold | 5a5bc35 | 2015-07-23 10:50:02 +0200 | [diff] [blame] | 196 | |
Greg Kroah-Hartman | b750fa3 | 2015-10-16 16:56:38 -0700 | [diff] [blame] | 197 | kref_init(&connection->kref); |
Greg Kroah-Hartman | f0f61b9 | 2014-10-24 17:34:46 +0800 | [diff] [blame] | 198 | |
Johan Hovold | 729b260 | 2015-11-25 15:59:14 +0100 | [diff] [blame] | 199 | gb_connection_init_name(connection); |
| 200 | |
Alex Elder | 748e123 | 2014-10-03 14:14:22 -0500 | [diff] [blame] | 201 | spin_lock_irq(&gb_connections_lock); |
Viresh Kumar | 928f2ab | 2015-06-04 18:16:45 +0530 | [diff] [blame] | 202 | list_add(&connection->hd_links, &hd->connections); |
Viresh Kumar | 75662e5 | 2015-07-21 17:44:16 +0530 | [diff] [blame] | 203 | |
| 204 | if (bundle) |
| 205 | list_add(&connection->bundle_links, &bundle->connections); |
| 206 | else |
| 207 | INIT_LIST_HEAD(&connection->bundle_links); |
| 208 | |
Alex Elder | 748e123 | 2014-10-03 14:14:22 -0500 | [diff] [blame] | 209 | spin_unlock_irq(&gb_connections_lock); |
| 210 | |
Johan Hovold | 210b508 | 2016-01-19 12:51:26 +0100 | [diff] [blame] | 211 | mutex_unlock(&gb_connection_mutex); |
| 212 | |
Alex Elder | c68adb2 | 2014-10-01 21:54:14 -0500 | [diff] [blame] | 213 | return connection; |
Johan Hovold | 10f9fa1 | 2015-07-23 10:50:01 +0200 | [diff] [blame] | 214 | |
Johan Hovold | 5a5bc35 | 2015-07-23 10:50:02 +0200 | [diff] [blame] | 215 | err_free_connection: |
| 216 | kfree(connection); |
Johan Hovold | 10f9fa1 | 2015-07-23 10:50:01 +0200 | [diff] [blame] | 217 | err_remove_ida: |
| 218 | ida_simple_remove(id_map, hd_cport_id); |
Johan Hovold | 210b508 | 2016-01-19 12:51:26 +0100 | [diff] [blame] | 219 | err_unlock: |
| 220 | mutex_unlock(&gb_connection_mutex); |
Johan Hovold | 10f9fa1 | 2015-07-23 10:50:01 +0200 | [diff] [blame] | 221 | |
Johan Hovold | 24e094d | 2016-01-21 17:34:16 +0100 | [diff] [blame] | 222 | return ERR_PTR(ret); |
Alex Elder | c68adb2 | 2014-10-01 21:54:14 -0500 | [diff] [blame] | 223 | } |
| 224 | |
Johan Hovold | 2566fae | 2015-11-25 15:59:11 +0100 | [diff] [blame] | 225 | struct gb_connection * |
Johan Hovold | f7ee081 | 2016-01-21 17:34:21 +0100 | [diff] [blame] | 226 | gb_connection_create_static(struct gb_host_device *hd, u16 hd_cport_id, |
| 227 | gb_request_handler_t handler) |
Johan Hovold | 2566fae | 2015-11-25 15:59:11 +0100 | [diff] [blame] | 228 | { |
Johan Hovold | f7ee081 | 2016-01-21 17:34:21 +0100 | [diff] [blame] | 229 | return _gb_connection_create(hd, hd_cport_id, NULL, NULL, 0, handler); |
Johan Hovold | 2566fae | 2015-11-25 15:59:11 +0100 | [diff] [blame] | 230 | } |
| 231 | |
| 232 | struct gb_connection * |
Johan Hovold | 59507e2 | 2016-01-21 17:34:12 +0100 | [diff] [blame] | 233 | gb_connection_create_control(struct gb_interface *intf) |
| 234 | { |
Johan Hovold | f7ee081 | 2016-01-21 17:34:21 +0100 | [diff] [blame] | 235 | return _gb_connection_create(intf->hd, -1, intf, NULL, 0, NULL); |
Johan Hovold | 59507e2 | 2016-01-21 17:34:12 +0100 | [diff] [blame] | 236 | } |
| 237 | |
| 238 | struct gb_connection * |
Johan Hovold | f7ee081 | 2016-01-21 17:34:21 +0100 | [diff] [blame] | 239 | gb_connection_create(struct gb_bundle *bundle, u16 cport_id, |
| 240 | gb_request_handler_t handler) |
Johan Hovold | 2566fae | 2015-11-25 15:59:11 +0100 | [diff] [blame] | 241 | { |
Johan Hovold | 8cff6c6 | 2016-01-21 17:34:14 +0100 | [diff] [blame] | 242 | struct gb_interface *intf = bundle->intf; |
| 243 | |
Johan Hovold | f7ee081 | 2016-01-21 17:34:21 +0100 | [diff] [blame] | 244 | return _gb_connection_create(intf->hd, -1, intf, bundle, cport_id, |
| 245 | handler); |
Johan Hovold | 2566fae | 2015-11-25 15:59:11 +0100 | [diff] [blame] | 246 | } |
Johan Hovold | 96c2af5 | 2016-01-21 17:34:15 +0100 | [diff] [blame] | 247 | EXPORT_SYMBOL_GPL(gb_connection_create); |
Johan Hovold | 2566fae | 2015-11-25 15:59:11 +0100 | [diff] [blame] | 248 | |
Johan Hovold | d7ea30a5 | 2015-09-17 13:17:26 +0200 | [diff] [blame] | 249 | static int gb_connection_hd_cport_enable(struct gb_connection *connection) |
| 250 | { |
Johan Hovold | 2537636 | 2015-11-03 18:03:23 +0100 | [diff] [blame] | 251 | struct gb_host_device *hd = connection->hd; |
Johan Hovold | d7ea30a5 | 2015-09-17 13:17:26 +0200 | [diff] [blame] | 252 | int ret; |
| 253 | |
| 254 | if (!hd->driver->cport_enable) |
| 255 | return 0; |
| 256 | |
| 257 | ret = hd->driver->cport_enable(hd, connection->hd_cport_id); |
| 258 | if (ret) { |
Johan Hovold | 2adaefb | 2015-11-25 15:59:02 +0100 | [diff] [blame] | 259 | dev_err(&hd->dev, |
Greg Kroah-Hartman | 30482c1 | 2015-10-16 16:56:23 -0700 | [diff] [blame] | 260 | "failed to enable host cport: %d\n", ret); |
Johan Hovold | d7ea30a5 | 2015-09-17 13:17:26 +0200 | [diff] [blame] | 261 | return ret; |
| 262 | } |
| 263 | |
| 264 | return 0; |
| 265 | } |
| 266 | |
| 267 | static void gb_connection_hd_cport_disable(struct gb_connection *connection) |
| 268 | { |
Johan Hovold | 2537636 | 2015-11-03 18:03:23 +0100 | [diff] [blame] | 269 | struct gb_host_device *hd = connection->hd; |
Johan Hovold | d7ea30a5 | 2015-09-17 13:17:26 +0200 | [diff] [blame] | 270 | |
| 271 | if (!hd->driver->cport_disable) |
| 272 | return; |
| 273 | |
| 274 | hd->driver->cport_disable(hd, connection->hd_cport_id); |
| 275 | } |
| 276 | |
Fabien Parent | 9ed5e1b | 2016-02-23 18:46:08 +0100 | [diff] [blame] | 277 | static int gb_connection_hd_fct_flow_enable(struct gb_connection *connection) |
| 278 | { |
| 279 | struct gb_host_device *hd = connection->hd; |
| 280 | int ret; |
| 281 | |
| 282 | if (!hd->driver->fct_flow_enable) |
| 283 | return 0; |
| 284 | |
| 285 | ret = hd->driver->fct_flow_enable(hd, connection->hd_cport_id); |
| 286 | if (ret) { |
| 287 | dev_err(&hd->dev, "%s: failed to enable FCT flow: %d\n", |
| 288 | connection->name, ret); |
| 289 | return ret; |
| 290 | } |
| 291 | |
| 292 | return 0; |
| 293 | } |
| 294 | |
| 295 | static void gb_connection_hd_fct_flow_disable(struct gb_connection *connection) |
| 296 | { |
| 297 | struct gb_host_device *hd = connection->hd; |
| 298 | |
| 299 | if (!hd->driver->fct_flow_disable) |
| 300 | return; |
| 301 | |
| 302 | hd->driver->fct_flow_disable(hd, connection->hd_cport_id); |
| 303 | } |
| 304 | |
Alex Elder | c68adb2 | 2014-10-01 21:54:14 -0500 | [diff] [blame] | 305 | /* |
Johan Hovold | a95c258 | 2015-09-17 13:17:21 +0200 | [diff] [blame] | 306 | * Request the SVC to create a connection from AP's cport to interface's |
| 307 | * cport. |
| 308 | */ |
| 309 | static int |
| 310 | gb_connection_svc_connection_create(struct gb_connection *connection) |
| 311 | { |
Johan Hovold | 2537636 | 2015-11-03 18:03:23 +0100 | [diff] [blame] | 312 | struct gb_host_device *hd = connection->hd; |
Viresh Kumar | 1575ef1 | 2015-10-07 15:40:24 -0400 | [diff] [blame] | 313 | struct gb_interface *intf; |
Johan Hovold | a95c258 | 2015-09-17 13:17:21 +0200 | [diff] [blame] | 314 | int ret; |
| 315 | |
Johan Hovold | 4ec1574 | 2015-11-25 15:59:13 +0100 | [diff] [blame] | 316 | if (gb_connection_is_static(connection)) |
Fabien Parent | 71f6c32 | 2016-02-23 18:46:11 +0100 | [diff] [blame] | 317 | return gb_connection_hd_fct_flow_enable(connection); |
Johan Hovold | a95c258 | 2015-09-17 13:17:21 +0200 | [diff] [blame] | 318 | |
Johan Hovold | 35822c0 | 2015-11-25 15:59:22 +0100 | [diff] [blame] | 319 | intf = connection->intf; |
Johan Hovold | a95c258 | 2015-09-17 13:17:21 +0200 | [diff] [blame] | 320 | ret = gb_svc_connection_create(hd->svc, |
Johan Hovold | 66069fb | 2015-11-25 15:59:09 +0100 | [diff] [blame] | 321 | hd->svc->ap_intf_id, |
Johan Hovold | a95c258 | 2015-09-17 13:17:21 +0200 | [diff] [blame] | 322 | connection->hd_cport_id, |
Viresh Kumar | 1575ef1 | 2015-10-07 15:40:24 -0400 | [diff] [blame] | 323 | intf->interface_id, |
| 324 | connection->intf_cport_id, |
| 325 | intf->boot_over_unipro); |
Johan Hovold | a95c258 | 2015-09-17 13:17:21 +0200 | [diff] [blame] | 326 | if (ret) { |
Johan Hovold | 4c4b502 | 2015-11-25 15:59:15 +0100 | [diff] [blame] | 327 | dev_err(&connection->hd->dev, |
| 328 | "%s: failed to create svc connection: %d\n", |
| 329 | connection->name, ret); |
Johan Hovold | a95c258 | 2015-09-17 13:17:21 +0200 | [diff] [blame] | 330 | return ret; |
| 331 | } |
| 332 | |
Fabien Parent | 71f6c32 | 2016-02-23 18:46:11 +0100 | [diff] [blame] | 333 | ret = gb_connection_hd_fct_flow_enable(connection); |
| 334 | if (ret) { |
| 335 | gb_svc_connection_destroy(hd->svc, hd->svc->ap_intf_id, |
| 336 | connection->hd_cport_id, |
| 337 | intf->interface_id, |
| 338 | connection->intf_cport_id); |
| 339 | return ret; |
| 340 | } |
| 341 | |
Johan Hovold | a95c258 | 2015-09-17 13:17:21 +0200 | [diff] [blame] | 342 | return 0; |
| 343 | } |
| 344 | |
Viresh Kumar | 1b7a9cd | 2015-09-07 16:01:22 +0530 | [diff] [blame] | 345 | static void |
| 346 | gb_connection_svc_connection_destroy(struct gb_connection *connection) |
| 347 | { |
Fabien Parent | 71f6c32 | 2016-02-23 18:46:11 +0100 | [diff] [blame] | 348 | gb_connection_hd_fct_flow_disable(connection); |
| 349 | |
Johan Hovold | 4ec1574 | 2015-11-25 15:59:13 +0100 | [diff] [blame] | 350 | if (gb_connection_is_static(connection)) |
Viresh Kumar | 1b7a9cd | 2015-09-07 16:01:22 +0530 | [diff] [blame] | 351 | return; |
| 352 | |
| 353 | gb_svc_connection_destroy(connection->hd->svc, |
Johan Hovold | 66069fb | 2015-11-25 15:59:09 +0100 | [diff] [blame] | 354 | connection->hd->svc->ap_intf_id, |
Viresh Kumar | 1b7a9cd | 2015-09-07 16:01:22 +0530 | [diff] [blame] | 355 | connection->hd_cport_id, |
Johan Hovold | 35822c0 | 2015-11-25 15:59:22 +0100 | [diff] [blame] | 356 | connection->intf->interface_id, |
Viresh Kumar | 1b7a9cd | 2015-09-07 16:01:22 +0530 | [diff] [blame] | 357 | connection->intf_cport_id); |
| 358 | } |
| 359 | |
Johan Hovold | 9d7fc25 | 2015-09-17 13:17:24 +0200 | [diff] [blame] | 360 | /* Inform Interface about active CPorts */ |
| 361 | static int gb_connection_control_connected(struct gb_connection *connection) |
| 362 | { |
Johan Hovold | 9d7fc25 | 2015-09-17 13:17:24 +0200 | [diff] [blame] | 363 | struct gb_control *control; |
| 364 | u16 cport_id = connection->intf_cport_id; |
| 365 | int ret; |
| 366 | |
Johan Hovold | bc3be17 | 2016-01-19 12:51:12 +0100 | [diff] [blame] | 367 | if (gb_connection_is_static(connection)) |
Johan Hovold | 9d7fc25 | 2015-09-17 13:17:24 +0200 | [diff] [blame] | 368 | return 0; |
| 369 | |
Johan Hovold | bc3be17 | 2016-01-19 12:51:12 +0100 | [diff] [blame] | 370 | control = connection->intf->control; |
| 371 | |
| 372 | if (connection == control->connection) |
| 373 | return 0; |
Johan Hovold | 9d7fc25 | 2015-09-17 13:17:24 +0200 | [diff] [blame] | 374 | |
| 375 | ret = gb_control_connected_operation(control, cport_id); |
| 376 | if (ret) { |
Greg Kroah-Hartman | 30482c1 | 2015-10-16 16:56:23 -0700 | [diff] [blame] | 377 | dev_err(&connection->bundle->dev, |
| 378 | "failed to connect cport: %d\n", ret); |
Johan Hovold | 9d7fc25 | 2015-09-17 13:17:24 +0200 | [diff] [blame] | 379 | return ret; |
| 380 | } |
| 381 | |
| 382 | return 0; |
| 383 | } |
| 384 | |
Johan Hovold | 72d7482 | 2015-09-17 13:17:23 +0200 | [diff] [blame] | 385 | /* Inform Interface about inactive CPorts */ |
| 386 | static void |
| 387 | gb_connection_control_disconnected(struct gb_connection *connection) |
Viresh Kumar | 1869065 | 2015-08-11 07:35:56 +0530 | [diff] [blame] | 388 | { |
| 389 | struct gb_control *control; |
Johan Hovold | 72d7482 | 2015-09-17 13:17:23 +0200 | [diff] [blame] | 390 | u16 cport_id = connection->intf_cport_id; |
Viresh Kumar | 1869065 | 2015-08-11 07:35:56 +0530 | [diff] [blame] | 391 | int ret; |
| 392 | |
Johan Hovold | bc3be17 | 2016-01-19 12:51:12 +0100 | [diff] [blame] | 393 | if (gb_connection_is_static(connection)) |
Viresh Kumar | 1869065 | 2015-08-11 07:35:56 +0530 | [diff] [blame] | 394 | return; |
| 395 | |
Johan Hovold | bc3be17 | 2016-01-19 12:51:12 +0100 | [diff] [blame] | 396 | control = connection->intf->control; |
| 397 | |
| 398 | if (connection == control->connection) |
| 399 | return; |
Viresh Kumar | 1869065 | 2015-08-11 07:35:56 +0530 | [diff] [blame] | 400 | |
| 401 | ret = gb_control_disconnected_operation(control, cport_id); |
Johan Hovold | 72d7482 | 2015-09-17 13:17:23 +0200 | [diff] [blame] | 402 | if (ret) { |
Greg Kroah-Hartman | 30482c1 | 2015-10-16 16:56:23 -0700 | [diff] [blame] | 403 | dev_warn(&connection->bundle->dev, |
| 404 | "failed to disconnect cport: %d\n", ret); |
Johan Hovold | 72d7482 | 2015-09-17 13:17:23 +0200 | [diff] [blame] | 405 | } |
Viresh Kumar | 1869065 | 2015-08-11 07:35:56 +0530 | [diff] [blame] | 406 | } |
| 407 | |
Johan Hovold | 2846d3e | 2015-09-17 13:17:25 +0200 | [diff] [blame] | 408 | /* |
Johan Hovold | 520c6ea | 2016-01-19 12:51:04 +0100 | [diff] [blame] | 409 | * Cancel all active operations on a connection. |
| 410 | * |
| 411 | * Locking: Called with connection lock held and state set to DISABLED. |
| 412 | */ |
| 413 | static void gb_connection_cancel_operations(struct gb_connection *connection, |
| 414 | int errno) |
Viresh Kumar | 127c1fb | 2016-01-28 15:50:48 +0530 | [diff] [blame] | 415 | __must_hold(&connection->lock) |
Johan Hovold | 520c6ea | 2016-01-19 12:51:04 +0100 | [diff] [blame] | 416 | { |
| 417 | struct gb_operation *operation; |
| 418 | |
| 419 | while (!list_empty(&connection->operations)) { |
| 420 | operation = list_last_entry(&connection->operations, |
| 421 | struct gb_operation, links); |
| 422 | gb_operation_get(operation); |
| 423 | spin_unlock_irq(&connection->lock); |
| 424 | |
| 425 | if (gb_operation_is_incoming(operation)) |
| 426 | gb_operation_cancel_incoming(operation, errno); |
| 427 | else |
| 428 | gb_operation_cancel(operation, errno); |
| 429 | |
| 430 | gb_operation_put(operation); |
| 431 | |
| 432 | spin_lock_irq(&connection->lock); |
| 433 | } |
| 434 | } |
| 435 | |
Johan Hovold | beb6b7f | 2016-01-19 12:51:08 +0100 | [diff] [blame] | 436 | /* |
| 437 | * Cancel all active incoming operations on a connection. |
| 438 | * |
| 439 | * Locking: Called with connection lock held and state set to ENABLED_TX. |
| 440 | */ |
| 441 | static void |
| 442 | gb_connection_flush_incoming_operations(struct gb_connection *connection, |
| 443 | int errno) |
Viresh Kumar | 127c1fb | 2016-01-28 15:50:48 +0530 | [diff] [blame] | 444 | __must_hold(&connection->lock) |
Johan Hovold | beb6b7f | 2016-01-19 12:51:08 +0100 | [diff] [blame] | 445 | { |
| 446 | struct gb_operation *operation; |
| 447 | bool incoming; |
| 448 | |
| 449 | while (!list_empty(&connection->operations)) { |
| 450 | incoming = false; |
| 451 | list_for_each_entry(operation, &connection->operations, |
| 452 | links) { |
| 453 | if (gb_operation_is_incoming(operation)) { |
| 454 | gb_operation_get(operation); |
| 455 | incoming = true; |
| 456 | break; |
| 457 | } |
| 458 | } |
| 459 | |
| 460 | if (!incoming) |
| 461 | break; |
| 462 | |
| 463 | spin_unlock_irq(&connection->lock); |
| 464 | |
| 465 | /* FIXME: flush, not cancel? */ |
| 466 | gb_operation_cancel_incoming(operation, errno); |
| 467 | gb_operation_put(operation); |
| 468 | |
| 469 | spin_lock_irq(&connection->lock); |
| 470 | } |
| 471 | } |
| 472 | |
Johan Hovold | f7ee081 | 2016-01-21 17:34:21 +0100 | [diff] [blame] | 473 | /* |
| 474 | * _gb_connection_enable() - enable a connection |
| 475 | * @connection: connection to enable |
| 476 | * @rx: whether to enable incoming requests |
| 477 | * |
| 478 | * Connection-enable helper for DISABLED->ENABLED, DISABLED->ENABLED_TX, and |
| 479 | * ENABLED_TX->ENABLED state transitions. |
| 480 | * |
| 481 | * Locking: Caller holds connection->mutex. |
| 482 | */ |
| 483 | static int _gb_connection_enable(struct gb_connection *connection, bool rx) |
Alex Elder | 574341c | 2014-10-16 06:35:35 -0500 | [diff] [blame] | 484 | { |
Alex Elder | 36561f2 | 2014-10-22 02:04:30 -0500 | [diff] [blame] | 485 | int ret; |
| 486 | |
Johan Hovold | f7ee081 | 2016-01-21 17:34:21 +0100 | [diff] [blame] | 487 | /* Handle ENABLED_TX -> ENABLED transitions. */ |
Johan Hovold | 570dfa7 | 2016-01-19 12:51:07 +0100 | [diff] [blame] | 488 | if (connection->state == GB_CONNECTION_STATE_ENABLED_TX) { |
Johan Hovold | f7ee081 | 2016-01-21 17:34:21 +0100 | [diff] [blame] | 489 | if (!(connection->handler && rx)) |
| 490 | return 0; |
Johan Hovold | 570dfa7 | 2016-01-19 12:51:07 +0100 | [diff] [blame] | 491 | |
| 492 | spin_lock_irq(&connection->lock); |
Johan Hovold | 570dfa7 | 2016-01-19 12:51:07 +0100 | [diff] [blame] | 493 | connection->state = GB_CONNECTION_STATE_ENABLED; |
| 494 | spin_unlock_irq(&connection->lock); |
| 495 | |
Johan Hovold | f7ee081 | 2016-01-21 17:34:21 +0100 | [diff] [blame] | 496 | return 0; |
Johan Hovold | 570dfa7 | 2016-01-19 12:51:07 +0100 | [diff] [blame] | 497 | } |
| 498 | |
Johan Hovold | d7ea30a5 | 2015-09-17 13:17:26 +0200 | [diff] [blame] | 499 | ret = gb_connection_hd_cport_enable(connection); |
Johan Hovold | a95c258 | 2015-09-17 13:17:21 +0200 | [diff] [blame] | 500 | if (ret) |
Johan Hovold | f7ee081 | 2016-01-21 17:34:21 +0100 | [diff] [blame] | 501 | return ret; |
Viresh Kumar | a1163fa | 2015-09-07 16:01:21 +0530 | [diff] [blame] | 502 | |
Johan Hovold | d7ea30a5 | 2015-09-17 13:17:26 +0200 | [diff] [blame] | 503 | ret = gb_connection_svc_connection_create(connection); |
| 504 | if (ret) |
| 505 | goto err_hd_cport_disable; |
| 506 | |
Johan Hovold | cad09a8 | 2015-07-14 15:43:30 +0200 | [diff] [blame] | 507 | spin_lock_irq(&connection->lock); |
Johan Hovold | f7ee081 | 2016-01-21 17:34:21 +0100 | [diff] [blame] | 508 | if (connection->handler && rx) |
Johan Hovold | 570dfa7 | 2016-01-19 12:51:07 +0100 | [diff] [blame] | 509 | connection->state = GB_CONNECTION_STATE_ENABLED; |
| 510 | else |
| 511 | connection->state = GB_CONNECTION_STATE_ENABLED_TX; |
Johan Hovold | cad09a8 | 2015-07-14 15:43:30 +0200 | [diff] [blame] | 512 | spin_unlock_irq(&connection->lock); |
| 513 | |
Johan Hovold | 4d0bee1 | 2016-01-08 20:13:45 +0100 | [diff] [blame] | 514 | ret = gb_connection_control_connected(connection); |
| 515 | if (ret) |
| 516 | goto err_svc_destroy; |
| 517 | |
Johan Hovold | 8d7a712 | 2015-09-17 13:17:22 +0200 | [diff] [blame] | 518 | return 0; |
| 519 | |
Johan Hovold | 3ea6a81 | 2016-01-08 20:13:46 +0100 | [diff] [blame] | 520 | err_svc_destroy: |
| 521 | spin_lock_irq(&connection->lock); |
| 522 | connection->state = GB_CONNECTION_STATE_DISABLED; |
Johan Hovold | 192bee4 | 2016-01-19 12:51:05 +0100 | [diff] [blame] | 523 | gb_connection_cancel_operations(connection, -ESHUTDOWN); |
Johan Hovold | 3ea6a81 | 2016-01-08 20:13:46 +0100 | [diff] [blame] | 524 | spin_unlock_irq(&connection->lock); |
| 525 | |
| 526 | gb_connection_svc_connection_destroy(connection); |
| 527 | err_hd_cport_disable: |
| 528 | gb_connection_hd_cport_disable(connection); |
Johan Hovold | f7ee081 | 2016-01-21 17:34:21 +0100 | [diff] [blame] | 529 | |
| 530 | return ret; |
| 531 | } |
| 532 | |
| 533 | int gb_connection_enable(struct gb_connection *connection) |
| 534 | { |
| 535 | int ret = 0; |
| 536 | |
| 537 | mutex_lock(&connection->mutex); |
| 538 | |
| 539 | if (connection->state == GB_CONNECTION_STATE_ENABLED) |
| 540 | goto out_unlock; |
| 541 | |
| 542 | ret = _gb_connection_enable(connection, true); |
| 543 | out_unlock: |
Johan Hovold | 2326878 | 2016-01-19 12:51:06 +0100 | [diff] [blame] | 544 | mutex_unlock(&connection->mutex); |
Johan Hovold | 3ea6a81 | 2016-01-08 20:13:46 +0100 | [diff] [blame] | 545 | |
| 546 | return ret; |
| 547 | } |
| 548 | EXPORT_SYMBOL_GPL(gb_connection_enable); |
| 549 | |
Johan Hovold | f7ee081 | 2016-01-21 17:34:21 +0100 | [diff] [blame] | 550 | int gb_connection_enable_tx(struct gb_connection *connection) |
| 551 | { |
| 552 | int ret = 0; |
| 553 | |
| 554 | mutex_lock(&connection->mutex); |
| 555 | |
| 556 | if (connection->state == GB_CONNECTION_STATE_ENABLED) { |
| 557 | ret = -EINVAL; |
| 558 | goto out_unlock; |
| 559 | } |
| 560 | |
| 561 | if (connection->state == GB_CONNECTION_STATE_ENABLED_TX) |
| 562 | goto out_unlock; |
| 563 | |
| 564 | ret = _gb_connection_enable(connection, false); |
| 565 | out_unlock: |
| 566 | mutex_unlock(&connection->mutex); |
| 567 | |
| 568 | return ret; |
| 569 | } |
| 570 | EXPORT_SYMBOL_GPL(gb_connection_enable_tx); |
| 571 | |
Johan Hovold | beb6b7f | 2016-01-19 12:51:08 +0100 | [diff] [blame] | 572 | void gb_connection_disable_rx(struct gb_connection *connection) |
| 573 | { |
| 574 | mutex_lock(&connection->mutex); |
| 575 | |
| 576 | spin_lock_irq(&connection->lock); |
| 577 | if (connection->state != GB_CONNECTION_STATE_ENABLED) { |
| 578 | spin_unlock_irq(&connection->lock); |
| 579 | goto out_unlock; |
| 580 | } |
| 581 | connection->state = GB_CONNECTION_STATE_ENABLED_TX; |
| 582 | gb_connection_flush_incoming_operations(connection, -ESHUTDOWN); |
Johan Hovold | beb6b7f | 2016-01-19 12:51:08 +0100 | [diff] [blame] | 583 | spin_unlock_irq(&connection->lock); |
| 584 | |
| 585 | out_unlock: |
| 586 | mutex_unlock(&connection->mutex); |
| 587 | } |
| 588 | |
Johan Hovold | 3ea6a81 | 2016-01-08 20:13:46 +0100 | [diff] [blame] | 589 | void gb_connection_disable(struct gb_connection *connection) |
| 590 | { |
Johan Hovold | 2326878 | 2016-01-19 12:51:06 +0100 | [diff] [blame] | 591 | mutex_lock(&connection->mutex); |
| 592 | |
Johan Hovold | 81fba249 | 2016-01-19 12:51:03 +0100 | [diff] [blame] | 593 | if (connection->state == GB_CONNECTION_STATE_DISABLED) |
Johan Hovold | 2326878 | 2016-01-19 12:51:06 +0100 | [diff] [blame] | 594 | goto out_unlock; |
Johan Hovold | 81fba249 | 2016-01-19 12:51:03 +0100 | [diff] [blame] | 595 | |
Johan Hovold | 72d7482 | 2015-09-17 13:17:23 +0200 | [diff] [blame] | 596 | gb_connection_control_disconnected(connection); |
Johan Hovold | 4d0bee1 | 2016-01-08 20:13:45 +0100 | [diff] [blame] | 597 | |
| 598 | spin_lock_irq(&connection->lock); |
| 599 | connection->state = GB_CONNECTION_STATE_DISABLED; |
Johan Hovold | 81fba249 | 2016-01-19 12:51:03 +0100 | [diff] [blame] | 600 | gb_connection_cancel_operations(connection, -ESHUTDOWN); |
Johan Hovold | 520c6ea | 2016-01-19 12:51:04 +0100 | [diff] [blame] | 601 | spin_unlock_irq(&connection->lock); |
Johan Hovold | 81fba249 | 2016-01-19 12:51:03 +0100 | [diff] [blame] | 602 | |
Viresh Kumar | 1b7a9cd | 2015-09-07 16:01:22 +0530 | [diff] [blame] | 603 | gb_connection_svc_connection_destroy(connection); |
Johan Hovold | d7ea30a5 | 2015-09-17 13:17:26 +0200 | [diff] [blame] | 604 | gb_connection_hd_cport_disable(connection); |
Johan Hovold | 2326878 | 2016-01-19 12:51:06 +0100 | [diff] [blame] | 605 | |
| 606 | out_unlock: |
| 607 | mutex_unlock(&connection->mutex); |
Johan Hovold | 3ea6a81 | 2016-01-08 20:13:46 +0100 | [diff] [blame] | 608 | } |
| 609 | EXPORT_SYMBOL_GPL(gb_connection_disable); |
| 610 | |
Johan Hovold | c3681f6 | 2016-01-19 12:51:23 +0100 | [diff] [blame] | 611 | /* Caller must have disabled the connection before destroying it. */ |
Viresh Kumar | fda2381 | 2015-08-31 17:21:13 +0530 | [diff] [blame] | 612 | void gb_connection_destroy(struct gb_connection *connection) |
| 613 | { |
| 614 | struct ida *id_map; |
| 615 | |
Johan Hovold | 2edbf5f | 2016-01-19 12:51:22 +0100 | [diff] [blame] | 616 | if (!connection) |
Viresh Kumar | fda2381 | 2015-08-31 17:21:13 +0530 | [diff] [blame] | 617 | return; |
| 618 | |
Johan Hovold | 210b508 | 2016-01-19 12:51:26 +0100 | [diff] [blame] | 619 | mutex_lock(&gb_connection_mutex); |
| 620 | |
Viresh Kumar | fda2381 | 2015-08-31 17:21:13 +0530 | [diff] [blame] | 621 | spin_lock_irq(&gb_connections_lock); |
| 622 | list_del(&connection->bundle_links); |
| 623 | list_del(&connection->hd_links); |
| 624 | spin_unlock_irq(&gb_connections_lock); |
| 625 | |
Johan Hovold | c3681f6 | 2016-01-19 12:51:23 +0100 | [diff] [blame] | 626 | destroy_workqueue(connection->wq); |
| 627 | |
Viresh Kumar | fda2381 | 2015-08-31 17:21:13 +0530 | [diff] [blame] | 628 | id_map = &connection->hd->cport_id_map; |
| 629 | ida_simple_remove(id_map, connection->hd_cport_id); |
| 630 | connection->hd_cport_id = CPORT_ID_BAD; |
| 631 | |
Johan Hovold | 210b508 | 2016-01-19 12:51:26 +0100 | [diff] [blame] | 632 | mutex_unlock(&gb_connection_mutex); |
| 633 | |
Johan Hovold | 0e46fab | 2016-01-19 12:51:25 +0100 | [diff] [blame] | 634 | gb_connection_put(connection); |
Viresh Kumar | fda2381 | 2015-08-31 17:21:13 +0530 | [diff] [blame] | 635 | } |
Johan Hovold | 98fdf5a | 2016-01-21 17:34:09 +0100 | [diff] [blame] | 636 | EXPORT_SYMBOL_GPL(gb_connection_destroy); |
Viresh Kumar | fda2381 | 2015-08-31 17:21:13 +0530 | [diff] [blame] | 637 | |
Bryan O'Donoghue | e7e2efc | 2015-10-15 16:10:42 +0100 | [diff] [blame] | 638 | void gb_connection_latency_tag_enable(struct gb_connection *connection) |
| 639 | { |
Johan Hovold | 2537636 | 2015-11-03 18:03:23 +0100 | [diff] [blame] | 640 | struct gb_host_device *hd = connection->hd; |
Bryan O'Donoghue | e7e2efc | 2015-10-15 16:10:42 +0100 | [diff] [blame] | 641 | int ret; |
| 642 | |
| 643 | if (!hd->driver->latency_tag_enable) |
| 644 | return; |
| 645 | |
| 646 | ret = hd->driver->latency_tag_enable(hd, connection->hd_cport_id); |
| 647 | if (ret) { |
Johan Hovold | 4c4b502 | 2015-11-25 15:59:15 +0100 | [diff] [blame] | 648 | dev_err(&connection->hd->dev, |
| 649 | "%s: failed to enable latency tag: %d\n", |
| 650 | connection->name, ret); |
Bryan O'Donoghue | e7e2efc | 2015-10-15 16:10:42 +0100 | [diff] [blame] | 651 | } |
| 652 | } |
| 653 | EXPORT_SYMBOL_GPL(gb_connection_latency_tag_enable); |
| 654 | |
| 655 | void gb_connection_latency_tag_disable(struct gb_connection *connection) |
| 656 | { |
Johan Hovold | 2537636 | 2015-11-03 18:03:23 +0100 | [diff] [blame] | 657 | struct gb_host_device *hd = connection->hd; |
Bryan O'Donoghue | e7e2efc | 2015-10-15 16:10:42 +0100 | [diff] [blame] | 658 | int ret; |
| 659 | |
| 660 | if (!hd->driver->latency_tag_disable) |
| 661 | return; |
| 662 | |
| 663 | ret = hd->driver->latency_tag_disable(hd, connection->hd_cport_id); |
| 664 | if (ret) { |
Johan Hovold | 4c4b502 | 2015-11-25 15:59:15 +0100 | [diff] [blame] | 665 | dev_err(&connection->hd->dev, |
| 666 | "%s: failed to disable latency tag: %d\n", |
| 667 | connection->name, ret); |
Bryan O'Donoghue | e7e2efc | 2015-10-15 16:10:42 +0100 | [diff] [blame] | 668 | } |
| 669 | } |
| 670 | EXPORT_SYMBOL_GPL(gb_connection_latency_tag_disable); |