| .. | .. |
|---|
| 1 | 1 | // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) |
|---|
| 2 | 2 | /* |
|---|
| 3 | 3 | * Copyright 2013-2016 Freescale Semiconductor Inc. |
|---|
| 4 | + * Copyright 2020 NXP |
|---|
| 4 | 5 | * |
|---|
| 5 | 6 | */ |
|---|
| 6 | 7 | #include <linux/kernel.h> |
|---|
| 7 | 8 | #include <linux/fsl/mc.h> |
|---|
| 8 | 9 | |
|---|
| 9 | 10 | #include "fsl-mc-private.h" |
|---|
| 11 | + |
|---|
| 12 | +/* |
|---|
| 13 | + * cache the DPRC version to reduce the number of commands |
|---|
| 14 | + * towards the mc firmware |
|---|
| 15 | + */ |
|---|
| 16 | +static u16 dprc_major_ver; |
|---|
| 17 | +static u16 dprc_minor_ver; |
|---|
| 10 | 18 | |
|---|
| 11 | 19 | /** |
|---|
| 12 | 20 | * dprc_open() - Open DPRC object for use |
|---|
| .. | .. |
|---|
| 71 | 79 | return mc_send_command(mc_io, &cmd); |
|---|
| 72 | 80 | } |
|---|
| 73 | 81 | EXPORT_SYMBOL_GPL(dprc_close); |
|---|
| 82 | + |
|---|
| 83 | +/** |
|---|
| 84 | + * dprc_reset_container - Reset child container. |
|---|
| 85 | + * @mc_io: Pointer to MC portal's I/O object |
|---|
| 86 | + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' |
|---|
| 87 | + * @token: Token of DPRC object |
|---|
| 88 | + * @child_container_id: ID of the container to reset |
|---|
| 89 | + * @options: 32 bit options: |
|---|
| 90 | + * - 0 (no bits set) - all the objects inside the container are |
|---|
| 91 | + * reset. The child containers are entered recursively and the |
|---|
| 92 | + * objects reset. All the objects (including the child containers) |
|---|
| 93 | + * are closed. |
|---|
| 94 | + * - bit 0 set - all the objects inside the container are reset. |
|---|
| 95 | + * However the child containers are not entered recursively. |
|---|
| 96 | + * This option is supported for API versions >= 6.5 |
|---|
| 97 | + * In case a software context crashes or becomes non-responsive, the parent |
|---|
| 98 | + * may wish to reset its resources container before the software context is |
|---|
| 99 | + * restarted. |
|---|
| 100 | + * |
|---|
| 101 | + * This routine informs all objects assigned to the child container that the |
|---|
| 102 | + * container is being reset, so they may perform any cleanup operations that are |
|---|
| 103 | + * needed. All objects handles that were owned by the child container shall be |
|---|
| 104 | + * closed. |
|---|
| 105 | + * |
|---|
| 106 | + * Note that such request may be submitted even if the child software context |
|---|
| 107 | + * has not crashed, but the resulting object cleanup operations will not be |
|---|
| 108 | + * aware of that. |
|---|
| 109 | + * |
|---|
| 110 | + * Return: '0' on Success; Error code otherwise. |
|---|
| 111 | + */ |
|---|
| 112 | +int dprc_reset_container(struct fsl_mc_io *mc_io, |
|---|
| 113 | + u32 cmd_flags, |
|---|
| 114 | + u16 token, |
|---|
| 115 | + int child_container_id, |
|---|
| 116 | + u32 options) |
|---|
| 117 | +{ |
|---|
| 118 | + struct fsl_mc_command cmd = { 0 }; |
|---|
| 119 | + struct dprc_cmd_reset_container *cmd_params; |
|---|
| 120 | + u32 cmdid = DPRC_CMDID_RESET_CONT; |
|---|
| 121 | + int err; |
|---|
| 122 | + |
|---|
| 123 | + /* |
|---|
| 124 | + * If the DPRC object version was not yet cached, cache it now. |
|---|
| 125 | + * Otherwise use the already cached value. |
|---|
| 126 | + */ |
|---|
| 127 | + if (!dprc_major_ver && !dprc_minor_ver) { |
|---|
| 128 | + err = dprc_get_api_version(mc_io, 0, |
|---|
| 129 | + &dprc_major_ver, |
|---|
| 130 | + &dprc_minor_ver); |
|---|
| 131 | + if (err) |
|---|
| 132 | + return err; |
|---|
| 133 | + } |
|---|
| 134 | + |
|---|
| 135 | + /* |
|---|
| 136 | + * MC API 6.5 introduced a new field in the command used to pass |
|---|
| 137 | + * some flags. |
|---|
| 138 | + * Bit 0 indicates that the child containers are not recursively reset. |
|---|
| 139 | + */ |
|---|
| 140 | + if (dprc_major_ver > 6 || (dprc_major_ver == 6 && dprc_minor_ver >= 5)) |
|---|
| 141 | + cmdid = DPRC_CMDID_RESET_CONT_V2; |
|---|
| 142 | + |
|---|
| 143 | + /* prepare command */ |
|---|
| 144 | + cmd.header = mc_encode_cmd_header(cmdid, cmd_flags, token); |
|---|
| 145 | + cmd_params = (struct dprc_cmd_reset_container *)cmd.params; |
|---|
| 146 | + cmd_params->child_container_id = cpu_to_le32(child_container_id); |
|---|
| 147 | + cmd_params->options = cpu_to_le32(options); |
|---|
| 148 | + |
|---|
| 149 | + /* send command to mc*/ |
|---|
| 150 | + return mc_send_command(mc_io, &cmd); |
|---|
| 151 | +} |
|---|
| 152 | +EXPORT_SYMBOL_GPL(dprc_reset_container); |
|---|
| 74 | 153 | |
|---|
| 75 | 154 | /** |
|---|
| 76 | 155 | * dprc_set_irq() - Set IRQ information for the DPRC to trigger an interrupt. |
|---|
| .. | .. |
|---|
| 281 | 360 | /* retrieve response parameters */ |
|---|
| 282 | 361 | rsp_params = (struct dprc_rsp_get_attributes *)cmd.params; |
|---|
| 283 | 362 | attr->container_id = le32_to_cpu(rsp_params->container_id); |
|---|
| 284 | | - attr->icid = le16_to_cpu(rsp_params->icid); |
|---|
| 363 | + attr->icid = le32_to_cpu(rsp_params->icid); |
|---|
| 285 | 364 | attr->options = le32_to_cpu(rsp_params->options); |
|---|
| 286 | 365 | attr->portal_id = le32_to_cpu(rsp_params->portal_id); |
|---|
| 287 | 366 | |
|---|
| .. | .. |
|---|
| 445 | 524 | struct dprc_rsp_get_obj_region *rsp_params; |
|---|
| 446 | 525 | int err; |
|---|
| 447 | 526 | |
|---|
| 448 | | - /* prepare command */ |
|---|
| 449 | | - cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_OBJ_REG, |
|---|
| 450 | | - cmd_flags, token); |
|---|
| 527 | + /* |
|---|
| 528 | + * If the DPRC object version was not yet cached, cache it now. |
|---|
| 529 | + * Otherwise use the already cached value. |
|---|
| 530 | + */ |
|---|
| 531 | + if (!dprc_major_ver && !dprc_minor_ver) { |
|---|
| 532 | + err = dprc_get_api_version(mc_io, 0, |
|---|
| 533 | + &dprc_major_ver, |
|---|
| 534 | + &dprc_minor_ver); |
|---|
| 535 | + if (err) |
|---|
| 536 | + return err; |
|---|
| 537 | + } |
|---|
| 538 | + |
|---|
| 539 | + if (dprc_major_ver > 6 || (dprc_major_ver == 6 && dprc_minor_ver >= 6)) { |
|---|
| 540 | + /* |
|---|
| 541 | + * MC API version 6.6 changed the size of the MC portals and software |
|---|
| 542 | + * portals to 64K (as implemented by hardware). If older API is in use the |
|---|
| 543 | + * size reported is less (64 bytes for mc portals and 4K for software |
|---|
| 544 | + * portals). |
|---|
| 545 | + */ |
|---|
| 546 | + |
|---|
| 547 | + cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_OBJ_REG_V3, |
|---|
| 548 | + cmd_flags, token); |
|---|
| 549 | + |
|---|
| 550 | + } else if (dprc_major_ver == 6 && dprc_minor_ver >= 3) { |
|---|
| 551 | + /* |
|---|
| 552 | + * MC API version 6.3 introduced a new field to the region |
|---|
| 553 | + * descriptor: base_address. If the older API is in use then the base |
|---|
| 554 | + * address is set to zero to indicate it needs to be obtained elsewhere |
|---|
| 555 | + * (typically the device tree). |
|---|
| 556 | + */ |
|---|
| 557 | + cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_OBJ_REG_V2, |
|---|
| 558 | + cmd_flags, token); |
|---|
| 559 | + } else { |
|---|
| 560 | + cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_OBJ_REG, |
|---|
| 561 | + cmd_flags, token); |
|---|
| 562 | + } |
|---|
| 563 | + |
|---|
| 451 | 564 | cmd_params = (struct dprc_cmd_get_obj_region *)cmd.params; |
|---|
| 452 | 565 | cmd_params->obj_id = cpu_to_le32(obj_id); |
|---|
| 453 | 566 | cmd_params->region_index = region_index; |
|---|
| .. | .. |
|---|
| 461 | 574 | |
|---|
| 462 | 575 | /* retrieve response parameters */ |
|---|
| 463 | 576 | rsp_params = (struct dprc_rsp_get_obj_region *)cmd.params; |
|---|
| 464 | | - region_desc->base_offset = le64_to_cpu(rsp_params->base_addr); |
|---|
| 577 | + region_desc->base_offset = le64_to_cpu(rsp_params->base_offset); |
|---|
| 465 | 578 | region_desc->size = le32_to_cpu(rsp_params->size); |
|---|
| 579 | + if (dprc_major_ver > 6 || (dprc_major_ver == 6 && dprc_minor_ver >= 3)) |
|---|
| 580 | + region_desc->base_address = le64_to_cpu(rsp_params->base_addr); |
|---|
| 581 | + else |
|---|
| 582 | + region_desc->base_address = 0; |
|---|
| 466 | 583 | |
|---|
| 467 | 584 | return 0; |
|---|
| 468 | 585 | } |
|---|
| .. | .. |
|---|
| 530 | 647 | |
|---|
| 531 | 648 | return 0; |
|---|
| 532 | 649 | } |
|---|
| 650 | + |
|---|
| 651 | +/** |
|---|
| 652 | + * dprc_get_connection() - Get connected endpoint and link status if connection |
|---|
| 653 | + * exists. |
|---|
| 654 | + * @mc_io: Pointer to MC portal's I/O object |
|---|
| 655 | + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' |
|---|
| 656 | + * @token: Token of DPRC object |
|---|
| 657 | + * @endpoint1: Endpoint 1 configuration parameters |
|---|
| 658 | + * @endpoint2: Returned endpoint 2 configuration parameters |
|---|
| 659 | + * @state: Returned link state: |
|---|
| 660 | + * 1 - link is up; |
|---|
| 661 | + * 0 - link is down; |
|---|
| 662 | + * -1 - no connection (endpoint2 information is irrelevant) |
|---|
| 663 | + * |
|---|
| 664 | + * Return: '0' on Success; -ENOTCONN if connection does not exist. |
|---|
| 665 | + */ |
|---|
| 666 | +int dprc_get_connection(struct fsl_mc_io *mc_io, |
|---|
| 667 | + u32 cmd_flags, |
|---|
| 668 | + u16 token, |
|---|
| 669 | + const struct dprc_endpoint *endpoint1, |
|---|
| 670 | + struct dprc_endpoint *endpoint2, |
|---|
| 671 | + int *state) |
|---|
| 672 | +{ |
|---|
| 673 | + struct dprc_cmd_get_connection *cmd_params; |
|---|
| 674 | + struct dprc_rsp_get_connection *rsp_params; |
|---|
| 675 | + struct fsl_mc_command cmd = { 0 }; |
|---|
| 676 | + int err, i; |
|---|
| 677 | + |
|---|
| 678 | + /* prepare command */ |
|---|
| 679 | + cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_CONNECTION, |
|---|
| 680 | + cmd_flags, |
|---|
| 681 | + token); |
|---|
| 682 | + cmd_params = (struct dprc_cmd_get_connection *)cmd.params; |
|---|
| 683 | + cmd_params->ep1_id = cpu_to_le32(endpoint1->id); |
|---|
| 684 | + cmd_params->ep1_interface_id = cpu_to_le16(endpoint1->if_id); |
|---|
| 685 | + for (i = 0; i < 16; i++) |
|---|
| 686 | + cmd_params->ep1_type[i] = endpoint1->type[i]; |
|---|
| 687 | + |
|---|
| 688 | + /* send command to mc */ |
|---|
| 689 | + err = mc_send_command(mc_io, &cmd); |
|---|
| 690 | + if (err) |
|---|
| 691 | + return -ENOTCONN; |
|---|
| 692 | + |
|---|
| 693 | + /* retrieve response parameters */ |
|---|
| 694 | + rsp_params = (struct dprc_rsp_get_connection *)cmd.params; |
|---|
| 695 | + endpoint2->id = le32_to_cpu(rsp_params->ep2_id); |
|---|
| 696 | + endpoint2->if_id = le16_to_cpu(rsp_params->ep2_interface_id); |
|---|
| 697 | + *state = le32_to_cpu(rsp_params->state); |
|---|
| 698 | + for (i = 0; i < 16; i++) |
|---|
| 699 | + endpoint2->type[i] = rsp_params->ep2_type[i]; |
|---|
| 700 | + |
|---|
| 701 | + return 0; |
|---|
| 702 | +} |
|---|