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

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch '20260105-kvmrprocv10-v10-0-022e96815380@oss.qualcomm.com' into drivers-for-6.20

Merge the support for loading and managing the TrustZone-based remote
processors found in the Glymur platform through a 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 ··· 119 118 enum qcom_scm_qseecom_tz_cmd_info { 120 119 QSEECOM_TZ_CMD_INFO_VERSION = 3, 121 120 }; 121 + 122 + #define RSCTABLE_BUFFER_NOT_SUFFICIENT 20 122 123 123 124 #define QSEECOM_MAX_APP_NAME_SIZE 64 124 125 #define SHMBRIDGE_RESULT_NOTSUPP 4 ··· 572 569 } 573 570 574 571 /** 572 + * devm_qcom_scm_pas_context_alloc() - Allocate peripheral authentication service 573 + * context for a given peripheral 574 + * 575 + * PAS context is device-resource managed, so the caller does not need 576 + * to worry about freeing the context memory. 577 + * 578 + * @dev: PAS firmware device 579 + * @pas_id: peripheral authentication service id 580 + * @mem_phys: Subsystem reserve memory start address 581 + * @mem_size: Subsystem reserve memory size 582 + * 583 + * Returns: The new PAS context, or ERR_PTR() on failure. 584 + */ 585 + struct qcom_scm_pas_context *devm_qcom_scm_pas_context_alloc(struct device *dev, 586 + u32 pas_id, 587 + phys_addr_t mem_phys, 588 + size_t mem_size) 589 + { 590 + struct qcom_scm_pas_context *ctx; 591 + 592 + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); 593 + if (!ctx) 594 + return ERR_PTR(-ENOMEM); 595 + 596 + ctx->dev = dev; 597 + ctx->pas_id = pas_id; 598 + ctx->mem_phys = mem_phys; 599 + ctx->mem_size = mem_size; 600 + 601 + return ctx; 602 + } 603 + EXPORT_SYMBOL_GPL(devm_qcom_scm_pas_context_alloc); 604 + 605 + static int __qcom_scm_pas_init_image(u32 pas_id, dma_addr_t mdata_phys, 606 + struct qcom_scm_res *res) 607 + { 608 + struct qcom_scm_desc desc = { 609 + .svc = QCOM_SCM_SVC_PIL, 610 + .cmd = QCOM_SCM_PIL_PAS_INIT_IMAGE, 611 + .arginfo = QCOM_SCM_ARGS(2, QCOM_SCM_VAL, QCOM_SCM_RW), 612 + .args[0] = pas_id, 613 + .owner = ARM_SMCCC_OWNER_SIP, 614 + }; 615 + int ret; 616 + 617 + ret = qcom_scm_clk_enable(); 618 + if (ret) 619 + return ret; 620 + 621 + ret = qcom_scm_bw_enable(); 622 + if (ret) 623 + goto disable_clk; 624 + 625 + desc.args[1] = mdata_phys; 626 + 627 + ret = qcom_scm_call(__scm->dev, &desc, res); 628 + qcom_scm_bw_disable(); 629 + 630 + disable_clk: 631 + qcom_scm_clk_disable(); 632 + 633 + return ret; 634 + } 635 + 636 + static int qcom_scm_pas_prep_and_init_image(struct qcom_scm_pas_context *ctx, 637 + const void *metadata, size_t size) 638 + { 639 + struct qcom_scm_res res; 640 + phys_addr_t mdata_phys; 641 + void *mdata_buf; 642 + int ret; 643 + 644 + mdata_buf = qcom_tzmem_alloc(__scm->mempool, size, GFP_KERNEL); 645 + if (!mdata_buf) 646 + return -ENOMEM; 647 + 648 + memcpy(mdata_buf, metadata, size); 649 + mdata_phys = qcom_tzmem_to_phys(mdata_buf); 650 + 651 + ret = __qcom_scm_pas_init_image(ctx->pas_id, mdata_phys, &res); 652 + if (ret < 0) 653 + qcom_tzmem_free(mdata_buf); 654 + else 655 + ctx->ptr = mdata_buf; 656 + 657 + return ret ? : res.result[0]; 658 + } 659 + 660 + /** 575 661 * qcom_scm_pas_init_image() - Initialize peripheral authentication service 576 662 * state machine for a given peripheral, using the 577 663 * metadata 578 - * @peripheral: peripheral id 664 + * @pas_id: peripheral authentication service id 579 665 * @metadata: pointer to memory containing ELF header, program header table 580 666 * and optional blob of data used for authenticating the metadata 581 667 * and the rest of the firmware 582 668 * @size: size of the metadata 583 - * @ctx: optional metadata context 669 + * @ctx: optional pas context 584 670 * 585 671 * Return: 0 on success. 586 672 * ··· 677 585 * track the metadata allocation, this needs to be released by invoking 678 586 * qcom_scm_pas_metadata_release() by the caller. 679 587 */ 680 - int qcom_scm_pas_init_image(u32 peripheral, const void *metadata, size_t size, 681 - struct qcom_scm_pas_metadata *ctx) 588 + int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size, 589 + struct qcom_scm_pas_context *ctx) 682 590 { 591 + struct qcom_scm_res res; 683 592 dma_addr_t mdata_phys; 684 593 void *mdata_buf; 685 594 int ret; 686 - struct qcom_scm_desc desc = { 687 - .svc = QCOM_SCM_SVC_PIL, 688 - .cmd = QCOM_SCM_PIL_PAS_INIT_IMAGE, 689 - .arginfo = QCOM_SCM_ARGS(2, QCOM_SCM_VAL, QCOM_SCM_RW), 690 - .args[0] = peripheral, 691 - .owner = ARM_SMCCC_OWNER_SIP, 692 - }; 693 - struct qcom_scm_res res; 595 + 596 + if (ctx && ctx->use_tzmem) 597 + return qcom_scm_pas_prep_and_init_image(ctx, metadata, size); 694 598 695 599 /* 696 600 * During the scm call memory protection will be enabled for the meta ··· 707 619 708 620 memcpy(mdata_buf, metadata, size); 709 621 710 - ret = qcom_scm_clk_enable(); 711 - if (ret) 712 - goto out; 713 - 714 - ret = qcom_scm_bw_enable(); 715 - if (ret) 716 - goto disable_clk; 717 - 718 - desc.args[1] = mdata_phys; 719 - 720 - ret = qcom_scm_call(__scm->dev, &desc, &res); 721 - qcom_scm_bw_disable(); 722 - 723 - disable_clk: 724 - qcom_scm_clk_disable(); 725 - 726 - out: 622 + ret = __qcom_scm_pas_init_image(pas_id, mdata_phys, &res); 727 623 if (ret < 0 || !ctx) { 728 624 dma_free_coherent(__scm->dev, size, mdata_buf, mdata_phys); 729 625 } else if (ctx) { ··· 722 650 723 651 /** 724 652 * qcom_scm_pas_metadata_release() - release metadata context 725 - * @ctx: metadata context 653 + * @ctx: pas context 726 654 */ 727 - void qcom_scm_pas_metadata_release(struct qcom_scm_pas_metadata *ctx) 655 + void qcom_scm_pas_metadata_release(struct qcom_scm_pas_context *ctx) 728 656 { 729 657 if (!ctx->ptr) 730 658 return; 731 659 732 - dma_free_coherent(__scm->dev, ctx->size, ctx->ptr, ctx->phys); 660 + if (ctx->use_tzmem) 661 + qcom_tzmem_free(ctx->ptr); 662 + else 663 + dma_free_coherent(__scm->dev, ctx->size, ctx->ptr, ctx->phys); 733 664 734 665 ctx->ptr = NULL; 735 - ctx->phys = 0; 736 - ctx->size = 0; 737 666 } 738 667 EXPORT_SYMBOL_GPL(qcom_scm_pas_metadata_release); 739 668 740 669 /** 741 670 * qcom_scm_pas_mem_setup() - Prepare the memory related to a given peripheral 742 671 * for firmware loading 743 - * @peripheral: peripheral id 672 + * @pas_id: peripheral authentication service id 744 673 * @addr: start address of memory area to prepare 745 674 * @size: size of the memory area to prepare 746 675 * 747 676 * Returns 0 on success. 748 677 */ 749 - int qcom_scm_pas_mem_setup(u32 peripheral, phys_addr_t addr, phys_addr_t size) 678 + int qcom_scm_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size) 750 679 { 751 680 int ret; 752 681 struct qcom_scm_desc desc = { 753 682 .svc = QCOM_SCM_SVC_PIL, 754 683 .cmd = QCOM_SCM_PIL_PAS_MEM_SETUP, 755 684 .arginfo = QCOM_SCM_ARGS(3), 756 - .args[0] = peripheral, 685 + .args[0] = pas_id, 757 686 .args[1] = addr, 758 687 .args[2] = size, 759 688 .owner = ARM_SMCCC_OWNER_SIP, ··· 779 706 } 780 707 EXPORT_SYMBOL_GPL(qcom_scm_pas_mem_setup); 781 708 709 + static void *__qcom_scm_pas_get_rsc_table(u32 pas_id, void *input_rt_tzm, 710 + size_t input_rt_size, 711 + size_t *output_rt_size) 712 + { 713 + struct qcom_scm_desc desc = { 714 + .svc = QCOM_SCM_SVC_PIL, 715 + .cmd = QCOM_SCM_PIL_PAS_GET_RSCTABLE, 716 + .arginfo = QCOM_SCM_ARGS(5, QCOM_SCM_VAL, QCOM_SCM_RO, QCOM_SCM_VAL, 717 + QCOM_SCM_RW, QCOM_SCM_VAL), 718 + .args[0] = pas_id, 719 + .owner = ARM_SMCCC_OWNER_SIP, 720 + }; 721 + struct qcom_scm_res res; 722 + void *output_rt_tzm; 723 + int ret; 724 + 725 + output_rt_tzm = qcom_tzmem_alloc(__scm->mempool, *output_rt_size, GFP_KERNEL); 726 + if (!output_rt_tzm) 727 + return ERR_PTR(-ENOMEM); 728 + 729 + desc.args[1] = qcom_tzmem_to_phys(input_rt_tzm); 730 + desc.args[2] = input_rt_size; 731 + desc.args[3] = qcom_tzmem_to_phys(output_rt_tzm); 732 + desc.args[4] = *output_rt_size; 733 + 734 + /* 735 + * Whether SMC fail or pass, res.result[2] will hold actual resource table 736 + * size. 737 + * 738 + * If passed 'output_rt_size' buffer size is not sufficient to hold the 739 + * resource table TrustZone sends, response code in res.result[1] as 740 + * RSCTABLE_BUFFER_NOT_SUFFICIENT so that caller can retry this SMC call 741 + * with output_rt_tzm buffer with res.result[2] size however, It should not 742 + * be of unresonable size. 743 + */ 744 + ret = qcom_scm_call(__scm->dev, &desc, &res); 745 + if (!ret && res.result[2] > SZ_1G) { 746 + ret = -E2BIG; 747 + goto free_output_rt; 748 + } 749 + 750 + *output_rt_size = res.result[2]; 751 + if (ret && res.result[1] == RSCTABLE_BUFFER_NOT_SUFFICIENT) 752 + ret = -EOVERFLOW; 753 + 754 + free_output_rt: 755 + if (ret) 756 + qcom_tzmem_free(output_rt_tzm); 757 + 758 + return ret ? ERR_PTR(ret) : output_rt_tzm; 759 + } 760 + 761 + /** 762 + * qcom_scm_pas_get_rsc_table() - Retrieve the resource table in passed output buffer 763 + * for a given peripheral. 764 + * 765 + * Qualcomm remote processor may rely on both static and dynamic resources for 766 + * its functionality. Static resources typically refer to memory-mapped addresses 767 + * required by the subsystem and are often embedded within the firmware binary 768 + * and dynamic resources, such as shared memory in DDR etc., are determined at 769 + * runtime during the boot process. 770 + * 771 + * On Qualcomm Technologies devices, it's possible that static resources are not 772 + * embedded in the firmware binary and instead are provided by TrustZone However, 773 + * dynamic resources are always expected to come from TrustZone. This indicates 774 + * that for Qualcomm devices, all resources (static and dynamic) will be provided 775 + * by TrustZone via the SMC call. 776 + * 777 + * If the remote processor firmware binary does contain static resources, they 778 + * should be passed in input_rt. These will be forwarded to TrustZone for 779 + * authentication. TrustZone will then append the dynamic resources and return 780 + * the complete resource table in output_rt_tzm. 781 + * 782 + * If the remote processor firmware binary does not include a resource table, 783 + * the caller of this function should set input_rt as NULL and input_rt_size 784 + * as zero respectively. 785 + * 786 + * More about documentation on resource table data structures can be found in 787 + * include/linux/remoteproc.h 788 + * 789 + * @ctx: PAS context 790 + * @pas_id: peripheral authentication service id 791 + * @input_rt: resource table buffer which is present in firmware binary 792 + * @input_rt_size: size of the resource table present in firmware binary 793 + * @output_rt_size: TrustZone expects caller should pass worst case size for 794 + * the output_rt_tzm. 795 + * 796 + * Return: 797 + * On success, returns a pointer to the allocated buffer containing the final 798 + * resource table and output_rt_size will have actual resource table size from 799 + * TrustZone. The caller is responsible for freeing the buffer. On failure, 800 + * returns ERR_PTR(-errno). 801 + */ 802 + struct resource_table *qcom_scm_pas_get_rsc_table(struct qcom_scm_pas_context *ctx, 803 + void *input_rt, 804 + size_t input_rt_size, 805 + size_t *output_rt_size) 806 + { 807 + struct resource_table empty_rsc = {}; 808 + size_t size = SZ_16K; 809 + void *output_rt_tzm; 810 + void *input_rt_tzm; 811 + void *tbl_ptr; 812 + int ret; 813 + 814 + ret = qcom_scm_clk_enable(); 815 + if (ret) 816 + return ERR_PTR(ret); 817 + 818 + ret = qcom_scm_bw_enable(); 819 + if (ret) 820 + goto disable_clk; 821 + 822 + /* 823 + * TrustZone can not accept buffer as NULL value as argument hence, 824 + * we need to pass a input buffer indicating that subsystem firmware 825 + * does not have resource table by filling resource table structure. 826 + */ 827 + if (!input_rt) { 828 + input_rt = &empty_rsc; 829 + input_rt_size = sizeof(empty_rsc); 830 + } 831 + 832 + input_rt_tzm = qcom_tzmem_alloc(__scm->mempool, input_rt_size, GFP_KERNEL); 833 + if (!input_rt_tzm) { 834 + ret = -ENOMEM; 835 + goto disable_scm_bw; 836 + } 837 + 838 + memcpy(input_rt_tzm, input_rt, input_rt_size); 839 + 840 + output_rt_tzm = __qcom_scm_pas_get_rsc_table(ctx->pas_id, input_rt_tzm, 841 + input_rt_size, &size); 842 + if (PTR_ERR(output_rt_tzm) == -EOVERFLOW) 843 + /* Try again with the size requested by the TZ */ 844 + output_rt_tzm = __qcom_scm_pas_get_rsc_table(ctx->pas_id, 845 + input_rt_tzm, 846 + input_rt_size, 847 + &size); 848 + if (IS_ERR(output_rt_tzm)) { 849 + ret = PTR_ERR(output_rt_tzm); 850 + goto free_input_rt; 851 + } 852 + 853 + tbl_ptr = kzalloc(size, GFP_KERNEL); 854 + if (!tbl_ptr) { 855 + qcom_tzmem_free(output_rt_tzm); 856 + ret = -ENOMEM; 857 + goto free_input_rt; 858 + } 859 + 860 + memcpy(tbl_ptr, output_rt_tzm, size); 861 + *output_rt_size = size; 862 + qcom_tzmem_free(output_rt_tzm); 863 + 864 + free_input_rt: 865 + qcom_tzmem_free(input_rt_tzm); 866 + 867 + disable_scm_bw: 868 + qcom_scm_bw_disable(); 869 + 870 + disable_clk: 871 + qcom_scm_clk_disable(); 872 + 873 + return ret ? ERR_PTR(ret) : tbl_ptr; 874 + } 875 + EXPORT_SYMBOL_GPL(qcom_scm_pas_get_rsc_table); 876 + 782 877 /** 783 878 * qcom_scm_pas_auth_and_reset() - Authenticate the given peripheral firmware 784 879 * and reset the remote processor 785 - * @peripheral: peripheral id 880 + * @pas_id: peripheral authentication service id 786 881 * 787 882 * Return 0 on success. 788 883 */ 789 - int qcom_scm_pas_auth_and_reset(u32 peripheral) 884 + int qcom_scm_pas_auth_and_reset(u32 pas_id) 790 885 { 791 886 int ret; 792 887 struct qcom_scm_desc desc = { 793 888 .svc = QCOM_SCM_SVC_PIL, 794 889 .cmd = QCOM_SCM_PIL_PAS_AUTH_AND_RESET, 795 890 .arginfo = QCOM_SCM_ARGS(1), 796 - .args[0] = peripheral, 891 + .args[0] = pas_id, 797 892 .owner = ARM_SMCCC_OWNER_SIP, 798 893 }; 799 894 struct qcom_scm_res res; ··· 985 744 EXPORT_SYMBOL_GPL(qcom_scm_pas_auth_and_reset); 986 745 987 746 /** 747 + * qcom_scm_pas_prepare_and_auth_reset() - Prepare, authenticate, and reset the 748 + * remote processor 749 + * 750 + * @ctx: Context saved during call to qcom_scm_pas_context_init() 751 + * 752 + * This function performs the necessary steps to prepare a PAS subsystem, 753 + * authenticate it using the provided metadata, and initiate a reset sequence. 754 + * 755 + * It should be used when Linux is in control setting up the IOMMU hardware 756 + * for remote subsystem during secure firmware loading processes. The preparation 757 + * step sets up a shmbridge over the firmware memory before TrustZone accesses the 758 + * firmware memory region for authentication. The authentication step verifies 759 + * the integrity and authenticity of the firmware or configuration using secure 760 + * metadata. Finally, the reset step ensures the subsystem starts in a clean and 761 + * sane state. 762 + * 763 + * Return: 0 on success, negative errno on failure. 764 + */ 765 + int qcom_scm_pas_prepare_and_auth_reset(struct qcom_scm_pas_context *ctx) 766 + { 767 + u64 handle; 768 + int ret; 769 + 770 + /* 771 + * When Linux running @ EL1, Gunyah hypervisor running @ EL2 traps the 772 + * auth_and_reset call and create an shmbridge on the remote subsystem 773 + * memory region and then invokes a call to TrustZone to authenticate. 774 + */ 775 + if (!ctx->use_tzmem) 776 + return qcom_scm_pas_auth_and_reset(ctx->pas_id); 777 + 778 + /* 779 + * When Linux runs @ EL2 Linux must create the shmbridge itself and then 780 + * subsequently call TrustZone for authenticate and reset. 781 + */ 782 + ret = qcom_tzmem_shm_bridge_create(ctx->mem_phys, ctx->mem_size, &handle); 783 + if (ret) 784 + return ret; 785 + 786 + ret = qcom_scm_pas_auth_and_reset(ctx->pas_id); 787 + qcom_tzmem_shm_bridge_delete(handle); 788 + 789 + return ret; 790 + } 791 + EXPORT_SYMBOL_GPL(qcom_scm_pas_prepare_and_auth_reset); 792 + 793 + /** 988 794 * qcom_scm_pas_shutdown() - Shut down the remote processor 989 - * @peripheral: peripheral id 795 + * @pas_id: peripheral authentication service id 990 796 * 991 797 * Returns 0 on success. 992 798 */ 993 - int qcom_scm_pas_shutdown(u32 peripheral) 799 + int qcom_scm_pas_shutdown(u32 pas_id) 994 800 { 995 801 int ret; 996 802 struct qcom_scm_desc desc = { 997 803 .svc = QCOM_SCM_SVC_PIL, 998 804 .cmd = QCOM_SCM_PIL_PAS_SHUTDOWN, 999 805 .arginfo = QCOM_SCM_ARGS(1), 1000 - .args[0] = peripheral, 806 + .args[0] = pas_id, 1001 807 .owner = ARM_SMCCC_OWNER_SIP, 1002 808 }; 1003 809 struct qcom_scm_res res; ··· 1070 782 /** 1071 783 * qcom_scm_pas_supported() - Check if the peripheral authentication service is 1072 784 * available for the given peripherial 1073 - * @peripheral: peripheral id 785 + * @pas_id: peripheral authentication service id 1074 786 * 1075 787 * Returns true if PAS is supported for this peripheral, otherwise false. 1076 788 */ 1077 - bool qcom_scm_pas_supported(u32 peripheral) 789 + bool qcom_scm_pas_supported(u32 pas_id) 1078 790 { 1079 791 int ret; 1080 792 struct qcom_scm_desc desc = { 1081 793 .svc = QCOM_SCM_SVC_PIL, 1082 794 .cmd = QCOM_SCM_PIL_PAS_IS_SUPPORTED, 1083 795 .arginfo = QCOM_SCM_ARGS(1), 1084 - .args[0] = peripheral, 796 + .args[0] = pas_id, 1085 797 .owner = ARM_SMCCC_OWNER_SIP, 1086 798 }; 1087 799 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 }