[PATCH v2 1/7] ufs: Convert quirks to BIT() macro

Use BIT() macro for quirks, no functional change.
Signed-off-by: Marek Vasut marek.vasut+renesas@mailbox.org --- Cc: Bhupesh Sharma bhupesh.sharma@linaro.org Cc: Faiz Abbas faiz_abbas@ti.com --- V2: New patch --- drivers/ufs/ufs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/ufs/ufs.h b/drivers/ufs/ufs.h index 8a38832b05f..5a5c13aefdf 100644 --- a/drivers/ufs/ufs.h +++ b/drivers/ufs/ufs.h @@ -717,7 +717,7 @@ struct ufs_hba { * the LCC transmission on UFS device (by clearing TX_LCC_ENABLE * attribute of device to 0). */ -#define UFSHCD_QUIRK_BROKEN_LCC 0x1 +#define UFSHCD_QUIRK_BROKEN_LCC BIT(0)
/* Virtual memory reference */ struct utp_transfer_cmd_desc *ucdl;

Add UFSHCD_QUIRK_BROKEN_64BIT_ADDRESS for host controllers which do not support 64-bit addressing.
Ported from Linux kernel commit 6554400d6f66 ("scsi: ufs: core: Add UFSHCD_QUIRK_BROKEN_64BIT_ADDRESS") with ufs_scsi_buffer_aligned() based on U-Boot generic bounce buffer.
Signed-off-by: Marek Vasut marek.vasut+renesas@mailbox.org --- Cc: Bhupesh Sharma bhupesh.sharma@linaro.org Cc: Faiz Abbas faiz_abbas@ti.com --- V2: Use BIT() macro --- drivers/ufs/ufs.c | 26 ++++++++++++++++++++++++++ drivers/ufs/ufs.h | 6 ++++++ 2 files changed, 32 insertions(+)
diff --git a/drivers/ufs/ufs.c b/drivers/ufs/ufs.c index 3bf1a95e7f2..da0550d98c6 100644 --- a/drivers/ufs/ufs.c +++ b/drivers/ufs/ufs.c @@ -8,6 +8,7 @@ * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com */
+#include <bouncebuf.h> #include <charset.h> #include <common.h> #include <dm.h> @@ -1889,6 +1890,8 @@ int ufshcd_probe(struct udevice *ufs_dev, struct ufs_hba_ops *hba_ops)
/* Read capabilties registers */ hba->capabilities = ufshcd_readl(hba, REG_CONTROLLER_CAPABILITIES); + if (hba->quirks & UFSHCD_QUIRK_BROKEN_64BIT_ADDRESS) + hba->capabilities &= ~MASK_64_ADDRESSING_SUPPORT;
/* Get UFS version supported by the controller */ hba->version = ufshcd_get_ufs_version(hba); @@ -1942,8 +1945,31 @@ int ufs_scsi_bind(struct udevice *ufs_dev, struct udevice **scsi_devp) return ret; }
+#if IS_ENABLED(CONFIG_BOUNCE_BUFFER) +static int ufs_scsi_buffer_aligned(struct udevice *scsi_dev, struct bounce_buffer *state) +{ +#ifdef CONFIG_PHYS_64BIT + struct ufs_hba *hba = dev_get_uclass_priv(scsi_dev->parent); + uintptr_t ubuf = (uintptr_t)state->user_buffer; + size_t len = state->len_aligned; + + /* Check if below 32bit boundary */ + if ((hba->quirks & UFSHCD_QUIRK_BROKEN_64BIT_ADDRESS) && + ((ubuf >> 32) || (ubuf + len) >> 32)) { + dev_dbg(scsi_dev, "Buffer above 32bit boundary %lx-%lx\n", + ubuf, ubuf + len); + return 0; + } +#endif + return 1; +} +#endif /* CONFIG_BOUNCE_BUFFER */ + static struct scsi_ops ufs_ops = { .exec = ufs_scsi_exec, +#if IS_ENABLED(CONFIG_BOUNCE_BUFFER) + .buffer_aligned = ufs_scsi_buffer_aligned, +#endif /* CONFIG_BOUNCE_BUFFER */ };
int ufs_probe_dev(int index) diff --git a/drivers/ufs/ufs.h b/drivers/ufs/ufs.h index 5a5c13aefdf..e5ddb6f64a9 100644 --- a/drivers/ufs/ufs.h +++ b/drivers/ufs/ufs.h @@ -719,6 +719,12 @@ struct ufs_hba { */ #define UFSHCD_QUIRK_BROKEN_LCC BIT(0)
+/* + * This quirk needs to be enabled if the host controller has + * 64-bit addressing supported capability but it doesn't work. + */ +#define UFSHCD_QUIRK_BROKEN_64BIT_ADDRESS BIT(1) + /* Virtual memory reference */ struct utp_transfer_cmd_desc *ucdl; struct utp_transfer_req_desc *utrdl;

On 8/16/23 8:35 PM, Marek Vasut wrote:
Add UFSHCD_QUIRK_BROKEN_64BIT_ADDRESS for host controllers which do not support 64-bit addressing.
Ported from Linux kernel commit 6554400d6f66 ("scsi: ufs: core: Add UFSHCD_QUIRK_BROKEN_64BIT_ADDRESS") with ufs_scsi_buffer_aligned() based on U-Boot generic bounce buffer.
Signed-off-by: Marek Vasut marek.vasut+renesas@mailbox.org
Cc: Bhupesh Sharma bhupesh.sharma@linaro.org Cc: Faiz Abbas faiz_abbas@ti.com
V2: Use BIT() macro
drivers/ufs/ufs.c | 26 ++++++++++++++++++++++++++ drivers/ufs/ufs.h | 6 ++++++ 2 files changed, 32 insertions(+)
diff --git a/drivers/ufs/ufs.c b/drivers/ufs/ufs.c index 3bf1a95e7f2..da0550d98c6 100644 --- a/drivers/ufs/ufs.c +++ b/drivers/ufs/ufs.c @@ -8,6 +8,7 @@
- Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com
*/
+#include <bouncebuf.h> #include <charset.h> #include <common.h> #include <dm.h> @@ -1889,6 +1890,8 @@ int ufshcd_probe(struct udevice *ufs_dev, struct ufs_hba_ops *hba_ops)
/* Read capabilties registers */ hba->capabilities = ufshcd_readl(hba, REG_CONTROLLER_CAPABILITIES);
if (hba->quirks & UFSHCD_QUIRK_BROKEN_64BIT_ADDRESS)
hba->capabilities &= ~MASK_64_ADDRESSING_SUPPORT;
/* Get UFS version supported by the controller */ hba->version = ufshcd_get_ufs_version(hba);
@@ -1942,8 +1945,31 @@ int ufs_scsi_bind(struct udevice *ufs_dev, struct udevice **scsi_devp) return ret; }
+#if IS_ENABLED(CONFIG_BOUNCE_BUFFER) +static int ufs_scsi_buffer_aligned(struct udevice *scsi_dev, struct bounce_buffer *state) +{ +#ifdef CONFIG_PHYS_64BIT
- struct ufs_hba *hba = dev_get_uclass_priv(scsi_dev->parent);
- uintptr_t ubuf = (uintptr_t)state->user_buffer;
- size_t len = state->len_aligned;
- /* Check if below 32bit boundary */
- if ((hba->quirks & UFSHCD_QUIRK_BROKEN_64BIT_ADDRESS) &&
((ubuf >> 32) || (ubuf + len) >> 32)) {
dev_dbg(scsi_dev, "Buffer above 32bit boundary %lx-%lx\n",
ubuf, ubuf + len);
return 0;
- }
+#endif
- return 1;
+} +#endif /* CONFIG_BOUNCE_BUFFER */
- static struct scsi_ops ufs_ops = { .exec = ufs_scsi_exec,
+#if IS_ENABLED(CONFIG_BOUNCE_BUFFER)
- .buffer_aligned = ufs_scsi_buffer_aligned,
+#endif /* CONFIG_BOUNCE_BUFFER */ };
int ufs_probe_dev(int index) diff --git a/drivers/ufs/ufs.h b/drivers/ufs/ufs.h index 5a5c13aefdf..e5ddb6f64a9 100644 --- a/drivers/ufs/ufs.h +++ b/drivers/ufs/ufs.h @@ -719,6 +719,12 @@ struct ufs_hba { */ #define UFSHCD_QUIRK_BROKEN_LCC BIT(0)
+/*
- This quirk needs to be enabled if the host controller has
- 64-bit addressing supported capability but it doesn't work.
- */
+#define UFSHCD_QUIRK_BROKEN_64BIT_ADDRESS BIT(1)
- /* Virtual memory reference */ struct utp_transfer_cmd_desc *ucdl; struct utp_transfer_req_desc *utrdl;
Reviewed-by: Bhupesh Sharma bhupesh.sharma@linaro.org Tested-by: Bhupesh Sharma bhupesh.sharma@linaro.org

Add UFSHCD_QUIRK_HIBERN_FASTAUTO quirk for host controllers which supports auto-hibernate the capability but only FASTAUTO mode.
Ported from Linux kernel commit 2f11bbc2c7f3 ("scsi: ufs: core: Add UFSHCD_QUIRK_HIBERN_FASTAUTO")
Signed-off-by: Marek Vasut marek.vasut+renesas@mailbox.org --- Cc: Bhupesh Sharma bhupesh.sharma@linaro.org Cc: Faiz Abbas faiz_abbas@ti.com --- V2: Use BIT() macro --- drivers/ufs/ufs.c | 9 +++++++-- drivers/ufs/ufs.h | 6 ++++++ 2 files changed, 13 insertions(+), 2 deletions(-)
diff --git a/drivers/ufs/ufs.c b/drivers/ufs/ufs.c index da0550d98c6..261ae2843c2 100644 --- a/drivers/ufs/ufs.c +++ b/drivers/ufs/ufs.c @@ -1631,8 +1631,13 @@ static int ufshcd_get_max_pwr_mode(struct ufs_hba *hba) if (hba->max_pwr_info.is_valid) return 0;
- pwr_info->pwr_tx = FAST_MODE; - pwr_info->pwr_rx = FAST_MODE; + if (hba->quirks & UFSHCD_QUIRK_HIBERN_FASTAUTO) { + pwr_info->pwr_tx = FASTAUTO_MODE; + pwr_info->pwr_rx = FASTAUTO_MODE; + } else { + pwr_info->pwr_tx = FAST_MODE; + pwr_info->pwr_rx = FAST_MODE; + } pwr_info->hs_rate = PA_HS_MODE_B;
/* Get the connected lane count */ diff --git a/drivers/ufs/ufs.h b/drivers/ufs/ufs.h index e5ddb6f64a9..638c10b5503 100644 --- a/drivers/ufs/ufs.h +++ b/drivers/ufs/ufs.h @@ -725,6 +725,12 @@ struct ufs_hba { */ #define UFSHCD_QUIRK_BROKEN_64BIT_ADDRESS BIT(1)
+/* + * This quirk needs to be enabled if the host controller has + * auto-hibernate capability but it's FASTAUTO only. + */ +#define UFSHCD_QUIRK_HIBERN_FASTAUTO BIT(2) + /* Virtual memory reference */ struct utp_transfer_cmd_desc *ucdl; struct utp_transfer_req_desc *utrdl;

On 8/16/23 8:35 PM, Marek Vasut wrote:
Add UFSHCD_QUIRK_HIBERN_FASTAUTO quirk for host controllers which supports auto-hibernate the capability but only FASTAUTO mode.
Ported from Linux kernel commit 2f11bbc2c7f3 ("scsi: ufs: core: Add UFSHCD_QUIRK_HIBERN_FASTAUTO")
Signed-off-by: Marek Vasut marek.vasut+renesas@mailbox.org
Cc: Bhupesh Sharma bhupesh.sharma@linaro.org Cc: Faiz Abbas faiz_abbas@ti.com
V2: Use BIT() macro
drivers/ufs/ufs.c | 9 +++++++-- drivers/ufs/ufs.h | 6 ++++++ 2 files changed, 13 insertions(+), 2 deletions(-)
diff --git a/drivers/ufs/ufs.c b/drivers/ufs/ufs.c index da0550d98c6..261ae2843c2 100644 --- a/drivers/ufs/ufs.c +++ b/drivers/ufs/ufs.c @@ -1631,8 +1631,13 @@ static int ufshcd_get_max_pwr_mode(struct ufs_hba *hba) if (hba->max_pwr_info.is_valid) return 0;
- pwr_info->pwr_tx = FAST_MODE;
- pwr_info->pwr_rx = FAST_MODE;
if (hba->quirks & UFSHCD_QUIRK_HIBERN_FASTAUTO) {
pwr_info->pwr_tx = FASTAUTO_MODE;
pwr_info->pwr_rx = FASTAUTO_MODE;
} else {
pwr_info->pwr_tx = FAST_MODE;
pwr_info->pwr_rx = FAST_MODE;
} pwr_info->hs_rate = PA_HS_MODE_B;
/* Get the connected lane count */
diff --git a/drivers/ufs/ufs.h b/drivers/ufs/ufs.h index e5ddb6f64a9..638c10b5503 100644 --- a/drivers/ufs/ufs.h +++ b/drivers/ufs/ufs.h @@ -725,6 +725,12 @@ struct ufs_hba { */ #define UFSHCD_QUIRK_BROKEN_64BIT_ADDRESS BIT(1)
+/*
- This quirk needs to be enabled if the host controller has
- auto-hibernate capability but it's FASTAUTO only.
- */
+#define UFSHCD_QUIRK_HIBERN_FASTAUTO BIT(2)
- /* Virtual memory reference */ struct utp_transfer_cmd_desc *ucdl; struct utp_transfer_req_desc *utrdl;
Reviewed-by: Bhupesh Sharma bhupesh.sharma@linaro.org Tested-by: Bhupesh Sharma bhupesh.sharma@linaro.org

Extend the version check to handle UFS 3.0 controllers as well. Tested on R-Car S4 UFS 3.0 controller.
Signed-off-by: Marek Vasut marek.vasut+renesas@mailbox.org --- Cc: Bhupesh Sharma bhupesh.sharma@linaro.org Cc: Faiz Abbas faiz_abbas@ti.com --- V2: No change --- drivers/ufs/ufs.c | 3 ++- drivers/ufs/ufs.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/ufs/ufs.c b/drivers/ufs/ufs.c index 261ae2843c2..58830c8ddca 100644 --- a/drivers/ufs/ufs.c +++ b/drivers/ufs/ufs.c @@ -1903,7 +1903,8 @@ int ufshcd_probe(struct udevice *ufs_dev, struct ufs_hba_ops *hba_ops) if (hba->version != UFSHCI_VERSION_10 && hba->version != UFSHCI_VERSION_11 && hba->version != UFSHCI_VERSION_20 && - hba->version != UFSHCI_VERSION_21) + hba->version != UFSHCI_VERSION_21 && + hba->version != UFSHCI_VERSION_30) dev_err(hba->dev, "invalid UFS version 0x%x\n", hba->version);
diff --git a/drivers/ufs/ufs.h b/drivers/ufs/ufs.h index 638c10b5503..9daaf03d222 100644 --- a/drivers/ufs/ufs.h +++ b/drivers/ufs/ufs.h @@ -781,6 +781,7 @@ enum { UFSHCI_VERSION_11 = 0x00010100, /* 1.1 */ UFSHCI_VERSION_20 = 0x00000200, /* 2.0 */ UFSHCI_VERSION_21 = 0x00000210, /* 2.1 */ + UFSHCI_VERSION_30 = 0x00000300, /* 3.0 */ };
/* Interrupt disable masks */

On 8/16/23 8:35 PM, Marek Vasut wrote:
Extend the version check to handle UFS 3.0 controllers as well. Tested on R-Car S4 UFS 3.0 controller.
Signed-off-by: Marek Vasut marek.vasut+renesas@mailbox.org
Cc: Bhupesh Sharma bhupesh.sharma@linaro.org Cc: Faiz Abbas faiz_abbas@ti.com
V2: No change
drivers/ufs/ufs.c | 3 ++- drivers/ufs/ufs.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/ufs/ufs.c b/drivers/ufs/ufs.c index 261ae2843c2..58830c8ddca 100644 --- a/drivers/ufs/ufs.c +++ b/drivers/ufs/ufs.c @@ -1903,7 +1903,8 @@ int ufshcd_probe(struct udevice *ufs_dev, struct ufs_hba_ops *hba_ops) if (hba->version != UFSHCI_VERSION_10 && hba->version != UFSHCI_VERSION_11 && hba->version != UFSHCI_VERSION_20 &&
hba->version != UFSHCI_VERSION_21)
hba->version != UFSHCI_VERSION_21 &&
dev_err(hba->dev, "invalid UFS version 0x%x\n", hba->version);hba->version != UFSHCI_VERSION_30)
diff --git a/drivers/ufs/ufs.h b/drivers/ufs/ufs.h index 638c10b5503..9daaf03d222 100644 --- a/drivers/ufs/ufs.h +++ b/drivers/ufs/ufs.h @@ -781,6 +781,7 @@ enum { UFSHCI_VERSION_11 = 0x00010100, /* 1.1 */ UFSHCI_VERSION_20 = 0x00000200, /* 2.0 */ UFSHCI_VERSION_21 = 0x00000210, /* 2.1 */
UFSHCI_VERSION_30 = 0x00000300, /* 3.0 */ };
/* Interrupt disable masks */
Reviewed-by: Bhupesh Sharma bhupesh.sharma@linaro.org Tested-by: Bhupesh Sharma bhupesh.sharma@linaro.org

Pass the hba pointer itself to ufshcd_prepare_req_desc_hdr() instead of duplicating utp_transfer_req_desc access at each call site. No functional change.
Signed-off-by: Marek Vasut marek.vasut+renesas@mailbox.org --- Cc: Bhupesh Sharma bhupesh.sharma@linaro.org Cc: Faiz Abbas faiz_abbas@ti.com --- V2: No change --- drivers/ufs/ufs.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/drivers/ufs/ufs.c b/drivers/ufs/ufs.c index 58830c8ddca..da1009e2c14 100644 --- a/drivers/ufs/ufs.c +++ b/drivers/ufs/ufs.c @@ -696,10 +696,11 @@ static inline u8 ufshcd_get_upmcrs(struct ufs_hba *hba) * ufshcd_prepare_req_desc_hdr() - Fills the requests header * descriptor according to request */ -static void ufshcd_prepare_req_desc_hdr(struct utp_transfer_req_desc *req_desc, +static void ufshcd_prepare_req_desc_hdr(struct ufs_hba *hba, u32 *upiu_flags, enum dma_data_direction cmd_dir) { + struct utp_transfer_req_desc *req_desc = hba->utrdl; u32 data_direction; u32 dword_0;
@@ -793,11 +794,10 @@ static int ufshcd_comp_devman_upiu(struct ufs_hba *hba, { u32 upiu_flags; int ret = 0; - struct utp_transfer_req_desc *req_desc = hba->utrdl;
hba->dev_cmd.type = cmd_type;
- ufshcd_prepare_req_desc_hdr(req_desc, &upiu_flags, DMA_NONE); + ufshcd_prepare_req_desc_hdr(hba, &upiu_flags, DMA_NONE); switch (cmd_type) { case DEV_CMD_TYPE_QUERY: ufshcd_prepare_utp_query_req_upiu(hba, upiu_flags); @@ -1449,12 +1449,11 @@ static void prepare_prdt_table(struct ufs_hba *hba, struct scsi_cmd *pccb) static int ufs_scsi_exec(struct udevice *scsi_dev, struct scsi_cmd *pccb) { struct ufs_hba *hba = dev_get_uclass_priv(scsi_dev->parent); - struct utp_transfer_req_desc *req_desc = hba->utrdl; u32 upiu_flags; int ocs, result = 0; u8 scsi_status;
- ufshcd_prepare_req_desc_hdr(req_desc, &upiu_flags, pccb->dma_dir); + ufshcd_prepare_req_desc_hdr(hba, &upiu_flags, pccb->dma_dir); ufshcd_prepare_utp_scsi_cmd_upiu(hba, pccb, upiu_flags); prepare_prdt_table(hba, pccb);

On 8/16/23 8:35 PM, Marek Vasut wrote:
Pass the hba pointer itself to ufshcd_prepare_req_desc_hdr() instead of duplicating utp_transfer_req_desc access at each call site. No functional change.
Signed-off-by: Marek Vasut marek.vasut+renesas@mailbox.org
Cc: Bhupesh Sharma bhupesh.sharma@linaro.org Cc: Faiz Abbas faiz_abbas@ti.com
V2: No change
drivers/ufs/ufs.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/drivers/ufs/ufs.c b/drivers/ufs/ufs.c index 58830c8ddca..da1009e2c14 100644 --- a/drivers/ufs/ufs.c +++ b/drivers/ufs/ufs.c @@ -696,10 +696,11 @@ static inline u8 ufshcd_get_upmcrs(struct ufs_hba *hba)
- ufshcd_prepare_req_desc_hdr() - Fills the requests header
- descriptor according to request
*/ -static void ufshcd_prepare_req_desc_hdr(struct utp_transfer_req_desc *req_desc, +static void ufshcd_prepare_req_desc_hdr(struct ufs_hba *hba, u32 *upiu_flags, enum dma_data_direction cmd_dir) {
- struct utp_transfer_req_desc *req_desc = hba->utrdl; u32 data_direction; u32 dword_0;
@@ -793,11 +794,10 @@ static int ufshcd_comp_devman_upiu(struct ufs_hba *hba, { u32 upiu_flags; int ret = 0;
struct utp_transfer_req_desc *req_desc = hba->utrdl;
hba->dev_cmd.type = cmd_type;
ufshcd_prepare_req_desc_hdr(req_desc, &upiu_flags, DMA_NONE);
- ufshcd_prepare_req_desc_hdr(hba, &upiu_flags, DMA_NONE); switch (cmd_type) { case DEV_CMD_TYPE_QUERY: ufshcd_prepare_utp_query_req_upiu(hba, upiu_flags);
@@ -1449,12 +1449,11 @@ static void prepare_prdt_table(struct ufs_hba *hba, struct scsi_cmd *pccb) static int ufs_scsi_exec(struct udevice *scsi_dev, struct scsi_cmd *pccb) { struct ufs_hba *hba = dev_get_uclass_priv(scsi_dev->parent);
struct utp_transfer_req_desc *req_desc = hba->utrdl; u32 upiu_flags; int ocs, result = 0; u8 scsi_status;
ufshcd_prepare_req_desc_hdr(req_desc, &upiu_flags, pccb->dma_dir);
- ufshcd_prepare_req_desc_hdr(hba, &upiu_flags, pccb->dma_dir); ufshcd_prepare_utp_scsi_cmd_upiu(hba, pccb, upiu_flags); prepare_prdt_table(hba, pccb);
Reviewed-by: Bhupesh Sharma bhupesh.sharma@linaro.org Tested-by: Bhupesh Sharma bhupesh.sharma@linaro.org

Use utp_transfer_req_desc pointer to reference to utrdl queue instead of referencing the queue directly. This makes the code more consistent. No functional change.
Signed-off-by: Marek Vasut marek.vasut+renesas@mailbox.org --- Cc: Bhupesh Sharma bhupesh.sharma@linaro.org Cc: Faiz Abbas faiz_abbas@ti.com --- V2: No change --- drivers/ufs/ufs.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/ufs/ufs.c b/drivers/ufs/ufs.c index da1009e2c14..041caee714f 100644 --- a/drivers/ufs/ufs.c +++ b/drivers/ufs/ufs.c @@ -858,7 +858,9 @@ static inline int ufshcd_get_req_rsp(struct utp_upiu_rsp *ucd_rsp_ptr) */ static inline int ufshcd_get_tr_ocs(struct ufs_hba *hba) { - return le32_to_cpu(hba->utrdl->header.dword_2) & MASK_OCS; + struct utp_transfer_req_desc *req_desc = hba->utrdl; + + return le32_to_cpu(req_desc->header.dword_2) & MASK_OCS; }
static inline int ufshcd_get_rsp_upiu_result(struct utp_upiu_rsp *ucd_rsp_ptr)

On 8/16/23 8:35 PM, Marek Vasut wrote:
Use utp_transfer_req_desc pointer to reference to utrdl queue instead of referencing the queue directly. This makes the code more consistent. No functional change.
Signed-off-by: Marek Vasut marek.vasut+renesas@mailbox.org
Cc: Bhupesh Sharma bhupesh.sharma@linaro.org Cc: Faiz Abbas faiz_abbas@ti.com
V2: No change
drivers/ufs/ufs.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/ufs/ufs.c b/drivers/ufs/ufs.c index da1009e2c14..041caee714f 100644 --- a/drivers/ufs/ufs.c +++ b/drivers/ufs/ufs.c @@ -858,7 +858,9 @@ static inline int ufshcd_get_req_rsp(struct utp_upiu_rsp *ucd_rsp_ptr) */ static inline int ufshcd_get_tr_ocs(struct ufs_hba *hba) {
- return le32_to_cpu(hba->utrdl->header.dword_2) & MASK_OCS;
struct utp_transfer_req_desc *req_desc = hba->utrdl;
return le32_to_cpu(req_desc->header.dword_2) & MASK_OCS; }
static inline int ufshcd_get_rsp_upiu_result(struct utp_upiu_rsp *ucd_rsp_ptr)
Reviewed-by: Bhupesh Sharma bhupesh.sharma@linaro.org Tested-by: Bhupesh Sharma bhupesh.sharma@linaro.org

Add function to flush and invalidate cache over request and response queue entries, and perform flush and optional invalidate over block layer data that are passed into the UFS layer. This makes it possible to use UFS with caches enabled.
Signed-off-by: Marek Vasut marek.vasut+renesas@mailbox.org --- Cc: Bhupesh Sharma bhupesh.sharma@linaro.org Cc: Faiz Abbas faiz_abbas@ti.com --- V2: No change --- drivers/ufs/ufs.c | 42 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-)
diff --git a/drivers/ufs/ufs.c b/drivers/ufs/ufs.c index 041caee714f..7c48d57f99d 100644 --- a/drivers/ufs/ufs.c +++ b/drivers/ufs/ufs.c @@ -692,6 +692,21 @@ static inline u8 ufshcd_get_upmcrs(struct ufs_hba *hba) return (ufshcd_readl(hba, REG_CONTROLLER_STATUS) >> 8) & 0x7; }
+/** + * ufshcd_cache_flush_and_invalidate - Flush and invalidate cache + * + * Flush and invalidate cache in aligned address..address+size range. + * The invalidation is in place to avoid stale data in cache. + */ +static void ufshcd_cache_flush_and_invalidate(void *addr, unsigned long size) +{ + uintptr_t aaddr = (uintptr_t)addr & ~(ARCH_DMA_MINALIGN - 1); + unsigned long asize = ALIGN(size, ARCH_DMA_MINALIGN); + + flush_dcache_range(aaddr, aaddr + asize); + invalidate_dcache_range(aaddr, aaddr + asize); +} + /** * ufshcd_prepare_req_desc_hdr() - Fills the requests header * descriptor according to request @@ -735,6 +750,8 @@ static void ufshcd_prepare_req_desc_hdr(struct ufs_hba *hba, req_desc->header.dword_3 = 0;
req_desc->prd_table_length = 0; + + ufshcd_cache_flush_and_invalidate(req_desc, sizeof(*req_desc)); }
static void ufshcd_prepare_utp_query_req_upiu(struct ufs_hba *hba, @@ -763,10 +780,15 @@ static void ufshcd_prepare_utp_query_req_upiu(struct ufs_hba *hba, memcpy(&ucd_req_ptr->qr, &query->request.upiu_req, QUERY_OSF_SIZE);
/* Copy the Descriptor */ - if (query->request.upiu_req.opcode == UPIU_QUERY_OPCODE_WRITE_DESC) + if (query->request.upiu_req.opcode == UPIU_QUERY_OPCODE_WRITE_DESC) { memcpy(ucd_req_ptr + 1, query->descriptor, len); + ufshcd_cache_flush_and_invalidate(ucd_req_ptr, 2 * sizeof(*ucd_req_ptr)); + } else { + ufshcd_cache_flush_and_invalidate(ucd_req_ptr, sizeof(*ucd_req_ptr)); + }
memset(hba->ucd_rsp_ptr, 0, sizeof(struct utp_upiu_rsp)); + ufshcd_cache_flush_and_invalidate(hba->ucd_rsp_ptr, sizeof(*hba->ucd_rsp_ptr)); }
static inline void ufshcd_prepare_utp_nop_upiu(struct ufs_hba *hba) @@ -783,6 +805,9 @@ static inline void ufshcd_prepare_utp_nop_upiu(struct ufs_hba *hba) ucd_req_ptr->header.dword_2 = 0;
memset(hba->ucd_rsp_ptr, 0, sizeof(struct utp_upiu_rsp)); + + ufshcd_cache_flush_and_invalidate(ucd_req_ptr, sizeof(*ucd_req_ptr)); + ufshcd_cache_flush_and_invalidate(hba->ucd_rsp_ptr, sizeof(*hba->ucd_rsp_ptr)); }
/** @@ -1409,6 +1434,8 @@ void ufshcd_prepare_utp_scsi_cmd_upiu(struct ufs_hba *hba, memcpy(ucd_req_ptr->sc.cdb, pccb->cmd, cdb_len);
memset(hba->ucd_rsp_ptr, 0, sizeof(struct utp_upiu_rsp)); + ufshcd_cache_flush_and_invalidate(ucd_req_ptr, sizeof(*ucd_req_ptr)); + ufshcd_cache_flush_and_invalidate(hba->ucd_rsp_ptr, sizeof(*hba->ucd_rsp_ptr)); }
static inline void prepare_prdt_desc(struct ufshcd_sg_entry *entry, @@ -1423,6 +1450,7 @@ static void prepare_prdt_table(struct ufs_hba *hba, struct scsi_cmd *pccb) { struct utp_transfer_req_desc *req_desc = hba->utrdl; struct ufshcd_sg_entry *prd_table = hba->ucd_prdt_ptr; + uintptr_t aaddr = (uintptr_t)(pccb->pdata) & ~(ARCH_DMA_MINALIGN - 1); ulong datalen = pccb->datalen; int table_length; u8 *buf; @@ -1430,9 +1458,19 @@ static void prepare_prdt_table(struct ufs_hba *hba, struct scsi_cmd *pccb)
if (!datalen) { req_desc->prd_table_length = 0; + ufshcd_cache_flush_and_invalidate(req_desc, sizeof(*req_desc)); return; }
+ if (pccb->dma_dir == DMA_TO_DEVICE) { /* Write to device */ + flush_dcache_range(aaddr, aaddr + + ALIGN(datalen, ARCH_DMA_MINALIGN)); + } + + /* In any case, invalidate cache to avoid stale data in it. */ + invalidate_dcache_range(aaddr, aaddr + + ALIGN(datalen, ARCH_DMA_MINALIGN)); + table_length = DIV_ROUND_UP(pccb->datalen, MAX_PRDT_ENTRY); buf = pccb->pdata; i = table_length; @@ -1446,6 +1484,8 @@ static void prepare_prdt_table(struct ufs_hba *hba, struct scsi_cmd *pccb) prepare_prdt_desc(&prd_table[table_length - i - 1], buf, datalen - 1);
req_desc->prd_table_length = table_length; + ufshcd_cache_flush_and_invalidate(prd_table, sizeof(*prd_table) * table_length); + ufshcd_cache_flush_and_invalidate(req_desc, sizeof(*req_desc)); }
static int ufs_scsi_exec(struct udevice *scsi_dev, struct scsi_cmd *pccb)

On 8/16/23 8:35 PM, Marek Vasut wrote:
Add function to flush and invalidate cache over request and response queue entries, and perform flush and optional invalidate over block layer data that are passed into the UFS layer. This makes it possible to use UFS with caches enabled.
Signed-off-by: Marek Vasut marek.vasut+renesas@mailbox.org
Cc: Bhupesh Sharma bhupesh.sharma@linaro.org Cc: Faiz Abbas faiz_abbas@ti.com
V2: No change
drivers/ufs/ufs.c | 42 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-)
diff --git a/drivers/ufs/ufs.c b/drivers/ufs/ufs.c index 041caee714f..7c48d57f99d 100644 --- a/drivers/ufs/ufs.c +++ b/drivers/ufs/ufs.c @@ -692,6 +692,21 @@ static inline u8 ufshcd_get_upmcrs(struct ufs_hba *hba) return (ufshcd_readl(hba, REG_CONTROLLER_STATUS) >> 8) & 0x7; }
+/**
- ufshcd_cache_flush_and_invalidate - Flush and invalidate cache
- Flush and invalidate cache in aligned address..address+size range.
- The invalidation is in place to avoid stale data in cache.
- */
+static void ufshcd_cache_flush_and_invalidate(void *addr, unsigned long size) +{
- uintptr_t aaddr = (uintptr_t)addr & ~(ARCH_DMA_MINALIGN - 1);
- unsigned long asize = ALIGN(size, ARCH_DMA_MINALIGN);
- flush_dcache_range(aaddr, aaddr + asize);
- invalidate_dcache_range(aaddr, aaddr + asize);
+}
- /**
- ufshcd_prepare_req_desc_hdr() - Fills the requests header
- descriptor according to request
@@ -735,6 +750,8 @@ static void ufshcd_prepare_req_desc_hdr(struct ufs_hba *hba, req_desc->header.dword_3 = 0;
req_desc->prd_table_length = 0;
ufshcd_cache_flush_and_invalidate(req_desc, sizeof(*req_desc)); }
static void ufshcd_prepare_utp_query_req_upiu(struct ufs_hba *hba,
@@ -763,10 +780,15 @@ static void ufshcd_prepare_utp_query_req_upiu(struct ufs_hba *hba, memcpy(&ucd_req_ptr->qr, &query->request.upiu_req, QUERY_OSF_SIZE);
/* Copy the Descriptor */
- if (query->request.upiu_req.opcode == UPIU_QUERY_OPCODE_WRITE_DESC)
if (query->request.upiu_req.opcode == UPIU_QUERY_OPCODE_WRITE_DESC) { memcpy(ucd_req_ptr + 1, query->descriptor, len);
ufshcd_cache_flush_and_invalidate(ucd_req_ptr, 2 * sizeof(*ucd_req_ptr));
} else {
ufshcd_cache_flush_and_invalidate(ucd_req_ptr, sizeof(*ucd_req_ptr));
}
memset(hba->ucd_rsp_ptr, 0, sizeof(struct utp_upiu_rsp));
ufshcd_cache_flush_and_invalidate(hba->ucd_rsp_ptr, sizeof(*hba->ucd_rsp_ptr)); }
static inline void ufshcd_prepare_utp_nop_upiu(struct ufs_hba *hba)
@@ -783,6 +805,9 @@ static inline void ufshcd_prepare_utp_nop_upiu(struct ufs_hba *hba) ucd_req_ptr->header.dword_2 = 0;
memset(hba->ucd_rsp_ptr, 0, sizeof(struct utp_upiu_rsp));
ufshcd_cache_flush_and_invalidate(ucd_req_ptr, sizeof(*ucd_req_ptr));
ufshcd_cache_flush_and_invalidate(hba->ucd_rsp_ptr, sizeof(*hba->ucd_rsp_ptr)); }
/**
@@ -1409,6 +1434,8 @@ void ufshcd_prepare_utp_scsi_cmd_upiu(struct ufs_hba *hba, memcpy(ucd_req_ptr->sc.cdb, pccb->cmd, cdb_len);
memset(hba->ucd_rsp_ptr, 0, sizeof(struct utp_upiu_rsp));
ufshcd_cache_flush_and_invalidate(ucd_req_ptr, sizeof(*ucd_req_ptr));
ufshcd_cache_flush_and_invalidate(hba->ucd_rsp_ptr, sizeof(*hba->ucd_rsp_ptr)); }
static inline void prepare_prdt_desc(struct ufshcd_sg_entry *entry,
@@ -1423,6 +1450,7 @@ static void prepare_prdt_table(struct ufs_hba *hba, struct scsi_cmd *pccb) { struct utp_transfer_req_desc *req_desc = hba->utrdl; struct ufshcd_sg_entry *prd_table = hba->ucd_prdt_ptr;
- uintptr_t aaddr = (uintptr_t)(pccb->pdata) & ~(ARCH_DMA_MINALIGN - 1); ulong datalen = pccb->datalen; int table_length; u8 *buf;
@@ -1430,9 +1458,19 @@ static void prepare_prdt_table(struct ufs_hba *hba, struct scsi_cmd *pccb)
if (!datalen) { req_desc->prd_table_length = 0;
ufshcd_cache_flush_and_invalidate(req_desc, sizeof(*req_desc));
return; }
if (pccb->dma_dir == DMA_TO_DEVICE) { /* Write to device */
flush_dcache_range(aaddr, aaddr +
ALIGN(datalen, ARCH_DMA_MINALIGN));
}
/* In any case, invalidate cache to avoid stale data in it. */
invalidate_dcache_range(aaddr, aaddr +
ALIGN(datalen, ARCH_DMA_MINALIGN));
table_length = DIV_ROUND_UP(pccb->datalen, MAX_PRDT_ENTRY); buf = pccb->pdata; i = table_length;
@@ -1446,6 +1484,8 @@ static void prepare_prdt_table(struct ufs_hba *hba, struct scsi_cmd *pccb) prepare_prdt_desc(&prd_table[table_length - i - 1], buf, datalen - 1);
req_desc->prd_table_length = table_length;
ufshcd_cache_flush_and_invalidate(prd_table, sizeof(*prd_table) * table_length);
ufshcd_cache_flush_and_invalidate(req_desc, sizeof(*req_desc)); }
static int ufs_scsi_exec(struct udevice *scsi_dev, struct scsi_cmd *pccb)
Reviewed-by: Bhupesh Sharma bhupesh.sharma@linaro.org Tested-by: Bhupesh Sharma bhupesh.sharma@linaro.org

On 8/16/23 8:35 PM, Marek Vasut wrote:
Use BIT() macro for quirks, no functional change.
Signed-off-by: Marek Vasut marek.vasut+renesas@mailbox.org
Cc: Bhupesh Sharma bhupesh.sharma@linaro.org Cc: Faiz Abbas faiz_abbas@ti.com
V2: New patch
drivers/ufs/ufs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/ufs/ufs.h b/drivers/ufs/ufs.h index 8a38832b05f..5a5c13aefdf 100644 --- a/drivers/ufs/ufs.h +++ b/drivers/ufs/ufs.h @@ -717,7 +717,7 @@ struct ufs_hba {
- the LCC transmission on UFS device (by clearing TX_LCC_ENABLE
- attribute of device to 0).
*/ -#define UFSHCD_QUIRK_BROKEN_LCC 0x1 +#define UFSHCD_QUIRK_BROKEN_LCC BIT(0)
/* Virtual memory reference */ struct utp_transfer_cmd_desc *ucdl;
Reviewed-by: Bhupesh Sharma bhupesh.sharma@linaro.org
participants (3)
-
Bhupesh Sharma
-
Marek Vasut
-
Tom Rini