Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

greybus: connection: implement new connection handling

Implement the new connection setup and tear-down sequences for control
connections and bundle connections (offloaded and non-offloaded).

Signed-off-by: Johan Hovold <johan@hovoldconsulting.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>

authored by

Johan Hovold and committed by
Greg Kroah-Hartman
aac0839e 77e52b3b

+98 -37
+93 -36
drivers/staging/greybus/connection.c
··· 13 13 #include "greybus_trace.h" 14 14 15 15 16 + #define GB_CONNECTION_CPORT_QUIESCE_TIMEOUT 1000 17 + 18 + 16 19 static void gb_connection_kref_release(struct kref *kref); 17 20 18 21 ··· 315 312 } 316 313 } 317 314 315 + static int gb_connection_hd_cport_connected(struct gb_connection *connection) 316 + { 317 + struct gb_host_device *hd = connection->hd; 318 + int ret; 319 + 320 + if (!hd->driver->cport_connected) 321 + return 0; 322 + 323 + ret = hd->driver->cport_connected(hd, connection->hd_cport_id); 324 + if (ret) { 325 + dev_err(&hd->dev, "%s: failed to set connected state: %d\n", 326 + connection->name, ret); 327 + return ret; 328 + } 329 + 330 + return 0; 331 + } 332 + 318 333 static int gb_connection_hd_cport_flush(struct gb_connection *connection) 319 334 { 320 335 struct gb_host_device *hd = connection->hd; ··· 351 330 return 0; 352 331 } 353 332 354 - static int 355 - gb_connection_hd_cport_features_enable(struct gb_connection *connection) 333 + static int gb_connection_hd_cport_quiesce(struct gb_connection *connection) 356 334 { 357 335 struct gb_host_device *hd = connection->hd; 336 + size_t peer_space; 358 337 int ret; 359 338 360 - if (!hd->driver->cport_features_enable) 361 - return 0; 339 + peer_space = sizeof(struct gb_operation_msg_hdr) + 340 + sizeof(struct gb_cport_shutdown_request); 362 341 363 - ret = hd->driver->cport_features_enable(hd, connection->hd_cport_id); 342 + if (connection->mode_switch) 343 + peer_space += sizeof(struct gb_operation_msg_hdr); 344 + 345 + ret = hd->driver->cport_quiesce(hd, connection->hd_cport_id, 346 + peer_space, 347 + GB_CONNECTION_CPORT_QUIESCE_TIMEOUT); 364 348 if (ret) { 365 - dev_err(&hd->dev, "%s: failed to enable CPort features: %d\n", 366 - connection->name, ret); 349 + dev_err(&hd->dev, "%s: failed to quiesce host cport: %d\n", 350 + connection->name, ret); 367 351 return ret; 368 352 } 369 353 370 354 return 0; 371 355 } 372 356 373 - static void 374 - gb_connection_hd_cport_features_disable(struct gb_connection *connection) 357 + static int gb_connection_hd_cport_clear(struct gb_connection *connection) 375 358 { 376 359 struct gb_host_device *hd = connection->hd; 360 + int ret; 377 361 378 - if (!hd->driver->cport_features_disable) 379 - return; 362 + ret = hd->driver->cport_clear(hd, connection->hd_cport_id); 363 + if (ret) { 364 + dev_err(&hd->dev, "%s: failed to clear host cport: %d\n", 365 + connection->name, ret); 366 + return ret; 367 + } 380 368 381 - hd->driver->cport_features_disable(hd, connection->hd_cport_id); 369 + return 0; 382 370 } 383 371 384 372 /* ··· 526 496 } 527 497 } 528 498 529 - static int gb_connection_ping_operation(struct gb_connection *connection) 499 + static int gb_connection_shutdown_operation(struct gb_connection *connection, 500 + u8 phase) 530 501 { 502 + struct gb_cport_shutdown_request *req; 531 503 struct gb_operation *operation; 532 504 int ret; 533 505 534 506 operation = gb_operation_create_core(connection, 535 - GB_REQUEST_TYPE_PING, 536 - 0, 0, 0, 507 + GB_REQUEST_TYPE_CPORT_SHUTDOWN, 508 + sizeof(*req), 0, 0, 537 509 GFP_KERNEL); 538 510 if (!operation) 539 511 return -ENOMEM; 512 + 513 + req = operation->request->payload; 514 + req->phase = phase; 540 515 541 516 ret = gb_operation_request_send_sync(operation); 542 517 ··· 550 515 return ret; 551 516 } 552 517 553 - static int gb_connection_ping(struct gb_connection *connection) 518 + static int gb_connection_cport_shutdown(struct gb_connection *connection, 519 + u8 phase) 554 520 { 555 521 struct gb_host_device *hd = connection->hd; 522 + const struct gb_hd_driver *drv = hd->driver; 556 523 int ret; 557 524 558 525 if (gb_connection_is_static(connection)) 559 526 return 0; 560 527 561 528 if (gb_connection_is_offloaded(connection)) { 562 - if (!hd->driver->cport_ping) 529 + if (!drv->cport_shutdown) 563 530 return 0; 564 531 565 - ret = hd->driver->cport_ping(hd, connection->hd_cport_id); 532 + ret = drv->cport_shutdown(hd, connection->hd_cport_id, phase, 533 + GB_OPERATION_TIMEOUT_DEFAULT); 566 534 } else { 567 - ret = gb_connection_ping_operation(connection); 535 + ret = gb_connection_shutdown_operation(connection, phase); 568 536 } 569 537 570 538 if (ret) { 571 - dev_err(&hd->dev, "%s: failed to send ping: %d\n", 572 - connection->name, ret); 539 + dev_err(&hd->dev, "%s: failed to send cport shutdown (phase %d): %d\n", 540 + connection->name, phase, ret); 573 541 return ret; 574 542 } 575 543 576 544 return 0; 545 + } 546 + 547 + static int 548 + gb_connection_cport_shutdown_phase_1(struct gb_connection *connection) 549 + { 550 + return gb_connection_cport_shutdown(connection, 1); 551 + } 552 + 553 + static int 554 + gb_connection_cport_shutdown_phase_2(struct gb_connection *connection) 555 + { 556 + return gb_connection_cport_shutdown(connection, 2); 577 557 } 578 558 579 559 /* ··· 689 639 690 640 ret = gb_connection_svc_connection_create(connection); 691 641 if (ret) 692 - goto err_hd_cport_disable; 642 + goto err_hd_cport_clear; 693 643 694 - ret = gb_connection_hd_cport_features_enable(connection); 644 + ret = gb_connection_hd_cport_connected(connection); 695 645 if (ret) 696 646 goto err_svc_connection_destroy; 697 647 ··· 709 659 return 0; 710 660 711 661 err_control_disconnecting: 712 - gb_connection_control_disconnecting(connection); 713 - 714 662 spin_lock_irq(&connection->lock); 715 663 connection->state = GB_CONNECTION_STATE_DISCONNECTING; 716 664 gb_connection_cancel_operations(connection, -ESHUTDOWN); ··· 717 669 /* Transmit queue should already be empty. */ 718 670 gb_connection_hd_cport_flush(connection); 719 671 720 - gb_connection_ping(connection); 721 - gb_connection_hd_cport_features_disable(connection); 672 + gb_connection_control_disconnecting(connection); 673 + gb_connection_cport_shutdown_phase_1(connection); 674 + gb_connection_hd_cport_quiesce(connection); 675 + gb_connection_cport_shutdown_phase_2(connection); 722 676 gb_connection_control_disconnected(connection); 723 677 connection->state = GB_CONNECTION_STATE_DISABLED; 724 678 err_svc_connection_destroy: 725 679 gb_connection_svc_connection_destroy(connection); 726 - err_hd_cport_disable: 680 + err_hd_cport_clear: 681 + gb_connection_hd_cport_clear(connection); 682 + 727 683 gb_connection_hd_cport_disable(connection); 728 684 729 685 return ret; ··· 806 754 void gb_connection_mode_switch_complete(struct gb_connection *connection) 807 755 { 808 756 gb_connection_svc_connection_destroy(connection); 757 + gb_connection_hd_cport_clear(connection); 758 + 809 759 gb_connection_hd_cport_disable(connection); 760 + 810 761 connection->mode_switch = false; 811 762 } 812 763 ··· 822 767 823 768 trace_gb_connection_disable(connection); 824 769 825 - gb_connection_control_disconnecting(connection); 826 - 827 770 spin_lock_irq(&connection->lock); 828 771 connection->state = GB_CONNECTION_STATE_DISCONNECTING; 829 772 gb_connection_cancel_operations(connection, -ESHUTDOWN); ··· 829 776 830 777 gb_connection_hd_cport_flush(connection); 831 778 832 - gb_connection_ping(connection); 833 - gb_connection_hd_cport_features_disable(connection); 834 - 779 + gb_connection_control_disconnecting(connection); 780 + gb_connection_cport_shutdown_phase_1(connection); 781 + gb_connection_hd_cport_quiesce(connection); 782 + gb_connection_cport_shutdown_phase_2(connection); 835 783 gb_connection_control_disconnected(connection); 836 784 837 785 connection->state = GB_CONNECTION_STATE_DISABLED; ··· 840 786 /* control-connection tear down is deferred when mode switching */ 841 787 if (!connection->mode_switch) { 842 788 gb_connection_svc_connection_destroy(connection); 789 + gb_connection_hd_cport_clear(connection); 790 + 843 791 gb_connection_hd_cport_disable(connection); 844 792 } 845 793 ··· 866 810 spin_unlock_irq(&connection->lock); 867 811 868 812 gb_connection_hd_cport_flush(connection); 869 - gb_connection_hd_cport_features_disable(connection); 870 - gb_connection_svc_connection_destroy(connection); 871 - gb_connection_hd_cport_disable(connection); 872 813 814 + gb_connection_svc_connection_destroy(connection); 815 + gb_connection_hd_cport_clear(connection); 816 + 817 + gb_connection_hd_cport_disable(connection); 873 818 out_unlock: 874 819 mutex_unlock(&connection->mutex); 875 820 }
+5 -1
drivers/staging/greybus/greybus_protocols.h
··· 96 96 97 97 98 98 /* Generic request types */ 99 - #define GB_REQUEST_TYPE_PING 0x00 99 + #define GB_REQUEST_TYPE_CPORT_SHUTDOWN 0x00 100 100 #define GB_REQUEST_TYPE_INVALID 0x7f 101 + 102 + struct gb_cport_shutdown_request { 103 + __u8 phase; 104 + } __packed; 101 105 102 106 103 107 /* Control Protocol */