diff options
Diffstat (limited to 'drivers/firmware/qcom_scm.c')
-rw-r--r-- | drivers/firmware/qcom_scm.c | 109 |
1 files changed, 105 insertions, 4 deletions
diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c index 0e7233a20f34..e8bbf2d38ae7 100644 --- a/drivers/firmware/qcom_scm.c +++ b/drivers/firmware/qcom_scm.c @@ -391,7 +391,7 @@ static int __qcom_scm_set_dload_mode(struct device *dev, bool enable) desc.args[1] = enable ? QCOM_SCM_BOOT_SET_DLOAD_MODE : 0; - return qcom_scm_call(__scm->dev, &desc, NULL); + return qcom_scm_call_atomic(__scm->dev, &desc, NULL); } static void qcom_scm_set_download_mode(bool enable) @@ -650,7 +650,7 @@ int qcom_scm_io_readl(phys_addr_t addr, unsigned int *val) int ret; - ret = qcom_scm_call(__scm->dev, &desc, &res); + ret = qcom_scm_call_atomic(__scm->dev, &desc, &res); if (ret >= 0) *val = res.result[0]; @@ -669,8 +669,7 @@ int qcom_scm_io_writel(phys_addr_t addr, unsigned int val) .owner = ARM_SMCCC_OWNER_SIP, }; - - return qcom_scm_call(__scm->dev, &desc, NULL); + return qcom_scm_call_atomic(__scm->dev, &desc, NULL); } EXPORT_SYMBOL(qcom_scm_io_writel); @@ -924,6 +923,107 @@ int qcom_scm_ocmem_unlock(enum qcom_scm_ocmem_client id, u32 offset, u32 size) EXPORT_SYMBOL(qcom_scm_ocmem_unlock); /** + * qcom_scm_ice_available() - Is the ICE key programming interface available? + * + * Return: true iff the SCM calls wrapped by qcom_scm_ice_invalidate_key() and + * qcom_scm_ice_set_key() are available. + */ +bool qcom_scm_ice_available(void) +{ + return __qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_ES, + QCOM_SCM_ES_INVALIDATE_ICE_KEY) && + __qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_ES, + QCOM_SCM_ES_CONFIG_SET_ICE_KEY); +} +EXPORT_SYMBOL(qcom_scm_ice_available); + +/** + * qcom_scm_ice_invalidate_key() - Invalidate an inline encryption key + * @index: the keyslot to invalidate + * + * The UFSHCI standard defines a standard way to do this, but it doesn't work on + * these SoCs; only this SCM call does. + * + * Return: 0 on success; -errno on failure. + */ +int qcom_scm_ice_invalidate_key(u32 index) +{ + struct qcom_scm_desc desc = { + .svc = QCOM_SCM_SVC_ES, + .cmd = QCOM_SCM_ES_INVALIDATE_ICE_KEY, + .arginfo = QCOM_SCM_ARGS(1), + .args[0] = index, + .owner = ARM_SMCCC_OWNER_SIP, + }; + + return qcom_scm_call(__scm->dev, &desc, NULL); +} +EXPORT_SYMBOL(qcom_scm_ice_invalidate_key); + +/** + * qcom_scm_ice_set_key() - Set an inline encryption key + * @index: the keyslot into which to set the key + * @key: the key to program + * @key_size: the size of the key in bytes + * @cipher: the encryption algorithm the key is for + * @data_unit_size: the encryption data unit size, i.e. the size of each + * individual plaintext and ciphertext. Given in 512-byte + * units, e.g. 1 = 512 bytes, 8 = 4096 bytes, etc. + * + * Program a key into a keyslot of Qualcomm ICE (Inline Crypto Engine), where it + * can then be used to encrypt/decrypt UFS I/O requests inline. + * + * The UFSHCI standard defines a standard way to do this, but it doesn't work on + * these SoCs; only this SCM call does. + * + * Return: 0 on success; -errno on failure. + */ +int qcom_scm_ice_set_key(u32 index, const u8 *key, u32 key_size, + enum qcom_scm_ice_cipher cipher, u32 data_unit_size) +{ + struct qcom_scm_desc desc = { + .svc = QCOM_SCM_SVC_ES, + .cmd = QCOM_SCM_ES_CONFIG_SET_ICE_KEY, + .arginfo = QCOM_SCM_ARGS(5, QCOM_SCM_VAL, QCOM_SCM_RW, + QCOM_SCM_VAL, QCOM_SCM_VAL, + QCOM_SCM_VAL), + .args[0] = index, + .args[2] = key_size, + .args[3] = cipher, + .args[4] = data_unit_size, + .owner = ARM_SMCCC_OWNER_SIP, + }; + void *keybuf; + dma_addr_t key_phys; + int ret; + + /* + * 'key' may point to vmalloc()'ed memory, but we need to pass a + * physical address that's been properly flushed. The sanctioned way to + * do this is by using the DMA API. But as is best practice for crypto + * keys, we also must wipe the key after use. This makes kmemdup() + + * dma_map_single() not clearly correct, since the DMA API can use + * bounce buffers. Instead, just use dma_alloc_coherent(). Programming + * keys is normally rare and thus not performance-critical. + */ + + keybuf = dma_alloc_coherent(__scm->dev, key_size, &key_phys, + GFP_KERNEL); + if (!keybuf) + return -ENOMEM; + memcpy(keybuf, key, key_size); + desc.args[1] = key_phys; + + ret = qcom_scm_call(__scm->dev, &desc, NULL); + + memzero_explicit(keybuf, key_size); + + dma_free_coherent(__scm->dev, key_size, keybuf, key_phys); + return ret; +} +EXPORT_SYMBOL(qcom_scm_ice_set_key); + +/** * qcom_scm_hdcp_available() - Check if secure environment supports HDCP. * * Return true if HDCP is supported, false if not. @@ -1151,6 +1251,7 @@ static const struct of_device_id qcom_scm_dt_match[] = { SCM_HAS_IFACE_CLK | SCM_HAS_BUS_CLK) }, + { .compatible = "qcom,scm-msm8994" }, { .compatible = "qcom,scm-msm8996" }, { .compatible = "qcom,scm" }, {} |