brintos

brintos / linux-shallow public Read only

0
0
Text · 22.6 KiB · 9c88861 Raw
940 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Greybus connections4 *5 * Copyright 2014 Google Inc.6 * Copyright 2014 Linaro Ltd.7 */8 9#include <linux/workqueue.h>10#include <linux/greybus.h>11 12#include "greybus_trace.h"13 14#define GB_CONNECTION_CPORT_QUIESCE_TIMEOUT	100015 16static void gb_connection_kref_release(struct kref *kref);17 18static DEFINE_SPINLOCK(gb_connections_lock);19static DEFINE_MUTEX(gb_connection_mutex);20 21/* Caller holds gb_connection_mutex. */22static bool gb_connection_cport_in_use(struct gb_interface *intf, u16 cport_id)23{24	struct gb_host_device *hd = intf->hd;25	struct gb_connection *connection;26 27	list_for_each_entry(connection, &hd->connections, hd_links) {28		if (connection->intf == intf &&29		    connection->intf_cport_id == cport_id)30			return true;31	}32 33	return false;34}35 36static void gb_connection_get(struct gb_connection *connection)37{38	kref_get(&connection->kref);39 40	trace_gb_connection_get(connection);41}42 43static void gb_connection_put(struct gb_connection *connection)44{45	trace_gb_connection_put(connection);46 47	kref_put(&connection->kref, gb_connection_kref_release);48}49 50/*51 * Returns a reference-counted pointer to the connection if found.52 */53static struct gb_connection *54gb_connection_hd_find(struct gb_host_device *hd, u16 cport_id)55{56	struct gb_connection *connection;57	unsigned long flags;58 59	spin_lock_irqsave(&gb_connections_lock, flags);60	list_for_each_entry(connection, &hd->connections, hd_links)61		if (connection->hd_cport_id == cport_id) {62			gb_connection_get(connection);63			goto found;64		}65	connection = NULL;66found:67	spin_unlock_irqrestore(&gb_connections_lock, flags);68 69	return connection;70}71 72/*73 * Callback from the host driver to let us know that data has been74 * received on the bundle.75 */76void greybus_data_rcvd(struct gb_host_device *hd, u16 cport_id,77		       u8 *data, size_t length)78{79	struct gb_connection *connection;80 81	trace_gb_hd_in(hd);82 83	connection = gb_connection_hd_find(hd, cport_id);84	if (!connection) {85		dev_err(&hd->dev,86			"nonexistent connection (%zu bytes dropped)\n", length);87		return;88	}89	gb_connection_recv(connection, data, length);90	gb_connection_put(connection);91}92EXPORT_SYMBOL_GPL(greybus_data_rcvd);93 94static void gb_connection_kref_release(struct kref *kref)95{96	struct gb_connection *connection;97 98	connection = container_of(kref, struct gb_connection, kref);99 100	trace_gb_connection_release(connection);101 102	kfree(connection);103}104 105static void gb_connection_init_name(struct gb_connection *connection)106{107	u16 hd_cport_id = connection->hd_cport_id;108	u16 cport_id = 0;109	u8 intf_id = 0;110 111	if (connection->intf) {112		intf_id = connection->intf->interface_id;113		cport_id = connection->intf_cport_id;114	}115 116	snprintf(connection->name, sizeof(connection->name),117		 "%u/%u:%u", hd_cport_id, intf_id, cport_id);118}119 120/*121 * _gb_connection_create() - create a Greybus connection122 * @hd:			host device of the connection123 * @hd_cport_id:	host-device cport id, or -1 for dynamic allocation124 * @intf:		remote interface, or NULL for static connections125 * @bundle:		remote-interface bundle (may be NULL)126 * @cport_id:		remote-interface cport id, or 0 for static connections127 * @handler:		request handler (may be NULL)128 * @flags:		connection flags129 *130 * Create a Greybus connection, representing the bidirectional link131 * between a CPort on a (local) Greybus host device and a CPort on132 * another Greybus interface.133 *134 * A connection also maintains the state of operations sent over the135 * connection.136 *137 * Serialised against concurrent create and destroy using the138 * gb_connection_mutex.139 *140 * Return: A pointer to the new connection if successful, or an ERR_PTR141 * otherwise.142 */143static struct gb_connection *144_gb_connection_create(struct gb_host_device *hd, int hd_cport_id,145		      struct gb_interface *intf,146		      struct gb_bundle *bundle, int cport_id,147		      gb_request_handler_t handler,148		      unsigned long flags)149{150	struct gb_connection *connection;151	int ret;152 153	mutex_lock(&gb_connection_mutex);154 155	if (intf && gb_connection_cport_in_use(intf, cport_id)) {156		dev_err(&intf->dev, "cport %u already in use\n", cport_id);157		ret = -EBUSY;158		goto err_unlock;159	}160 161	ret = gb_hd_cport_allocate(hd, hd_cport_id, flags);162	if (ret < 0) {163		dev_err(&hd->dev, "failed to allocate cport: %d\n", ret);164		goto err_unlock;165	}166	hd_cport_id = ret;167 168	connection = kzalloc(sizeof(*connection), GFP_KERNEL);169	if (!connection) {170		ret = -ENOMEM;171		goto err_hd_cport_release;172	}173 174	connection->hd_cport_id = hd_cport_id;175	connection->intf_cport_id = cport_id;176	connection->hd = hd;177	connection->intf = intf;178	connection->bundle = bundle;179	connection->handler = handler;180	connection->flags = flags;181	if (intf && (intf->quirks & GB_INTERFACE_QUIRK_NO_CPORT_FEATURES))182		connection->flags |= GB_CONNECTION_FLAG_NO_FLOWCTRL;183	connection->state = GB_CONNECTION_STATE_DISABLED;184 185	atomic_set(&connection->op_cycle, 0);186	mutex_init(&connection->mutex);187	spin_lock_init(&connection->lock);188	INIT_LIST_HEAD(&connection->operations);189 190	connection->wq = alloc_ordered_workqueue("%s:%d", 0, dev_name(&hd->dev),191						 hd_cport_id);192	if (!connection->wq) {193		ret = -ENOMEM;194		goto err_free_connection;195	}196 197	kref_init(&connection->kref);198 199	gb_connection_init_name(connection);200 201	spin_lock_irq(&gb_connections_lock);202	list_add(&connection->hd_links, &hd->connections);203 204	if (bundle)205		list_add(&connection->bundle_links, &bundle->connections);206	else207		INIT_LIST_HEAD(&connection->bundle_links);208 209	spin_unlock_irq(&gb_connections_lock);210 211	mutex_unlock(&gb_connection_mutex);212 213	trace_gb_connection_create(connection);214 215	return connection;216 217err_free_connection:218	kfree(connection);219err_hd_cport_release:220	gb_hd_cport_release(hd, hd_cport_id);221err_unlock:222	mutex_unlock(&gb_connection_mutex);223 224	return ERR_PTR(ret);225}226 227struct gb_connection *228gb_connection_create_static(struct gb_host_device *hd, u16 hd_cport_id,229			    gb_request_handler_t handler)230{231	return _gb_connection_create(hd, hd_cport_id, NULL, NULL, 0, handler,232				     GB_CONNECTION_FLAG_HIGH_PRIO);233}234 235struct gb_connection *236gb_connection_create_control(struct gb_interface *intf)237{238	return _gb_connection_create(intf->hd, -1, intf, NULL, 0, NULL,239				     GB_CONNECTION_FLAG_CONTROL |240				     GB_CONNECTION_FLAG_HIGH_PRIO);241}242 243struct gb_connection *244gb_connection_create(struct gb_bundle *bundle, u16 cport_id,245		     gb_request_handler_t handler)246{247	struct gb_interface *intf = bundle->intf;248 249	return _gb_connection_create(intf->hd, -1, intf, bundle, cport_id,250				     handler, 0);251}252EXPORT_SYMBOL_GPL(gb_connection_create);253 254struct gb_connection *255gb_connection_create_flags(struct gb_bundle *bundle, u16 cport_id,256			   gb_request_handler_t handler,257			   unsigned long flags)258{259	struct gb_interface *intf = bundle->intf;260 261	if (WARN_ON_ONCE(flags & GB_CONNECTION_FLAG_CORE_MASK))262		flags &= ~GB_CONNECTION_FLAG_CORE_MASK;263 264	return _gb_connection_create(intf->hd, -1, intf, bundle, cport_id,265				     handler, flags);266}267EXPORT_SYMBOL_GPL(gb_connection_create_flags);268 269struct gb_connection *270gb_connection_create_offloaded(struct gb_bundle *bundle, u16 cport_id,271			       unsigned long flags)272{273	flags |= GB_CONNECTION_FLAG_OFFLOADED;274 275	return gb_connection_create_flags(bundle, cport_id, NULL, flags);276}277EXPORT_SYMBOL_GPL(gb_connection_create_offloaded);278 279static int gb_connection_hd_cport_enable(struct gb_connection *connection)280{281	struct gb_host_device *hd = connection->hd;282	int ret;283 284	if (!hd->driver->cport_enable)285		return 0;286 287	ret = hd->driver->cport_enable(hd, connection->hd_cport_id,288				       connection->flags);289	if (ret) {290		dev_err(&hd->dev, "%s: failed to enable host cport: %d\n",291			connection->name, ret);292		return ret;293	}294 295	return 0;296}297 298static void gb_connection_hd_cport_disable(struct gb_connection *connection)299{300	struct gb_host_device *hd = connection->hd;301	int ret;302 303	if (!hd->driver->cport_disable)304		return;305 306	ret = hd->driver->cport_disable(hd, connection->hd_cport_id);307	if (ret) {308		dev_err(&hd->dev, "%s: failed to disable host cport: %d\n",309			connection->name, ret);310	}311}312 313static int gb_connection_hd_cport_connected(struct gb_connection *connection)314{315	struct gb_host_device *hd = connection->hd;316	int ret;317 318	if (!hd->driver->cport_connected)319		return 0;320 321	ret = hd->driver->cport_connected(hd, connection->hd_cport_id);322	if (ret) {323		dev_err(&hd->dev, "%s: failed to set connected state: %d\n",324			connection->name, ret);325		return ret;326	}327 328	return 0;329}330 331static int gb_connection_hd_cport_flush(struct gb_connection *connection)332{333	struct gb_host_device *hd = connection->hd;334	int ret;335 336	if (!hd->driver->cport_flush)337		return 0;338 339	ret = hd->driver->cport_flush(hd, connection->hd_cport_id);340	if (ret) {341		dev_err(&hd->dev, "%s: failed to flush host cport: %d\n",342			connection->name, ret);343		return ret;344	}345 346	return 0;347}348 349static int gb_connection_hd_cport_quiesce(struct gb_connection *connection)350{351	struct gb_host_device *hd = connection->hd;352	size_t peer_space;353	int ret;354 355	if (!hd->driver->cport_quiesce)356		return 0;357 358	peer_space = sizeof(struct gb_operation_msg_hdr) +359			sizeof(struct gb_cport_shutdown_request);360 361	if (connection->mode_switch)362		peer_space += sizeof(struct gb_operation_msg_hdr);363 364	ret = hd->driver->cport_quiesce(hd, connection->hd_cport_id,365					peer_space,366					GB_CONNECTION_CPORT_QUIESCE_TIMEOUT);367	if (ret) {368		dev_err(&hd->dev, "%s: failed to quiesce host cport: %d\n",369			connection->name, ret);370		return ret;371	}372 373	return 0;374}375 376static int gb_connection_hd_cport_clear(struct gb_connection *connection)377{378	struct gb_host_device *hd = connection->hd;379	int ret;380 381	if (!hd->driver->cport_clear)382		return 0;383 384	ret = hd->driver->cport_clear(hd, connection->hd_cport_id);385	if (ret) {386		dev_err(&hd->dev, "%s: failed to clear host cport: %d\n",387			connection->name, ret);388		return ret;389	}390 391	return 0;392}393 394/*395 * Request the SVC to create a connection from AP's cport to interface's396 * cport.397 */398static int399gb_connection_svc_connection_create(struct gb_connection *connection)400{401	struct gb_host_device *hd = connection->hd;402	struct gb_interface *intf;403	u8 cport_flags;404	int ret;405 406	if (gb_connection_is_static(connection))407		return 0;408 409	intf = connection->intf;410 411	/*412	 * Enable either E2EFC or CSD, unless no flow control is requested.413	 */414	cport_flags = GB_SVC_CPORT_FLAG_CSV_N;415	if (gb_connection_flow_control_disabled(connection)) {416		cport_flags |= GB_SVC_CPORT_FLAG_CSD_N;417	} else if (gb_connection_e2efc_enabled(connection)) {418		cport_flags |= GB_SVC_CPORT_FLAG_CSD_N |419				GB_SVC_CPORT_FLAG_E2EFC;420	}421 422	ret = gb_svc_connection_create(hd->svc,423				       hd->svc->ap_intf_id,424				       connection->hd_cport_id,425				       intf->interface_id,426				       connection->intf_cport_id,427				       cport_flags);428	if (ret) {429		dev_err(&connection->hd->dev,430			"%s: failed to create svc connection: %d\n",431			connection->name, ret);432		return ret;433	}434 435	return 0;436}437 438static void439gb_connection_svc_connection_destroy(struct gb_connection *connection)440{441	if (gb_connection_is_static(connection))442		return;443 444	gb_svc_connection_destroy(connection->hd->svc,445				  connection->hd->svc->ap_intf_id,446				  connection->hd_cport_id,447				  connection->intf->interface_id,448				  connection->intf_cport_id);449}450 451/* Inform Interface about active CPorts */452static int gb_connection_control_connected(struct gb_connection *connection)453{454	struct gb_control *control;455	u16 cport_id = connection->intf_cport_id;456	int ret;457 458	if (gb_connection_is_static(connection))459		return 0;460 461	if (gb_connection_is_control(connection))462		return 0;463 464	control = connection->intf->control;465 466	ret = gb_control_connected_operation(control, cport_id);467	if (ret) {468		dev_err(&connection->bundle->dev,469			"failed to connect cport: %d\n", ret);470		return ret;471	}472 473	return 0;474}475 476static void477gb_connection_control_disconnecting(struct gb_connection *connection)478{479	struct gb_control *control;480	u16 cport_id = connection->intf_cport_id;481	int ret;482 483	if (gb_connection_is_static(connection))484		return;485 486	control = connection->intf->control;487 488	ret = gb_control_disconnecting_operation(control, cport_id);489	if (ret) {490		dev_err(&connection->hd->dev,491			"%s: failed to send disconnecting: %d\n",492			connection->name, ret);493	}494}495 496static void497gb_connection_control_disconnected(struct gb_connection *connection)498{499	struct gb_control *control;500	u16 cport_id = connection->intf_cport_id;501	int ret;502 503	if (gb_connection_is_static(connection))504		return;505 506	control = connection->intf->control;507 508	if (gb_connection_is_control(connection)) {509		if (connection->mode_switch) {510			ret = gb_control_mode_switch_operation(control);511			if (ret) {512				/*513				 * Allow mode switch to time out waiting for514				 * mailbox event.515				 */516				return;517			}518		}519 520		return;521	}522 523	ret = gb_control_disconnected_operation(control, cport_id);524	if (ret) {525		dev_warn(&connection->bundle->dev,526			 "failed to disconnect cport: %d\n", ret);527	}528}529 530static int gb_connection_shutdown_operation(struct gb_connection *connection,531					    u8 phase)532{533	struct gb_cport_shutdown_request *req;534	struct gb_operation *operation;535	int ret;536 537	operation = gb_operation_create_core(connection,538					     GB_REQUEST_TYPE_CPORT_SHUTDOWN,539					     sizeof(*req), 0, 0,540					     GFP_KERNEL);541	if (!operation)542		return -ENOMEM;543 544	req = operation->request->payload;545	req->phase = phase;546 547	ret = gb_operation_request_send_sync(operation);548 549	gb_operation_put(operation);550 551	return ret;552}553 554static int gb_connection_cport_shutdown(struct gb_connection *connection,555					u8 phase)556{557	struct gb_host_device *hd = connection->hd;558	const struct gb_hd_driver *drv = hd->driver;559	int ret;560 561	if (gb_connection_is_static(connection))562		return 0;563 564	if (gb_connection_is_offloaded(connection)) {565		if (!drv->cport_shutdown)566			return 0;567 568		ret = drv->cport_shutdown(hd, connection->hd_cport_id, phase,569					  GB_OPERATION_TIMEOUT_DEFAULT);570	} else {571		ret = gb_connection_shutdown_operation(connection, phase);572	}573 574	if (ret) {575		dev_err(&hd->dev, "%s: failed to send cport shutdown (phase %d): %d\n",576			connection->name, phase, ret);577		return ret;578	}579 580	return 0;581}582 583static int584gb_connection_cport_shutdown_phase_1(struct gb_connection *connection)585{586	return gb_connection_cport_shutdown(connection, 1);587}588 589static int590gb_connection_cport_shutdown_phase_2(struct gb_connection *connection)591{592	return gb_connection_cport_shutdown(connection, 2);593}594 595/*596 * Cancel all active operations on a connection.597 *598 * Locking: Called with connection lock held and state set to DISABLED or599 * DISCONNECTING.600 */601static void gb_connection_cancel_operations(struct gb_connection *connection,602					    int errno)603	__must_hold(&connection->lock)604{605	struct gb_operation *operation;606 607	while (!list_empty(&connection->operations)) {608		operation = list_last_entry(&connection->operations,609					    struct gb_operation, links);610		gb_operation_get(operation);611		spin_unlock_irq(&connection->lock);612 613		if (gb_operation_is_incoming(operation))614			gb_operation_cancel_incoming(operation, errno);615		else616			gb_operation_cancel(operation, errno);617 618		gb_operation_put(operation);619 620		spin_lock_irq(&connection->lock);621	}622}623 624/*625 * Cancel all active incoming operations on a connection.626 *627 * Locking: Called with connection lock held and state set to ENABLED_TX.628 */629static void630gb_connection_flush_incoming_operations(struct gb_connection *connection,631					int errno)632	__must_hold(&connection->lock)633{634	struct gb_operation *operation;635	bool incoming;636 637	while (!list_empty(&connection->operations)) {638		incoming = false;639		list_for_each_entry(operation, &connection->operations,640				    links) {641			if (gb_operation_is_incoming(operation)) {642				gb_operation_get(operation);643				incoming = true;644				break;645			}646		}647 648		if (!incoming)649			break;650 651		spin_unlock_irq(&connection->lock);652 653		/* FIXME: flush, not cancel? */654		gb_operation_cancel_incoming(operation, errno);655		gb_operation_put(operation);656 657		spin_lock_irq(&connection->lock);658	}659}660 661/*662 * _gb_connection_enable() - enable a connection663 * @connection:		connection to enable664 * @rx:			whether to enable incoming requests665 *666 * Connection-enable helper for DISABLED->ENABLED, DISABLED->ENABLED_TX, and667 * ENABLED_TX->ENABLED state transitions.668 *669 * Locking: Caller holds connection->mutex.670 */671static int _gb_connection_enable(struct gb_connection *connection, bool rx)672{673	int ret;674 675	/* Handle ENABLED_TX -> ENABLED transitions. */676	if (connection->state == GB_CONNECTION_STATE_ENABLED_TX) {677		if (!(connection->handler && rx))678			return 0;679 680		spin_lock_irq(&connection->lock);681		connection->state = GB_CONNECTION_STATE_ENABLED;682		spin_unlock_irq(&connection->lock);683 684		return 0;685	}686 687	ret = gb_connection_hd_cport_enable(connection);688	if (ret)689		return ret;690 691	ret = gb_connection_svc_connection_create(connection);692	if (ret)693		goto err_hd_cport_clear;694 695	ret = gb_connection_hd_cport_connected(connection);696	if (ret)697		goto err_svc_connection_destroy;698 699	spin_lock_irq(&connection->lock);700	if (connection->handler && rx)701		connection->state = GB_CONNECTION_STATE_ENABLED;702	else703		connection->state = GB_CONNECTION_STATE_ENABLED_TX;704	spin_unlock_irq(&connection->lock);705 706	ret = gb_connection_control_connected(connection);707	if (ret)708		goto err_control_disconnecting;709 710	return 0;711 712err_control_disconnecting:713	spin_lock_irq(&connection->lock);714	connection->state = GB_CONNECTION_STATE_DISCONNECTING;715	gb_connection_cancel_operations(connection, -ESHUTDOWN);716	spin_unlock_irq(&connection->lock);717 718	/* Transmit queue should already be empty. */719	gb_connection_hd_cport_flush(connection);720 721	gb_connection_control_disconnecting(connection);722	gb_connection_cport_shutdown_phase_1(connection);723	gb_connection_hd_cport_quiesce(connection);724	gb_connection_cport_shutdown_phase_2(connection);725	gb_connection_control_disconnected(connection);726	connection->state = GB_CONNECTION_STATE_DISABLED;727err_svc_connection_destroy:728	gb_connection_svc_connection_destroy(connection);729err_hd_cport_clear:730	gb_connection_hd_cport_clear(connection);731 732	gb_connection_hd_cport_disable(connection);733 734	return ret;735}736 737int gb_connection_enable(struct gb_connection *connection)738{739	int ret = 0;740 741	mutex_lock(&connection->mutex);742 743	if (connection->state == GB_CONNECTION_STATE_ENABLED)744		goto out_unlock;745 746	ret = _gb_connection_enable(connection, true);747	if (!ret)748		trace_gb_connection_enable(connection);749 750out_unlock:751	mutex_unlock(&connection->mutex);752 753	return ret;754}755EXPORT_SYMBOL_GPL(gb_connection_enable);756 757int gb_connection_enable_tx(struct gb_connection *connection)758{759	int ret = 0;760 761	mutex_lock(&connection->mutex);762 763	if (connection->state == GB_CONNECTION_STATE_ENABLED) {764		ret = -EINVAL;765		goto out_unlock;766	}767 768	if (connection->state == GB_CONNECTION_STATE_ENABLED_TX)769		goto out_unlock;770 771	ret = _gb_connection_enable(connection, false);772	if (!ret)773		trace_gb_connection_enable(connection);774 775out_unlock:776	mutex_unlock(&connection->mutex);777 778	return ret;779}780EXPORT_SYMBOL_GPL(gb_connection_enable_tx);781 782void gb_connection_disable_rx(struct gb_connection *connection)783{784	mutex_lock(&connection->mutex);785 786	spin_lock_irq(&connection->lock);787	if (connection->state != GB_CONNECTION_STATE_ENABLED) {788		spin_unlock_irq(&connection->lock);789		goto out_unlock;790	}791	connection->state = GB_CONNECTION_STATE_ENABLED_TX;792	gb_connection_flush_incoming_operations(connection, -ESHUTDOWN);793	spin_unlock_irq(&connection->lock);794 795	trace_gb_connection_disable(connection);796 797out_unlock:798	mutex_unlock(&connection->mutex);799}800EXPORT_SYMBOL_GPL(gb_connection_disable_rx);801 802void gb_connection_mode_switch_prepare(struct gb_connection *connection)803{804	connection->mode_switch = true;805}806 807void gb_connection_mode_switch_complete(struct gb_connection *connection)808{809	gb_connection_svc_connection_destroy(connection);810	gb_connection_hd_cport_clear(connection);811 812	gb_connection_hd_cport_disable(connection);813 814	connection->mode_switch = false;815}816 817void gb_connection_disable(struct gb_connection *connection)818{819	mutex_lock(&connection->mutex);820 821	if (connection->state == GB_CONNECTION_STATE_DISABLED)822		goto out_unlock;823 824	trace_gb_connection_disable(connection);825 826	spin_lock_irq(&connection->lock);827	connection->state = GB_CONNECTION_STATE_DISCONNECTING;828	gb_connection_cancel_operations(connection, -ESHUTDOWN);829	spin_unlock_irq(&connection->lock);830 831	gb_connection_hd_cport_flush(connection);832 833	gb_connection_control_disconnecting(connection);834	gb_connection_cport_shutdown_phase_1(connection);835	gb_connection_hd_cport_quiesce(connection);836	gb_connection_cport_shutdown_phase_2(connection);837	gb_connection_control_disconnected(connection);838 839	connection->state = GB_CONNECTION_STATE_DISABLED;840 841	/* control-connection tear down is deferred when mode switching */842	if (!connection->mode_switch) {843		gb_connection_svc_connection_destroy(connection);844		gb_connection_hd_cport_clear(connection);845 846		gb_connection_hd_cport_disable(connection);847	}848 849out_unlock:850	mutex_unlock(&connection->mutex);851}852EXPORT_SYMBOL_GPL(gb_connection_disable);853 854/* Disable a connection without communicating with the remote end. */855void gb_connection_disable_forced(struct gb_connection *connection)856{857	mutex_lock(&connection->mutex);858 859	if (connection->state == GB_CONNECTION_STATE_DISABLED)860		goto out_unlock;861 862	trace_gb_connection_disable(connection);863 864	spin_lock_irq(&connection->lock);865	connection->state = GB_CONNECTION_STATE_DISABLED;866	gb_connection_cancel_operations(connection, -ESHUTDOWN);867	spin_unlock_irq(&connection->lock);868 869	gb_connection_hd_cport_flush(connection);870 871	gb_connection_svc_connection_destroy(connection);872	gb_connection_hd_cport_clear(connection);873 874	gb_connection_hd_cport_disable(connection);875out_unlock:876	mutex_unlock(&connection->mutex);877}878EXPORT_SYMBOL_GPL(gb_connection_disable_forced);879 880/* Caller must have disabled the connection before destroying it. */881void gb_connection_destroy(struct gb_connection *connection)882{883	if (!connection)884		return;885 886	if (WARN_ON(connection->state != GB_CONNECTION_STATE_DISABLED))887		gb_connection_disable(connection);888 889	mutex_lock(&gb_connection_mutex);890 891	spin_lock_irq(&gb_connections_lock);892	list_del(&connection->bundle_links);893	list_del(&connection->hd_links);894	spin_unlock_irq(&gb_connections_lock);895 896	destroy_workqueue(connection->wq);897 898	gb_hd_cport_release(connection->hd, connection->hd_cport_id);899	connection->hd_cport_id = CPORT_ID_BAD;900 901	mutex_unlock(&gb_connection_mutex);902 903	gb_connection_put(connection);904}905EXPORT_SYMBOL_GPL(gb_connection_destroy);906 907void gb_connection_latency_tag_enable(struct gb_connection *connection)908{909	struct gb_host_device *hd = connection->hd;910	int ret;911 912	if (!hd->driver->latency_tag_enable)913		return;914 915	ret = hd->driver->latency_tag_enable(hd, connection->hd_cport_id);916	if (ret) {917		dev_err(&connection->hd->dev,918			"%s: failed to enable latency tag: %d\n",919			connection->name, ret);920	}921}922EXPORT_SYMBOL_GPL(gb_connection_latency_tag_enable);923 924void gb_connection_latency_tag_disable(struct gb_connection *connection)925{926	struct gb_host_device *hd = connection->hd;927	int ret;928 929	if (!hd->driver->latency_tag_disable)930		return;931 932	ret = hd->driver->latency_tag_disable(hd, connection->hd_cport_id);933	if (ret) {934		dev_err(&connection->hd->dev,935			"%s: failed to disable latency tag: %d\n",936			connection->name, ret);937	}938}939EXPORT_SYMBOL_GPL(gb_connection_latency_tag_disable);940