diff --git a/block/blk-crypto-fallback.c b/block/blk-crypto-fallback.c index 18b6851d8301..ee36438393cf 100644 --- a/block/blk-crypto-fallback.c +++ b/block/blk-crypto-fallback.c @@ -600,7 +600,7 @@ int __init blk_crypto_fallback_init(void) crypto_mode_supported[i] = 0xFFFFFFFF; crypto_mode_supported[BLK_ENCRYPTION_MODE_INVALID] = 0; - blk_crypto_ksm = keyslot_manager_create(blk_crypto_num_keyslots, + blk_crypto_ksm = keyslot_manager_create(NULL, blk_crypto_num_keyslots, &blk_crypto_ksm_ll_ops, BLK_CRYPTO_FEATURE_STANDARD_KEYS, crypto_mode_supported, NULL); diff --git a/block/keyslot-manager.c b/block/keyslot-manager.c index 13d34b857625..901545c5854c 100644 --- a/block/keyslot-manager.c +++ b/block/keyslot-manager.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -48,6 +49,11 @@ struct keyslot_manager { unsigned int max_dun_bytes_supported; void *ll_priv_data; +#ifdef CONFIG_PM + /* Device for runtime power management (NULL if none) */ + struct device *dev; +#endif + /* Protects programming and evicting keys from the device */ struct rw_semaphore lock; @@ -74,8 +80,60 @@ static inline bool keyslot_manager_is_passthrough(struct keyslot_manager *ksm) return ksm->num_slots == 0; } +#ifdef CONFIG_PM +static inline void keyslot_manager_set_dev(struct keyslot_manager *ksm, + struct device *dev) +{ + ksm->dev = dev; +} + +/* If there's an underlying device and it's suspended, resume it. */ +static inline void keyslot_manager_pm_get(struct keyslot_manager *ksm) +{ + if (ksm->dev) + pm_runtime_get_sync(ksm->dev); +} + +static inline void keyslot_manager_pm_put(struct keyslot_manager *ksm) +{ + if (ksm->dev) + pm_runtime_put_sync(ksm->dev); +} +#else /* CONFIG_PM */ +static inline void keyslot_manager_set_dev(struct keyslot_manager *ksm, + struct device *dev) +{ +} + +static inline void keyslot_manager_pm_get(struct keyslot_manager *ksm) +{ +} + +static inline void keyslot_manager_pm_put(struct keyslot_manager *ksm) +{ +} +#endif /* !CONFIG_PM */ + +static inline void keyslot_manager_hw_enter(struct keyslot_manager *ksm) +{ + /* + * Calling into the driver requires ksm->lock held and the device + * resumed. But we must resume the device first, since that can acquire + * and release ksm->lock via keyslot_manager_reprogram_all_keys(). + */ + keyslot_manager_pm_get(ksm); + down_write(&ksm->lock); +} + +static inline void keyslot_manager_hw_exit(struct keyslot_manager *ksm) +{ + up_write(&ksm->lock); + keyslot_manager_pm_put(ksm); +} + /** * keyslot_manager_create() - Create a keyslot manager + * @dev: Device for runtime power management (NULL if none) * @num_slots: The number of key slots to manage. * @ksm_ll_ops: The struct keyslot_mgmt_ll_ops for the device that this keyslot * manager will use to perform operations like programming and @@ -97,7 +155,9 @@ static inline bool keyslot_manager_is_passthrough(struct keyslot_manager *ksm) * Context: May sleep * Return: Pointer to constructed keyslot manager or NULL on error. */ -struct keyslot_manager *keyslot_manager_create(unsigned int num_slots, +struct keyslot_manager *keyslot_manager_create( + struct device *dev, + unsigned int num_slots, const struct keyslot_mgmt_ll_ops *ksm_ll_ops, unsigned int features, const unsigned int crypto_mode_supported[BLK_ENCRYPTION_MODE_MAX], @@ -126,6 +186,7 @@ struct keyslot_manager *keyslot_manager_create(unsigned int num_slots, sizeof(ksm->crypto_mode_supported)); ksm->max_dun_bytes_supported = BLK_CRYPTO_MAX_IV_SIZE; ksm->ll_priv_data = ll_priv_data; + keyslot_manager_set_dev(ksm, dev); init_rwsem(&ksm->lock); @@ -242,10 +303,10 @@ int keyslot_manager_get_slot_for_key(struct keyslot_manager *ksm, return slot; for (;;) { - down_write(&ksm->lock); + keyslot_manager_hw_enter(ksm); slot = find_and_grab_keyslot(ksm, key); if (slot != -ENOKEY) { - up_write(&ksm->lock); + keyslot_manager_hw_exit(ksm); return slot; } @@ -256,7 +317,7 @@ int keyslot_manager_get_slot_for_key(struct keyslot_manager *ksm, if (!list_empty(&ksm->idle_slots)) break; - up_write(&ksm->lock); + keyslot_manager_hw_exit(ksm); wait_event(ksm->idle_slots_wait_queue, !list_empty(&ksm->idle_slots)); } @@ -268,7 +329,7 @@ int keyslot_manager_get_slot_for_key(struct keyslot_manager *ksm, err = ksm->ksm_ll_ops.keyslot_program(ksm, key, slot); if (err) { wake_up(&ksm->idle_slots_wait_queue); - up_write(&ksm->lock); + keyslot_manager_hw_exit(ksm); return err; } @@ -282,7 +343,7 @@ int keyslot_manager_get_slot_for_key(struct keyslot_manager *ksm, remove_slot_from_lru_list(ksm, slot); - up_write(&ksm->lock); + keyslot_manager_hw_exit(ksm); return slot; } @@ -397,15 +458,16 @@ int keyslot_manager_evict_key(struct keyslot_manager *ksm, if (keyslot_manager_is_passthrough(ksm)) { if (ksm->ksm_ll_ops.keyslot_evict) { - down_write(&ksm->lock); + keyslot_manager_hw_enter(ksm); err = ksm->ksm_ll_ops.keyslot_evict(ksm, key, -1); - up_write(&ksm->lock); + keyslot_manager_hw_exit(ksm); return err; } return 0; } - down_write(&ksm->lock); + keyslot_manager_hw_enter(ksm); + slot = find_keyslot(ksm, key); if (slot < 0) { err = slot; @@ -425,7 +487,7 @@ int keyslot_manager_evict_key(struct keyslot_manager *ksm, memzero_explicit(&slotp->key, sizeof(slotp->key)); err = 0; out_unlock: - up_write(&ksm->lock); + keyslot_manager_hw_exit(ksm); return err; } @@ -445,6 +507,7 @@ void keyslot_manager_reprogram_all_keys(struct keyslot_manager *ksm) if (WARN_ON(keyslot_manager_is_passthrough(ksm))) return; + /* This is for device initialization, so don't resume the device */ down_write(&ksm->lock); for (slot = 0; slot < ksm->num_slots; slot++) { const struct keyslot *slotp = &ksm->slots[slot]; @@ -484,6 +547,7 @@ EXPORT_SYMBOL_GPL(keyslot_manager_destroy); /** * keyslot_manager_create_passthrough() - Create a passthrough keyslot manager + * @dev: Device for runtime power management (NULL if none) * @ksm_ll_ops: The struct keyslot_mgmt_ll_ops * @features: Bitmask of BLK_CRYPTO_FEATURE_* flags * @crypto_mode_supported: Bitmasks for supported encryption modes @@ -501,6 +565,7 @@ EXPORT_SYMBOL_GPL(keyslot_manager_destroy); * Return: Pointer to constructed keyslot manager or NULL on error. */ struct keyslot_manager *keyslot_manager_create_passthrough( + struct device *dev, const struct keyslot_mgmt_ll_ops *ksm_ll_ops, unsigned int features, const unsigned int crypto_mode_supported[BLK_ENCRYPTION_MODE_MAX], @@ -518,6 +583,7 @@ struct keyslot_manager *keyslot_manager_create_passthrough( sizeof(ksm->crypto_mode_supported)); ksm->max_dun_bytes_supported = BLK_CRYPTO_MAX_IV_SIZE; ksm->ll_priv_data = ll_priv_data; + keyslot_manager_set_dev(ksm, dev); init_rwsem(&ksm->lock); @@ -583,15 +649,15 @@ int keyslot_manager_derive_raw_secret(struct keyslot_manager *ksm, { int err; - down_write(&ksm->lock); if (ksm->ksm_ll_ops.derive_raw_secret) { + keyslot_manager_hw_enter(ksm); err = ksm->ksm_ll_ops.derive_raw_secret(ksm, wrapped_key, wrapped_key_size, secret, secret_size); + keyslot_manager_hw_exit(ksm); } else { err = -EOPNOTSUPP; } - up_write(&ksm->lock); return err; } diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 1c621a8a7886..20212c6394b6 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -2178,7 +2178,8 @@ static int dm_init_inline_encryption(struct mapped_device *md) BLK_CRYPTO_FEATURE_WRAPPED_KEYS; memset(mode_masks, 0xFF, sizeof(mode_masks)); - md->queue->ksm = keyslot_manager_create_passthrough(&dm_ksm_ll_ops, + md->queue->ksm = keyslot_manager_create_passthrough(NULL, + &dm_ksm_ll_ops, features, mode_masks, md); if (!md->queue->ksm) diff --git a/drivers/mmc/host/cmdq_hci-crypto-qti.c b/drivers/mmc/host/cmdq_hci-crypto-qti.c index 873c436e4b09..80fb35ff35a5 100644 --- a/drivers/mmc/host/cmdq_hci-crypto-qti.c +++ b/drivers/mmc/host/cmdq_hci-crypto-qti.c @@ -108,12 +108,9 @@ static int cmdq_crypto_qti_keyslot_program(struct keyslot_manager *ksm, crypto_alg_id = cmdq_crypto_cap_find(host, key->crypto_mode, key->data_unit_size); - pm_runtime_get_sync(&host->mmc->card->dev); - if (!cmdq_is_crypto_enabled(host) || !cmdq_keyslot_valid(host, slot) || !ice_cap_idx_valid(host, crypto_alg_id)) { - pm_runtime_put_sync(&host->mmc->card->dev); return -EINVAL; } @@ -121,7 +118,6 @@ static int cmdq_crypto_qti_keyslot_program(struct keyslot_manager *ksm, if (!(data_unit_mask & host->crypto_cap_array[crypto_alg_id].sdus_mask)) { - pm_runtime_put_sync(&host->mmc->card->dev); return -EINVAL; } @@ -130,8 +126,6 @@ static int cmdq_crypto_qti_keyslot_program(struct keyslot_manager *ksm, if (err) pr_err("%s: failed with error %d\n", __func__, err); - pm_runtime_put_sync(&host->mmc->card->dev); - return err; } @@ -225,10 +219,11 @@ int cmdq_host_init_crypto_qti_spec(struct cmdq_host *host, crypto_modes_supported[blk_mode_num] |= CRYPTO_CDU_SIZE * 512; - host->ksm = keyslot_manager_create(cmdq_num_keyslots(host), ksm_ops, - BLK_CRYPTO_FEATURE_STANDARD_KEYS | - BLK_CRYPTO_FEATURE_WRAPPED_KEYS, - crypto_modes_supported, host); + host->ksm = keyslot_manager_create(host->mmc->parent, + cmdq_num_keyslots(host), ksm_ops, + BLK_CRYPTO_FEATURE_STANDARD_KEYS | + BLK_CRYPTO_FEATURE_WRAPPED_KEYS, + crypto_modes_supported, host); if (!host->ksm) { err = -ENOMEM; @@ -306,7 +301,8 @@ int cmdq_host_init_crypto_qti_spec(struct cmdq_host *host, host->crypto_cap_array[cap_idx].sdus_mask * 512; } - host->ksm = keyslot_manager_create(cmdq_num_keyslots(host), ksm_ops, + host->ksm = keyslot_manager_create(host->mmc->parent, + cmdq_num_keyslots(host), ksm_ops, BLK_CRYPTO_FEATURE_STANDARD_KEYS | BLK_CRYPTO_FEATURE_WRAPPED_KEYS, crypto_modes_supported, host); diff --git a/drivers/mmc/host/cmdq_hci-crypto.c b/drivers/mmc/host/cmdq_hci-crypto.c index 26f84001f064..1e1f62529a5e 100644 --- a/drivers/mmc/host/cmdq_hci-crypto.c +++ b/drivers/mmc/host/cmdq_hci-crypto.c @@ -342,7 +342,8 @@ int cmdq_host_init_crypto_spec(struct cmdq_host *host, cmdq_crypto_clear_all_keyslots(host); - host->ksm = keyslot_manager_create(cmdq_num_keyslots(host), ksm_ops, + host->ksm = keyslot_manager_create(host->mmc->parent, + cmdq_num_keyslots(host), ksm_ops, BLK_CRYPTO_FEATURE_STANDARD_KEYS, crypto_modes_supported, host); diff --git a/drivers/scsi/ufs/ufshcd-crypto-qti.c b/drivers/scsi/ufs/ufshcd-crypto-qti.c index 4e23fb06c385..88966855f499 100644 --- a/drivers/scsi/ufs/ufshcd-crypto-qti.c +++ b/drivers/scsi/ufs/ufshcd-crypto-qti.c @@ -100,7 +100,6 @@ static int ufshcd_crypto_qti_keyslot_program(struct keyslot_manager *ksm, hba->crypto_cap_array[crypto_alg_id].sdus_mask)) return -EINVAL; - pm_runtime_get_sync(hba->dev); err = ufshcd_hold(hba, false); if (err) { pr_err("%s: failed to enable clocks, err %d\n", __func__, err); @@ -109,17 +108,12 @@ static int ufshcd_crypto_qti_keyslot_program(struct keyslot_manager *ksm, err = crypto_qti_keyslot_program(hba->crypto_vops->priv, key, slot, data_unit_mask, crypto_alg_id); - if (err) { + if (err) pr_err("%s: failed with error %d\n", __func__, err); - ufshcd_release(hba, false); - pm_runtime_put_sync(hba->dev); - return err; - } ufshcd_release(hba, false); - pm_runtime_put_sync(hba->dev); - return 0; + return err; } static int ufshcd_crypto_qti_keyslot_evict(struct keyslot_manager *ksm, @@ -240,7 +234,8 @@ static int ufshcd_hba_init_crypto_qti_spec(struct ufs_hba *hba, hba->crypto_cap_array[cap_idx].sdus_mask * 512; } - hba->ksm = keyslot_manager_create(ufshcd_num_keyslots(hba), ksm_ops, + hba->ksm = keyslot_manager_create(hba->dev, ufshcd_num_keyslots(hba), + ksm_ops, BLK_CRYPTO_FEATURE_STANDARD_KEYS | BLK_CRYPTO_FEATURE_WRAPPED_KEYS, crypto_modes_supported, hba); diff --git a/drivers/scsi/ufs/ufshcd-crypto.c b/drivers/scsi/ufs/ufshcd-crypto.c index d6ef8a7699b2..8df645f42d20 100644 --- a/drivers/scsi/ufs/ufshcd-crypto.c +++ b/drivers/scsi/ufs/ufshcd-crypto.c @@ -125,7 +125,6 @@ static int ufshcd_program_key(struct ufs_hba *hba, u32 slot_offset = hba->crypto_cfg_register + slot * sizeof(*cfg); int err; - pm_runtime_get_sync(hba->dev); ufshcd_hold(hba, false); if (hba->var->vops->program_key) { @@ -155,7 +154,6 @@ static int ufshcd_program_key(struct ufs_hba *hba, err = 0; out: ufshcd_release(hba, false); - pm_runtime_put_sync(hba->dev); return err; } @@ -337,7 +335,7 @@ int ufshcd_hba_init_crypto_spec(struct ufs_hba *hba, ufshcd_clear_all_keyslots(hba); - hba->ksm = keyslot_manager_create(ufshcd_num_keyslots(hba), + hba->ksm = keyslot_manager_create(hba->dev, ufshcd_num_keyslots(hba), ksm_ops, BLK_CRYPTO_FEATURE_STANDARD_KEYS, crypto_modes_supported, hba); diff --git a/include/linux/keyslot-manager.h b/include/linux/keyslot-manager.h index 57000863beb7..f5e0eed468b0 100644 --- a/include/linux/keyslot-manager.h +++ b/include/linux/keyslot-manager.h @@ -50,7 +50,9 @@ struct keyslot_mgmt_ll_ops { u8 *secret, unsigned int secret_size); }; -struct keyslot_manager *keyslot_manager_create(unsigned int num_slots, +struct keyslot_manager *keyslot_manager_create( + struct device *dev, + unsigned int num_slots, const struct keyslot_mgmt_ll_ops *ksm_ops, unsigned int features, const unsigned int crypto_mode_supported[BLK_ENCRYPTION_MODE_MAX], @@ -82,6 +84,7 @@ void *keyslot_manager_private(struct keyslot_manager *ksm); void keyslot_manager_destroy(struct keyslot_manager *ksm); struct keyslot_manager *keyslot_manager_create_passthrough( + struct device *dev, const struct keyslot_mgmt_ll_ops *ksm_ops, unsigned int features, const unsigned int crypto_mode_supported[BLK_ENCRYPTION_MODE_MAX],