scsi: ufs: Add support to control UFS device background operations
Subsystems (2)
v4 cover scsi: ufs: Add support to control UFS device background operations
Add host assisted background operations for UFS device and runtime PM helpers for ufshcd platform and pci glue drivers. The background operations are disabled during runtime resume and enabled when the device is idle and runtime suspended.
These patches depends on:
[PATCH V4 1/2] scsi: ufs: Add support for sending NOP OUT UPIU [PATCH V4 2/2] scsi: ufs: Set fDeviceInit flag to initiate device initialization
Changes from v3:
- Addressed some of the comments by Seungwon Jeon on runtime PM.
Changes from v2:
- Enable auto bkops by default explicitly during bootup so that we may not assume it as enabled after reset.
- Enable runtime PM support for contexts that are not part of SCSI, so that the host is not suspended while running other contexts like bkops exception handling.
Changes from v1:
- Minor cleanup and rebase
- Forced enable of auto bkops during initialization to make sure device and driver state are matched.
Sujit Reddy Thumma (2):
scsi: ufs: Add support for host assisted background operations
scsi: ufs: Add runtime PM support for UFS host controller driver
drivers/scsi/ufs/ufs.h | 23 +++ drivers/scsi/ufs/ufshcd-pci.c | 62 ++++++- drivers/scsi/ufs/ufshcd-pltfrm.c | 48 +++++- drivers/scsi/ufs/ufshcd.c | 351 ++++++++++++++++++++++++++++++++++++++ drivers/scsi/ufs/ufshcd.h | 10 + 5 files changed, 487 insertions(+), 7 deletions(-)
Signature · 2 lines
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation.
PATCH v4 1/2 scsi: ufs: Add support for host assisted background operations
Background operations in the UFS device can be disabled by the host to reduce the response latency of transfer requests. Add support for enabling/disabling the background operations during runtime suspend/resume of the device.
If the device is in critical need of BKOPS it will raise an URGENT_BKOPS exception which should be handled by the host to make sure the device performs as expected.
During bootup, the BKOPS is enabled in the device by default. The disable of BKOPS is supported only when the driver supports runtime suspend/resume operations as the runtime PM framework provides a way to determine the device idleness and hence BKOPS can be managed effectively. During runtime resume the BKOPS is disabled to reduce latency and during runtime suspend the BKOPS is enabled to allow device to carry out idle time BKOPS.
In some cases where the BKOPS is disabled during runtime resume and due to continuous data transfers the runtime suspend is not triggered, the BKOPS is enabled when the device raises a level-2 exception (outstanding operations - performance impact).
--- drivers/scsi/ufs/ufs.h | 23 +++ drivers/scsi/ufs/ufshcd.c | 343 +++++++++++++++++++++++++++++++++++++++++++++ drivers/scsi/ufs/ufshcd.h | 10 ++ 3 files changed, 376 insertions(+), 0 deletions(-)
drivers/scsi/ufs/ufs.h +23 -0
@@ -107,6 +107,28 @@ enum {/* Flag idn for Query Requests*/ enum flag_idn {QUERY_FLAG_IDN_FDEVICEINIT =0x01 , +QUERY_FLAG_IDN_BKOPS_EN =0x04 , +}; + +/* Attribute idn for Query requests */ +enum attr_idn { +QUERY_ATTR_IDN_BKOPS_STATUS =0x05 , +QUERY_ATTR_IDN_EE_CONTROL =0x0D , +QUERY_ATTR_IDN_EE_STATUS =0x0E , +}; + +/* Exception event mask values */ +enum { +MASK_EE_STATUS =0xFFFF , +MASK_EE_URGENT_BKOPS = (1 <<2 ), +}; + +/* Background operation status */ +enum { +BKOPS_STATUS_NO_OP =0x0 , +BKOPS_STATUS_NON_CRITICAL =0x1 , +BKOPS_STATUS_PERF_IMPACT =0x2 , +BKOPS_STATUS_CRITICAL =0x3 , };/* UTP QUERY Transaction Specific Fields OpCode */
@@ -155,6 +177,7 @@ enum {MASK_TASK_RESPONSE =0xFF00 ,MASK_RSP_UPIU_RESULT =0xFFFF ,MASK_QUERY_DATA_SEG_LEN =0xFFFF , + MASK_RSP_EXCEPTION_EVENT = 0x10000, };/* Task management service response */
drivers/scsi/ufs/ufshcd.c +343 -0
385 lines not on this page · raw message
drivers/scsi/ufs/ufshcd.h +10 -0
@@ -178,9 +178,12 @@ struct ufs_dev_cmd {* @tm_condition: condition variable for task management * @ufshcd_state: UFSHCD states * @intr_mask: Interrupt Mask Bits +* @ee_ctrl_mask: Exception event control mask * @feh_workq: Work queue for fatal controller error handling +* @eeh_work: Worker to handle exception events * @errors: HBA errors * @dev_cmd: ufs device management command information +* @auto_bkops_enabled: to track whether bkops is enabled in device */ struct ufs_hba {void __iomem *mmio_base;
@@ -218,15 +221,19 @@ struct ufs_hba {u32 ufshcd_state;u32 intr_mask; +u16 ee_ctrl_mask;/* Work Queues */ struct work_struct feh_workq; +struct work_struct eeh_work;/* HBA Errors */ u32 errors;/* Device management request data */ struct ufs_dev_cmd dev_cmd; + +bool auto_bkops_enabled; };#define ufshcd_writel (hba, val, reg) \
@@ -253,4 +260,7 @@ static inline void check_upiu_size(void) GENERAL_UPIU_REQUEST_SIZE + QUERY_DESC_MAX_SIZE); } +extern int ufshcd_runtime_suspend (struct ufs_hba *hba); +extern int ufshcd_runtime_resume (struct ufs_hba *hba); +extern int ufshcd_runtime_idle (struct ufs_hba *hba);#endif /* End of Header */
Signature · 2 lines
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation.
PATCH v4 2/2 scsi: ufs: Add runtime PM support for UFS host controller driver
In reply to Sujit Reddy ThummaAdd runtime PM helpers to suspend/resume UFS controller at runtime. Enable runtime PM by default for pci and platform drivers as the initialized hardware can suspend if it is not used after bootup.
--- drivers/scsi/ufs/ufshcd-pci.c | 62 ++++++++++++++++++++++++++++++++++---- drivers/scsi/ufs/ufshcd-pltfrm.c | 48 ++++++++++++++++++++++++++++- drivers/scsi/ufs/ufshcd.c | 8 +++++ 3 files changed, 111 insertions(+), 7 deletions(-)
drivers/scsi/ufs/ufshcd-pci.c +56 -6
@@ -35,6 +35,7 @@#include "ufshcd.h" #include <linux/pci.h> +#include <linux/pm_runtime.h> #ifdef CONFIG_PM /**
@@ -44,7 +45,7 @@* * Returns -ENOSYS */ -static int ufshcd_pci_suspend (struct pci_dev *pdev,pm_message_t state) +static int ufshcd_pci_suspend (struct device *dev) {/* * TODO:
@@ -61,7 +62,7 @@ static int ufshcd_pci_suspend(struct pci_dev *pdev, pm_message_t state)* * Returns -ENOSYS */ -static int ufshcd_pci_resume (struct pci_dev *pdev) +static int ufshcd_pci_resume (struct device *dev) {/* * TODO:
@@ -71,8 +72,45 @@ static int ufshcd_pci_resume(struct pci_dev *pdev)return -ENOSYS ; } +#else +#define ufshcd_pci_suspend NULL +#define ufshcd_pci_resume NULL#endif /* CONFIG_PM */ +#ifdef CONFIG_PM_RUNTIME +static int ufshcd_pci_runtime_suspend (struct device *dev) +{ +struct ufs_hba *hba =dev_get_drvdata (dev); + +if (!hba) +return 0 ; + +return ufshcd_runtime_suspend (hba); +} +static int ufshcd_pci_runtime_resume (struct device *dev) +{ +struct ufs_hba *hba =dev_get_drvdata (dev); + +if (!hba) +return 0 ; + +return ufshcd_runtime_resume (hba); +} +static int ufshcd_pci_runtime_idle (struct device *dev) +{ +struct ufs_hba *hba =dev_get_drvdata (dev); + +if (!hba) +return 0 ; + +return ufshcd_runtime_idle (hba); +} +#else /* !CONFIG_PM_RUNTIME */ +#define ufshcd_pci_runtime_suspend NULL +#define ufshcd_pci_runtime_resume NULL +#define ufshcd_pci_runtime_idle NULL +#endif /* CONFIG_PM_RUNTIME */ +/** * ufshcd_pci_shutdown - main function to put the controller in reset state * @pdev: pointer to PCI device handle
@@ -91,6 +129,9 @@ static void ufshcd_pci_remove(struct pci_dev *pdev) {struct ufs_hba *hba =pci_get_drvdata (pdev); +pm_runtime_forbid (&pdev->dev); +pm_runtime_get_noresume (&pdev->dev); +disable_irq (pdev->irq);ufshcd_remove (hba);pci_release_regions (pdev);
@@ -168,6 +209,8 @@ ufshcd_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) }pci_set_drvdata (pdev, hba); +pm_runtime_put_noidle (&pdev->dev); +pm_runtime_allow (&pdev->dev);return 0 ;
@@ -182,6 +225,14 @@ out_error:return err; } +static const struct dev_pm_ops ufshcd_pci_pm_ops = { + .suspend = ufshcd_pci_suspend, + .resume = ufshcd_pci_resume, + .runtime_suspend = ufshcd_pci_runtime_suspend, + .runtime_resume = ufshcd_pci_runtime_resume, + .runtime_idle = ufshcd_pci_runtime_idle, +}; +static DEFINE_PCI_DEVICE_TABLE (ufshcd_pci_tbl) = { {PCI_VENDOR_ID_SAMSUNG ,0xC00C ,PCI_ANY_ID ,PCI_ANY_ID ,0 ,0 ,0 }, { }/* terminate list */
@@ -195,10 +246,9 @@ static struct pci_driver ufshcd_pci_driver = { .probe = ufshcd_pci_probe, .remove = ufshcd_pci_remove, .shutdown = ufshcd_pci_shutdown, -#ifdef CONFIG_PM - .suspend = ufshcd_pci_suspend, - .resume = ufshcd_pci_resume, -#endif + .driver = { + .pm = &ufshcd_pci_pm_ops + }, };module_pci_driver (ufshcd_pci_driver);
drivers/scsi/ufs/ufshcd-pltfrm.c +47 -1
85 lines not on this page · raw message
drivers/scsi/ufs/ufshcd.c +8 -0
@@ -2169,6 +2169,7 @@ static void ufshcd_exception_event_handler(struct work_struct *work)u32 status =0 ; hba = container_of(work, struct ufs_hba, eeh_work); +pm_runtime_get_sync (hba->dev); err =ufshcd_get_ee_status (hba, &status);if (err) { dev_err(hba->dev, "%s: failed to get exception status %d\n",
@@ -2184,6 +2185,7 @@ static void ufshcd_exception_event_handler(struct work_struct *work) __func__, err); } out: +pm_runtime_put_sync (hba->dev);return ; }
@@ -2196,9 +2198,11 @@ static void ufshcd_fatal_err_handler(struct work_struct *work)struct ufs_hba *hba; hba = container_of(work, struct ufs_hba, feh_workq); +pm_runtime_get_sync (hba->dev);/* check if reset is already in progress */ if (hba->ufshcd_state !=UFSHCD_STATE_RESET )ufshcd_do_reset (hba); +pm_runtime_put_sync (hba->dev); }/**
@@ -2500,6 +2504,7 @@ static void ufshcd_async_scan(void *data, async_cookie_t cookie)ufshcd_force_reset_auto_bkops (hba);scsi_scan_host (hba->host); +pm_runtime_put_sync (hba->dev); out:return ; }
@@ -2721,6 +2726,9 @@ int ufshcd_init(struct device *dev, struct ufs_hba **hba_handle, *hba_handle = hba; +/* Hold auto suspend until async scan completes */ +pm_runtime_get_sync (dev); +async_schedule (ufshcd_async_scan, hba);return 0 ;
Signature · 2 lines
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation.