linux/drivers/staging/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
  11#include "greybus.h"
  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        if (!hd->driver->cport_quiesce)
 365                return 0;
 366
 367        ret = hd->driver->cport_quiesce(hd, connection->hd_cport_id,
 368                                        peer_space,
 369                                        GB_CONNECTION_CPORT_QUIESCE_TIMEOUT);
 370        if (ret) {
 371                dev_err(&hd->dev, "%s: failed to quiesce host cport: %d\n",
 372                        connection->name, ret);
 373                return ret;
 374        }
 375
 376        return 0;
 377}
 378
 379static int gb_connection_hd_cport_clear(struct gb_connection *connection)
 380{
 381        struct gb_host_device *hd = connection->hd;
 382        int ret;
 383
 384        if (!hd->driver->cport_clear)
 385                return 0;
 386
 387        ret = hd->driver->cport_clear(hd, connection->hd_cport_id);
 388        if (ret) {
 389                dev_err(&hd->dev, "%s: failed to clear host cport: %d\n",
 390                        connection->name, ret);
 391                return ret;
 392        }
 393
 394        return 0;
 395}
 396
 397/*
 398 * Request the SVC to create a connection from AP's cport to interface's
 399 * cport.
 400 */
 401static int
 402gb_connection_svc_connection_create(struct gb_connection *connection)
 403{
 404        struct gb_host_device *hd = connection->hd;
 405        struct gb_interface *intf;
 406        u8 cport_flags;
 407        int ret;
 408
 409        if (gb_connection_is_static(connection))
 410                return 0;
 411
 412        intf = connection->intf;
 413
 414        /*
 415         * Enable either E2EFC or CSD, unless no flow control is requested.
 416         */
 417        cport_flags = GB_SVC_CPORT_FLAG_CSV_N;
 418        if (gb_connection_flow_control_disabled(connection)) {
 419                cport_flags |= GB_SVC_CPORT_FLAG_CSD_N;
 420        } else if (gb_connection_e2efc_enabled(connection)) {
 421                cport_flags |= GB_SVC_CPORT_FLAG_CSD_N |
 422                                GB_SVC_CPORT_FLAG_E2EFC;
 423        }
 424
 425        ret = gb_svc_connection_create(hd->svc,
 426                                       hd->svc->ap_intf_id,
 427                                       connection->hd_cport_id,
 428                                       intf->interface_id,
 429                                       connection->intf_cport_id,
 430                                       cport_flags);
 431        if (ret) {
 432                dev_err(&connection->hd->dev,
 433                        "%s: failed to create svc connection: %d\n",
 434                        connection->name, ret);
 435                return ret;
 436        }
 437
 438        return 0;
 439}
 440
 441static void
 442gb_connection_svc_connection_destroy(struct gb_connection *connection)
 443{
 444        if (gb_connection_is_static(connection))
 445                return;
 446
 447        gb_svc_connection_destroy(connection->hd->svc,
 448                                  connection->hd->svc->ap_intf_id,
 449                                  connection->hd_cport_id,
 450                                  connection->intf->interface_id,
 451                                  connection->intf_cport_id);
 452}
 453
 454/* Inform Interface about active CPorts */
 455static int gb_connection_control_connected(struct gb_connection *connection)
 456{
 457        struct gb_control *control;
 458        u16 cport_id = connection->intf_cport_id;
 459        int ret;
 460
 461        if (gb_connection_is_static(connection))
 462                return 0;
 463
 464        if (gb_connection_is_control(connection))
 465                return 0;
 466
 467        control = connection->intf->control;
 468
 469        ret = gb_control_connected_operation(control, cport_id);
 470        if (ret) {
 471                dev_err(&connection->bundle->dev,
 472                        "failed to connect cport: %d\n", ret);
 473                return ret;
 474        }
 475
 476        return 0;
 477}
 478
 479static void
 480gb_connection_control_disconnecting(struct gb_connection *connection)
 481{
 482        struct gb_control *control;
 483        u16 cport_id = connection->intf_cport_id;
 484        int ret;
 485
 486        if (gb_connection_is_static(connection))
 487                return;
 488
 489        control = connection->intf->control;
 490
 491        ret = gb_control_disconnecting_operation(control, cport_id);
 492        if (ret) {
 493                dev_err(&connection->hd->dev,
 494                        "%s: failed to send disconnecting: %d\n",
 495                        connection->name, ret);
 496        }
 497}
 498
 499static void
 500gb_connection_control_disconnected(struct gb_connection *connection)
 501{
 502        struct gb_control *control;
 503        u16 cport_id = connection->intf_cport_id;
 504        int ret;
 505
 506        if (gb_connection_is_static(connection))
 507                return;
 508
 509        control = connection->intf->control;
 510
 511        if (gb_connection_is_control(connection)) {
 512                if (connection->mode_switch) {
 513                        ret = gb_control_mode_switch_operation(control);
 514                        if (ret) {
 515                                /*
 516                                 * Allow mode switch to time out waiting for
 517                                 * mailbox event.
 518                                 */
 519                                return;
 520                        }
 521                }
 522
 523                return;
 524        }
 525
 526        ret = gb_control_disconnected_operation(control, cport_id);
 527        if (ret) {
 528                dev_warn(&connection->bundle->dev,
 529                         "failed to disconnect cport: %d\n", ret);
 530        }
 531}
 532
 533static int gb_connection_shutdown_operation(struct gb_connection *connection,
 534                                            u8 phase)
 535{
 536        struct gb_cport_shutdown_request *req;
 537        struct gb_operation *operation;
 538        int ret;
 539
 540        operation = gb_operation_create_core(connection,
 541                                             GB_REQUEST_TYPE_CPORT_SHUTDOWN,
 542                                             sizeof(*req), 0, 0,
 543                                             GFP_KERNEL);
 544        if (!operation)
 545                return -ENOMEM;
 546
 547        req = operation->request->payload;
 548        req->phase = phase;
 549
 550        ret = gb_operation_request_send_sync(operation);
 551
 552        gb_operation_put(operation);
 553
 554        return ret;
 555}
 556
 557static int gb_connection_cport_shutdown(struct gb_connection *connection,
 558                                        u8 phase)
 559{
 560        struct gb_host_device *hd = connection->hd;
 561        const struct gb_hd_driver *drv = hd->driver;
 562        int ret;
 563
 564        if (gb_connection_is_static(connection))
 565                return 0;
 566
 567        if (gb_connection_is_offloaded(connection)) {
 568                if (!drv->cport_shutdown)
 569                        return 0;
 570
 571                ret = drv->cport_shutdown(hd, connection->hd_cport_id, phase,
 572                                          GB_OPERATION_TIMEOUT_DEFAULT);
 573        } else {
 574                ret = gb_connection_shutdown_operation(connection, phase);
 575        }
 576
 577        if (ret) {
 578                dev_err(&hd->dev, "%s: failed to send cport shutdown (phase %d): %d\n",
 579                        connection->name, phase, ret);
 580                return ret;
 581        }
 582
 583        return 0;
 584}
 585
 586static int
 587gb_connection_cport_shutdown_phase_1(struct gb_connection *connection)
 588{
 589        return gb_connection_cport_shutdown(connection, 1);
 590}
 591
 592static int
 593gb_connection_cport_shutdown_phase_2(struct gb_connection *connection)
 594{
 595        return gb_connection_cport_shutdown(connection, 2);
 596}
 597
 598/*
 599 * Cancel all active operations on a connection.
 600 *
 601 * Locking: Called with connection lock held and state set to DISABLED or
 602 * DISCONNECTING.
 603 */
 604static void gb_connection_cancel_operations(struct gb_connection *connection,
 605                                            int errno)
 606        __must_hold(&connection->lock)
 607{
 608        struct gb_operation *operation;
 609
 610        while (!list_empty(&connection->operations)) {
 611                operation = list_last_entry(&connection->operations,
 612                                            struct gb_operation, links);
 613                gb_operation_get(operation);
 614                spin_unlock_irq(&connection->lock);
 615
 616                if (gb_operation_is_incoming(operation))
 617                        gb_operation_cancel_incoming(operation, errno);
 618                else
 619                        gb_operation_cancel(operation, errno);
 620
 621                gb_operation_put(operation);
 622
 623                spin_lock_irq(&connection->lock);
 624        }
 625}
 626
 627/*
 628 * Cancel all active incoming operations on a connection.
 629 *
 630 * Locking: Called with connection lock held and state set to ENABLED_TX.
 631 */
 632static void
 633gb_connection_flush_incoming_operations(struct gb_connection *connection,
 634                                        int errno)
 635        __must_hold(&connection->lock)
 636{
 637        struct gb_operation *operation;
 638        bool incoming;
 639
 640        while (!list_empty(&connection->operations)) {
 641                incoming = false;
 642                list_for_each_entry(operation, &connection->operations,
 643                                    links) {
 644                        if (gb_operation_is_incoming(operation)) {
 645                                gb_operation_get(operation);
 646                                incoming = true;
 647                                break;
 648                        }
 649                }
 650
 651                if (!incoming)
 652                        break;
 653
 654                spin_unlock_irq(&connection->lock);
 655
 656                /* FIXME: flush, not cancel? */
 657                gb_operation_cancel_incoming(operation, errno);
 658                gb_operation_put(operation);
 659
 660                spin_lock_irq(&connection->lock);
 661        }
 662}
 663
 664/*
 665 * _gb_connection_enable() - enable a connection
 666 * @connection:         connection to enable
 667 * @rx:                 whether to enable incoming requests
 668 *
 669 * Connection-enable helper for DISABLED->ENABLED, DISABLED->ENABLED_TX, and
 670 * ENABLED_TX->ENABLED state transitions.
 671 *
 672 * Locking: Caller holds connection->mutex.
 673 */
 674static int _gb_connection_enable(struct gb_connection *connection, bool rx)
 675{
 676        int ret;
 677
 678        /* Handle ENABLED_TX -> ENABLED transitions. */
 679        if (connection->state == GB_CONNECTION_STATE_ENABLED_TX) {
 680                if (!(connection->handler && rx))
 681                        return 0;
 682
 683                spin_lock_irq(&connection->lock);
 684                connection->state = GB_CONNECTION_STATE_ENABLED;
 685                spin_unlock_irq(&connection->lock);
 686
 687                return 0;
 688        }
 689
 690        ret = gb_connection_hd_cport_enable(connection);
 691        if (ret)
 692                return ret;
 693
 694        ret = gb_connection_svc_connection_create(connection);
 695        if (ret)
 696                goto err_hd_cport_clear;
 697
 698        ret = gb_connection_hd_cport_connected(connection);
 699        if (ret)
 700                goto err_svc_connection_destroy;
 701
 702        spin_lock_irq(&connection->lock);
 703        if (connection->handler && rx)
 704                connection->state = GB_CONNECTION_STATE_ENABLED;
 705        else
 706                connection->state = GB_CONNECTION_STATE_ENABLED_TX;
 707        spin_unlock_irq(&connection->lock);
 708
 709        ret = gb_connection_control_connected(connection);
 710        if (ret)
 711                goto err_control_disconnecting;
 712
 713        return 0;
 714
 715err_control_disconnecting:
 716        spin_lock_irq(&connection->lock);
 717        connection->state = GB_CONNECTION_STATE_DISCONNECTING;
 718        gb_connection_cancel_operations(connection, -ESHUTDOWN);
 719        spin_unlock_irq(&connection->lock);
 720
 721        /* Transmit queue should already be empty. */
 722        gb_connection_hd_cport_flush(connection);
 723
 724        gb_connection_control_disconnecting(connection);
 725        gb_connection_cport_shutdown_phase_1(connection);
 726        gb_connection_hd_cport_quiesce(connection);
 727        gb_connection_cport_shutdown_phase_2(connection);
 728        gb_connection_control_disconnected(connection);
 729        connection->state = GB_CONNECTION_STATE_DISABLED;
 730err_svc_connection_destroy:
 731        gb_connection_svc_connection_destroy(connection);
 732err_hd_cport_clear:
 733        gb_connection_hd_cport_clear(connection);
 734
 735        gb_connection_hd_cport_disable(connection);
 736
 737        return ret;
 738}
 739
 740int gb_connection_enable(struct gb_connection *connection)
 741{
 742        int ret = 0;
 743
 744        mutex_lock(&connection->mutex);
 745
 746        if (connection->state == GB_CONNECTION_STATE_ENABLED)
 747                goto out_unlock;
 748
 749        ret = _gb_connection_enable(connection, true);
 750        if (!ret)
 751                trace_gb_connection_enable(connection);
 752
 753out_unlock:
 754        mutex_unlock(&connection->mutex);
 755
 756        return ret;
 757}
 758EXPORT_SYMBOL_GPL(gb_connection_enable);
 759
 760int gb_connection_enable_tx(struct gb_connection *connection)
 761{
 762        int ret = 0;
 763
 764        mutex_lock(&connection->mutex);
 765
 766        if (connection->state == GB_CONNECTION_STATE_ENABLED) {
 767                ret = -EINVAL;
 768                goto out_unlock;
 769        }
 770
 771        if (connection->state == GB_CONNECTION_STATE_ENABLED_TX)
 772                goto out_unlock;
 773
 774        ret = _gb_connection_enable(connection, false);
 775        if (!ret)
 776                trace_gb_connection_enable(connection);
 777
 778out_unlock:
 779        mutex_unlock(&connection->mutex);
 780
 781        return ret;
 782}
 783EXPORT_SYMBOL_GPL(gb_connection_enable_tx);
 784
 785void gb_connection_disable_rx(struct gb_connection *connection)
 786{
 787        mutex_lock(&connection->mutex);
 788
 789        spin_lock_irq(&connection->lock);
 790        if (connection->state != GB_CONNECTION_STATE_ENABLED) {
 791                spin_unlock_irq(&connection->lock);
 792                goto out_unlock;
 793        }
 794        connection->state = GB_CONNECTION_STATE_ENABLED_TX;
 795        gb_connection_flush_incoming_operations(connection, -ESHUTDOWN);
 796        spin_unlock_irq(&connection->lock);
 797
 798        trace_gb_connection_disable(connection);
 799
 800out_unlock:
 801        mutex_unlock(&connection->mutex);
 802}
 803EXPORT_SYMBOL_GPL(gb_connection_disable_rx);
 804
 805void gb_connection_mode_switch_prepare(struct gb_connection *connection)
 806{
 807        connection->mode_switch = true;
 808}
 809
 810void gb_connection_mode_switch_complete(struct gb_connection *connection)
 811{
 812        gb_connection_svc_connection_destroy(connection);
 813        gb_connection_hd_cport_clear(connection);
 814
 815        gb_connection_hd_cport_disable(connection);
 816
 817        connection->mode_switch = false;
 818}
 819
 820void gb_connection_disable(struct gb_connection *connection)
 821{
 822        mutex_lock(&connection->mutex);
 823
 824        if (connection->state == GB_CONNECTION_STATE_DISABLED)
 825                goto out_unlock;
 826
 827        trace_gb_connection_disable(connection);
 828
 829        spin_lock_irq(&connection->lock);
 830        connection->state = GB_CONNECTION_STATE_DISCONNECTING;
 831        gb_connection_cancel_operations(connection, -ESHUTDOWN);
 832        spin_unlock_irq(&connection->lock);
 833
 834        gb_connection_hd_cport_flush(connection);
 835
 836        gb_connection_control_disconnecting(connection);
 837        gb_connection_cport_shutdown_phase_1(connection);
 838        gb_connection_hd_cport_quiesce(connection);
 839        gb_connection_cport_shutdown_phase_2(connection);
 840        gb_connection_control_disconnected(connection);
 841
 842        connection->state = GB_CONNECTION_STATE_DISABLED;
 843
 844        /* control-connection tear down is deferred when mode switching */
 845        if (!connection->mode_switch) {
 846                gb_connection_svc_connection_destroy(connection);
 847                gb_connection_hd_cport_clear(connection);
 848
 849                gb_connection_hd_cport_disable(connection);
 850        }
 851
 852out_unlock:
 853        mutex_unlock(&connection->mutex);
 854}
 855EXPORT_SYMBOL_GPL(gb_connection_disable);
 856
 857/* Disable a connection without communicating with the remote end. */
 858void gb_connection_disable_forced(struct gb_connection *connection)
 859{
 860        mutex_lock(&connection->mutex);
 861
 862        if (connection->state == GB_CONNECTION_STATE_DISABLED)
 863                goto out_unlock;
 864
 865        trace_gb_connection_disable(connection);
 866
 867        spin_lock_irq(&connection->lock);
 868        connection->state = GB_CONNECTION_STATE_DISABLED;
 869        gb_connection_cancel_operations(connection, -ESHUTDOWN);
 870        spin_unlock_irq(&connection->lock);
 871
 872        gb_connection_hd_cport_flush(connection);
 873
 874        gb_connection_svc_connection_destroy(connection);
 875        gb_connection_hd_cport_clear(connection);
 876
 877        gb_connection_hd_cport_disable(connection);
 878out_unlock:
 879        mutex_unlock(&connection->mutex);
 880}
 881EXPORT_SYMBOL_GPL(gb_connection_disable_forced);
 882
 883/* Caller must have disabled the connection before destroying it. */
 884void gb_connection_destroy(struct gb_connection *connection)
 885{
 886        if (!connection)
 887                return;
 888
 889        if (WARN_ON(connection->state != GB_CONNECTION_STATE_DISABLED))
 890                gb_connection_disable(connection);
 891
 892        mutex_lock(&gb_connection_mutex);
 893
 894        spin_lock_irq(&gb_connections_lock);
 895        list_del(&connection->bundle_links);
 896        list_del(&connection->hd_links);
 897        spin_unlock_irq(&gb_connections_lock);
 898
 899        destroy_workqueue(connection->wq);
 900
 901        gb_hd_cport_release(connection->hd, connection->hd_cport_id);
 902        connection->hd_cport_id = CPORT_ID_BAD;
 903
 904        mutex_unlock(&gb_connection_mutex);
 905
 906        gb_connection_put(connection);
 907}
 908EXPORT_SYMBOL_GPL(gb_connection_destroy);
 909
 910void gb_connection_latency_tag_enable(struct gb_connection *connection)
 911{
 912        struct gb_host_device *hd = connection->hd;
 913        int ret;
 914
 915        if (!hd->driver->latency_tag_enable)
 916                return;
 917
 918        ret = hd->driver->latency_tag_enable(hd, connection->hd_cport_id);
 919        if (ret) {
 920                dev_err(&connection->hd->dev,
 921                        "%s: failed to enable latency tag: %d\n",
 922                        connection->name, ret);
 923        }
 924}
 925EXPORT_SYMBOL_GPL(gb_connection_latency_tag_enable);
 926
 927void gb_connection_latency_tag_disable(struct gb_connection *connection)
 928{
 929        struct gb_host_device *hd = connection->hd;
 930        int ret;
 931
 932        if (!hd->driver->latency_tag_disable)
 933                return;
 934
 935        ret = hd->driver->latency_tag_disable(hd, connection->hd_cport_id);
 936        if (ret) {
 937                dev_err(&connection->hd->dev,
 938                        "%s: failed to disable latency tag: %d\n",
 939                        connection->name, ret);
 940        }
 941}
 942EXPORT_SYMBOL_GPL(gb_connection_latency_tag_disable);
 943