ANDROID: scsi: ufs: split up UFSHCD_QUIRK_NO_KEYSLOTS

UFSHCD_QUIRK_NO_KEYSLOTS does several different things:

    1. Skip writing CRYPTO_GENERAL_ENABLE to REG_CONTROLLER_ENABLE.
    2. Skip initializing the keyslot manager via the standard UFS crypto
       capability registers.
    3. Skip clearing and re-programming all keyslots.

The current use case for this is FMP, which needs all these behaviors.

However, some new hardware will still need behaviors (1) and (2),
but will no longer need (3) since the hardware will have keyslots.

To support this hardware, split up UFSHCD_QUIRK_NO_KEYSLOTS as follows:

  1. UFSHCD_QUIRK_BROKEN_CRYPTO_ENABLE
  2. UFSHCD_QUIRK_BROKEN_CRYPTO_CAPS
  3. No quirk bit; just use hba->ksm.num_slots.

Also adjust the crypto quirk bits to start at (1 << 20) to avoid
collisions with backports from upstream.

Bug: 166139333
Bug: 162257402
Change-Id: I1e740f7ce0db7a1bafada0eb73343cd04966fee0
Signed-off-by: Eric Biggers <ebiggers@google.com>
diff --git a/drivers/scsi/ufs/ufshcd-crypto.c b/drivers/scsi/ufs/ufshcd-crypto.c
index 4a7b7a4..f6f51e9 100644
--- a/drivers/scsi/ufs/ufshcd-crypto.c
+++ b/drivers/scsi/ufs/ufshcd-crypto.c
@@ -119,11 +119,13 @@
 	if (!(hba->caps & UFSHCD_CAP_CRYPTO))
 		return false;
 
-	if (hba->quirks & UFSHCD_QUIRK_NO_KEYSLOTS)
+	/* Reset might clear all keys, so reprogram all the keys. */
+	if (hba->ksm.num_slots)
+		blk_ksm_reprogram_all_keys(&hba->ksm);
+
+	if (hba->quirks & UFSHCD_QUIRK_BROKEN_CRYPTO_ENABLE)
 		return false;
 
-	/* Reset might clear all keys, so reprogram all the keys. */
-	blk_ksm_reprogram_all_keys(&hba->ksm);
 	return true;
 }
 
@@ -160,7 +162,7 @@
 	int err = 0;
 	enum blk_crypto_mode_num blk_mode_num;
 
-	if (hba->quirks & UFSHCD_QUIRK_NO_KEYSLOTS)
+	if (hba->quirks & UFSHCD_QUIRK_BROKEN_CRYPTO_CAPS)
 		return 0;
 
 	/*
@@ -234,11 +236,8 @@
 	if (!(hba->caps & UFSHCD_CAP_CRYPTO))
 		return;
 
-	if (hba->quirks & UFSHCD_QUIRK_NO_KEYSLOTS)
-		return;
-
-	/* Clear all keyslots - the number of keyslots is (CFGC + 1) */
-	for (slot = 0; slot < hba->crypto_capabilities.config_count + 1; slot++)
+	/* Clear all keyslots */
+	for (slot = 0; slot < hba->ksm.num_slots; slot++)
 		ufshcd_clear_keyslot(hba, slot);
 }
 
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index bfbaa90..c029893c 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -709,19 +709,25 @@
 
 	/*
 	 * This quirk needs to be enabled if the host controller supports inline
-	 * encryption, but it uses a nonstandard mechanism where the standard
-	 * crypto registers aren't used and there is no concept of keyslots.
-	 * ufs_hba_variant_ops::init() is expected to initialize ufs_hba::ksm as
-	 * a passthrough keyslot manager.
+	 * encryption, but it doesn't use the standard crypto capability
+	 * registers.  If enabled, the standard code won't initialize the
+	 * keyslot manager; ufs_hba_variant_ops::init() must do it instead.
 	 */
-	#define UFSHCD_QUIRK_NO_KEYSLOTS			0x2000
+	#define UFSHCD_QUIRK_BROKEN_CRYPTO_CAPS			0x100000
+
+	/*
+	 * This quirk needs to be enabled if the host controller supports inline
+	 * encryption, but the CRYPTO_GENERAL_ENABLE bit is not implemented and
+	 * breaks the HCE sequence if used.
+	 */
+	#define UFSHCD_QUIRK_BROKEN_CRYPTO_ENABLE		0x200000
 
 	/*
 	 * This quirk needs to be enabled if the host controller requires that
 	 * the PRDT be cleared after each encrypted request because encryption
 	 * keys were stored in it.
 	 */
-	#define UFSHCD_QUIRK_KEYS_IN_PRDT			0x4000
+	#define UFSHCD_QUIRK_KEYS_IN_PRDT			0x400000
 
 	unsigned int quirks;	/* Deviations from standard UFSHCI spec. */