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

Merge branch '20250911-qcom-tee-using-tee-ss-without-mem-obj-v12-2-17f07a942b8d@oss.qualcomm.com' into drivers-for-6.18

Merge the addition of support for object invocation into the SCM driver
though a topic branch, to enable sharing this with TEE subsystem.

+199 -11
+119
drivers/firmware/qcom/qcom_scm.c
··· 2098 2098 #endif /* CONFIG_QCOM_QSEECOM */ 2099 2099 2100 2100 /** 2101 + * qcom_scm_qtee_invoke_smc() - Invoke a QTEE object. 2102 + * @inbuf: start address of memory area used for inbound buffer. 2103 + * @inbuf_size: size of the memory area used for inbound buffer. 2104 + * @outbuf: start address of memory area used for outbound buffer. 2105 + * @outbuf_size: size of the memory area used for outbound buffer. 2106 + * @result: result of QTEE object invocation. 2107 + * @response_type: response type returned by QTEE. 2108 + * 2109 + * @response_type determines how the contents of @inbuf and @outbuf 2110 + * should be processed. 2111 + * 2112 + * Return: On success, return 0 or <0 on failure. 2113 + */ 2114 + int qcom_scm_qtee_invoke_smc(phys_addr_t inbuf, size_t inbuf_size, 2115 + phys_addr_t outbuf, size_t outbuf_size, 2116 + u64 *result, u64 *response_type) 2117 + { 2118 + struct qcom_scm_desc desc = { 2119 + .svc = QCOM_SCM_SVC_SMCINVOKE, 2120 + .cmd = QCOM_SCM_SMCINVOKE_INVOKE, 2121 + .owner = ARM_SMCCC_OWNER_TRUSTED_OS, 2122 + .args[0] = inbuf, 2123 + .args[1] = inbuf_size, 2124 + .args[2] = outbuf, 2125 + .args[3] = outbuf_size, 2126 + .arginfo = QCOM_SCM_ARGS(4, QCOM_SCM_RW, QCOM_SCM_VAL, 2127 + QCOM_SCM_RW, QCOM_SCM_VAL), 2128 + }; 2129 + struct qcom_scm_res res; 2130 + int ret; 2131 + 2132 + ret = qcom_scm_call(__scm->dev, &desc, &res); 2133 + if (ret) 2134 + return ret; 2135 + 2136 + if (response_type) 2137 + *response_type = res.result[0]; 2138 + 2139 + if (result) 2140 + *result = res.result[1]; 2141 + 2142 + return 0; 2143 + } 2144 + EXPORT_SYMBOL(qcom_scm_qtee_invoke_smc); 2145 + 2146 + /** 2147 + * qcom_scm_qtee_callback_response() - Submit response for callback request. 2148 + * @buf: start address of memory area used for outbound buffer. 2149 + * @buf_size: size of the memory area used for outbound buffer. 2150 + * @result: Result of QTEE object invocation. 2151 + * @response_type: Response type returned by QTEE. 2152 + * 2153 + * @response_type determines how the contents of @buf should be processed. 2154 + * 2155 + * Return: On success, return 0 or <0 on failure. 2156 + */ 2157 + int qcom_scm_qtee_callback_response(phys_addr_t buf, size_t buf_size, 2158 + u64 *result, u64 *response_type) 2159 + { 2160 + struct qcom_scm_desc desc = { 2161 + .svc = QCOM_SCM_SVC_SMCINVOKE, 2162 + .cmd = QCOM_SCM_SMCINVOKE_CB_RSP, 2163 + .owner = ARM_SMCCC_OWNER_TRUSTED_OS, 2164 + .args[0] = buf, 2165 + .args[1] = buf_size, 2166 + .arginfo = QCOM_SCM_ARGS(2, QCOM_SCM_RW, QCOM_SCM_VAL), 2167 + }; 2168 + struct qcom_scm_res res; 2169 + int ret; 2170 + 2171 + ret = qcom_scm_call(__scm->dev, &desc, &res); 2172 + if (ret) 2173 + return ret; 2174 + 2175 + if (response_type) 2176 + *response_type = res.result[0]; 2177 + 2178 + if (result) 2179 + *result = res.result[1]; 2180 + 2181 + return 0; 2182 + } 2183 + EXPORT_SYMBOL(qcom_scm_qtee_callback_response); 2184 + 2185 + static void qcom_scm_qtee_free(void *data) 2186 + { 2187 + struct platform_device *qtee_dev = data; 2188 + 2189 + platform_device_unregister(qtee_dev); 2190 + } 2191 + 2192 + static void qcom_scm_qtee_init(struct qcom_scm *scm) 2193 + { 2194 + struct platform_device *qtee_dev; 2195 + u64 result, response_type; 2196 + int ret; 2197 + 2198 + /* 2199 + * Probe for smcinvoke support. This will fail due to invalid buffers, 2200 + * but first, it checks whether the call is supported in QTEE syscall 2201 + * handler. If it is not supported, -EIO is returned. 2202 + */ 2203 + ret = qcom_scm_qtee_invoke_smc(0, 0, 0, 0, &result, &response_type); 2204 + if (ret == -EIO) 2205 + return; 2206 + 2207 + /* Setup QTEE interface device. */ 2208 + qtee_dev = platform_device_register_data(scm->dev, "qcomtee", 2209 + PLATFORM_DEVID_NONE, NULL, 0); 2210 + if (IS_ERR(qtee_dev)) 2211 + return; 2212 + 2213 + devm_add_action_or_reset(scm->dev, qcom_scm_qtee_free, qtee_dev); 2214 + } 2215 + 2216 + /** 2101 2217 * qcom_scm_is_available() - Checks if SCM is available 2102 2218 */ 2103 2219 bool qcom_scm_is_available(void) ··· 2444 2328 */ 2445 2329 ret = qcom_scm_qseecom_init(scm); 2446 2330 WARN(ret < 0, "failed to initialize qseecom: %d\n", ret); 2331 + 2332 + /* Initialize the QTEE object interface. */ 2333 + qcom_scm_qtee_init(scm); 2447 2334 2448 2335 return 0; 2449 2336 }
+7
drivers/firmware/qcom/qcom_scm.h
··· 156 156 #define QCOM_SCM_SVC_GPU 0x28 157 157 #define QCOM_SCM_SVC_GPU_INIT_REGS 0x01 158 158 159 + /* ARM_SMCCC_OWNER_TRUSTED_OS calls */ 160 + 161 + #define QCOM_SCM_SVC_SMCINVOKE 0x06 162 + #define QCOM_SCM_SMCINVOKE_INVOKE_LEGACY 0x00 163 + #define QCOM_SCM_SMCINVOKE_CB_RSP 0x01 164 + #define QCOM_SCM_SMCINVOKE_INVOKE 0x02 165 + 159 166 /* common error codes */ 160 167 #define QCOM_SCM_V2_EBUSY -12 161 168 #define QCOM_SCM_ENOMEM -5
+52 -11
drivers/firmware/qcom/qcom_tzmem.c
··· 110 110 return 0; 111 111 } 112 112 113 - static int qcom_tzmem_init_area(struct qcom_tzmem_area *area) 113 + /** 114 + * qcom_tzmem_shm_bridge_create() - Create a SHM bridge. 115 + * @paddr: Physical address of the memory to share. 116 + * @size: Size of the memory to share. 117 + * @handle: Handle to the SHM bridge. 118 + * 119 + * On platforms that support SHM bridge, this function creates a SHM bridge 120 + * for the given memory region with QTEE. The handle returned by this function 121 + * must be passed to qcom_tzmem_shm_bridge_delete() to free the SHM bridge. 122 + * 123 + * Return: On success, returns 0; on failure, returns < 0. 124 + */ 125 + int qcom_tzmem_shm_bridge_create(phys_addr_t paddr, size_t size, u64 *handle) 114 126 { 115 127 u64 pfn_and_ns_perm, ipfn_and_s_perm, size_and_flags; 116 128 int ret; ··· 130 118 if (!qcom_tzmem_using_shm_bridge) 131 119 return 0; 132 120 133 - pfn_and_ns_perm = (u64)area->paddr | QCOM_SCM_PERM_RW; 134 - ipfn_and_s_perm = (u64)area->paddr | QCOM_SCM_PERM_RW; 135 - size_and_flags = area->size | (1 << QCOM_SHM_BRIDGE_NUM_VM_SHIFT); 121 + pfn_and_ns_perm = paddr | QCOM_SCM_PERM_RW; 122 + ipfn_and_s_perm = paddr | QCOM_SCM_PERM_RW; 123 + size_and_flags = size | (1 << QCOM_SHM_BRIDGE_NUM_VM_SHIFT); 124 + 125 + ret = qcom_scm_shm_bridge_create(pfn_and_ns_perm, ipfn_and_s_perm, 126 + size_and_flags, QCOM_SCM_VMID_HLOS, 127 + handle); 128 + if (ret) { 129 + dev_err(qcom_tzmem_dev, 130 + "SHM Bridge failed: ret %d paddr 0x%pa, size %zu\n", 131 + ret, &paddr, size); 132 + 133 + return ret; 134 + } 135 + 136 + return 0; 137 + } 138 + EXPORT_SYMBOL_GPL(qcom_tzmem_shm_bridge_create); 139 + 140 + /** 141 + * qcom_tzmem_shm_bridge_delete() - Delete a SHM bridge. 142 + * @handle: Handle to the SHM bridge. 143 + * 144 + * On platforms that support SHM bridge, this function deletes the SHM bridge 145 + * for the given memory region. The handle must be the same as the one 146 + * returned by qcom_tzmem_shm_bridge_create(). 147 + */ 148 + void qcom_tzmem_shm_bridge_delete(u64 handle) 149 + { 150 + if (qcom_tzmem_using_shm_bridge) 151 + qcom_scm_shm_bridge_delete(handle); 152 + } 153 + EXPORT_SYMBOL_GPL(qcom_tzmem_shm_bridge_delete); 154 + 155 + static int qcom_tzmem_init_area(struct qcom_tzmem_area *area) 156 + { 157 + int ret; 136 158 137 159 u64 *handle __free(kfree) = kzalloc(sizeof(*handle), GFP_KERNEL); 138 160 if (!handle) 139 161 return -ENOMEM; 140 162 141 - ret = qcom_scm_shm_bridge_create(pfn_and_ns_perm, ipfn_and_s_perm, 142 - size_and_flags, QCOM_SCM_VMID_HLOS, 143 - handle); 163 + ret = qcom_tzmem_shm_bridge_create(area->paddr, area->size, handle); 144 164 if (ret) 145 165 return ret; 146 166 ··· 185 141 { 186 142 u64 *handle = area->priv; 187 143 188 - if (!qcom_tzmem_using_shm_bridge) 189 - return; 190 - 191 - qcom_scm_shm_bridge_delete(*handle); 144 + qcom_tzmem_shm_bridge_delete(*handle); 192 145 kfree(handle); 193 146 } 194 147
+6
include/linux/firmware/qcom/qcom_scm.h
··· 175 175 176 176 #endif /* CONFIG_QCOM_QSEECOM */ 177 177 178 + int qcom_scm_qtee_invoke_smc(phys_addr_t inbuf, size_t inbuf_size, 179 + phys_addr_t outbuf, size_t outbuf_size, 180 + u64 *result, u64 *response_type); 181 + int qcom_scm_qtee_callback_response(phys_addr_t buf, size_t buf_size, 182 + u64 *result, u64 *response_type); 183 + 178 184 #endif
+15
include/linux/firmware/qcom/qcom_tzmem.h
··· 53 53 54 54 phys_addr_t qcom_tzmem_to_phys(void *ptr); 55 55 56 + #if IS_ENABLED(CONFIG_QCOM_TZMEM_MODE_SHMBRIDGE) 57 + int qcom_tzmem_shm_bridge_create(phys_addr_t paddr, size_t size, u64 *handle); 58 + void qcom_tzmem_shm_bridge_delete(u64 handle); 59 + #else 60 + static inline int qcom_tzmem_shm_bridge_create(phys_addr_t paddr, 61 + size_t size, u64 *handle) 62 + { 63 + return 0; 64 + } 65 + 66 + static inline void qcom_tzmem_shm_bridge_delete(u64 handle) 67 + { 68 + } 69 + #endif 70 + 56 71 #endif /* __QCOM_TZMEM */