From e31931d646d3bc2223d9a275bac9cdc4963c5bc1 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 12 Sep 2024 15:30:03 -0700 Subject: scsi: ufs: core: Make ufshcd_uic_cmd_compl() easier to read Introduce a local variable for the expression hba->active_uic_cmd. Remove superfluous parentheses. No functionality has been changed. Reviewed-by: Bean Huo Reviewed-by: Peter Wang Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20240912223019.3510966-3-bvanassche@acm.org Reviewed-by: Bao D. Nguyen Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) (limited to 'drivers/ufs/core') diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 24a32e2fd75e..8212e2d14256 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -5477,31 +5477,30 @@ static bool ufshcd_is_auto_hibern8_error(struct ufs_hba *hba, static irqreturn_t ufshcd_uic_cmd_compl(struct ufs_hba *hba, u32 intr_status) { irqreturn_t retval = IRQ_NONE; + struct uic_command *cmd; spin_lock(hba->host->host_lock); + cmd = hba->active_uic_cmd; if (ufshcd_is_auto_hibern8_error(hba, intr_status)) hba->errors |= (UFSHCD_UIC_HIBERN8_MASK & intr_status); - if ((intr_status & UIC_COMMAND_COMPL) && hba->active_uic_cmd) { - hba->active_uic_cmd->argument2 |= - ufshcd_get_uic_cmd_result(hba); - hba->active_uic_cmd->argument3 = - ufshcd_get_dme_attr_val(hba); + if (intr_status & UIC_COMMAND_COMPL && cmd) { + cmd->argument2 |= ufshcd_get_uic_cmd_result(hba); + cmd->argument3 = ufshcd_get_dme_attr_val(hba); if (!hba->uic_async_done) - hba->active_uic_cmd->cmd_active = 0; - complete(&hba->active_uic_cmd->done); + cmd->cmd_active = 0; + complete(&cmd->done); retval = IRQ_HANDLED; } - if ((intr_status & UFSHCD_UIC_PWR_MASK) && hba->uic_async_done) { - hba->active_uic_cmd->cmd_active = 0; + if (intr_status & UFSHCD_UIC_PWR_MASK && hba->uic_async_done) { + cmd->cmd_active = 0; complete(hba->uic_async_done); retval = IRQ_HANDLED; } if (retval == IRQ_HANDLED) - ufshcd_add_uic_command_trace(hba, hba->active_uic_cmd, - UFS_CMD_COMP); + ufshcd_add_uic_command_trace(hba, cmd, UFS_CMD_COMP); spin_unlock(hba->host->host_lock); return retval; } -- cgit v1.2.3 From fcd8b0450a9acbf3f0e88d749a72ef932df97663 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 12 Sep 2024 15:30:04 -0700 Subject: scsi: ufs: core: Make ufshcd_uic_cmd_compl() easier to analyze In ufshcd_uic_cmd_compl(), there is code that dereferences 'cmd' with and without checking the 'cmd' pointer. This confuses static source code analyzers like Coverity and sparse. Since none of the code in ufshcd_uic_cmd_compl() can do anything useful if 'cmd' is NULL, move the 'cmd' test near the start of this function. Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20240912223019.3510966-4-bvanassche@acm.org Reviewed-by: Peter Wang Reviewed-by: Bao D. Nguyen Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/ufs/core') diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 8212e2d14256..0c803b6f2221 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -5481,10 +5481,13 @@ static irqreturn_t ufshcd_uic_cmd_compl(struct ufs_hba *hba, u32 intr_status) spin_lock(hba->host->host_lock); cmd = hba->active_uic_cmd; + if (WARN_ON_ONCE(!cmd)) + goto unlock; + if (ufshcd_is_auto_hibern8_error(hba, intr_status)) hba->errors |= (UFSHCD_UIC_HIBERN8_MASK & intr_status); - if (intr_status & UIC_COMMAND_COMPL && cmd) { + if (intr_status & UIC_COMMAND_COMPL) { cmd->argument2 |= ufshcd_get_uic_cmd_result(hba); cmd->argument3 = ufshcd_get_dme_attr_val(hba); if (!hba->uic_async_done) @@ -5501,7 +5504,10 @@ static irqreturn_t ufshcd_uic_cmd_compl(struct ufs_hba *hba, u32 intr_status) if (retval == IRQ_HANDLED) ufshcd_add_uic_command_trace(hba, cmd, UFS_CMD_COMP); + +unlock: spin_unlock(hba->host->host_lock); + return retval; } -- cgit v1.2.3 From b1e8c53749adb795bfb0bf4e2f7836e26684bb90 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 12 Sep 2024 15:30:05 -0700 Subject: scsi: ufs: core: Always initialize the UIC done completion Simplify __ufshcd_send_uic_cmd() by always initializing the uic_cmd::done completion. This is fine since the time required to initialize a completion is small compared to the time required to process an UIC command. Reviewed-by: Peter Wang Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20240912223019.3510966-5-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'drivers/ufs/core') diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 0c803b6f2221..d6528048c77f 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -2551,13 +2551,11 @@ ufshcd_wait_for_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd) * __ufshcd_send_uic_cmd - Send UIC commands and retrieve the result * @hba: per adapter instance * @uic_cmd: UIC command - * @completion: initialize the completion only if this is set to true * * Return: 0 only if success. */ static int -__ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd, - bool completion) +__ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd) { lockdep_assert_held(&hba->uic_cmd_mutex); @@ -2567,8 +2565,7 @@ __ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd, return -EIO; } - if (completion) - init_completion(&uic_cmd->done); + init_completion(&uic_cmd->done); uic_cmd->cmd_active = 1; ufshcd_dispatch_uic_cmd(hba, uic_cmd); @@ -2594,7 +2591,7 @@ int ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd) mutex_lock(&hba->uic_cmd_mutex); ufshcd_add_delay_before_dme_cmd(hba); - ret = __ufshcd_send_uic_cmd(hba, uic_cmd, true); + ret = __ufshcd_send_uic_cmd(hba, uic_cmd); if (!ret) ret = ufshcd_wait_for_uic_cmd(hba, uic_cmd); @@ -4289,7 +4286,7 @@ static int ufshcd_uic_pwr_ctrl(struct ufs_hba *hba, struct uic_command *cmd) reenable_intr = true; } spin_unlock_irqrestore(hba->host->host_lock, flags); - ret = __ufshcd_send_uic_cmd(hba, cmd, false); + ret = __ufshcd_send_uic_cmd(hba, cmd); if (ret) { dev_err(hba->dev, "pwr ctrl cmd 0x%x with mode 0x%x uic error %d\n", -- cgit v1.2.3 From 71ef4e6b05ae0a1b6bd8ba864815b01e041dfd10 Mon Sep 17 00:00:00 2001 From: Avri Altman Date: Thu, 19 Sep 2024 14:24:42 +0300 Subject: scsi: ufs: core: Do not open code read_poll_timeout ufshcd_wait_for_register() practically does just that - replace with read_poll_timeout. Signed-off-by: Avri Altman Link: https://lore.kernel.org/r/20240919112442.48491-1-avri.altman@wdc.com Reviewed-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) (limited to 'drivers/ufs/core') diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index d6528048c77f..14a41d7c2d1a 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -739,25 +739,15 @@ EXPORT_SYMBOL_GPL(ufshcd_delay_us); * Return: -ETIMEDOUT on error, zero on success. */ static int ufshcd_wait_for_register(struct ufs_hba *hba, u32 reg, u32 mask, - u32 val, unsigned long interval_us, - unsigned long timeout_ms) + u32 val, unsigned long interval_us, + unsigned long timeout_ms) { - int err = 0; - unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms); - - /* ignore bits that we don't intend to wait on */ - val = val & mask; + u32 v; - while ((ufshcd_readl(hba, reg) & mask) != val) { - usleep_range(interval_us, interval_us + 50); - if (time_after(jiffies, timeout)) { - if ((ufshcd_readl(hba, reg) & mask) != val) - err = -ETIMEDOUT; - break; - } - } + val &= mask; /* ignore bits that we don't intend to wait on */ - return err; + return read_poll_timeout(ufshcd_readl, v, (v & mask) == val, + interval_us, timeout_ms * 1000, false, hba, reg); } /** -- cgit v1.2.3 From 43abe48d95fee8816f79e085ea9c86e4f65607e7 Mon Sep 17 00:00:00 2001 From: Avri Altman Date: Sat, 21 Sep 2024 09:23:06 +0300 Subject: scsi: ufs: core: Zero utp_upiu_req at the beginning of each command This patch introduces a previously missing step: zeroing the 'utp_upiu_req' structure at the beginning of each upiu transaction. This ensures that the upiu request fields are properly initialized, preventing potential issues caused by residual data from previous commands. While at it, re-use some of the common initializations for query and command upiu. Reviewed-by: Bart Van Assche Signed-off-by: Avri Altman Link: https://lore.kernel.org/r/20240921062306.56019-1-avri.altman@wdc.com Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) (limited to 'drivers/ufs/core') diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 14a41d7c2d1a..9e6d008f4ea4 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -2762,7 +2762,6 @@ void ufshcd_prepare_utp_scsi_cmd_upiu(struct ufshcd_lrb *lrbp, u8 upiu_flags) ucd_req_ptr->sc.exp_data_transfer_len = cpu_to_be32(cmd->sdb.length); cdb_len = min_t(unsigned short, cmd->cmd_len, UFS_CDB_SIZE); - memset(ucd_req_ptr->sc.cdb, 0, UFS_CDB_SIZE); memcpy(ucd_req_ptr->sc.cdb, cmd->cmnd, cdb_len); memset(lrbp->ucd_rsp_ptr, 0, sizeof(struct utp_upiu_rsp)); @@ -2865,6 +2864,26 @@ static void ufshcd_comp_scsi_upiu(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) ufshcd_prepare_utp_scsi_cmd_upiu(lrbp, upiu_flags); } +static void __ufshcd_setup_cmd(struct ufshcd_lrb *lrbp, struct scsi_cmnd *cmd, u8 lun, int tag) +{ + memset(lrbp->ucd_req_ptr, 0, sizeof(*lrbp->ucd_req_ptr)); + + lrbp->cmd = cmd; + lrbp->task_tag = tag; + lrbp->lun = lun; + ufshcd_prepare_lrbp_crypto(cmd ? scsi_cmd_to_rq(cmd) : NULL, lrbp); +} + +static void ufshcd_setup_scsi_cmd(struct ufs_hba *hba, struct ufshcd_lrb *lrbp, + struct scsi_cmnd *cmd, u8 lun, int tag) +{ + __ufshcd_setup_cmd(lrbp, cmd, lun, tag); + lrbp->intr_cmd = !ufshcd_is_intr_aggr_allowed(hba); + lrbp->req_abort_skip = false; + + ufshcd_comp_scsi_upiu(hba, lrbp); +} + /** * ufshcd_upiu_wlun_to_scsi_wlun - maps UPIU W-LUN id to SCSI W-LUN ID * @upiu_wlun_id: UPIU W-LUN id @@ -2998,16 +3017,8 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) ufshcd_hold(hba); lrbp = &hba->lrb[tag]; - lrbp->cmd = cmd; - lrbp->task_tag = tag; - lrbp->lun = ufshcd_scsi_to_upiu_lun(cmd->device->lun); - lrbp->intr_cmd = !ufshcd_is_intr_aggr_allowed(hba); - ufshcd_prepare_lrbp_crypto(scsi_cmd_to_rq(cmd), lrbp); - - lrbp->req_abort_skip = false; - - ufshcd_comp_scsi_upiu(hba, lrbp); + ufshcd_setup_scsi_cmd(hba, lrbp, cmd, ufshcd_scsi_to_upiu_lun(cmd->device->lun), tag); err = ufshcd_map_sg(hba, lrbp); if (err) { @@ -3035,11 +3046,8 @@ out: static void ufshcd_setup_dev_cmd(struct ufs_hba *hba, struct ufshcd_lrb *lrbp, enum dev_cmd_type cmd_type, u8 lun, int tag) { - lrbp->cmd = NULL; - lrbp->task_tag = tag; - lrbp->lun = lun; + __ufshcd_setup_cmd(lrbp, NULL, lun, tag); lrbp->intr_cmd = true; /* No interrupt aggregation */ - ufshcd_prepare_lrbp_crypto(NULL, lrbp); hba->dev_cmd.type = cmd_type; } -- cgit v1.2.3 From 10c58d7eea443c6961135a7f16f9fa03bf8e5823 Mon Sep 17 00:00:00 2001 From: SEO HOYOUNG Date: Thu, 10 Oct 2024 16:52:28 +0900 Subject: scsi: ufs: core: check asymmetric connected lanes Performance problems may occur if there is a problem with the asymmetric connected lane such as h/w failure. Currently, only check connected lane for rx/tx is checked if it is not 0. But it should also be checked if it is asymmetrically connected. Signed-off-by: SEO HOYOUNG Link: https://lore.kernel.org/r/e82b4b65b5f6501a687c624dd06e5c362e160f32.1728544727.git.hy50.seo@samsung.com Reviewed-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/ufs/core') diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 9e6d008f4ea4..945253eb590e 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -4535,6 +4535,14 @@ static int ufshcd_get_max_pwr_mode(struct ufs_hba *hba) return -EINVAL; } + if (pwr_info->lane_rx != pwr_info->lane_tx) { + dev_err(hba->dev, "%s: asymmetric connected lanes. rx=%d, tx=%d\n", + __func__, + pwr_info->lane_rx, + pwr_info->lane_tx); + return -EINVAL; + } + /* * First, get the maximum gears of HS speed. * If a zero value, it means there is no HSGEAR capability. -- cgit v1.2.3 From 6c1143bb5d122ec542b10288bfca183788c547e8 Mon Sep 17 00:00:00 2001 From: Avri Altman Date: Wed, 16 Oct 2024 13:21:41 +0300 Subject: scsi: ufs: core: Use ufshcd_wait_for_register() in HCE init The current so called "inner loop" in ufshcd_hba_execute_hce() is open coding ufshcd_wait_for_register(). Replace it by ufshcd_wait_for_register(). This is a code simplification - no functional change. Signed-off-by: Avri Altman Link: https://lore.kernel.org/r/20241016102141.441382-1-avri.altman@wdc.com Reviewed-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 67 +++++++++++++++++++++-------------------------- 1 file changed, 30 insertions(+), 37 deletions(-) (limited to 'drivers/ufs/core') diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 945253eb590e..f2b3e7e45ea2 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -4826,51 +4826,44 @@ EXPORT_SYMBOL_GPL(ufshcd_hba_stop); */ static int ufshcd_hba_execute_hce(struct ufs_hba *hba) { - int retry_outer = 3; - int retry_inner; + int retry; -start: - if (ufshcd_is_hba_active(hba)) - /* change controller state to "reset state" */ - ufshcd_hba_stop(hba); + for (retry = 3; retry > 0; retry--) { + if (ufshcd_is_hba_active(hba)) + /* change controller state to "reset state" */ + ufshcd_hba_stop(hba); - /* UniPro link is disabled at this point */ - ufshcd_set_link_off(hba); + /* UniPro link is disabled at this point */ + ufshcd_set_link_off(hba); - ufshcd_vops_hce_enable_notify(hba, PRE_CHANGE); + ufshcd_vops_hce_enable_notify(hba, PRE_CHANGE); - /* start controller initialization sequence */ - ufshcd_hba_start(hba); + /* start controller initialization sequence */ + ufshcd_hba_start(hba); - /* - * To initialize a UFS host controller HCE bit must be set to 1. - * During initialization the HCE bit value changes from 1->0->1. - * When the host controller completes initialization sequence - * it sets the value of HCE bit to 1. The same HCE bit is read back - * to check if the controller has completed initialization sequence. - * So without this delay the value HCE = 1, set in the previous - * instruction might be read back. - * This delay can be changed based on the controller. - */ - ufshcd_delay_us(hba->vps->hba_enable_delay_us, 100); + /* + * To initialize a UFS host controller HCE bit must be set to 1. + * During initialization the HCE bit value changes from 1->0->1. + * When the host controller completes initialization sequence + * it sets the value of HCE bit to 1. The same HCE bit is read back + * to check if the controller has completed initialization sequence. + * So without this delay the value HCE = 1, set in the previous + * instruction might be read back. + * This delay can be changed based on the controller. + */ + ufshcd_delay_us(hba->vps->hba_enable_delay_us, 100); - /* wait for the host controller to complete initialization */ - retry_inner = 50; - while (!ufshcd_is_hba_active(hba)) { - if (retry_inner) { - retry_inner--; - } else { - dev_err(hba->dev, - "Controller enable failed\n"); - if (retry_outer) { - retry_outer--; - goto start; - } - return -EIO; - } - usleep_range(1000, 1100); + /* wait for the host controller to complete initialization */ + if (!ufshcd_wait_for_register(hba, REG_CONTROLLER_ENABLE, CONTROLLER_ENABLE, + CONTROLLER_ENABLE, 1000, 50)) + break; + + dev_err(hba->dev, "Enabling the controller failed\n"); } + if (!retry) + return -EIO; + /* enable UIC related interrupts */ ufshcd_enable_intr(hba, UFSHCD_UIC_MASK); -- cgit v1.2.3 From 78bc671bd1501e2f6c571e063301a4fdc5db53b2 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 18 Oct 2024 12:47:39 -0700 Subject: scsi: ufs: core: Make DMA mask configuration more flexible Replace UFSHCD_QUIRK_BROKEN_64BIT_ADDRESS with ufs_hba_variant_ops::set_dma_mask. Update the Renesas driver accordingly. This patch enables supporting other configurations than 32-bit or 64-bit DMA addresses, e.g. 36-bit DMA addresses. Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20241018194753.775074-1-bvanassche@acm.org Reviewed-by: Avri Altman Reviewed-by: Peter Wang Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 4 ++-- drivers/ufs/host/ufs-renesas.c | 9 ++++++++- include/ufs/ufshcd.h | 9 +++------ 3 files changed, 13 insertions(+), 9 deletions(-) (limited to 'drivers/ufs/core') diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index f2b3e7e45ea2..2877e487637d 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -2401,8 +2401,6 @@ static inline int ufshcd_hba_capabilities(struct ufs_hba *hba) int err; hba->capabilities = ufshcd_readl(hba, REG_CONTROLLER_CAPABILITIES); - if (hba->quirks & UFSHCD_QUIRK_BROKEN_64BIT_ADDRESS) - hba->capabilities &= ~MASK_64_ADDRESSING_SUPPORT; /* nutrs and nutmrs are 0 based values */ hba->nutrs = (hba->capabilities & MASK_TRANSFER_REQUESTS_SLOTS_SDB) + 1; @@ -10315,6 +10313,8 @@ EXPORT_SYMBOL_GPL(ufshcd_dealloc_host); */ static int ufshcd_set_dma_mask(struct ufs_hba *hba) { + if (hba->vops && hba->vops->set_dma_mask) + return hba->vops->set_dma_mask(hba); if (hba->capabilities & MASK_64_ADDRESSING_SUPPORT) { if (!dma_set_mask_and_coherent(hba->dev, DMA_BIT_MASK(64))) return 0; diff --git a/drivers/ufs/host/ufs-renesas.c b/drivers/ufs/host/ufs-renesas.c index 8711e5cbc968..3ff97112e1f6 100644 --- a/drivers/ufs/host/ufs-renesas.c +++ b/drivers/ufs/host/ufs-renesas.c @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -364,14 +365,20 @@ static int ufs_renesas_init(struct ufs_hba *hba) return -ENOMEM; ufshcd_set_variant(hba, priv); - hba->quirks |= UFSHCD_QUIRK_BROKEN_64BIT_ADDRESS | UFSHCD_QUIRK_HIBERN_FASTAUTO; + hba->quirks |= UFSHCD_QUIRK_HIBERN_FASTAUTO; return 0; } +static int ufs_renesas_set_dma_mask(struct ufs_hba *hba) +{ + return dma_set_mask_and_coherent(hba->dev, DMA_BIT_MASK(32)); +} + static const struct ufs_hba_variant_ops ufs_renesas_vops = { .name = "renesas", .init = ufs_renesas_init, + .set_dma_mask = ufs_renesas_set_dma_mask, .setup_clocks = ufs_renesas_setup_clocks, .hce_enable_notify = ufs_renesas_hce_enable_notify, .dbg_register_dump = ufs_renesas_dbg_register_dump, diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h index a95282b9f743..a2d600ff4372 100644 --- a/include/ufs/ufshcd.h +++ b/include/ufs/ufshcd.h @@ -299,6 +299,8 @@ struct ufs_pwr_mode_info { * @max_num_rtt: maximum RTT supported by the host * @init: called when the driver is initialized * @exit: called to cleanup everything done in init + * @set_dma_mask: For setting another DMA mask than indicated by the 64AS + * capability bit. * @get_ufs_hci_version: called to get UFS HCI version * @clk_scale_notify: notifies that clks are scaled up/down * @setup_clocks: called before touching any of the controller registers @@ -341,6 +343,7 @@ struct ufs_hba_variant_ops { int (*init)(struct ufs_hba *); void (*exit)(struct ufs_hba *); u32 (*get_ufs_hci_version)(struct ufs_hba *); + int (*set_dma_mask)(struct ufs_hba *); int (*clk_scale_notify)(struct ufs_hba *, bool, enum ufs_notify_change_status); int (*setup_clocks)(struct ufs_hba *, bool, @@ -623,12 +626,6 @@ enum ufshcd_quirks { */ UFSHCD_QUIRK_SKIP_PH_CONFIGURATION = 1 << 16, - /* - * This quirk needs to be enabled if the host controller has - * 64-bit addressing supported capability but it doesn't work. - */ - UFSHCD_QUIRK_BROKEN_64BIT_ADDRESS = 1 << 17, - /* * This quirk needs to be enabled if the host controller has * auto-hibernate capability but it's FASTAUTO only. -- cgit v1.2.3 From a085e03758b87ee5aea45de27c811576574d795b Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 22 Oct 2024 12:30:57 -0700 Subject: scsi: ufs: core: Move the ufshcd_mcq_enable_esi() definition Move the ufshcd_mcq_enable_esi() definition such that it occurs immediately before the ufshcd_mcq_config_esi() definition. Reviewed-by: Peter Wang Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20241022193130.2733293-2-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufs-mcq.c | 14 +++++++------- include/ufs/ufshcd.h | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/ufs/core') diff --git a/drivers/ufs/core/ufs-mcq.c b/drivers/ufs/core/ufs-mcq.c index 5891cdacd0b3..57ced1729b73 100644 --- a/drivers/ufs/core/ufs-mcq.c +++ b/drivers/ufs/core/ufs-mcq.c @@ -417,13 +417,6 @@ void ufshcd_mcq_make_queues_operational(struct ufs_hba *hba) } EXPORT_SYMBOL_GPL(ufshcd_mcq_make_queues_operational); -void ufshcd_mcq_enable_esi(struct ufs_hba *hba) -{ - ufshcd_writel(hba, ufshcd_readl(hba, REG_UFS_MEM_CFG) | 0x2, - REG_UFS_MEM_CFG); -} -EXPORT_SYMBOL_GPL(ufshcd_mcq_enable_esi); - void ufshcd_mcq_enable(struct ufs_hba *hba) { ufshcd_rmwl(hba, MCQ_MODE_SELECT, MCQ_MODE_SELECT, REG_UFS_MEM_CFG); @@ -437,6 +430,13 @@ void ufshcd_mcq_disable(struct ufs_hba *hba) hba->mcq_enabled = false; } +void ufshcd_mcq_enable_esi(struct ufs_hba *hba) +{ + ufshcd_writel(hba, ufshcd_readl(hba, REG_UFS_MEM_CFG) | 0x2, + REG_UFS_MEM_CFG); +} +EXPORT_SYMBOL_GPL(ufshcd_mcq_enable_esi); + void ufshcd_mcq_config_esi(struct ufs_hba *hba, struct msi_msg *msg) { ufshcd_writel(hba, msg->address_lo, REG_UFS_ESILBA); diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h index a2d600ff4372..d2dad221c12b 100644 --- a/include/ufs/ufshcd.h +++ b/include/ufs/ufshcd.h @@ -1318,8 +1318,8 @@ void ufshcd_mcq_write_cqis(struct ufs_hba *hba, u32 val, int i); unsigned long ufshcd_mcq_poll_cqe_lock(struct ufs_hba *hba, struct ufs_hw_queue *hwq); void ufshcd_mcq_make_queues_operational(struct ufs_hba *hba); -void ufshcd_mcq_enable_esi(struct ufs_hba *hba); void ufshcd_mcq_enable(struct ufs_hba *hba); +void ufshcd_mcq_enable_esi(struct ufs_hba *hba); void ufshcd_mcq_config_esi(struct ufs_hba *hba, struct msi_msg *msg); int ufshcd_opp_config_clks(struct device *dev, struct opp_table *opp_table, -- cgit v1.2.3 From 7df89440d0ec47a4d91c5d664a6fa33931800913 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 22 Oct 2024 12:30:58 -0700 Subject: scsi: ufs: core: Remove goto statements from ufshcd_try_to_abort_task() The only statement that follows the 'out:' label in ufshcd_try_to_abort_task() is a return-statement. Simplify this function by changing 'goto out' statements into return statements. Reviewed-by: Avri Altman Reviewed-by: Peter Wang Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20241022193130.2733293-3-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) (limited to 'drivers/ufs/core') diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 2877e487637d..ac69e6426d39 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -7485,7 +7485,7 @@ static void ufshcd_set_req_abort_skip(struct ufs_hba *hba, unsigned long bitmap) int ufshcd_try_to_abort_task(struct ufs_hba *hba, int tag) { struct ufshcd_lrb *lrbp = &hba->lrb[tag]; - int err = 0; + int err; int poll_cnt; u8 resp = 0xF; u32 reg; @@ -7515,7 +7515,7 @@ int ufshcd_try_to_abort_task(struct ufs_hba *hba, int tag) /* command completed already */ dev_err(hba->dev, "%s: cmd at tag=%d is cleared.\n", __func__, tag); - goto out; + return 0; } /* Single Doorbell Mode */ @@ -7528,21 +7528,17 @@ int ufshcd_try_to_abort_task(struct ufs_hba *hba, int tag) /* command completed already */ dev_err(hba->dev, "%s: cmd at tag %d successfully cleared from DB.\n", __func__, tag); - goto out; + return 0; } else { dev_err(hba->dev, "%s: no response from device. tag = %d, err %d\n", __func__, tag, err); - if (!err) - err = resp; /* service response error */ - goto out; + return err ? : resp; } } - if (!poll_cnt) { - err = -EBUSY; - goto out; - } + if (!poll_cnt) + return -EBUSY; err = ufshcd_issue_tm_cmd(hba, lrbp->lun, lrbp->task_tag, UFS_ABORT_TASK, &resp); @@ -7552,7 +7548,7 @@ int ufshcd_try_to_abort_task(struct ufs_hba *hba, int tag) dev_err(hba->dev, "%s: issued. tag = %d, err %d\n", __func__, tag, err); } - goto out; + return err; } err = ufshcd_clear_cmd(hba, tag); @@ -7560,7 +7556,6 @@ int ufshcd_try_to_abort_task(struct ufs_hba *hba, int tag) dev_err(hba->dev, "%s: Failed clearing cmd at tag %d, err %d\n", __func__, tag, err); -out: return err; } -- cgit v1.2.3 From 9a5f6c09d0fa5a7b2139a745368e0ef77dece34b Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 22 Oct 2024 12:30:59 -0700 Subject: scsi: ufs: core: Simplify ufshcd_try_to_abort_task() The MCQ code is also valid for legacy mode. Hence, remove the legacy mode code and retain the MCQ code. Since it is not an error if a command completes while ufshcd_try_to_abort_task() is in progress, use dev_info() instead of dev_err() to report this. Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20241022193130.2733293-4-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 32 ++++++++------------------------ 1 file changed, 8 insertions(+), 24 deletions(-) (limited to 'drivers/ufs/core') diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index ac69e6426d39..86e745b7e6bb 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -7488,7 +7488,6 @@ int ufshcd_try_to_abort_task(struct ufs_hba *hba, int tag) int err; int poll_cnt; u8 resp = 0xF; - u32 reg; for (poll_cnt = 100; poll_cnt; poll_cnt--) { err = ufshcd_issue_tm_cmd(hba, lrbp->lun, lrbp->task_tag, @@ -7503,32 +7502,17 @@ int ufshcd_try_to_abort_task(struct ufs_hba *hba, int tag) * cmd not pending in the device, check if it is * in transition. */ - dev_err(hba->dev, "%s: cmd at tag %d not pending in the device.\n", + dev_info( + hba->dev, + "%s: cmd with tag %d not pending in the device.\n", __func__, tag); - if (hba->mcq_enabled) { - /* MCQ mode */ - if (ufshcd_cmd_inflight(lrbp->cmd)) { - /* sleep for max. 200us same delay as in SDB mode */ - usleep_range(100, 200); - continue; - } - /* command completed already */ - dev_err(hba->dev, "%s: cmd at tag=%d is cleared.\n", - __func__, tag); + if (!ufshcd_cmd_inflight(lrbp->cmd)) { + dev_info(hba->dev, + "%s: cmd with tag=%d completed.\n", + __func__, tag); return 0; } - - /* Single Doorbell Mode */ - reg = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL); - if (reg & (1 << tag)) { - /* sleep for max. 200us to stabilize */ - usleep_range(100, 200); - continue; - } - /* command completed already */ - dev_err(hba->dev, "%s: cmd at tag %d successfully cleared from DB.\n", - __func__, tag); - return 0; + usleep_range(100, 200); } else { dev_err(hba->dev, "%s: no response from device. tag = %d, err %d\n", -- cgit v1.2.3 From b5d9da58a05172ec08301e06932338ade6d55f82 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 22 Oct 2024 12:31:00 -0700 Subject: scsi: ufs: core: Simplify ufshcd_exception_event_handler() The ufshcd_scsi_block_requests() and ufshcd_scsi_unblock_requests() calls were introduced in ufshcd_exception_event_handler() to prevent that querying the exception event information would time out. Commit 10fe5888a40e ("scsi: ufs: increase the scsi query response timeout") increased the timeout for querying exception information from 30 ms to 1.5 s and thereby eliminated the risk that a timeout would happen. Hence, the calls to block and unblock SCSI requests are superfluous. Remove these calls. Reviewed-by: Peter Wang Tested-by: Avri Altman Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20241022193130.2733293-5-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers/ufs/core') diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 86e745b7e6bb..656a09cd48e4 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -6194,12 +6194,11 @@ static void ufshcd_exception_event_handler(struct work_struct *work) u32 status = 0; hba = container_of(work, struct ufs_hba, eeh_work); - ufshcd_scsi_block_requests(hba); err = ufshcd_get_ee_status(hba, &status); if (err) { dev_err(hba->dev, "%s: failed to get exception status %d\n", __func__, err); - goto out; + return; } trace_ufshcd_exception_event(dev_name(hba->dev), status); @@ -6211,8 +6210,6 @@ static void ufshcd_exception_event_handler(struct work_struct *work) ufshcd_temp_exception_event_handler(hba, status); ufs_debugfs_exception_event(hba, status); -out: - ufshcd_scsi_unblock_requests(hba); } /* Complete requests that have door-bell cleared */ -- cgit v1.2.3 From 2a36646012fc58e6262435ff5d2c8c97456c253f Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 22 Oct 2024 12:31:01 -0700 Subject: scsi: ufs: core: Simplify ufshcd_err_handling_prepare() Use blk_mq_quiesce_tagset() instead of ufshcd_scsi_block_requests() and blk_mq_wait_quiesce_done(). Since this patch removes the last callers of ufshcd_scsi_block_requests() and ufshcd_scsi_unblock_requests(), remove these functions. Reviewed-by: Avri Altman Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20241022193130.2733293-6-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 19 +++---------------- include/ufs/ufshcd.h | 2 -- 2 files changed, 3 insertions(+), 18 deletions(-) (limited to 'drivers/ufs/core') diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 656a09cd48e4..c156c4787528 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -349,18 +349,6 @@ static void ufshcd_configure_wb(struct ufs_hba *hba) ufshcd_wb_toggle_buf_flush(hba, true); } -static void ufshcd_scsi_unblock_requests(struct ufs_hba *hba) -{ - if (atomic_dec_and_test(&hba->scsi_block_reqs_cnt)) - scsi_unblock_requests(hba->host); -} - -static void ufshcd_scsi_block_requests(struct ufs_hba *hba) -{ - if (atomic_inc_return(&hba->scsi_block_reqs_cnt) == 1) - scsi_block_requests(hba->host); -} - static void ufshcd_add_cmd_upiu_trace(struct ufs_hba *hba, unsigned int tag, enum ufs_trace_str_t str_t) { @@ -6375,15 +6363,14 @@ static void ufshcd_err_handling_prepare(struct ufs_hba *hba) ufshcd_suspend_clkscaling(hba); ufshcd_clk_scaling_allow(hba, false); } - ufshcd_scsi_block_requests(hba); /* Wait for ongoing ufshcd_queuecommand() calls to finish. */ - blk_mq_wait_quiesce_done(&hba->host->tag_set); + blk_mq_quiesce_tagset(&hba->host->tag_set); cancel_work_sync(&hba->eeh_work); } static void ufshcd_err_handling_unprepare(struct ufs_hba *hba) { - ufshcd_scsi_unblock_requests(hba); + blk_mq_unquiesce_tagset(&hba->host->tag_set); ufshcd_release(hba); if (ufshcd_is_clkscaling_supported(hba)) ufshcd_clk_scaling_suspend(hba, false); @@ -10558,7 +10545,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) /* Hold auto suspend until async scan completes */ pm_runtime_get_sync(dev); - atomic_set(&hba->scsi_block_reqs_cnt, 0); + /* * We are assuming that device wasn't put in sleep/power-down * state exclusively during the boot stage before kernel. diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h index d2dad221c12b..9ea2a7411bb5 100644 --- a/include/ufs/ufshcd.h +++ b/include/ufs/ufshcd.h @@ -925,7 +925,6 @@ enum ufshcd_mcq_opr { * @wb_mutex: used to serialize devfreq and sysfs write booster toggling * @clk_scaling_lock: used to serialize device commands and clock scaling * @desc_size: descriptor sizes reported by device - * @scsi_block_reqs_cnt: reference counting for scsi block requests * @bsg_dev: struct device associated with the BSG queue * @bsg_queue: BSG queue associated with the UFS controller * @rpm_dev_flush_recheck_work: used to suspend from RPM (runtime power @@ -1086,7 +1085,6 @@ struct ufs_hba { struct mutex wb_mutex; struct rw_semaphore clk_scaling_lock; - atomic_t scsi_block_reqs_cnt; struct device bsg_dev; struct request_queue *bsg_queue; -- cgit v1.2.3 From 2c73fb138da587597c2b02e72dcbeae18af60f4e Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 22 Oct 2024 12:31:02 -0700 Subject: scsi: ufs: core: Improve ufshcd_mcq_sq_cleanup() From the UFSHCI specification: "CleanUp Command Return Code (RTC): host controller sets this return code to provide more details of the cleanup process. It is valid only when CUS is 1." Hence, do not read RTC if the CUS bitfield is zero. Cc: Bao D. Nguyen Fixes: 8d7290348992 ("scsi: ufs: mcq: Add supporting functions for MCQ abort") Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20241022193130.2733293-7-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufs-mcq.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers/ufs/core') diff --git a/drivers/ufs/core/ufs-mcq.c b/drivers/ufs/core/ufs-mcq.c index 57ced1729b73..988400500560 100644 --- a/drivers/ufs/core/ufs-mcq.c +++ b/drivers/ufs/core/ufs-mcq.c @@ -572,14 +572,18 @@ int ufshcd_mcq_sq_cleanup(struct ufs_hba *hba, int task_tag) /* SQRTCy.ICU = 1 */ writel(SQ_ICU, opr_sqd_base + REG_SQRTC); - /* Poll SQRTSy.CUS = 1. Return result from SQRTSy.RTC */ + /* Wait until SQRTSy.CUS = 1. Report SQRTSy.RTC. */ reg = opr_sqd_base + REG_SQRTS; err = read_poll_timeout(readl, val, val & SQ_CUS, 20, MCQ_POLL_US, false, reg); if (err) - dev_err(hba->dev, "%s: failed. hwq=%d, tag=%d err=%ld\n", - __func__, id, task_tag, - FIELD_GET(SQ_ICU_ERR_CODE_MASK, readl(reg))); + dev_err(hba->dev, "%s: failed. hwq=%d, tag=%d err=%d\n", + __func__, id, task_tag, err); + else + dev_info(hba->dev, + "%s, hwq %d: cleanup return code (RTC) %ld\n", + __func__, id, + FIELD_GET(SQ_ICU_ERR_CODE_MASK, readl(reg))); if (ufshcd_mcq_sq_start(hba, hwq)) err = -ETIMEDOUT; -- cgit v1.2.3 From 2b314e182caabd32f656ddba22432a7749572013 Mon Sep 17 00:00:00 2001 From: Avri Altman Date: Thu, 24 Oct 2024 10:50:31 +0300 Subject: scsi: ufs: core: Remove redundant host_lock calls around UTMRLDBR There is no need to serialize single read/write calls to the host controller registers. Remove the redundant host_lock calls that protect access to the task management doorbell register: UTMRLDBR. Signed-off-by: Avri Altman Link: https://lore.kernel.org/r/20241024075033.562562-2-avri.altman@wdc.com Reviewed-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'drivers/ufs/core') diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index c156c4787528..5827575204fa 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -1233,11 +1233,13 @@ static bool ufshcd_is_devfreq_scaling_required(struct ufs_hba *hba, static u32 ufshcd_pending_cmds(struct ufs_hba *hba) { const struct scsi_device *sdev; + unsigned long flags; u32 pending = 0; - lockdep_assert_held(hba->host->host_lock); + spin_lock_irqsave(hba->host->host_lock, flags); __shost_for_each_device(sdev, hba->host) pending += sbitmap_weight(&sdev->budget_map); + spin_unlock_irqrestore(hba->host->host_lock, flags); return pending; } @@ -1251,7 +1253,6 @@ static u32 ufshcd_pending_cmds(struct ufs_hba *hba) static int ufshcd_wait_for_doorbell_clr(struct ufs_hba *hba, u64 wait_timeout_us) { - unsigned long flags; int ret = 0; u32 tm_doorbell; u32 tr_pending; @@ -1259,7 +1260,6 @@ static int ufshcd_wait_for_doorbell_clr(struct ufs_hba *hba, ktime_t start; ufshcd_hold(hba); - spin_lock_irqsave(hba->host->host_lock, flags); /* * Wait for all the outstanding tasks/transfer requests. * Verify by checking the doorbell registers are clear. @@ -1280,7 +1280,6 @@ static int ufshcd_wait_for_doorbell_clr(struct ufs_hba *hba, break; } - spin_unlock_irqrestore(hba->host->host_lock, flags); io_schedule_timeout(msecs_to_jiffies(20)); if (ktime_to_us(ktime_sub(ktime_get(), start)) > wait_timeout_us) { @@ -1292,7 +1291,6 @@ static int ufshcd_wait_for_doorbell_clr(struct ufs_hba *hba, */ do_last_check = true; } - spin_lock_irqsave(hba->host->host_lock, flags); } while (tm_doorbell || tr_pending); if (timeout) { @@ -1302,7 +1300,6 @@ static int ufshcd_wait_for_doorbell_clr(struct ufs_hba *hba, ret = -EBUSY; } out: - spin_unlock_irqrestore(hba->host->host_lock, flags); ufshcd_release(hba); return ret; } @@ -7048,12 +7045,13 @@ static int __ufshcd_issue_tm_cmd(struct ufs_hba *hba, memcpy(hba->utmrdl_base_addr + task_tag, treq, sizeof(*treq)); ufshcd_vops_setup_task_mgmt(hba, task_tag, tm_function); - /* send command to the controller */ __set_bit(task_tag, &hba->outstanding_tasks); - ufshcd_writel(hba, 1 << task_tag, REG_UTP_TASK_REQ_DOOR_BELL); spin_unlock_irqrestore(host->host_lock, flags); + /* send command to the controller */ + ufshcd_writel(hba, 1 << task_tag, REG_UTP_TASK_REQ_DOOR_BELL); + ufshcd_add_tm_upiu_trace(hba, task_tag, UFS_TM_SEND); /* wait until the task management command is completed */ -- cgit v1.2.3 From 5824e18b3db468e6eb5e9ef226eed80db26f581a Mon Sep 17 00:00:00 2001 From: Avri Altman Date: Thu, 24 Oct 2024 10:50:32 +0300 Subject: scsi: ufs: core: Remove redundant host_lock calls around UTMRLCLR There is no need to serialize single read/write calls to the host controller registers. Remove the redundant host_lock calls that protect access to the task management request List cLear register: UTMRLCLR. Reviewed-by: Bart Van Assche Signed-off-by: Avri Altman Link: https://lore.kernel.org/r/20241024075033.562562-3-avri.altman@wdc.com Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/ufs/core') diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 5827575204fa..f6e84a3bfcf4 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -6995,14 +6995,11 @@ static int ufshcd_clear_tm_cmd(struct ufs_hba *hba, int tag) { int err = 0; u32 mask = 1 << tag; - unsigned long flags; if (!test_bit(tag, &hba->outstanding_tasks)) goto out; - spin_lock_irqsave(hba->host->host_lock, flags); ufshcd_utmrl_clear(hba, tag); - spin_unlock_irqrestore(hba->host->host_lock, flags); /* poll for max. 1 sec to clear door bell register by h/w */ err = ufshcd_wait_for_register(hba, -- cgit v1.2.3 From 2a330f16ad305935c965dd84b727771c52701642 Mon Sep 17 00:00:00 2001 From: Avri Altman Date: Thu, 24 Oct 2024 10:50:33 +0300 Subject: scsi: ufs: core: Remove redundant host_lock calls around UTRLCLR. There is no need to serialize single read/write calls to the host controller registers. Remove the redundant host_lock calls that protect access to the request list cLear register: UTRLCLR. Reviewed-by: Bart Van Assche Signed-off-by: Avri Altman Link: https://lore.kernel.org/r/20241024075033.562562-4-avri.altman@wdc.com Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/ufs/core') diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index f6e84a3bfcf4..9458ecc1c10e 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -3062,7 +3062,6 @@ bool ufshcd_cmd_inflight(struct scsi_cmnd *cmd) static int ufshcd_clear_cmd(struct ufs_hba *hba, u32 task_tag) { u32 mask; - unsigned long flags; int err; if (hba->mcq_enabled) { @@ -3082,9 +3081,7 @@ static int ufshcd_clear_cmd(struct ufs_hba *hba, u32 task_tag) mask = 1U << task_tag; /* clear outstanding transaction before retry */ - spin_lock_irqsave(hba->host->host_lock, flags); ufshcd_utrl_clear(hba, mask); - spin_unlock_irqrestore(hba->host->host_lock, flags); /* * wait for h/w to clear corresponding bit in door-bell. -- cgit v1.2.3 From 17a973970397b3452fde2c93bc1ee051e7a8c79b Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Wed, 16 Oct 2024 13:11:57 -0700 Subject: scsi: ufs: core: Introduce ufshcd_add_scsi_host() Move the code for adding a SCSI host and also the code for managing TMF tags from ufshcd_init() into a new function called ufshcd_add_scsi_host(). This patch prepares for combining the two scsi_add_host() calls into a single call. No functionality has been changed. Reviewed-by: Avri Altman Reviewed-by: Bean Huo Reviewed-by: Bao D. Nguyen Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20241016201249.2256266-2-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 96 +++++++++++++++++++++++++++++------------------ 1 file changed, 59 insertions(+), 37 deletions(-) (limited to 'drivers/ufs/core') diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 9458ecc1c10e..7660d3546408 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -10333,6 +10333,62 @@ static const struct blk_mq_ops ufshcd_tmf_ops = { .queue_rq = ufshcd_queue_tmf, }; +static int ufshcd_add_scsi_host(struct ufs_hba *hba) +{ + int err; + + if (!is_mcq_supported(hba)) { + if (!hba->lsdb_sup) { + dev_err(hba->dev, + "%s: failed to initialize (legacy doorbell mode not supported)\n", + __func__); + return -EINVAL; + } + err = scsi_add_host(hba->host, hba->dev); + if (err) { + dev_err(hba->dev, "scsi_add_host failed\n"); + return err; + } + hba->scsi_host_added = true; + } + + hba->tmf_tag_set = (struct blk_mq_tag_set) { + .nr_hw_queues = 1, + .queue_depth = hba->nutmrs, + .ops = &ufshcd_tmf_ops, + .flags = BLK_MQ_F_NO_SCHED, + }; + err = blk_mq_alloc_tag_set(&hba->tmf_tag_set); + if (err < 0) + goto remove_scsi_host; + hba->tmf_queue = blk_mq_alloc_queue(&hba->tmf_tag_set, NULL, NULL); + if (IS_ERR(hba->tmf_queue)) { + err = PTR_ERR(hba->tmf_queue); + goto free_tmf_tag_set; + } + hba->tmf_rqs = devm_kcalloc(hba->dev, hba->nutmrs, + sizeof(*hba->tmf_rqs), GFP_KERNEL); + if (!hba->tmf_rqs) { + err = -ENOMEM; + goto free_tmf_queue; + } + + return 0; + +free_tmf_queue: + blk_mq_destroy_queue(hba->tmf_queue); + blk_put_queue(hba->tmf_queue); + +free_tmf_tag_set: + blk_mq_free_tag_set(&hba->tmf_tag_set); + +remove_scsi_host: + if (hba->scsi_host_added) + scsi_remove_host(hba->host); + + return err; +} + /** * ufshcd_init - Driver initialization routine * @hba: per-adapter instance @@ -10464,41 +10520,9 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) hba->is_irq_enabled = true; } - if (!is_mcq_supported(hba)) { - if (!hba->lsdb_sup) { - dev_err(hba->dev, "%s: failed to initialize (legacy doorbell mode not supported)\n", - __func__); - err = -EINVAL; - goto out_disable; - } - err = scsi_add_host(host, hba->dev); - if (err) { - dev_err(hba->dev, "scsi_add_host failed\n"); - goto out_disable; - } - hba->scsi_host_added = true; - } - - hba->tmf_tag_set = (struct blk_mq_tag_set) { - .nr_hw_queues = 1, - .queue_depth = hba->nutmrs, - .ops = &ufshcd_tmf_ops, - .flags = BLK_MQ_F_NO_SCHED, - }; - err = blk_mq_alloc_tag_set(&hba->tmf_tag_set); - if (err < 0) - goto out_remove_scsi_host; - hba->tmf_queue = blk_mq_alloc_queue(&hba->tmf_tag_set, NULL, NULL); - if (IS_ERR(hba->tmf_queue)) { - err = PTR_ERR(hba->tmf_queue); - goto free_tmf_tag_set; - } - hba->tmf_rqs = devm_kcalloc(hba->dev, hba->nutmrs, - sizeof(*hba->tmf_rqs), GFP_KERNEL); - if (!hba->tmf_rqs) { - err = -ENOMEM; - goto free_tmf_queue; - } + err = ufshcd_add_scsi_host(hba); + if (err) + goto out_disable; /* Reset the attached device */ ufshcd_device_reset(hba); @@ -10556,9 +10580,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) free_tmf_queue: blk_mq_destroy_queue(hba->tmf_queue); blk_put_queue(hba->tmf_queue); -free_tmf_tag_set: blk_mq_free_tag_set(&hba->tmf_tag_set); -out_remove_scsi_host: if (hba->scsi_host_added) scsi_remove_host(hba->host); out_disable: -- cgit v1.2.3 From 3192d28ec6608ace67e85753da2504c11a4fdb16 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Wed, 16 Oct 2024 13:11:58 -0700 Subject: scsi: ufs: core: Introduce ufshcd_post_device_init() Prepare for inlining one ufshcd_device_init() call by introducing the new function ufshcd_post_device_init(). No functionality has been changed. Reviewed-by: Avri Altman Reviewed-by: Manivannan Sadhasivam Reviewed-by: Bao D. Nguyen Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20241016201249.2256266-3-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 62 ++++++++++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 27 deletions(-) (limited to 'drivers/ufs/core') diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 7660d3546408..72f041338788 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -8686,6 +8686,40 @@ static void ufshcd_config_mcq(struct ufs_hba *hba) hba->nutrs); } +static int ufshcd_post_device_init(struct ufs_hba *hba) +{ + int ret; + + ufshcd_tune_unipro_params(hba); + + /* UFS device is also active now */ + ufshcd_set_ufs_dev_active(hba); + ufshcd_force_reset_auto_bkops(hba); + + ufshcd_set_timestamp_attr(hba); + schedule_delayed_work(&hba->ufs_rtc_update_work, + msecs_to_jiffies(UFS_RTC_UPDATE_INTERVAL_MS)); + + if (!hba->max_pwr_info.is_valid) + return 0; + + /* + * Set the right value to bRefClkFreq before attempting to + * switch to HS gears. + */ + if (hba->dev_ref_clk_freq != REF_CLK_FREQ_INVAL) + ufshcd_set_dev_ref_clk(hba); + /* Gear up to HS gear. */ + ret = ufshcd_config_pwr_mode(hba, &hba->max_pwr_info.info); + if (ret) { + dev_err(hba->dev, "%s: Failed setting power mode, err = %d\n", + __func__, ret); + return ret; + } + + return 0; +} + static int ufshcd_device_init(struct ufs_hba *hba, bool init_dev_params) { int ret; @@ -8755,33 +8789,7 @@ static int ufshcd_device_init(struct ufs_hba *hba, bool init_dev_params) } } - ufshcd_tune_unipro_params(hba); - - /* UFS device is also active now */ - ufshcd_set_ufs_dev_active(hba); - ufshcd_force_reset_auto_bkops(hba); - - ufshcd_set_timestamp_attr(hba); - schedule_delayed_work(&hba->ufs_rtc_update_work, - msecs_to_jiffies(UFS_RTC_UPDATE_INTERVAL_MS)); - - /* Gear up to HS gear if supported */ - if (hba->max_pwr_info.is_valid) { - /* - * Set the right value to bRefClkFreq before attempting to - * switch to HS gears. - */ - if (hba->dev_ref_clk_freq != REF_CLK_FREQ_INVAL) - ufshcd_set_dev_ref_clk(hba); - ret = ufshcd_config_pwr_mode(hba, &hba->max_pwr_info.info); - if (ret) { - dev_err(hba->dev, "%s: Failed setting power mode, err = %d\n", - __func__, ret); - return ret; - } - } - - return 0; + return ufshcd_post_device_init(hba); } /** -- cgit v1.2.3 From 7702c7f64f2df3e299ae26059e448bf4f08b867a Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Wed, 16 Oct 2024 13:11:59 -0700 Subject: scsi: ufs: core: Call ufshcd_add_scsi_host() later Call ufshcd_add_scsi_host() after host controller initialization has completed. This is safe because no code between the old and new ufshcd_add_scsi_host() call site depends on the scsi_add_host() call. Reviewed-by: Manivannan Sadhasivam Reviewed-by: Bean Huo Reviewed-by: Bao D. Nguyen Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20241016201249.2256266-4-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) (limited to 'drivers/ufs/core') diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 72f041338788..4fe2339b1deb 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -10528,10 +10528,6 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) hba->is_irq_enabled = true; } - err = ufshcd_add_scsi_host(hba); - if (err) - goto out_disable; - /* Reset the attached device */ ufshcd_device_reset(hba); @@ -10543,7 +10539,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) dev_err(hba->dev, "Host controller enable failed\n"); ufshcd_print_evt_hist(hba); ufshcd_print_host_state(hba); - goto free_tmf_queue; + goto out_disable; } /* @@ -10578,6 +10574,10 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) */ ufshcd_set_ufs_dev_active(hba); + err = ufshcd_add_scsi_host(hba); + if (err) + goto out_disable; + async_schedule(ufshcd_async_scan, hba); ufs_sysfs_add_nodes(hba->dev); @@ -10585,12 +10585,6 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) ufshcd_pm_qos_init(hba); return 0; -free_tmf_queue: - blk_mq_destroy_queue(hba->tmf_queue); - blk_put_queue(hba->tmf_queue); - blk_mq_free_tag_set(&hba->tmf_tag_set); - if (hba->scsi_host_added) - scsi_remove_host(hba->host); out_disable: hba->is_irq_enabled = false; ufshcd_hba_exit(hba); -- cgit v1.2.3 From 18ec23b60822fb52ae1f1f3a08df29289458b087 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Wed, 16 Oct 2024 13:12:00 -0700 Subject: scsi: ufs: core: Introduce ufshcd_process_probe_result() Prepare for moving a ufshcd_device_init() call from inside ufshcd_probe_hba() into the ufshcd_probe_hba() callers by introducing the function ufshcd_process_probe_result(). No functionality has been changed. Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20241016201249.2256266-5-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) (limited to 'drivers/ufs/core') diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 4fe2339b1deb..67ee6fba6f2a 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -7638,6 +7638,29 @@ release: return err; } +/** + * ufshcd_process_probe_result - Process the ufshcd_probe_hba() result. + * @hba: UFS host controller instance. + * @probe_start: time when the ufshcd_probe_hba() call started. + * @ret: ufshcd_probe_hba() return value. + */ +static void ufshcd_process_probe_result(struct ufs_hba *hba, + ktime_t probe_start, int ret) +{ + unsigned long flags; + + spin_lock_irqsave(hba->host->host_lock, flags); + if (ret) + hba->ufshcd_state = UFSHCD_STATE_ERROR; + else if (hba->ufshcd_state == UFSHCD_STATE_RESET) + hba->ufshcd_state = UFSHCD_STATE_OPERATIONAL; + spin_unlock_irqrestore(hba->host->host_lock, flags); + + trace_ufshcd_init(dev_name(hba->dev), ret, + ktime_to_us(ktime_sub(ktime_get(), probe_start)), + hba->curr_dev_pwr_mode, hba->uic_link_state); +} + /** * ufshcd_host_reset_and_restore - reset and restore host controller * @hba: per-adapter instance @@ -8804,7 +8827,6 @@ static int ufshcd_device_init(struct ufs_hba *hba, bool init_dev_params) static int ufshcd_probe_hba(struct ufs_hba *hba, bool init_dev_params) { ktime_t start = ktime_get(); - unsigned long flags; int ret; ret = ufshcd_device_init(hba, init_dev_params); @@ -8850,16 +8872,7 @@ static int ufshcd_probe_hba(struct ufs_hba *hba, bool init_dev_params) ufshcd_configure_auto_hibern8(hba); out: - spin_lock_irqsave(hba->host->host_lock, flags); - if (ret) - hba->ufshcd_state = UFSHCD_STATE_ERROR; - else if (hba->ufshcd_state == UFSHCD_STATE_RESET) - hba->ufshcd_state = UFSHCD_STATE_OPERATIONAL; - spin_unlock_irqrestore(hba->host->host_lock, flags); - - trace_ufshcd_init(dev_name(hba->dev), ret, - ktime_to_us(ktime_sub(ktime_get(), start)), - hba->curr_dev_pwr_mode, hba->uic_link_state); + ufshcd_process_probe_result(hba, start, ret); return ret; } -- cgit v1.2.3 From 0936001322646a15d7091f61232e5ded9bf1883f Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Wed, 16 Oct 2024 13:12:01 -0700 Subject: scsi: ufs: core: Convert a comment into an explicit check The comment /* UFSHCD_QUIRK_REINIT_AFTER_MAX_GEAR_SWITCH is set */ is only correct if ufshcd_device_init() is only called by ufshcd_probe_hba(). Convert the comment into an explicit check. This patch prepares for moving the ufshcd_device_init() calls. Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20241016201249.2256266-6-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/ufs/core') diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 67ee6fba6f2a..2ed1e5391152 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -8805,8 +8805,9 @@ static int ufshcd_device_init(struct ufs_hba *hba, bool init_dev_params) return ret; } hba->scsi_host_added = true; - } else if (is_mcq_supported(hba)) { - /* UFSHCD_QUIRK_REINIT_AFTER_MAX_GEAR_SWITCH is set */ + } else if (is_mcq_supported(hba) && + hba->quirks & + UFSHCD_QUIRK_REINIT_AFTER_MAX_GEAR_SWITCH) { ufshcd_config_mcq(hba); ufshcd_mcq_enable(hba); } -- cgit v1.2.3 From 639e2043b58998b3950ab90413c1b726945058bf Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Wed, 16 Oct 2024 13:12:02 -0700 Subject: scsi: ufs: core: Move the ufshcd_device_init() calls Move the ufshcd_device_init() and ufshcd_process_hba_result() calls to the ufshcd_probe_hba() callers. This change refactors the code without modifying the behavior of the UFSHCI driver. This change prepares for moving one ufshcd_device_init() call into ufshcd_init(). Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20241016201249.2256266-7-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) (limited to 'drivers/ufs/core') diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 2ed1e5391152..1c9ffa1c3670 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -298,6 +298,7 @@ static int ufshcd_reset_and_restore(struct ufs_hba *hba); static int ufshcd_eh_host_reset_handler(struct scsi_cmnd *cmd); static int ufshcd_clear_tm_cmd(struct ufs_hba *hba, int tag); static void ufshcd_hba_exit(struct ufs_hba *hba); +static int ufshcd_device_init(struct ufs_hba *hba, bool init_dev_params); static int ufshcd_probe_hba(struct ufs_hba *hba, bool init_dev_params); static int ufshcd_setup_clocks(struct ufs_hba *hba, bool on); static inline void ufshcd_add_delay_before_dme_cmd(struct ufs_hba *hba); @@ -7690,8 +7691,14 @@ static int ufshcd_host_reset_and_restore(struct ufs_hba *hba) err = ufshcd_hba_enable(hba); /* Establish the link again and restore the device */ - if (!err) - err = ufshcd_probe_hba(hba, false); + if (!err) { + ktime_t probe_start = ktime_get(); + + err = ufshcd_device_init(hba, /*init_dev_params=*/false); + if (!err) + err = ufshcd_probe_hba(hba, false); + ufshcd_process_probe_result(hba, probe_start, err); + } if (err) dev_err(hba->dev, "%s: Host init failed %d\n", __func__, err); @@ -8827,13 +8834,8 @@ static int ufshcd_device_init(struct ufs_hba *hba, bool init_dev_params) */ static int ufshcd_probe_hba(struct ufs_hba *hba, bool init_dev_params) { - ktime_t start = ktime_get(); int ret; - ret = ufshcd_device_init(hba, init_dev_params); - if (ret) - goto out; - if (!hba->pm_op_in_progress && (hba->quirks & UFSHCD_QUIRK_REINIT_AFTER_MAX_GEAR_SWITCH)) { /* Reset the device and controller before doing reinit */ @@ -8846,13 +8848,13 @@ static int ufshcd_probe_hba(struct ufs_hba *hba, bool init_dev_params) dev_err(hba->dev, "Host controller enable failed\n"); ufshcd_print_evt_hist(hba); ufshcd_print_host_state(hba); - goto out; + return ret; } /* Reinit the device */ ret = ufshcd_device_init(hba, init_dev_params); if (ret) - goto out; + return ret; } ufshcd_print_pwr_info(hba); @@ -8872,9 +8874,7 @@ static int ufshcd_probe_hba(struct ufs_hba *hba, bool init_dev_params) ufshcd_write_ee_control(hba); ufshcd_configure_auto_hibern8(hba); -out: - ufshcd_process_probe_result(hba, start, ret); - return ret; + return 0; } /** @@ -8885,11 +8885,16 @@ out: static void ufshcd_async_scan(void *data, async_cookie_t cookie) { struct ufs_hba *hba = (struct ufs_hba *)data; + ktime_t probe_start; int ret; down(&hba->host_sem); /* Initialize hba, detect and initialize UFS device */ - ret = ufshcd_probe_hba(hba, true); + probe_start = ktime_get(); + ret = ufshcd_device_init(hba, /*init_dev_params=*/true); + if (ret == 0) + ret = ufshcd_probe_hba(hba, true); + ufshcd_process_probe_result(hba, probe_start, ret); up(&hba->host_sem); if (ret) goto out; -- cgit v1.2.3 From 69f5eb78d4b0cc978fe83dd2bfea1b67547290bf Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Wed, 16 Oct 2024 13:12:03 -0700 Subject: scsi: ufs: core: Move the ufshcd_device_init(hba, true) call ufshcd_async_scan() is called (asynchronously) only by ufshcd_init(). Move the ufshcd_device_init(hba, true) call from ufshcd_async_scan() into ufshcd_init(). This patch prepares for moving both scsi_add_host() calls into ufshcd_add_scsi_host(). Calling ufshcd_device_init() from ufshcd_init() without holding hba->host_sem is safe. This is safe because hba->host_sem serializes core code and sysfs callbacks. The ufshcd_device_init() call is moved before the scsi_add_host() call and hence happens before any SCSI sysfs attributes are created. Since ufshcd_device_init() may call scsi_add_host(), only call scsi_add_host() from ufshcd_add_scsi_host() if the SCSI host has not yet been added by ufshcd_device_init(). Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20241016201249.2256266-8-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers/ufs/core') diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 1c9ffa1c3670..0f69653510cc 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -8891,9 +8891,7 @@ static void ufshcd_async_scan(void *data, async_cookie_t cookie) down(&hba->host_sem); /* Initialize hba, detect and initialize UFS device */ probe_start = ktime_get(); - ret = ufshcd_device_init(hba, /*init_dev_params=*/true); - if (ret == 0) - ret = ufshcd_probe_hba(hba, true); + ret = ufshcd_probe_hba(hba, true); ufshcd_process_probe_result(hba, probe_start, ret); up(&hba->host_sem); if (ret) @@ -10364,7 +10362,8 @@ static int ufshcd_add_scsi_host(struct ufs_hba *hba) { int err; - if (!is_mcq_supported(hba)) { + if (!hba->scsi_host_added) { + WARN_ON_ONCE(is_mcq_supported(hba)); if (!hba->lsdb_sup) { dev_err(hba->dev, "%s: failed to initialize (legacy doorbell mode not supported)\n", @@ -10593,6 +10592,11 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) */ ufshcd_set_ufs_dev_active(hba); + /* Initialize hba, detect and initialize UFS device */ + err = ufshcd_device_init(hba, /*init_dev_params=*/true); + if (err) + goto out_disable; + err = ufshcd_add_scsi_host(hba); if (err) goto out_disable; -- cgit v1.2.3 From a390e6677f4119e3b9e6364ac2c5cbe3ef1321a2 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Wed, 16 Oct 2024 13:12:04 -0700 Subject: scsi: ufs: core: Expand the ufshcd_device_init(hba, true) call Expand the ufshcd_device_init(hba, true) call and remove all code that depends on init_dev_params == false. This change prepares for combining the two scsi_add_host() calls. Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20241016201249.2256266-9-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) (limited to 'drivers/ufs/core') diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 0f69653510cc..239e826f4b49 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -10593,7 +10593,61 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) ufshcd_set_ufs_dev_active(hba); /* Initialize hba, detect and initialize UFS device */ - err = ufshcd_device_init(hba, /*init_dev_params=*/true); + ktime_t probe_start = ktime_get(); + + hba->ufshcd_state = UFSHCD_STATE_RESET; + + err = ufshcd_link_startup(hba); + if (err) + goto out_disable; + + if (hba->quirks & UFSHCD_QUIRK_SKIP_PH_CONFIGURATION) + goto initialized; + + /* Debug counters initialization */ + ufshcd_clear_dbg_ufs_stats(hba); + + /* UniPro link is active now */ + ufshcd_set_link_active(hba); + + /* Verify device initialization by sending NOP OUT UPIU */ + err = ufshcd_verify_dev_init(hba); + if (err) + goto out_disable; + + /* Initiate UFS initialization, and waiting until completion */ + err = ufshcd_complete_dev_init(hba); + if (err) + goto out_disable; + + err = ufshcd_device_params_init(hba); + if (err) + goto out_disable; + + if (is_mcq_supported(hba)) { + ufshcd_mcq_enable(hba); + err = ufshcd_alloc_mcq(hba); + if (!err) { + ufshcd_config_mcq(hba); + } else { + /* Continue with SDB mode */ + ufshcd_mcq_disable(hba); + use_mcq_mode = false; + dev_err(hba->dev, "MCQ mode is disabled, err=%d\n", + err); + } + err = scsi_add_host(host, hba->dev); + if (err) { + dev_err(hba->dev, "scsi_add_host failed\n"); + goto out_disable; + } + hba->scsi_host_added = true; + } + + err = ufshcd_post_device_init(hba); + +initialized: + ufshcd_process_probe_result(hba, probe_start, err); if (err) goto out_disable; -- cgit v1.2.3 From b6195d02b914ddfddb50e3ceb6b66928ebf0fdb8 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Wed, 16 Oct 2024 13:12:05 -0700 Subject: scsi: ufs: core: Remove code that is no longer needed Previous changes guarantee that hba->scsi_host_added is true before ufshcd_device_init() is called. Hence, remove the code from ufshcd_device_init() that depends on hba->scsi_host_added being false. Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20241016201249.2256266-10-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 26 ++++---------------------- 1 file changed, 4 insertions(+), 22 deletions(-) (limited to 'drivers/ufs/core') diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 239e826f4b49..4103b1c9c388 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -8753,7 +8753,8 @@ static int ufshcd_post_device_init(struct ufs_hba *hba) static int ufshcd_device_init(struct ufs_hba *hba, bool init_dev_params) { int ret; - struct Scsi_Host *host = hba->host; + + WARN_ON_ONCE(!hba->scsi_host_added); hba->ufshcd_state = UFSHCD_STATE_RESET; @@ -8794,27 +8795,8 @@ static int ufshcd_device_init(struct ufs_hba *hba, bool init_dev_params) ret = ufshcd_device_params_init(hba); if (ret) return ret; - if (is_mcq_supported(hba) && !hba->scsi_host_added) { - ufshcd_mcq_enable(hba); - ret = ufshcd_alloc_mcq(hba); - if (!ret) { - ufshcd_config_mcq(hba); - } else { - /* Continue with SDB mode */ - ufshcd_mcq_disable(hba); - use_mcq_mode = false; - dev_err(hba->dev, "MCQ mode is disabled, err=%d\n", - ret); - } - ret = scsi_add_host(host, hba->dev); - if (ret) { - dev_err(hba->dev, "scsi_add_host failed\n"); - return ret; - } - hba->scsi_host_added = true; - } else if (is_mcq_supported(hba) && - hba->quirks & - UFSHCD_QUIRK_REINIT_AFTER_MAX_GEAR_SWITCH) { + if (is_mcq_supported(hba) && + hba->quirks & UFSHCD_QUIRK_REINIT_AFTER_MAX_GEAR_SWITCH) { ufshcd_config_mcq(hba); ufshcd_mcq_enable(hba); } -- cgit v1.2.3 From 72e979225ed2e9427396e317d33050bcf50ad899 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Wed, 16 Oct 2024 13:12:06 -0700 Subject: scsi: ufs: core: Move the MCQ scsi_add_host() call Whether or not MCQ is used, call scsi_add_host() from ufshcd_add_scsi_host(). For MCQ this patch swaps the order of the scsi_add_host() and UFS device initialization. This patch prepares for combining the two scsi_add_host() calls. Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20241016201249.2256266-11-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 41 +++++++++++++++++++---------------------- 1 file changed, 19 insertions(+), 22 deletions(-) (limited to 'drivers/ufs/core') diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 4103b1c9c388..fd2783623a89 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -10344,8 +10344,25 @@ static int ufshcd_add_scsi_host(struct ufs_hba *hba) { int err; - if (!hba->scsi_host_added) { - WARN_ON_ONCE(is_mcq_supported(hba)); + if (is_mcq_supported(hba)) { + ufshcd_mcq_enable(hba); + err = ufshcd_alloc_mcq(hba); + if (!err) { + ufshcd_config_mcq(hba); + } else { + /* Continue with SDB mode */ + ufshcd_mcq_disable(hba); + use_mcq_mode = false; + dev_err(hba->dev, "MCQ mode is disabled, err=%d\n", + err); + } + err = scsi_add_host(hba->host, hba->dev); + if (err) { + dev_err(hba->dev, "scsi_add_host failed\n"); + return err; + } + hba->scsi_host_added = true; + } else { if (!hba->lsdb_sup) { dev_err(hba->dev, "%s: failed to initialize (legacy doorbell mode not supported)\n", @@ -10606,26 +10623,6 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) if (err) goto out_disable; - if (is_mcq_supported(hba)) { - ufshcd_mcq_enable(hba); - err = ufshcd_alloc_mcq(hba); - if (!err) { - ufshcd_config_mcq(hba); - } else { - /* Continue with SDB mode */ - ufshcd_mcq_disable(hba); - use_mcq_mode = false; - dev_err(hba->dev, "MCQ mode is disabled, err=%d\n", - err); - } - err = scsi_add_host(host, hba->dev); - if (err) { - dev_err(hba->dev, "scsi_add_host failed\n"); - goto out_disable; - } - hba->scsi_host_added = true; - } - err = ufshcd_post_device_init(hba); initialized: -- cgit v1.2.3 From b92e5937e3523b0b7d41373681256bec78d7e134 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Wed, 16 Oct 2024 13:12:07 -0700 Subject: scsi: ufs: core: Move code out of an if-statement The previous patch in this series introduced identical code in both branches of an if-statement. Move that code outside the if-statement. Reviewed-by: Bao D. Nguyen Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20241016201249.2256266-12-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) (limited to 'drivers/ufs/core') diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index fd2783623a89..099373a25017 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -10356,26 +10356,20 @@ static int ufshcd_add_scsi_host(struct ufs_hba *hba) dev_err(hba->dev, "MCQ mode is disabled, err=%d\n", err); } - err = scsi_add_host(hba->host, hba->dev); - if (err) { - dev_err(hba->dev, "scsi_add_host failed\n"); - return err; - } - hba->scsi_host_added = true; - } else { - if (!hba->lsdb_sup) { - dev_err(hba->dev, - "%s: failed to initialize (legacy doorbell mode not supported)\n", - __func__); - return -EINVAL; - } - err = scsi_add_host(hba->host, hba->dev); - if (err) { - dev_err(hba->dev, "scsi_add_host failed\n"); - return err; - } - hba->scsi_host_added = true; } + if (!is_mcq_supported(hba) && !hba->lsdb_sup) { + dev_err(hba->dev, + "%s: failed to initialize (legacy doorbell mode not supported)\n", + __func__); + return -EINVAL; + } + + err = scsi_add_host(hba->host, hba->dev); + if (err) { + dev_err(hba->dev, "scsi_add_host failed\n"); + return err; + } + hba->scsi_host_added = true; hba->tmf_tag_set = (struct blk_mq_tag_set) { .nr_hw_queues = 1, -- cgit v1.2.3 From 7670e74ff31939acd792ff59fa83bc73d040dd8e Mon Sep 17 00:00:00 2001 From: Ed Tsai Date: Tue, 8 Oct 2024 14:59:42 +0800 Subject: scsi: ufs: ufs-mediatek: Configure individual LU queue flags Previously, ufs vops config_scsi_dev was removed because there were no users. ufs-mediatek needs it to configure the queue flags for each LU individually. Therefore, bring it back and customize the queue flag as required. [mkp: fixed typo] Signed-off-by: Ed Tsai Link: https://lore.kernel.org/r/20241008065950.23431-1-ed.tsai@mediatek.com Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 3 +++ drivers/ufs/host/ufs-mediatek.c | 10 ++++++++++ include/ufs/ufshcd.h | 1 + 3 files changed, 14 insertions(+) (limited to 'drivers/ufs/core') diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 5607aad42469..e338867bc96c 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -5235,6 +5235,9 @@ static int ufshcd_device_configure(struct scsi_device *sdev, */ sdev->silence_suspend = 1; + if (hba->vops && hba->vops->config_scsi_dev) + hba->vops->config_scsi_dev(sdev); + ufshcd_crypto_register(hba, q); return 0; diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c index 9a5919434c4e..06ab1e5e8b6f 100644 --- a/drivers/ufs/host/ufs-mediatek.c +++ b/drivers/ufs/host/ufs-mediatek.c @@ -1780,6 +1780,15 @@ static int ufs_mtk_config_esi(struct ufs_hba *hba) return ufs_mtk_config_mcq(hba, true); } +static void ufs_mtk_config_scsi_dev(struct scsi_device *sdev) +{ + struct ufs_hba *hba = shost_priv(sdev->host); + + dev_dbg(hba->dev, "lu %llu scsi device configured", sdev->lun); + if (sdev->lun == 2) + blk_queue_flag_set(QUEUE_FLAG_SAME_FORCE, sdev->request_queue); +} + /* * struct ufs_hba_mtk_vops - UFS MTK specific variant operations * @@ -1809,6 +1818,7 @@ static const struct ufs_hba_variant_ops ufs_hba_mtk_vops = { .op_runtime_config = ufs_mtk_op_runtime_config, .mcq_config_resource = ufs_mtk_mcq_config_resource, .config_esi = ufs_mtk_config_esi, + .config_scsi_dev = ufs_mtk_config_scsi_dev, }; /** diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h index 9ea2a7411bb5..d7aca9e61684 100644 --- a/include/ufs/ufshcd.h +++ b/include/ufs/ufshcd.h @@ -386,6 +386,7 @@ struct ufs_hba_variant_ops { int (*get_outstanding_cqs)(struct ufs_hba *hba, unsigned long *ocqs); int (*config_esi)(struct ufs_hba *hba); + void (*config_scsi_dev)(struct scsi_device *sdev); }; /* clock gating state */ -- cgit v1.2.3