From: linlzhan On Qualcomm platforms where UFS inline encryption is shared between the host and guest VMs, the ICE hardware keyslots must be partitioned so that each VM operates only within its own physical slot range. Without this, the host's blk_crypto_profile would manage all hardware slots, conflicting with slots already allocated to guests. Add ufs_qcom_ice_parse_slot_table() to read the qcom,ice-keyslot-map device-tree node. The function parses all child entries and validates that no entry's slot range or the combined total exceeds the hardware slot count from REG_UFS_CCAP. The first child entry is taken as the host's own reservation; its slot count and offset are returned to the caller. In ufs_qcom_ice_init(), use the parsed host reservation to initialize the blk_crypto_profile with only the host's slot count rather than the full hardware range. Set profile->slot_offset so that blk_crypto_keyslot_index() returns the correct physical ICE slot number when programming hardware. If no qcom,ice-keyslot-map node is present, the existing behaviour (profile manages all slots) is preserved. Note: This patch is submitted for visibility. The ufs-qcom driver gets its max_slots and slot_offset based on the the current DT-based keyslot mechanis. we are aware this may need to be replaced by a TZ SCM interface, submit it RFC for design discussion. Signed-off-by: linlzhan --- drivers/ufs/host/ufs-qcom.c | 91 ++++++++++++++++++++++++++++++++++++- 1 file changed, 90 insertions(+), 1 deletion(-) diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c index 62396212a0a7..0611ab50f4cc 100644 --- a/drivers/ufs/host/ufs-qcom.c +++ b/drivers/ufs/host/ufs-qcom.c @@ -163,6 +163,74 @@ static inline void ufs_qcom_ice_enable(struct ufs_qcom_host *host) qcom_ice_enable(host->ice); } +/** + * ufs_qcom_ice_parse_slot_table() - parse qcom,ice-keyslot-map DT node + * @dev: UFS controller device + * @hw_max_slots: total physical ICE keyslots reported by REG_UFS_CCAP + * @num_slots: receives host max_ice_slots (0 = no partitioning) + * @slot_offset: receives host ice-slot-offset + * + * Parses the qcom,ice-keyslot-map device-tree node. The first child entry + * is the host's own reservation; subsequent children are guest reservations. + * Validates that no entry's range exceeds @hw_max_slots and that the sum of + * all entries does not exceed @hw_max_slots. + * + * If no qcom,ice-keyslot-map phandle is present, sets @num_slots to 0 and + * returns 0. Returns -EINVAL if any entry or the total exceeds @hw_max_slots. + */ +static int ufs_qcom_ice_parse_slot_table(struct device *dev, + unsigned int hw_max_slots, + unsigned int *num_slots, + unsigned int *slot_offset) +{ + struct device_node *slots_np, *child; + unsigned int total_slots = 0; + bool first = true; + int ret = 0; + + *num_slots = 0; + *slot_offset = 0; + + slots_np = of_parse_phandle(dev->of_node, "qcom,ice-keyslot-map", 0); + if (!slots_np) + return 0; + + for_each_child_of_node(slots_np, child) { + u32 off, max; + + if (of_property_read_u32(child, "qcom,ice-slot-offset", &off) || + of_property_read_u32(child, "qcom,max-ice-slots", &max)) + continue; + + if (off + max > hw_max_slots) { + dev_err(dev, + "ice-keyslot-map: slots [%u..%u) exceed hw max %u\n", + off, off + max, hw_max_slots); + of_node_put(child); + ret = -EINVAL; + break; + } + + if (first) { + *num_slots = max; + *slot_offset = off; + first = false; + } + total_slots += max; + } + + of_node_put(slots_np); + + if (!ret && total_slots > hw_max_slots) { + dev_err(dev, + "ice-keyslot-map: total slots %u exceed hw max %u\n", + total_slots, hw_max_slots); + ret = -EINVAL; + } + + return ret; +} + static const struct blk_crypto_ll_ops ufs_qcom_crypto_ops; /* forward decl */ static int ufs_qcom_ice_init(struct ufs_qcom_host *host) @@ -173,6 +241,8 @@ static int ufs_qcom_ice_init(struct ufs_qcom_host *host) struct qcom_ice *ice; union ufs_crypto_capabilities caps; union ufs_crypto_cap_entry cap; + unsigned int num_slots, slot_offset; + unsigned int hw_max_slots; int err; int i; @@ -192,7 +262,23 @@ static int ufs_qcom_ice_init(struct ufs_qcom_host *host) caps.reg_val = cpu_to_le32(ufshcd_readl(hba, REG_UFS_CCAP)); /* The number of keyslots supported is (CFGC+1) */ - err = devm_blk_crypto_profile_init(dev, profile, caps.config_count + 1); + hw_max_slots = caps.config_count + 1; + + /* + * Parse the qcom,ice-keyslot-map DT node: validate all entries against + * the hardware slot count and read the host's own reservation. If no + * partitioning is configured (num_slots == 0), the profile manages the + * full hardware slot range. + */ + err = ufs_qcom_ice_parse_slot_table(dev, hw_max_slots, + &num_slots, &slot_offset); + if (err) { + dev_err(dev, "failed to parse ICE slot table: %d\n", err); + return err; + } + + err = devm_blk_crypto_profile_init(dev, profile, + num_slots ? num_slots : hw_max_slots); if (err) return err; @@ -201,6 +287,9 @@ static int ufs_qcom_ice_init(struct ufs_qcom_host *host) profile->key_types_supported = qcom_ice_get_supported_key_type(ice); profile->dev = dev; + if (num_slots) + profile->slot_offset = slot_offset; + /* * Currently this driver only supports AES-256-XTS. All known versions * of ICE support it, but to be safe make sure it is really declared in -- 2.34.1