linux/drivers/greybus/connection.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Greybus connections
   4 *
   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     1000
  15
  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 been
  74 * 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 connection
 122 * @hd:                 host device of the connection
 123 * @hd_cport_id:        host-device cport id, or -1 for dynamic allocation
 124 * @intf:               remote interface, or NULL for static connections
 125 * @bundle:             remote-interface bundle (may be NULL)
 126 * @cport_id:           remote-interface cport id, or 0 for static connections
 127 * @handler:            request handler (may be NULL)
 128 * @flags:              connection flags
 129 *
 130 * Create a Greybus connection, representing the bidirectional link
 131 * between a CPort on a (local) Greybus host device and a CPort on
 132 * another Greybus interface.
 133 *
 134 * A connection also maintains the state of operations sent over the
 135 * connection.
 136 *
 137 * Serialised against concurrent create and destroy using the
 138 * gb_connection_mutex.
 139 *
 140 * Return: A pointer to the new connection if successful, or an ERR_PTR
 141 * 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_workqueue("%s:%d", WQ_UNBOUND, 1,
 191                                         dev_name(&hd->dev), 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        else
 207                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's
 396 * cport.
 397 */
 398static int
 399gb_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 void
 439gb_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 void
 477gb_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 void
 497gb_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 for
 514                                 * 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 int
 584gb_connection_cport_shutdown_phase_1(struct gb_connection *connection)
 585{
 586        return gb_connection_cport_shutdown(connection, 1);
 587}
 588
 589static int
 590gb_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 or
 599 * 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                else
 616                        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 void
 630gb_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 connection
 663 * @connection:         connection to enable
 664 * @rx:                 whether to enable incoming requests
 665 *
 666 * Connection-enable helper for DISABLED->ENABLED, DISABLED->ENABLED_TX, and
 667 * 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        else
 703                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