[PATCH 04/10] scsi: ufs: rework link start-up process
From: Seungwon Jeon tgih@samsung.com Link start-up requires long time with multiphase handshakes between UFS host and device. This affects driver's probe time. This patch let link start-up run asynchronously. Link start-up will be executed at the end of prove separately. Along with this change, the following is worked. Defined completion time of uic command to avoid a permanent wait. Added mutex to guarantee of uic command at a time. Adapted some sequence of controller initialization after link statup according to HCI standard. Signed-off-by: Seungwon Jeon tgih@samsung.com Signed-off-by: Sujit Reddy Thumma sthu...@codeaurora.org Tested-by: Maya Erez me...@codeaurora.org Signed-off-by: Santosh Y santos...@gmail.com diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 2e02483..48a7645 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -33,11 +33,15 @@ * this program. */ +#include linux/async.h + #include ufshcd.h #define UFSHCD_ENABLE_INTRS(UTP_TRANSFER_REQ_COMPL |\ UTP_TASK_REQ_COMPL |\ UFSHCD_ERROR_MASK) +/* UIC command timeout, unit: ms */ +#define UIC_CMD_TIMEOUT500 enum { UFSHCD_MAX_CHANNEL = 0, @@ -349,24 +353,122 @@ static inline void ufshcd_hba_capabilities(struct ufs_hba *hba) } /** - * ufshcd_send_uic_command - Send UIC commands to unipro layers + * ufshcd_ready_for_uic_cmd - Check if controller is ready + *to accept UIC commands * @hba: per adapter instance - * @uic_command: UIC command + * Return true on success, else false + */ +static inline bool ufshcd_ready_for_uic_cmd(struct ufs_hba *hba) +{ + if (ufshcd_readl(hba, REG_CONTROLLER_STATUS) UIC_COMMAND_READY) + return true; + else + return false; +} + +/** + * ufshcd_dispatch_uic_cmd - Dispatch UIC commands to unipro layers + * @hba: per adapter instance + * @uic_cmd: UIC command + * + * Mutex must be held. */ static inline void -ufshcd_send_uic_command(struct ufs_hba *hba, struct uic_command *uic_cmnd) +ufshcd_dispatch_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd) { + WARN_ON(hba-active_uic_cmd); + + hba-active_uic_cmd = uic_cmd; + /* Write Args */ - ufshcd_writel(hba, uic_cmnd-argument1, REG_UIC_COMMAND_ARG_1); - ufshcd_writel(hba, uic_cmnd-argument2, REG_UIC_COMMAND_ARG_2); - ufshcd_writel(hba, uic_cmnd-argument3, REG_UIC_COMMAND_ARG_3); + ufshcd_writel(hba, uic_cmd-argument1, REG_UIC_COMMAND_ARG_1); + ufshcd_writel(hba, uic_cmd-argument2, REG_UIC_COMMAND_ARG_2); + ufshcd_writel(hba, uic_cmd-argument3, REG_UIC_COMMAND_ARG_3); /* Write UIC Cmd */ - ufshcd_writel(hba, uic_cmnd-command COMMAND_OPCODE_MASK, + ufshcd_writel(hba, uic_cmd-command COMMAND_OPCODE_MASK, REG_UIC_COMMAND); } /** + * ufshcd_wait_for_uic_cmd - Wait complectioin of UIC command + * @hba: per adapter instance + * @uic_command: UIC command + * + * Must be called with mutex held. + * Returns 0 only if success. + */ +static int +ufshcd_wait_for_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd) +{ + int ret; + unsigned long flags; + + if (wait_for_completion_timeout(uic_cmd-done, + msecs_to_jiffies(UIC_CMD_TIMEOUT))) + ret = uic_cmd-argument2 MASK_UIC_COMMAND_RESULT; + else + ret = -ETIMEDOUT; + + spin_lock_irqsave(hba-host-host_lock, flags); + hba-active_uic_cmd = NULL; + spin_unlock_irqrestore(hba-host-host_lock, flags); + + return ret; +} + +/** + * __ufshcd_send_uic_cmd - Send UIC commands and retrieve the result + * @hba: per adapter instance + * @uic_cmd: UIC command + * + * Identical to ufshcd_send_uic_cmd() expect mutex. Must be called + * with mutex held. + * Returns 0 only if success. + */ +static int +__ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd) +{ + int ret; + unsigned long flags; + + if (!ufshcd_ready_for_uic_cmd(hba)) { + dev_err(hba-dev, + Controller not ready to accept UIC commands\n); + return -EIO; + } + + init_completion(uic_cmd-done); + + spin_lock_irqsave(hba-host-host_lock, flags); + ufshcd_dispatch_uic_cmd(hba, uic_cmd); + spin_unlock_irqrestore(hba-host-host_lock, flags); + + ret = ufshcd_wait_for_uic_cmd(hba, uic_cmd); + + return ret; +} + +/** + * ufshcd_send_uic_cmd - Send UIC commands and retrieve the result + * @hba: per adapter instance + * @uic_cmd: UIC command + * + * Returns 0 only if success. + */ +static int +ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd) +{ + int ret; + + mutex_lock(hba-uic_cmd_mutex); + ret = __ufshcd_send_uic_cmd(hba, uic_cmd); + mutex_unlock(hba-uic_cmd_mutex); + +
[PATCH 04/10] scsi: ufs: rework link start-up process
From: Seungwon Jeon tgih@samsung.com Link start-up requires long time with multiphase handshakes between UFS host and device. This affects driver's probe time. This patch let link start-up run asynchronously. Link start-up will be executed at the end of prove separately. Along with this change, the following is worked. Defined completion time of uic command to avoid a permanent wait. Added mutex to guarantee of uic command at a time. Adapted some sequence of controller initialization after link statup according to HCI standard. Signed-off-by: Seungwon Jeon tgih@samsung.com Signed-off-by: Sujit Reddy Thumma sthu...@codeaurora.org Tested-by: Maya Erez me...@codeaurora.org Signed-off-by: Santosh Y santos...@gmail.com diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 2e02483..48a7645 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -33,11 +33,15 @@ * this program. */ +#include linux/async.h + #include ufshcd.h #define UFSHCD_ENABLE_INTRS(UTP_TRANSFER_REQ_COMPL |\ UTP_TASK_REQ_COMPL |\ UFSHCD_ERROR_MASK) +/* UIC command timeout, unit: ms */ +#define UIC_CMD_TIMEOUT500 enum { UFSHCD_MAX_CHANNEL = 0, @@ -349,24 +353,122 @@ static inline void ufshcd_hba_capabilities(struct ufs_hba *hba) } /** - * ufshcd_send_uic_command - Send UIC commands to unipro layers + * ufshcd_ready_for_uic_cmd - Check if controller is ready + *to accept UIC commands * @hba: per adapter instance - * @uic_command: UIC command + * Return true on success, else false + */ +static inline bool ufshcd_ready_for_uic_cmd(struct ufs_hba *hba) +{ + if (ufshcd_readl(hba, REG_CONTROLLER_STATUS) UIC_COMMAND_READY) + return true; + else + return false; +} + +/** + * ufshcd_dispatch_uic_cmd - Dispatch UIC commands to unipro layers + * @hba: per adapter instance + * @uic_cmd: UIC command + * + * Mutex must be held. */ static inline void -ufshcd_send_uic_command(struct ufs_hba *hba, struct uic_command *uic_cmnd) +ufshcd_dispatch_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd) { + WARN_ON(hba-active_uic_cmd); + + hba-active_uic_cmd = uic_cmd; + /* Write Args */ - ufshcd_writel(hba, uic_cmnd-argument1, REG_UIC_COMMAND_ARG_1); - ufshcd_writel(hba, uic_cmnd-argument2, REG_UIC_COMMAND_ARG_2); - ufshcd_writel(hba, uic_cmnd-argument3, REG_UIC_COMMAND_ARG_3); + ufshcd_writel(hba, uic_cmd-argument1, REG_UIC_COMMAND_ARG_1); + ufshcd_writel(hba, uic_cmd-argument2, REG_UIC_COMMAND_ARG_2); + ufshcd_writel(hba, uic_cmd-argument3, REG_UIC_COMMAND_ARG_3); /* Write UIC Cmd */ - ufshcd_writel(hba, uic_cmnd-command COMMAND_OPCODE_MASK, + ufshcd_writel(hba, uic_cmd-command COMMAND_OPCODE_MASK, REG_UIC_COMMAND); } /** + * ufshcd_wait_for_uic_cmd - Wait complectioin of UIC command + * @hba: per adapter instance + * @uic_command: UIC command + * + * Must be called with mutex held. + * Returns 0 only if success. + */ +static int +ufshcd_wait_for_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd) +{ + int ret; + unsigned long flags; + + if (wait_for_completion_timeout(uic_cmd-done, + msecs_to_jiffies(UIC_CMD_TIMEOUT))) + ret = uic_cmd-argument2 MASK_UIC_COMMAND_RESULT; + else + ret = -ETIMEDOUT; + + spin_lock_irqsave(hba-host-host_lock, flags); + hba-active_uic_cmd = NULL; + spin_unlock_irqrestore(hba-host-host_lock, flags); + + return ret; +} + +/** + * __ufshcd_send_uic_cmd - Send UIC commands and retrieve the result + * @hba: per adapter instance + * @uic_cmd: UIC command + * + * Identical to ufshcd_send_uic_cmd() expect mutex. Must be called + * with mutex held. + * Returns 0 only if success. + */ +static int +__ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd) +{ + int ret; + unsigned long flags; + + if (!ufshcd_ready_for_uic_cmd(hba)) { + dev_err(hba-dev, + Controller not ready to accept UIC commands\n); + return -EIO; + } + + init_completion(uic_cmd-done); + + spin_lock_irqsave(hba-host-host_lock, flags); + ufshcd_dispatch_uic_cmd(hba, uic_cmd); + spin_unlock_irqrestore(hba-host-host_lock, flags); + + ret = ufshcd_wait_for_uic_cmd(hba, uic_cmd); + + return ret; +} + +/** + * ufshcd_send_uic_cmd - Send UIC commands and retrieve the result + * @hba: per adapter instance + * @uic_cmd: UIC command + * + * Returns 0 only if success. + */ +static int +ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd) +{ + int ret; + + mutex_lock(hba-uic_cmd_mutex); + ret = __ufshcd_send_uic_cmd(hba, uic_cmd); + mutex_unlock(hba-uic_cmd_mutex); + +