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

Merge branch '20260105-kvmrprocv10-v10-0-022e96815380@oss.qualcomm.com' of https://git.kernel.org/pub/scm/linux/kernel/git/qcom/linux into rproc-next

Merge the support for loading and managing TustZone-based remote
processors found in the Qualcomm Glymur platform from a shared topic
branch, as it's a mix of qcom-soc and remoteproc patches.

+536 -116
+3
Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml
··· 44 44 - const: stop-ack 45 45 - const: shutdown-ack 46 46 47 + iommus: 48 + maxItems: 1 49 + 47 50 power-domains: 48 51 minItems: 1 49 52 maxItems: 3
+334 -46
drivers/firmware/qcom/qcom_scm.c
··· 27 27 #include <linux/of_reserved_mem.h> 28 28 #include <linux/platform_device.h> 29 29 #include <linux/reset-controller.h> 30 + #include <linux/remoteproc.h> 30 31 #include <linux/sizes.h> 31 32 #include <linux/types.h> 32 33 ··· 111 110 enum qcom_scm_qseecom_tz_cmd_info { 112 111 QSEECOM_TZ_CMD_INFO_VERSION = 3, 113 112 }; 113 + 114 + #define RSCTABLE_BUFFER_NOT_SUFFICIENT 20 114 115 115 116 #define QSEECOM_MAX_APP_NAME_SIZE 64 116 117 #define SHMBRIDGE_RESULT_NOTSUPP 4 ··· 562 559 } 563 560 564 561 /** 562 + * devm_qcom_scm_pas_context_alloc() - Allocate peripheral authentication service 563 + * context for a given peripheral 564 + * 565 + * PAS context is device-resource managed, so the caller does not need 566 + * to worry about freeing the context memory. 567 + * 568 + * @dev: PAS firmware device 569 + * @pas_id: peripheral authentication service id 570 + * @mem_phys: Subsystem reserve memory start address 571 + * @mem_size: Subsystem reserve memory size 572 + * 573 + * Returns: The new PAS context, or ERR_PTR() on failure. 574 + */ 575 + struct qcom_scm_pas_context *devm_qcom_scm_pas_context_alloc(struct device *dev, 576 + u32 pas_id, 577 + phys_addr_t mem_phys, 578 + size_t mem_size) 579 + { 580 + struct qcom_scm_pas_context *ctx; 581 + 582 + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); 583 + if (!ctx) 584 + return ERR_PTR(-ENOMEM); 585 + 586 + ctx->dev = dev; 587 + ctx->pas_id = pas_id; 588 + ctx->mem_phys = mem_phys; 589 + ctx->mem_size = mem_size; 590 + 591 + return ctx; 592 + } 593 + EXPORT_SYMBOL_GPL(devm_qcom_scm_pas_context_alloc); 594 + 595 + static int __qcom_scm_pas_init_image(u32 pas_id, dma_addr_t mdata_phys, 596 + struct qcom_scm_res *res) 597 + { 598 + struct qcom_scm_desc desc = { 599 + .svc = QCOM_SCM_SVC_PIL, 600 + .cmd = QCOM_SCM_PIL_PAS_INIT_IMAGE, 601 + .arginfo = QCOM_SCM_ARGS(2, QCOM_SCM_VAL, QCOM_SCM_RW), 602 + .args[0] = pas_id, 603 + .owner = ARM_SMCCC_OWNER_SIP, 604 + }; 605 + int ret; 606 + 607 + ret = qcom_scm_clk_enable(); 608 + if (ret) 609 + return ret; 610 + 611 + ret = qcom_scm_bw_enable(); 612 + if (ret) 613 + goto disable_clk; 614 + 615 + desc.args[1] = mdata_phys; 616 + 617 + ret = qcom_scm_call(__scm->dev, &desc, res); 618 + qcom_scm_bw_disable(); 619 + 620 + disable_clk: 621 + qcom_scm_clk_disable(); 622 + 623 + return ret; 624 + } 625 + 626 + static int qcom_scm_pas_prep_and_init_image(struct qcom_scm_pas_context *ctx, 627 + const void *metadata, size_t size) 628 + { 629 + struct qcom_scm_res res; 630 + phys_addr_t mdata_phys; 631 + void *mdata_buf; 632 + int ret; 633 + 634 + mdata_buf = qcom_tzmem_alloc(__scm->mempool, size, GFP_KERNEL); 635 + if (!mdata_buf) 636 + return -ENOMEM; 637 + 638 + memcpy(mdata_buf, metadata, size); 639 + mdata_phys = qcom_tzmem_to_phys(mdata_buf); 640 + 641 + ret = __qcom_scm_pas_init_image(ctx->pas_id, mdata_phys, &res); 642 + if (ret < 0) 643 + qcom_tzmem_free(mdata_buf); 644 + else 645 + ctx->ptr = mdata_buf; 646 + 647 + return ret ? : res.result[0]; 648 + } 649 + 650 + /** 565 651 * qcom_scm_pas_init_image() - Initialize peripheral authentication service 566 652 * state machine for a given peripheral, using the 567 653 * metadata 568 - * @peripheral: peripheral id 654 + * @pas_id: peripheral authentication service id 569 655 * @metadata: pointer to memory containing ELF header, program header table 570 656 * and optional blob of data used for authenticating the metadata 571 657 * and the rest of the firmware 572 658 * @size: size of the metadata 573 - * @ctx: optional metadata context 659 + * @ctx: optional pas context 574 660 * 575 661 * Return: 0 on success. 576 662 * ··· 667 575 * track the metadata allocation, this needs to be released by invoking 668 576 * qcom_scm_pas_metadata_release() by the caller. 669 577 */ 670 - int qcom_scm_pas_init_image(u32 peripheral, const void *metadata, size_t size, 671 - struct qcom_scm_pas_metadata *ctx) 578 + int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size, 579 + struct qcom_scm_pas_context *ctx) 672 580 { 581 + struct qcom_scm_res res; 673 582 dma_addr_t mdata_phys; 674 583 void *mdata_buf; 675 584 int ret; 676 - struct qcom_scm_desc desc = { 677 - .svc = QCOM_SCM_SVC_PIL, 678 - .cmd = QCOM_SCM_PIL_PAS_INIT_IMAGE, 679 - .arginfo = QCOM_SCM_ARGS(2, QCOM_SCM_VAL, QCOM_SCM_RW), 680 - .args[0] = peripheral, 681 - .owner = ARM_SMCCC_OWNER_SIP, 682 - }; 683 - struct qcom_scm_res res; 585 + 586 + if (ctx && ctx->use_tzmem) 587 + return qcom_scm_pas_prep_and_init_image(ctx, metadata, size); 684 588 685 589 /* 686 590 * During the scm call memory protection will be enabled for the meta ··· 697 609 698 610 memcpy(mdata_buf, metadata, size); 699 611 700 - ret = qcom_scm_clk_enable(); 701 - if (ret) 702 - goto out; 703 - 704 - ret = qcom_scm_bw_enable(); 705 - if (ret) 706 - goto disable_clk; 707 - 708 - desc.args[1] = mdata_phys; 709 - 710 - ret = qcom_scm_call(__scm->dev, &desc, &res); 711 - qcom_scm_bw_disable(); 712 - 713 - disable_clk: 714 - qcom_scm_clk_disable(); 715 - 716 - out: 612 + ret = __qcom_scm_pas_init_image(pas_id, mdata_phys, &res); 717 613 if (ret < 0 || !ctx) { 718 614 dma_free_coherent(__scm->dev, size, mdata_buf, mdata_phys); 719 615 } else if (ctx) { ··· 712 640 713 641 /** 714 642 * qcom_scm_pas_metadata_release() - release metadata context 715 - * @ctx: metadata context 643 + * @ctx: pas context 716 644 */ 717 - void qcom_scm_pas_metadata_release(struct qcom_scm_pas_metadata *ctx) 645 + void qcom_scm_pas_metadata_release(struct qcom_scm_pas_context *ctx) 718 646 { 719 647 if (!ctx->ptr) 720 648 return; 721 649 722 - dma_free_coherent(__scm->dev, ctx->size, ctx->ptr, ctx->phys); 650 + if (ctx->use_tzmem) 651 + qcom_tzmem_free(ctx->ptr); 652 + else 653 + dma_free_coherent(__scm->dev, ctx->size, ctx->ptr, ctx->phys); 723 654 724 655 ctx->ptr = NULL; 725 - ctx->phys = 0; 726 - ctx->size = 0; 727 656 } 728 657 EXPORT_SYMBOL_GPL(qcom_scm_pas_metadata_release); 729 658 730 659 /** 731 660 * qcom_scm_pas_mem_setup() - Prepare the memory related to a given peripheral 732 661 * for firmware loading 733 - * @peripheral: peripheral id 662 + * @pas_id: peripheral authentication service id 734 663 * @addr: start address of memory area to prepare 735 664 * @size: size of the memory area to prepare 736 665 * 737 666 * Returns 0 on success. 738 667 */ 739 - int qcom_scm_pas_mem_setup(u32 peripheral, phys_addr_t addr, phys_addr_t size) 668 + int qcom_scm_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size) 740 669 { 741 670 int ret; 742 671 struct qcom_scm_desc desc = { 743 672 .svc = QCOM_SCM_SVC_PIL, 744 673 .cmd = QCOM_SCM_PIL_PAS_MEM_SETUP, 745 674 .arginfo = QCOM_SCM_ARGS(3), 746 - .args[0] = peripheral, 675 + .args[0] = pas_id, 747 676 .args[1] = addr, 748 677 .args[2] = size, 749 678 .owner = ARM_SMCCC_OWNER_SIP, ··· 769 696 } 770 697 EXPORT_SYMBOL_GPL(qcom_scm_pas_mem_setup); 771 698 699 + static void *__qcom_scm_pas_get_rsc_table(u32 pas_id, void *input_rt_tzm, 700 + size_t input_rt_size, 701 + size_t *output_rt_size) 702 + { 703 + struct qcom_scm_desc desc = { 704 + .svc = QCOM_SCM_SVC_PIL, 705 + .cmd = QCOM_SCM_PIL_PAS_GET_RSCTABLE, 706 + .arginfo = QCOM_SCM_ARGS(5, QCOM_SCM_VAL, QCOM_SCM_RO, QCOM_SCM_VAL, 707 + QCOM_SCM_RW, QCOM_SCM_VAL), 708 + .args[0] = pas_id, 709 + .owner = ARM_SMCCC_OWNER_SIP, 710 + }; 711 + struct qcom_scm_res res; 712 + void *output_rt_tzm; 713 + int ret; 714 + 715 + output_rt_tzm = qcom_tzmem_alloc(__scm->mempool, *output_rt_size, GFP_KERNEL); 716 + if (!output_rt_tzm) 717 + return ERR_PTR(-ENOMEM); 718 + 719 + desc.args[1] = qcom_tzmem_to_phys(input_rt_tzm); 720 + desc.args[2] = input_rt_size; 721 + desc.args[3] = qcom_tzmem_to_phys(output_rt_tzm); 722 + desc.args[4] = *output_rt_size; 723 + 724 + /* 725 + * Whether SMC fail or pass, res.result[2] will hold actual resource table 726 + * size. 727 + * 728 + * If passed 'output_rt_size' buffer size is not sufficient to hold the 729 + * resource table TrustZone sends, response code in res.result[1] as 730 + * RSCTABLE_BUFFER_NOT_SUFFICIENT so that caller can retry this SMC call 731 + * with output_rt_tzm buffer with res.result[2] size however, It should not 732 + * be of unresonable size. 733 + */ 734 + ret = qcom_scm_call(__scm->dev, &desc, &res); 735 + if (!ret && res.result[2] > SZ_1G) { 736 + ret = -E2BIG; 737 + goto free_output_rt; 738 + } 739 + 740 + *output_rt_size = res.result[2]; 741 + if (ret && res.result[1] == RSCTABLE_BUFFER_NOT_SUFFICIENT) 742 + ret = -EOVERFLOW; 743 + 744 + free_output_rt: 745 + if (ret) 746 + qcom_tzmem_free(output_rt_tzm); 747 + 748 + return ret ? ERR_PTR(ret) : output_rt_tzm; 749 + } 750 + 751 + /** 752 + * qcom_scm_pas_get_rsc_table() - Retrieve the resource table in passed output buffer 753 + * for a given peripheral. 754 + * 755 + * Qualcomm remote processor may rely on both static and dynamic resources for 756 + * its functionality. Static resources typically refer to memory-mapped addresses 757 + * required by the subsystem and are often embedded within the firmware binary 758 + * and dynamic resources, such as shared memory in DDR etc., are determined at 759 + * runtime during the boot process. 760 + * 761 + * On Qualcomm Technologies devices, it's possible that static resources are not 762 + * embedded in the firmware binary and instead are provided by TrustZone However, 763 + * dynamic resources are always expected to come from TrustZone. This indicates 764 + * that for Qualcomm devices, all resources (static and dynamic) will be provided 765 + * by TrustZone via the SMC call. 766 + * 767 + * If the remote processor firmware binary does contain static resources, they 768 + * should be passed in input_rt. These will be forwarded to TrustZone for 769 + * authentication. TrustZone will then append the dynamic resources and return 770 + * the complete resource table in output_rt_tzm. 771 + * 772 + * If the remote processor firmware binary does not include a resource table, 773 + * the caller of this function should set input_rt as NULL and input_rt_size 774 + * as zero respectively. 775 + * 776 + * More about documentation on resource table data structures can be found in 777 + * include/linux/remoteproc.h 778 + * 779 + * @ctx: PAS context 780 + * @pas_id: peripheral authentication service id 781 + * @input_rt: resource table buffer which is present in firmware binary 782 + * @input_rt_size: size of the resource table present in firmware binary 783 + * @output_rt_size: TrustZone expects caller should pass worst case size for 784 + * the output_rt_tzm. 785 + * 786 + * Return: 787 + * On success, returns a pointer to the allocated buffer containing the final 788 + * resource table and output_rt_size will have actual resource table size from 789 + * TrustZone. The caller is responsible for freeing the buffer. On failure, 790 + * returns ERR_PTR(-errno). 791 + */ 792 + struct resource_table *qcom_scm_pas_get_rsc_table(struct qcom_scm_pas_context *ctx, 793 + void *input_rt, 794 + size_t input_rt_size, 795 + size_t *output_rt_size) 796 + { 797 + struct resource_table empty_rsc = {}; 798 + size_t size = SZ_16K; 799 + void *output_rt_tzm; 800 + void *input_rt_tzm; 801 + void *tbl_ptr; 802 + int ret; 803 + 804 + ret = qcom_scm_clk_enable(); 805 + if (ret) 806 + return ERR_PTR(ret); 807 + 808 + ret = qcom_scm_bw_enable(); 809 + if (ret) 810 + goto disable_clk; 811 + 812 + /* 813 + * TrustZone can not accept buffer as NULL value as argument hence, 814 + * we need to pass a input buffer indicating that subsystem firmware 815 + * does not have resource table by filling resource table structure. 816 + */ 817 + if (!input_rt) { 818 + input_rt = &empty_rsc; 819 + input_rt_size = sizeof(empty_rsc); 820 + } 821 + 822 + input_rt_tzm = qcom_tzmem_alloc(__scm->mempool, input_rt_size, GFP_KERNEL); 823 + if (!input_rt_tzm) { 824 + ret = -ENOMEM; 825 + goto disable_scm_bw; 826 + } 827 + 828 + memcpy(input_rt_tzm, input_rt, input_rt_size); 829 + 830 + output_rt_tzm = __qcom_scm_pas_get_rsc_table(ctx->pas_id, input_rt_tzm, 831 + input_rt_size, &size); 832 + if (PTR_ERR(output_rt_tzm) == -EOVERFLOW) 833 + /* Try again with the size requested by the TZ */ 834 + output_rt_tzm = __qcom_scm_pas_get_rsc_table(ctx->pas_id, 835 + input_rt_tzm, 836 + input_rt_size, 837 + &size); 838 + if (IS_ERR(output_rt_tzm)) { 839 + ret = PTR_ERR(output_rt_tzm); 840 + goto free_input_rt; 841 + } 842 + 843 + tbl_ptr = kzalloc(size, GFP_KERNEL); 844 + if (!tbl_ptr) { 845 + qcom_tzmem_free(output_rt_tzm); 846 + ret = -ENOMEM; 847 + goto free_input_rt; 848 + } 849 + 850 + memcpy(tbl_ptr, output_rt_tzm, size); 851 + *output_rt_size = size; 852 + qcom_tzmem_free(output_rt_tzm); 853 + 854 + free_input_rt: 855 + qcom_tzmem_free(input_rt_tzm); 856 + 857 + disable_scm_bw: 858 + qcom_scm_bw_disable(); 859 + 860 + disable_clk: 861 + qcom_scm_clk_disable(); 862 + 863 + return ret ? ERR_PTR(ret) : tbl_ptr; 864 + } 865 + EXPORT_SYMBOL_GPL(qcom_scm_pas_get_rsc_table); 866 + 772 867 /** 773 868 * qcom_scm_pas_auth_and_reset() - Authenticate the given peripheral firmware 774 869 * and reset the remote processor 775 - * @peripheral: peripheral id 870 + * @pas_id: peripheral authentication service id 776 871 * 777 872 * Return 0 on success. 778 873 */ 779 - int qcom_scm_pas_auth_and_reset(u32 peripheral) 874 + int qcom_scm_pas_auth_and_reset(u32 pas_id) 780 875 { 781 876 int ret; 782 877 struct qcom_scm_desc desc = { 783 878 .svc = QCOM_SCM_SVC_PIL, 784 879 .cmd = QCOM_SCM_PIL_PAS_AUTH_AND_RESET, 785 880 .arginfo = QCOM_SCM_ARGS(1), 786 - .args[0] = peripheral, 881 + .args[0] = pas_id, 787 882 .owner = ARM_SMCCC_OWNER_SIP, 788 883 }; 789 884 struct qcom_scm_res res; ··· 975 734 EXPORT_SYMBOL_GPL(qcom_scm_pas_auth_and_reset); 976 735 977 736 /** 737 + * qcom_scm_pas_prepare_and_auth_reset() - Prepare, authenticate, and reset the 738 + * remote processor 739 + * 740 + * @ctx: Context saved during call to qcom_scm_pas_context_init() 741 + * 742 + * This function performs the necessary steps to prepare a PAS subsystem, 743 + * authenticate it using the provided metadata, and initiate a reset sequence. 744 + * 745 + * It should be used when Linux is in control setting up the IOMMU hardware 746 + * for remote subsystem during secure firmware loading processes. The preparation 747 + * step sets up a shmbridge over the firmware memory before TrustZone accesses the 748 + * firmware memory region for authentication. The authentication step verifies 749 + * the integrity and authenticity of the firmware or configuration using secure 750 + * metadata. Finally, the reset step ensures the subsystem starts in a clean and 751 + * sane state. 752 + * 753 + * Return: 0 on success, negative errno on failure. 754 + */ 755 + int qcom_scm_pas_prepare_and_auth_reset(struct qcom_scm_pas_context *ctx) 756 + { 757 + u64 handle; 758 + int ret; 759 + 760 + /* 761 + * When Linux running @ EL1, Gunyah hypervisor running @ EL2 traps the 762 + * auth_and_reset call and create an shmbridge on the remote subsystem 763 + * memory region and then invokes a call to TrustZone to authenticate. 764 + */ 765 + if (!ctx->use_tzmem) 766 + return qcom_scm_pas_auth_and_reset(ctx->pas_id); 767 + 768 + /* 769 + * When Linux runs @ EL2 Linux must create the shmbridge itself and then 770 + * subsequently call TrustZone for authenticate and reset. 771 + */ 772 + ret = qcom_tzmem_shm_bridge_create(ctx->mem_phys, ctx->mem_size, &handle); 773 + if (ret) 774 + return ret; 775 + 776 + ret = qcom_scm_pas_auth_and_reset(ctx->pas_id); 777 + qcom_tzmem_shm_bridge_delete(handle); 778 + 779 + return ret; 780 + } 781 + EXPORT_SYMBOL_GPL(qcom_scm_pas_prepare_and_auth_reset); 782 + 783 + /** 978 784 * qcom_scm_pas_shutdown() - Shut down the remote processor 979 - * @peripheral: peripheral id 785 + * @pas_id: peripheral authentication service id 980 786 * 981 787 * Returns 0 on success. 982 788 */ 983 - int qcom_scm_pas_shutdown(u32 peripheral) 789 + int qcom_scm_pas_shutdown(u32 pas_id) 984 790 { 985 791 int ret; 986 792 struct qcom_scm_desc desc = { 987 793 .svc = QCOM_SCM_SVC_PIL, 988 794 .cmd = QCOM_SCM_PIL_PAS_SHUTDOWN, 989 795 .arginfo = QCOM_SCM_ARGS(1), 990 - .args[0] = peripheral, 796 + .args[0] = pas_id, 991 797 .owner = ARM_SMCCC_OWNER_SIP, 992 798 }; 993 799 struct qcom_scm_res res; ··· 1060 772 /** 1061 773 * qcom_scm_pas_supported() - Check if the peripheral authentication service is 1062 774 * available for the given peripherial 1063 - * @peripheral: peripheral id 775 + * @pas_id: peripheral authentication service id 1064 776 * 1065 777 * Returns true if PAS is supported for this peripheral, otherwise false. 1066 778 */ 1067 - bool qcom_scm_pas_supported(u32 peripheral) 779 + bool qcom_scm_pas_supported(u32 pas_id) 1068 780 { 1069 781 int ret; 1070 782 struct qcom_scm_desc desc = { 1071 783 .svc = QCOM_SCM_SVC_PIL, 1072 784 .cmd = QCOM_SCM_PIL_PAS_IS_SUPPORTED, 1073 785 .arginfo = QCOM_SCM_ARGS(1), 1074 - .args[0] = peripheral, 786 + .args[0] = pas_id, 1075 787 .owner = ARM_SMCCC_OWNER_SIP, 1076 788 }; 1077 789 struct qcom_scm_res res;
+1
drivers/firmware/qcom/qcom_scm.h
··· 105 105 #define QCOM_SCM_PIL_PAS_SHUTDOWN 0x06 106 106 #define QCOM_SCM_PIL_PAS_IS_SUPPORTED 0x07 107 107 #define QCOM_SCM_PIL_PAS_MSS_RESET 0x0a 108 + #define QCOM_SCM_PIL_PAS_GET_RSCTABLE 0x21 108 109 109 110 #define QCOM_SCM_SVC_IO 0x05 110 111 #define QCOM_SCM_IO_READ 0x01
+130 -35
drivers/remoteproc/qcom_q6v5_pas.c
··· 11 11 #include <linux/delay.h> 12 12 #include <linux/firmware.h> 13 13 #include <linux/interrupt.h> 14 + #include <linux/iommu.h> 14 15 #include <linux/kernel.h> 15 16 #include <linux/module.h> 16 17 #include <linux/of.h> ··· 118 117 struct qcom_rproc_ssr ssr_subdev; 119 118 struct qcom_sysmon *sysmon; 120 119 121 - struct qcom_scm_pas_metadata pas_metadata; 122 - struct qcom_scm_pas_metadata dtb_pas_metadata; 120 + struct qcom_scm_pas_context *pas_ctx; 121 + struct qcom_scm_pas_context *dtb_pas_ctx; 123 122 }; 124 123 125 124 static void qcom_pas_segment_dump(struct rproc *rproc, ··· 212 211 * auth_and_reset() was successful, but in other cases clean it up 213 212 * here. 214 213 */ 215 - qcom_scm_pas_metadata_release(&pas->pas_metadata); 214 + qcom_scm_pas_metadata_release(pas->pas_ctx); 216 215 if (pas->dtb_pas_id) 217 - qcom_scm_pas_metadata_release(&pas->dtb_pas_metadata); 216 + qcom_scm_pas_metadata_release(pas->dtb_pas_ctx); 218 217 219 218 return 0; 220 219 } ··· 240 239 return ret; 241 240 } 242 241 243 - ret = qcom_mdt_pas_init(pas->dev, pas->dtb_firmware, pas->dtb_firmware_name, 244 - pas->dtb_pas_id, pas->dtb_mem_phys, 245 - &pas->dtb_pas_metadata); 246 - if (ret) 247 - goto release_dtb_firmware; 248 - 249 - ret = qcom_mdt_load_no_init(pas->dev, pas->dtb_firmware, pas->dtb_firmware_name, 250 - pas->dtb_mem_region, pas->dtb_mem_phys, 251 - pas->dtb_mem_size, &pas->dtb_mem_reloc); 242 + ret = qcom_mdt_pas_load(pas->dtb_pas_ctx, pas->dtb_firmware, 243 + pas->dtb_firmware_name, pas->dtb_mem_region, 244 + &pas->dtb_mem_reloc); 252 245 if (ret) 253 246 goto release_dtb_metadata; 254 247 } ··· 250 255 return 0; 251 256 252 257 release_dtb_metadata: 253 - qcom_scm_pas_metadata_release(&pas->dtb_pas_metadata); 254 - 255 - release_dtb_firmware: 258 + qcom_scm_pas_metadata_release(pas->dtb_pas_ctx); 256 259 release_firmware(pas->dtb_firmware); 257 260 261 + return ret; 262 + } 263 + 264 + static void qcom_pas_unmap_carveout(struct rproc *rproc, phys_addr_t mem_phys, size_t size) 265 + { 266 + if (rproc->has_iommu) 267 + iommu_unmap(rproc->domain, mem_phys, size); 268 + } 269 + 270 + static int qcom_pas_map_carveout(struct rproc *rproc, phys_addr_t mem_phys, size_t size) 271 + { 272 + int ret = 0; 273 + 274 + if (rproc->has_iommu) 275 + ret = iommu_map(rproc->domain, mem_phys, mem_phys, size, 276 + IOMMU_READ | IOMMU_WRITE, GFP_KERNEL); 258 277 return ret; 259 278 } 260 279 ··· 306 297 } 307 298 308 299 if (pas->dtb_pas_id) { 309 - ret = qcom_scm_pas_auth_and_reset(pas->dtb_pas_id); 300 + ret = qcom_pas_map_carveout(rproc, pas->dtb_mem_phys, pas->dtb_mem_size); 301 + if (ret) 302 + goto disable_px_supply; 303 + 304 + ret = qcom_scm_pas_prepare_and_auth_reset(pas->dtb_pas_ctx); 310 305 if (ret) { 311 306 dev_err(pas->dev, 312 307 "failed to authenticate dtb image and release reset\n"); 313 - goto disable_px_supply; 308 + goto unmap_dtb_carveout; 314 309 } 315 310 } 316 311 317 - ret = qcom_mdt_pas_init(pas->dev, pas->firmware, rproc->firmware, pas->pas_id, 318 - pas->mem_phys, &pas->pas_metadata); 319 - if (ret) 320 - goto disable_px_supply; 321 - 322 - ret = qcom_mdt_load_no_init(pas->dev, pas->firmware, rproc->firmware, 323 - pas->mem_region, pas->mem_phys, pas->mem_size, 324 - &pas->mem_reloc); 312 + ret = qcom_mdt_pas_load(pas->pas_ctx, pas->firmware, rproc->firmware, 313 + pas->mem_region, &pas->mem_reloc); 325 314 if (ret) 326 315 goto release_pas_metadata; 327 316 328 317 qcom_pil_info_store(pas->info_name, pas->mem_phys, pas->mem_size); 329 318 330 - ret = qcom_scm_pas_auth_and_reset(pas->pas_id); 319 + ret = qcom_pas_map_carveout(rproc, pas->mem_phys, pas->mem_size); 320 + if (ret) 321 + goto release_pas_metadata; 322 + 323 + ret = qcom_scm_pas_prepare_and_auth_reset(pas->pas_ctx); 331 324 if (ret) { 332 325 dev_err(pas->dev, 333 326 "failed to authenticate image and release reset\n"); 334 - goto release_pas_metadata; 327 + goto unmap_carveout; 335 328 } 336 329 337 330 ret = qcom_q6v5_wait_for_start(&pas->q6v5, msecs_to_jiffies(5000)); 338 331 if (ret == -ETIMEDOUT) { 339 332 dev_err(pas->dev, "start timed out\n"); 340 333 qcom_scm_pas_shutdown(pas->pas_id); 341 - goto release_pas_metadata; 334 + goto unmap_carveout; 342 335 } 343 336 344 - qcom_scm_pas_metadata_release(&pas->pas_metadata); 337 + qcom_scm_pas_metadata_release(pas->pas_ctx); 345 338 if (pas->dtb_pas_id) 346 - qcom_scm_pas_metadata_release(&pas->dtb_pas_metadata); 339 + qcom_scm_pas_metadata_release(pas->dtb_pas_ctx); 347 340 348 341 /* firmware is used to pass reference from qcom_pas_start(), drop it now */ 349 342 pas->firmware = NULL; 350 343 351 344 return 0; 352 345 346 + unmap_carveout: 347 + qcom_pas_unmap_carveout(rproc, pas->mem_phys, pas->mem_size); 353 348 release_pas_metadata: 354 - qcom_scm_pas_metadata_release(&pas->pas_metadata); 349 + qcom_scm_pas_metadata_release(pas->pas_ctx); 355 350 if (pas->dtb_pas_id) 356 - qcom_scm_pas_metadata_release(&pas->dtb_pas_metadata); 351 + qcom_scm_pas_metadata_release(pas->dtb_pas_ctx); 352 + 353 + unmap_dtb_carveout: 354 + if (pas->dtb_pas_id) 355 + qcom_pas_unmap_carveout(rproc, pas->dtb_mem_phys, pas->dtb_mem_size); 357 356 disable_px_supply: 358 357 if (pas->px_supply) 359 358 regulator_disable(pas->px_supply); ··· 417 400 ret = qcom_scm_pas_shutdown(pas->dtb_pas_id); 418 401 if (ret) 419 402 dev_err(pas->dev, "failed to shutdown dtb: %d\n", ret); 403 + 404 + qcom_pas_unmap_carveout(rproc, pas->dtb_mem_phys, pas->dtb_mem_size); 420 405 } 406 + 407 + qcom_pas_unmap_carveout(rproc, pas->mem_phys, pas->mem_size); 421 408 422 409 handover = qcom_q6v5_unprepare(&pas->q6v5); 423 410 if (handover) ··· 448 427 return pas->mem_region + offset; 449 428 } 450 429 430 + static int qcom_pas_parse_firmware(struct rproc *rproc, const struct firmware *fw) 431 + { 432 + struct qcom_pas *pas = rproc->priv; 433 + struct resource_table *table = NULL; 434 + size_t output_rt_size; 435 + void *output_rt; 436 + size_t table_sz; 437 + int ret; 438 + 439 + ret = qcom_register_dump_segments(rproc, fw); 440 + if (ret) { 441 + dev_err(pas->dev, "Error in registering dump segments\n"); 442 + return ret; 443 + } 444 + 445 + if (!rproc->has_iommu) 446 + return 0; 447 + 448 + ret = rproc_elf_load_rsc_table(rproc, fw); 449 + if (ret) 450 + dev_dbg(&rproc->dev, "Failed to load resource table from firmware\n"); 451 + 452 + table = rproc->table_ptr; 453 + table_sz = rproc->table_sz; 454 + 455 + /* 456 + * The resources consumed by Qualcomm remote processors fall into two categories: 457 + * static (such as the memory carveouts for the rproc firmware) and dynamic (like 458 + * shared memory pools). Both are managed by a Qualcomm hypervisor (such as QHEE 459 + * or Gunyah), if one is present. Otherwise, a resource table must be retrieved 460 + * via an SCM call. That table will list all dynamic resources (if any) and possibly 461 + * the static ones. The static resources may also come from a resource table embedded 462 + * in the rproc firmware instead. 463 + * 464 + * Here, we call rproc_elf_load_rsc_table() to check firmware binary has resources 465 + * or not and if it is not having then we pass NULL and zero as input resource 466 + * table pointer and size respectively to the argument of qcom_scm_pas_get_rsc_table() 467 + * and this is even true for Qualcomm remote processor who does follow remoteproc 468 + * framework. 469 + */ 470 + output_rt = qcom_scm_pas_get_rsc_table(pas->pas_ctx, table, table_sz, &output_rt_size); 471 + ret = IS_ERR(output_rt) ? PTR_ERR(output_rt) : 0; 472 + if (ret) { 473 + dev_err(pas->dev, "Error in getting resource table: %d\n", ret); 474 + return ret; 475 + } 476 + 477 + kfree(rproc->cached_table); 478 + rproc->cached_table = output_rt; 479 + rproc->table_ptr = rproc->cached_table; 480 + rproc->table_sz = output_rt_size; 481 + 482 + return ret; 483 + } 484 + 451 485 static unsigned long qcom_pas_panic(struct rproc *rproc) 452 486 { 453 487 struct qcom_pas *pas = rproc->priv; ··· 515 439 .start = qcom_pas_start, 516 440 .stop = qcom_pas_stop, 517 441 .da_to_va = qcom_pas_da_to_va, 518 - .parse_fw = qcom_register_dump_segments, 442 + .parse_fw = qcom_pas_parse_firmware, 519 443 .load = qcom_pas_load, 520 444 .panic = qcom_pas_panic, 521 445 }; ··· 525 449 .start = qcom_pas_start, 526 450 .stop = qcom_pas_stop, 527 451 .da_to_va = qcom_pas_da_to_va, 528 - .parse_fw = qcom_register_dump_segments, 452 + .parse_fw = qcom_pas_parse_firmware, 529 453 .load = qcom_pas_load, 530 454 .panic = qcom_pas_panic, 531 455 .coredump = qcom_pas_minidump, ··· 773 697 return -ENOMEM; 774 698 } 775 699 700 + rproc->has_iommu = of_property_present(pdev->dev.of_node, "iommus"); 776 701 rproc->auto_boot = desc->auto_boot; 777 702 rproc_coredump_set_elf_info(rproc, ELFCLASS32, EM_NONE); 778 703 ··· 837 760 } 838 761 839 762 qcom_add_ssr_subdev(rproc, &pas->ssr_subdev, desc->ssr_name); 763 + 764 + pas->pas_ctx = devm_qcom_scm_pas_context_alloc(pas->dev, pas->pas_id, 765 + pas->mem_phys, pas->mem_size); 766 + if (IS_ERR(pas->pas_ctx)) { 767 + ret = PTR_ERR(pas->pas_ctx); 768 + goto remove_ssr_sysmon; 769 + } 770 + 771 + pas->dtb_pas_ctx = devm_qcom_scm_pas_context_alloc(pas->dev, pas->dtb_pas_id, 772 + pas->dtb_mem_phys, 773 + pas->dtb_mem_size); 774 + if (IS_ERR(pas->dtb_pas_ctx)) { 775 + ret = PTR_ERR(pas->dtb_pas_ctx); 776 + goto remove_ssr_sysmon; 777 + } 778 + 779 + pas->pas_ctx->use_tzmem = rproc->has_iommu; 780 + pas->dtb_pas_ctx->use_tzmem = rproc->has_iommu; 840 781 ret = rproc_add(rproc); 841 782 if (ret) 842 783 goto remove_ssr_sysmon;
+35 -16
drivers/soc/qcom/mdt_loader.c
··· 227 227 } 228 228 EXPORT_SYMBOL_GPL(qcom_mdt_read_metadata); 229 229 230 - /** 231 - * qcom_mdt_pas_init() - initialize PAS region for firmware loading 232 - * @dev: device handle to associate resources with 233 - * @fw: firmware object for the mdt file 234 - * @fw_name: name of the firmware, for construction of segment file names 235 - * @pas_id: PAS identifier 236 - * @mem_phys: physical address of allocated memory region 237 - * @ctx: PAS metadata context, to be released by caller 238 - * 239 - * Returns 0 on success, negative errno otherwise. 240 - */ 241 - int qcom_mdt_pas_init(struct device *dev, const struct firmware *fw, 242 - const char *fw_name, int pas_id, phys_addr_t mem_phys, 243 - struct qcom_scm_pas_metadata *ctx) 230 + static int __qcom_mdt_pas_init(struct device *dev, const struct firmware *fw, 231 + const char *fw_name, int pas_id, phys_addr_t mem_phys, 232 + struct qcom_scm_pas_context *ctx) 244 233 { 245 234 const struct elf32_phdr *phdrs; 246 235 const struct elf32_phdr *phdr; ··· 291 302 out: 292 303 return ret; 293 304 } 294 - EXPORT_SYMBOL_GPL(qcom_mdt_pas_init); 295 305 296 306 static bool qcom_mdt_bins_are_split(const struct firmware *fw) 297 307 { ··· 457 469 { 458 470 int ret; 459 471 460 - ret = qcom_mdt_pas_init(dev, fw, fw_name, pas_id, mem_phys, NULL); 472 + ret = __qcom_mdt_pas_init(dev, fw, fw_name, pas_id, mem_phys, NULL); 461 473 if (ret) 462 474 return ret; 463 475 ··· 465 477 mem_size, reloc_base); 466 478 } 467 479 EXPORT_SYMBOL_GPL(qcom_mdt_load); 480 + 481 + /** 482 + * qcom_mdt_pas_load - Loads and authenticates the metadata of the firmware 483 + * (typically contained in the .mdt file), followed by loading the actual 484 + * firmware segments (e.g., .bXX files). Authentication of the segments done 485 + * by a separate call. 486 + * 487 + * The PAS context must be initialized using qcom_scm_pas_context_init() 488 + * prior to invoking this function. 489 + * 490 + * @ctx: Pointer to the PAS (Peripheral Authentication Service) context 491 + * @fw: Firmware object representing the .mdt file 492 + * @firmware: Name of the firmware used to construct segment file names 493 + * @mem_region: Memory region allocated for loading the firmware 494 + * @reloc_base: Physical address adjusted after relocation 495 + * 496 + * Return: 0 on success or a negative error code on failure. 497 + */ 498 + int qcom_mdt_pas_load(struct qcom_scm_pas_context *ctx, const struct firmware *fw, 499 + const char *firmware, void *mem_region, phys_addr_t *reloc_base) 500 + { 501 + int ret; 502 + 503 + ret = __qcom_mdt_pas_init(ctx->dev, fw, firmware, ctx->pas_id, ctx->mem_phys, ctx); 504 + if (ret) 505 + return ret; 506 + 507 + return qcom_mdt_load_no_init(ctx->dev, fw, firmware, mem_region, ctx->mem_phys, 508 + ctx->mem_size, reloc_base); 509 + } 510 + EXPORT_SYMBOL_GPL(qcom_mdt_pas_load); 468 511 469 512 MODULE_DESCRIPTION("Firmware parser for Qualcomm MDT format"); 470 513 MODULE_LICENSE("GPL v2");
+22 -8
include/linux/firmware/qcom/qcom_scm.h
··· 66 66 void qcom_scm_cpu_power_down(u32 flags); 67 67 int qcom_scm_set_remote_state(u32 state, u32 id); 68 68 69 - struct qcom_scm_pas_metadata { 69 + struct qcom_scm_pas_context { 70 + struct device *dev; 71 + u32 pas_id; 72 + phys_addr_t mem_phys; 73 + size_t mem_size; 70 74 void *ptr; 71 75 dma_addr_t phys; 72 76 ssize_t size; 77 + bool use_tzmem; 73 78 }; 74 79 75 - int qcom_scm_pas_init_image(u32 peripheral, const void *metadata, size_t size, 76 - struct qcom_scm_pas_metadata *ctx); 77 - void qcom_scm_pas_metadata_release(struct qcom_scm_pas_metadata *ctx); 78 - int qcom_scm_pas_mem_setup(u32 peripheral, phys_addr_t addr, phys_addr_t size); 79 - int qcom_scm_pas_auth_and_reset(u32 peripheral); 80 - int qcom_scm_pas_shutdown(u32 peripheral); 81 - bool qcom_scm_pas_supported(u32 peripheral); 80 + struct qcom_scm_pas_context *devm_qcom_scm_pas_context_alloc(struct device *dev, 81 + u32 pas_id, 82 + phys_addr_t mem_phys, 83 + size_t mem_size); 84 + int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size, 85 + struct qcom_scm_pas_context *ctx); 86 + void qcom_scm_pas_metadata_release(struct qcom_scm_pas_context *ctx); 87 + int qcom_scm_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size); 88 + int qcom_scm_pas_auth_and_reset(u32 pas_id); 89 + int qcom_scm_pas_shutdown(u32 pas_id); 90 + bool qcom_scm_pas_supported(u32 pas_id); 91 + struct resource_table *qcom_scm_pas_get_rsc_table(struct qcom_scm_pas_context *ctx, 92 + void *input_rt, size_t input_rt_size, 93 + size_t *output_rt_size); 94 + 95 + int qcom_scm_pas_prepare_and_auth_reset(struct qcom_scm_pas_context *ctx); 82 96 83 97 int qcom_scm_io_readl(phys_addr_t addr, unsigned int *val); 84 98 int qcom_scm_io_writel(phys_addr_t addr, unsigned int val);
+11 -11
include/linux/soc/qcom/mdt_loader.h
··· 10 10 11 11 struct device; 12 12 struct firmware; 13 - struct qcom_scm_pas_metadata; 13 + struct qcom_scm_pas_context; 14 14 15 15 #if IS_ENABLED(CONFIG_QCOM_MDT_LOADER) 16 16 17 17 ssize_t qcom_mdt_get_size(const struct firmware *fw); 18 - int qcom_mdt_pas_init(struct device *dev, const struct firmware *fw, 19 - const char *fw_name, int pas_id, phys_addr_t mem_phys, 20 - struct qcom_scm_pas_metadata *pas_metadata_ctx); 21 18 int qcom_mdt_load(struct device *dev, const struct firmware *fw, 22 19 const char *fw_name, int pas_id, void *mem_region, 23 20 phys_addr_t mem_phys, size_t mem_size, 24 21 phys_addr_t *reloc_base); 22 + 23 + int qcom_mdt_pas_load(struct qcom_scm_pas_context *ctx, const struct firmware *fw, 24 + const char *firmware, void *mem_region, phys_addr_t *reloc_base); 25 25 26 26 int qcom_mdt_load_no_init(struct device *dev, const struct firmware *fw, 27 27 const char *fw_name, void *mem_region, ··· 37 37 return -ENODEV; 38 38 } 39 39 40 - static inline int qcom_mdt_pas_init(struct device *dev, const struct firmware *fw, 41 - const char *fw_name, int pas_id, phys_addr_t mem_phys, 42 - struct qcom_scm_pas_metadata *pas_metadata_ctx) 43 - { 44 - return -ENODEV; 45 - } 46 - 47 40 static inline int qcom_mdt_load(struct device *dev, const struct firmware *fw, 48 41 const char *fw_name, int pas_id, 49 42 void *mem_region, phys_addr_t mem_phys, 50 43 size_t mem_size, phys_addr_t *reloc_base) 44 + { 45 + return -ENODEV; 46 + } 47 + 48 + static inline int qcom_mdt_pas_load(struct qcom_scm_pas_context *ctx, 49 + const struct firmware *fw, const char *firmware, 50 + void *mem_region, phys_addr_t *reloc_base) 51 51 { 52 52 return -ENODEV; 53 53 }