diff --git a/block/blk-crypto-fallback.c b/block/blk-crypto-fallback.c index cce3317cba80..b8e9ae1c1d5b 100644 --- a/block/blk-crypto-fallback.c +++ b/block/blk-crypto-fallback.c @@ -608,7 +608,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, crypto_mode_supported, NULL); if (!blk_crypto_ksm) diff --git a/block/keyslot-manager.c b/block/keyslot-manager.c index 7e42813c9de0..0b6dd460645e 100644 --- a/block/keyslot-manager.c +++ b/block/keyslot-manager.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -46,6 +47,11 @@ struct keyslot_manager { unsigned int crypto_mode_supported[BLK_ENCRYPTION_MODE_MAX]; 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; @@ -72,8 +78,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 @@ -93,7 +151,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, const unsigned int crypto_mode_supported[BLK_ENCRYPTION_MODE_MAX], void *ll_priv_data) @@ -119,6 +179,7 @@ struct keyslot_manager *keyslot_manager_create(unsigned int num_slots, memcpy(ksm->crypto_mode_supported, crypto_mode_supported, sizeof(ksm->crypto_mode_supported)); ksm->ll_priv_data = ll_priv_data; + keyslot_manager_set_dev(ksm, dev); init_rwsem(&ksm->lock); @@ -227,10 +288,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; } @@ -241,7 +302,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)); } @@ -253,7 +314,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; } @@ -267,7 +328,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; } @@ -369,15 +430,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; @@ -397,7 +459,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; } @@ -417,6 +479,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]; @@ -456,6 +519,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 * @crypto_mode_supported: Bitmasks for supported encryption modes * @ll_priv_data: Private data passed as is to the functions in ksm_ll_ops. @@ -472,6 +536,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, const unsigned int crypto_mode_supported[BLK_ENCRYPTION_MODE_MAX], void *ll_priv_data) @@ -486,6 +551,7 @@ struct keyslot_manager *keyslot_manager_create_passthrough( memcpy(ksm->crypto_mode_supported, crypto_mode_supported, sizeof(ksm->crypto_mode_supported)); ksm->ll_priv_data = ll_priv_data; + keyslot_manager_set_dev(ksm, dev); init_rwsem(&ksm->lock); @@ -545,15 +611,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 0189f70e87a0..0271ca072453 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -2102,7 +2102,8 @@ static int dm_init_inline_encryption(struct mapped_device *md) */ 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, mode_masks, md); if (!md->queue->ksm) return -ENOMEM; diff --git a/drivers/scsi/ufs/ufshcd-crypto.c b/drivers/scsi/ufs/ufshcd-crypto.c index 276b49ad13be..e3de448c9bbe 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->vops->program_key) { @@ -155,7 +154,6 @@ static int ufshcd_program_key(struct ufs_hba *hba, err = 0; out: ufshcd_release(hba); - pm_runtime_put_sync(hba->dev); return err; } @@ -337,8 +335,8 @@ int ufshcd_hba_init_crypto_spec(struct ufs_hba *hba, ufshcd_clear_all_keyslots(hba); - hba->ksm = keyslot_manager_create(ufshcd_num_keyslots(hba), ksm_ops, - crypto_modes_supported, hba); + hba->ksm = keyslot_manager_create(hba->dev, ufshcd_num_keyslots(hba), + ksm_ops, crypto_modes_supported, hba); if (!hba->ksm) { err = -ENOMEM; diff --git a/include/linux/keyslot-manager.h b/include/linux/keyslot-manager.h index 6d32a031218e..2f4aac2851bf 100644 --- a/include/linux/keyslot-manager.h +++ b/include/linux/keyslot-manager.h @@ -41,7 +41,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, const unsigned int crypto_mode_supported[BLK_ENCRYPTION_MODE_MAX], void *ll_priv_data); @@ -67,6 +69,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, const unsigned int crypto_mode_supported[BLK_ENCRYPTION_MODE_MAX], void *ll_priv_data);