Re: [PATCH v20 1/2] scsi: ufs: Enable power management for wlun

2021-04-19 Thread Asutosh Das (asd)

On 4/19/2021 11:37 AM, Adrian Hunter wrote:

On 16/04/21 10:49 pm, Asutosh Das wrote:


Co-developed-by: Can Guo 
Signed-off-by: Can Guo 
Signed-off-by: Asutosh Das 
---


I came across 3 issues while testing.  See comments below.


Hi Adrian
Thanks for the comments.




@@ -5794,7 +5839,7 @@ static void ufshcd_err_handling_unprepare(struct ufs_hba 
*hba)
if (ufshcd_is_clkscaling_supported(hba))
ufshcd_clk_scaling_suspend(hba, false);
ufshcd_clear_ua_wluns(hba);


ufshcd_clear_ua_wluns() deadlocks trying to clear UFS_UPIU_RPMB_WLUN
if sdev_rpmb is suspended and sdev_ufs_device is suspending.
e.g. ufshcd_wl_suspend() is waiting on host_sem while ufshcd_err_handler()
is running, at which point sdev_rpmb has already suspended.


Umm, I didn't understand this deadlock.
When you say, sdev_rpmb is suspended, does it mean runtime_suspended?
sdev_ufs_device is suspending - this can't be runtime_suspending, while 
ufshcd_err_handling_unprepare is running.


If you've a call-stack of this deadlock, please can you share it with 
me. I'll also try to reproduce this.


I'll address the other comments in the next version.


Thank you!


-   pm_runtime_put(hba->dev);
+   ufshcd_rpm_put(hba);
  }





+void ufshcd_resume_complete(struct device *dev)
+{


--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
Linux Foundation Collaborative Project


[PATCH v20 2/2] ufs: sysfs: Resume the proper scsi device

2021-04-16 Thread Asutosh Das
Resumes the actual scsi device the unit descriptor of which
is being accessed instead of the hba alone.

Reviewed-by: Adrian Hunter 
Reviewed-by: Can Guo 
Signed-off-by: Asutosh Das 
---
 drivers/scsi/ufs/ufs-sysfs.c | 24 
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/drivers/scsi/ufs/ufs-sysfs.c b/drivers/scsi/ufs/ufs-sysfs.c
index d7c3cff..4d9d4d8 100644
--- a/drivers/scsi/ufs/ufs-sysfs.c
+++ b/drivers/scsi/ufs/ufs-sysfs.c
@@ -245,9 +245,9 @@ static ssize_t wb_on_store(struct device *dev, struct 
device_attribute *attr,
goto out;
}
 
-   pm_runtime_get_sync(hba->dev);
+   ufshcd_rpm_get_sync(hba);
res = ufshcd_wb_toggle(hba, wb_enable);
-   pm_runtime_put_sync(hba->dev);
+   ufshcd_rpm_put_sync(hba);
 out:
up(>host_sem);
return res < 0 ? res : count;
@@ -297,10 +297,10 @@ static ssize_t ufs_sysfs_read_desc_param(struct ufs_hba 
*hba,
goto out;
}
 
-   pm_runtime_get_sync(hba->dev);
+   ufshcd_rpm_get_sync(hba);
ret = ufshcd_read_desc_param(hba, desc_id, desc_index,
param_offset, desc_buf, param_size);
-   pm_runtime_put_sync(hba->dev);
+   ufshcd_rpm_put_sync(hba);
if (ret) {
ret = -EINVAL;
goto out;
@@ -678,7 +678,7 @@ static ssize_t _name##_show(struct device *dev, 
\
up(>host_sem); \
return -ENOMEM; \
}   \
-   pm_runtime_get_sync(hba->dev);  \
+   ufshcd_rpm_get_sync(hba);   \
ret = ufshcd_query_descriptor_retry(hba,\
UPIU_QUERY_OPCODE_READ_DESC, QUERY_DESC_IDN_DEVICE, \
0, 0, desc_buf, _len); \
@@ -695,7 +695,7 @@ static ssize_t _name##_show(struct device *dev, 
\
goto out;   \
ret = sysfs_emit(buf, "%s\n", desc_buf);\
 out:   \
-   pm_runtime_put_sync(hba->dev);  \
+   ufshcd_rpm_put_sync(hba);   \
kfree(desc_buf);\
up(>host_sem); \
return ret; \
@@ -744,10 +744,10 @@ static ssize_t _name##_show(struct device *dev,   
\
}   \
if (ufshcd_is_wb_flags(QUERY_FLAG_IDN##_uname)) \
index = ufshcd_wb_get_query_index(hba); \
-   pm_runtime_get_sync(hba->dev);  \
+   ufshcd_rpm_get_sync(hba);   \
ret = ufshcd_query_flag(hba, UPIU_QUERY_OPCODE_READ_FLAG,   \
QUERY_FLAG_IDN##_uname, index, );  \
-   pm_runtime_put_sync(hba->dev);  \
+   ufshcd_rpm_put_sync(hba);   \
if (ret) {  \
ret = -EINVAL;  \
goto out;   \
@@ -813,10 +813,10 @@ static ssize_t _name##_show(struct device *dev,   
\
}   \
if (ufshcd_is_wb_attrs(QUERY_ATTR_IDN##_uname)) \
index = ufshcd_wb_get_query_index(hba); \
-   pm_runtime_get_sync(hba->dev);  \
+   ufshcd_rpm_get_sync(hba);   \
ret = ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_READ_ATTR,   \
QUERY_ATTR_IDN##_uname, index, 0, );  \
-   pm_runtime_put_sync(hba->dev);  \
+   ufshcd_rpm_put_sync(hba);   \
if (ret) {  \
ret = -EINVAL;  \
goto out;   \
@@ -964,10 +964,10 @@ static ssize_t dyn_cap_needed_attribute_show(struct 
device *dev,
goto out;
}
 
-   pm_runtime_get_sync(hba->dev);
+   ufshcd_rpm_get_sync(hba);
ret = ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_READ_ATTR

[PATCH v20 1/2] scsi: ufs: Enable power management for wlun

2021-04-16 Thread Asutosh Das
During runtime-suspend of ufs host, the scsi devices are
already suspended and so are the queues associated with them.
But the ufs host sends SSU (START_STOP_UNIT) to wlun
during its runtime-suspend.
During the process blk_queue_enter checks if the queue is not in
suspended state. If so, it waits for the queue to resume, and never
comes out of it.
The commit
(d55d15a33: scsi: block: Do not accept any requests while suspended)
adds the check if the queue is in suspended state in blk_queue_enter().

Call trace:
 __switch_to+0x174/0x2c4
 __schedule+0x478/0x764
 schedule+0x9c/0xe0
 blk_queue_enter+0x158/0x228
 blk_mq_alloc_request+0x40/0xa4
 blk_get_request+0x2c/0x70
 __scsi_execute+0x60/0x1c4
 ufshcd_set_dev_pwr_mode+0x124/0x1e4
 ufshcd_suspend+0x208/0x83c
 ufshcd_runtime_suspend+0x40/0x154
 ufshcd_pltfrm_runtime_suspend+0x14/0x20
 pm_generic_runtime_suspend+0x28/0x3c
 __rpm_callback+0x80/0x2a4
 rpm_suspend+0x308/0x614
 rpm_idle+0x158/0x228
 pm_runtime_work+0x84/0xac
 process_one_work+0x1f0/0x470
 worker_thread+0x26c/0x4c8
 kthread+0x13c/0x320
 ret_from_fork+0x10/0x18

Fix this by registering ufs device wlun as a scsi driver and
registering it for block runtime-pm. Also make this as a
supplier for all other luns. That way, this device wlun
suspends after all the consumers and resumes after
hba resumes. This also registers a new scsi driver for rpmb wlun.
This new driver is mostly used to clear rpmb uac.

Fixed smatch warnings:
Reported-by: kernel test robot 
Reported-by: Dan Carpenter 

Co-developed-by: Can Guo 
Signed-off-by: Can Guo 
Signed-off-by: Asutosh Das 
---
 drivers/scsi/ufs/cdns-pltfrm.c |   2 +
 drivers/scsi/ufs/tc-dwc-g210-pci.c |   2 +
 drivers/scsi/ufs/ufs-debugfs.c |   6 +-
 drivers/scsi/ufs/ufs-debugfs.h |   2 +-
 drivers/scsi/ufs/ufs-exynos.c  |   2 +
 drivers/scsi/ufs/ufs-hisi.c|   2 +
 drivers/scsi/ufs/ufs-mediatek.c|  12 +-
 drivers/scsi/ufs/ufs-qcom.c|   2 +
 drivers/scsi/ufs/ufs_bsg.c |   6 +-
 drivers/scsi/ufs/ufshcd-pci.c  |  36 +-
 drivers/scsi/ufs/ufshcd.c  | 719 ++---
 drivers/scsi/ufs/ufshcd.h  |  21 ++
 include/trace/events/ufs.h |  20 ++
 13 files changed, 580 insertions(+), 252 deletions(-)

diff --git a/drivers/scsi/ufs/cdns-pltfrm.c b/drivers/scsi/ufs/cdns-pltfrm.c
index 13d9204..908ff39 100644
--- a/drivers/scsi/ufs/cdns-pltfrm.c
+++ b/drivers/scsi/ufs/cdns-pltfrm.c
@@ -323,6 +323,8 @@ static const struct dev_pm_ops cdns_ufs_dev_pm_ops = {
.runtime_suspend = ufshcd_pltfrm_runtime_suspend,
.runtime_resume  = ufshcd_pltfrm_runtime_resume,
.runtime_idle= ufshcd_pltfrm_runtime_idle,
+   .prepare = ufshcd_suspend_prepare,
+   .complete= ufshcd_resume_complete,
 };
 
 static struct platform_driver cdns_ufs_pltfrm_driver = {
diff --git a/drivers/scsi/ufs/tc-dwc-g210-pci.c 
b/drivers/scsi/ufs/tc-dwc-g210-pci.c
index 67a6a61..ec4589a 100644
--- a/drivers/scsi/ufs/tc-dwc-g210-pci.c
+++ b/drivers/scsi/ufs/tc-dwc-g210-pci.c
@@ -148,6 +148,8 @@ static const struct dev_pm_ops tc_dwc_g210_pci_pm_ops = {
.runtime_suspend = tc_dwc_g210_pci_runtime_suspend,
.runtime_resume  = tc_dwc_g210_pci_runtime_resume,
.runtime_idle= tc_dwc_g210_pci_runtime_idle,
+   .prepare = ufshcd_suspend_prepare,
+   .complete= ufshcd_resume_complete,
 };
 
 static const struct pci_device_id tc_dwc_g210_pci_tbl[] = {
diff --git a/drivers/scsi/ufs/ufs-debugfs.c b/drivers/scsi/ufs/ufs-debugfs.c
index ced9ef4..4e1ff20 100644
--- a/drivers/scsi/ufs/ufs-debugfs.c
+++ b/drivers/scsi/ufs/ufs-debugfs.c
@@ -13,7 +13,7 @@ void __init ufs_debugfs_init(void)
ufs_debugfs_root = debugfs_create_dir("ufshcd", NULL);
 }
 
-void __exit ufs_debugfs_exit(void)
+void ufs_debugfs_exit(void)
 {
debugfs_remove_recursive(ufs_debugfs_root);
 }
@@ -60,14 +60,14 @@ __acquires(>host_sem)
up(>host_sem);
return -EBUSY;
}
-   pm_runtime_get_sync(hba->dev);
+   ufshcd_rpm_get_sync(hba);
return 0;
 }
 
 static void ufs_debugfs_put_user_access(struct ufs_hba *hba)
 __releases(>host_sem)
 {
-   pm_runtime_put_sync(hba->dev);
+   ufshcd_rpm_put_sync(hba);
up(>host_sem);
 }
 
diff --git a/drivers/scsi/ufs/ufs-debugfs.h b/drivers/scsi/ufs/ufs-debugfs.h
index 3ca29d3..97548a3 100644
--- a/drivers/scsi/ufs/ufs-debugfs.h
+++ b/drivers/scsi/ufs/ufs-debugfs.h
@@ -9,7 +9,7 @@ struct ufs_hba;
 
 #ifdef CONFIG_DEBUG_FS
 void __init ufs_debugfs_init(void);
-void __exit ufs_debugfs_exit(void);
+void ufs_debugfs_exit(void);
 void ufs_debugfs_hba_init(struct ufs_hba *hba);
 void ufs_debugfs_hba_exit(struct ufs_hba *hba);
 void ufs_debugfs_exception_event(struct ufs_hba *hba, u16 status);
diff --git a/drivers/scsi/ufs/ufs-exynos.c b/drivers/scsi/ufs/ufs-exynos.c
index 70647ea..8b31efb 100644
--- a/drivers/scsi/ufs/ufs-exynos.c
+++ b/drivers/scsi

Re: [PATCH v18 1/2] scsi: ufs: Enable power management for wlun

2021-04-16 Thread Asutosh Das (asd)

On 4/15/2021 4:11 PM, Bart Van Assche wrote:

On 4/14/21 11:58 AM, Asutosh Das wrote:

[ ... ]



Hi Bart,
Thanks for the comments. I will fix the comments in the next version.


The following code is executed before ufshcd_async_scan() is called:

dev = hba->dev;
[ ... ]
/* Hold auto suspend until async scan completes */
pm_runtime_get_sync(dev);

That would only keep the hba runtime resumed. At this point of time the 
luns are not detected yet.

and the following code occurs in ufshcd_add_lus():

pm_runtime_put_sync(hba->dev);

Isn't that sufficient to postpone enabling of runtime PM until LUN
scanning has finished? Or in other words, is adding a
pm_runtime_get_noresume() call in ufshcd_slave_configure() really necessary?

Yes, because the supplier (device wlun) may be suspended otherwise in 
scsi_sysfs_add_sdev().

@@ -4979,15 +5035,9 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct 
ufshcd_lrb *lrbp)
 */
if (!hba->pm_op_in_progress &&
!ufshcd_eh_in_progress(hba) &&
-   ufshcd_is_exception_event(lrbp->ucd_rsp_ptr) &&
-   schedule_work(>eeh_work)) {
-   /*
-* Prevent suspend once eeh_work is scheduled
-* to avoid deadlock between ufshcd_suspend
-* and exception event handler.
-*/
-   pm_runtime_get_noresume(hba->dev);
-   }
+   ufshcd_is_exception_event(lrbp->ucd_rsp_ptr))
+   /* Flushed in suspend */
+   schedule_work(>eeh_work);


What makes it safe to leave out the above pm_runtime_get_noresume() call?

The __ufshcd_wl_suspend() would flush this work so that it doesn't run 
after suspend.

Thanks,

Bart.




--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
Linux Foundation Collaborative Project


[PATCH v19 1/2] scsi: ufs: Enable power management for wlun

2021-04-15 Thread Asutosh Das
During runtime-suspend of ufs host, the scsi devices are
already suspended and so are the queues associated with them.
But the ufs host sends SSU (START_STOP_UNIT) to wlun
during its runtime-suspend.
During the process blk_queue_enter checks if the queue is not in
suspended state. If so, it waits for the queue to resume, and never
comes out of it.
The commit
(d55d15a33: scsi: block: Do not accept any requests while suspended)
adds the check if the queue is in suspended state in blk_queue_enter().

Call trace:
 __switch_to+0x174/0x2c4
 __schedule+0x478/0x764
 schedule+0x9c/0xe0
 blk_queue_enter+0x158/0x228
 blk_mq_alloc_request+0x40/0xa4
 blk_get_request+0x2c/0x70
 __scsi_execute+0x60/0x1c4
 ufshcd_set_dev_pwr_mode+0x124/0x1e4
 ufshcd_suspend+0x208/0x83c
 ufshcd_runtime_suspend+0x40/0x154
 ufshcd_pltfrm_runtime_suspend+0x14/0x20
 pm_generic_runtime_suspend+0x28/0x3c
 __rpm_callback+0x80/0x2a4
 rpm_suspend+0x308/0x614
 rpm_idle+0x158/0x228
 pm_runtime_work+0x84/0xac
 process_one_work+0x1f0/0x470
 worker_thread+0x26c/0x4c8
 kthread+0x13c/0x320
 ret_from_fork+0x10/0x18

Fix this by registering ufs device wlun as a scsi driver and
registering it for block runtime-pm. Also make this as a
supplier for all other luns. That way, this device wlun
suspends after all the consumers and resumes after
hba resumes.
This also registers a new scsi driver for rpmb wlun.
This new driver is mostly used to clear rpmb uac.
With this design, the driver would always be runtime resumed
before system suspend.

Fixed smatch warnings:
Reported-by: kernel test robot 
Reported-by: Dan Carpenter 

Co-developed-by: Can Guo 
Signed-off-by: Can Guo 
Signed-off-by: Asutosh Das 
---
 drivers/scsi/ufs/cdns-pltfrm.c |   2 +
 drivers/scsi/ufs/tc-dwc-g210-pci.c |   2 +
 drivers/scsi/ufs/ufs-debugfs.c |   6 +-
 drivers/scsi/ufs/ufs-debugfs.h |   2 +-
 drivers/scsi/ufs/ufs-exynos.c  |   2 +
 drivers/scsi/ufs/ufs-hisi.c|   2 +
 drivers/scsi/ufs/ufs-mediatek.c|  12 +-
 drivers/scsi/ufs/ufs-qcom.c|   2 +
 drivers/scsi/ufs/ufs_bsg.c |   6 +-
 drivers/scsi/ufs/ufshcd-pci.c  |  36 +-
 drivers/scsi/ufs/ufshcd.c  | 691 ++---
 drivers/scsi/ufs/ufshcd.h  |  21 ++
 include/trace/events/ufs.h |  20 ++
 13 files changed, 551 insertions(+), 253 deletions(-)

diff --git a/drivers/scsi/ufs/cdns-pltfrm.c b/drivers/scsi/ufs/cdns-pltfrm.c
index 13d9204..b9105e4 100644
--- a/drivers/scsi/ufs/cdns-pltfrm.c
+++ b/drivers/scsi/ufs/cdns-pltfrm.c
@@ -323,6 +323,8 @@ static const struct dev_pm_ops cdns_ufs_dev_pm_ops = {
.runtime_suspend = ufshcd_pltfrm_runtime_suspend,
.runtime_resume  = ufshcd_pltfrm_runtime_resume,
.runtime_idle= ufshcd_pltfrm_runtime_idle,
+   .prepare = ufshcd_suspend_prepare,
+   .complete   = ufshcd_resume_complete,
 };
 
 static struct platform_driver cdns_ufs_pltfrm_driver = {
diff --git a/drivers/scsi/ufs/tc-dwc-g210-pci.c 
b/drivers/scsi/ufs/tc-dwc-g210-pci.c
index 67a6a61..b01db12 100644
--- a/drivers/scsi/ufs/tc-dwc-g210-pci.c
+++ b/drivers/scsi/ufs/tc-dwc-g210-pci.c
@@ -148,6 +148,8 @@ static const struct dev_pm_ops tc_dwc_g210_pci_pm_ops = {
.runtime_suspend = tc_dwc_g210_pci_runtime_suspend,
.runtime_resume  = tc_dwc_g210_pci_runtime_resume,
.runtime_idle= tc_dwc_g210_pci_runtime_idle,
+   .prepare = ufshcd_suspend_prepare,
+   .complete   = ufshcd_resume_complete,
 };
 
 static const struct pci_device_id tc_dwc_g210_pci_tbl[] = {
diff --git a/drivers/scsi/ufs/ufs-debugfs.c b/drivers/scsi/ufs/ufs-debugfs.c
index ced9ef4..4e1ff20 100644
--- a/drivers/scsi/ufs/ufs-debugfs.c
+++ b/drivers/scsi/ufs/ufs-debugfs.c
@@ -13,7 +13,7 @@ void __init ufs_debugfs_init(void)
ufs_debugfs_root = debugfs_create_dir("ufshcd", NULL);
 }
 
-void __exit ufs_debugfs_exit(void)
+void ufs_debugfs_exit(void)
 {
debugfs_remove_recursive(ufs_debugfs_root);
 }
@@ -60,14 +60,14 @@ __acquires(>host_sem)
up(>host_sem);
return -EBUSY;
}
-   pm_runtime_get_sync(hba->dev);
+   ufshcd_rpm_get_sync(hba);
return 0;
 }
 
 static void ufs_debugfs_put_user_access(struct ufs_hba *hba)
 __releases(>host_sem)
 {
-   pm_runtime_put_sync(hba->dev);
+   ufshcd_rpm_put_sync(hba);
up(>host_sem);
 }
 
diff --git a/drivers/scsi/ufs/ufs-debugfs.h b/drivers/scsi/ufs/ufs-debugfs.h
index 3ca29d3..97548a3 100644
--- a/drivers/scsi/ufs/ufs-debugfs.h
+++ b/drivers/scsi/ufs/ufs-debugfs.h
@@ -9,7 +9,7 @@ struct ufs_hba;
 
 #ifdef CONFIG_DEBUG_FS
 void __init ufs_debugfs_init(void);
-void __exit ufs_debugfs_exit(void);
+void ufs_debugfs_exit(void);
 void ufs_debugfs_hba_init(struct ufs_hba *hba);
 void ufs_debugfs_hba_exit(struct ufs_hba *hba);
 void ufs_debugfs_exception_event(struct ufs_hba *hba, u16 status);
diff --git a/drivers/scsi/ufs/ufs-exynos.c b/drivers/scsi/ufs/ufs-exynos.c
i

[PATCH v19 2/2] ufs: sysfs: Resume the proper scsi device

2021-04-15 Thread Asutosh Das
Resumes the actual scsi device the unit descriptor of which
is being accessed instead of the hba alone.

Reviewed-by: Adrian Hunter 
Reviewed-by: Can Guo 
Signed-off-by: Asutosh Das 
---
 drivers/scsi/ufs/ufs-sysfs.c | 24 
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/drivers/scsi/ufs/ufs-sysfs.c b/drivers/scsi/ufs/ufs-sysfs.c
index d7c3cff..4d9d4d8 100644
--- a/drivers/scsi/ufs/ufs-sysfs.c
+++ b/drivers/scsi/ufs/ufs-sysfs.c
@@ -245,9 +245,9 @@ static ssize_t wb_on_store(struct device *dev, struct 
device_attribute *attr,
goto out;
}
 
-   pm_runtime_get_sync(hba->dev);
+   ufshcd_rpm_get_sync(hba);
res = ufshcd_wb_toggle(hba, wb_enable);
-   pm_runtime_put_sync(hba->dev);
+   ufshcd_rpm_put_sync(hba);
 out:
up(>host_sem);
return res < 0 ? res : count;
@@ -297,10 +297,10 @@ static ssize_t ufs_sysfs_read_desc_param(struct ufs_hba 
*hba,
goto out;
}
 
-   pm_runtime_get_sync(hba->dev);
+   ufshcd_rpm_get_sync(hba);
ret = ufshcd_read_desc_param(hba, desc_id, desc_index,
param_offset, desc_buf, param_size);
-   pm_runtime_put_sync(hba->dev);
+   ufshcd_rpm_put_sync(hba);
if (ret) {
ret = -EINVAL;
goto out;
@@ -678,7 +678,7 @@ static ssize_t _name##_show(struct device *dev, 
\
up(>host_sem); \
return -ENOMEM; \
}   \
-   pm_runtime_get_sync(hba->dev);  \
+   ufshcd_rpm_get_sync(hba);   \
ret = ufshcd_query_descriptor_retry(hba,\
UPIU_QUERY_OPCODE_READ_DESC, QUERY_DESC_IDN_DEVICE, \
0, 0, desc_buf, _len); \
@@ -695,7 +695,7 @@ static ssize_t _name##_show(struct device *dev, 
\
goto out;   \
ret = sysfs_emit(buf, "%s\n", desc_buf);\
 out:   \
-   pm_runtime_put_sync(hba->dev);  \
+   ufshcd_rpm_put_sync(hba);   \
kfree(desc_buf);\
up(>host_sem); \
return ret; \
@@ -744,10 +744,10 @@ static ssize_t _name##_show(struct device *dev,   
\
}   \
if (ufshcd_is_wb_flags(QUERY_FLAG_IDN##_uname)) \
index = ufshcd_wb_get_query_index(hba); \
-   pm_runtime_get_sync(hba->dev);  \
+   ufshcd_rpm_get_sync(hba);   \
ret = ufshcd_query_flag(hba, UPIU_QUERY_OPCODE_READ_FLAG,   \
QUERY_FLAG_IDN##_uname, index, );  \
-   pm_runtime_put_sync(hba->dev);  \
+   ufshcd_rpm_put_sync(hba);   \
if (ret) {  \
ret = -EINVAL;  \
goto out;   \
@@ -813,10 +813,10 @@ static ssize_t _name##_show(struct device *dev,   
\
}   \
if (ufshcd_is_wb_attrs(QUERY_ATTR_IDN##_uname)) \
index = ufshcd_wb_get_query_index(hba); \
-   pm_runtime_get_sync(hba->dev);  \
+   ufshcd_rpm_get_sync(hba);   \
ret = ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_READ_ATTR,   \
QUERY_ATTR_IDN##_uname, index, 0, );  \
-   pm_runtime_put_sync(hba->dev);  \
+   ufshcd_rpm_put_sync(hba);   \
if (ret) {  \
ret = -EINVAL;  \
goto out;   \
@@ -964,10 +964,10 @@ static ssize_t dyn_cap_needed_attribute_show(struct 
device *dev,
goto out;
}
 
-   pm_runtime_get_sync(hba->dev);
+   ufshcd_rpm_get_sync(hba);
ret = ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_READ_ATTR

[PATCH v18 2/2] ufs: sysfs: Resume the proper scsi device

2021-04-14 Thread Asutosh Das
Resumes the actual scsi device the unit descriptor of which
is being accessed instead of the hba alone.

Reviewed-by: Can Guo 
Signed-off-by: Asutosh Das 
---
 drivers/scsi/ufs/ufs-sysfs.c | 24 
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/drivers/scsi/ufs/ufs-sysfs.c b/drivers/scsi/ufs/ufs-sysfs.c
index d7c3cff..4d9d4d8 100644
--- a/drivers/scsi/ufs/ufs-sysfs.c
+++ b/drivers/scsi/ufs/ufs-sysfs.c
@@ -245,9 +245,9 @@ static ssize_t wb_on_store(struct device *dev, struct 
device_attribute *attr,
goto out;
}
 
-   pm_runtime_get_sync(hba->dev);
+   ufshcd_rpm_get_sync(hba);
res = ufshcd_wb_toggle(hba, wb_enable);
-   pm_runtime_put_sync(hba->dev);
+   ufshcd_rpm_put_sync(hba);
 out:
up(>host_sem);
return res < 0 ? res : count;
@@ -297,10 +297,10 @@ static ssize_t ufs_sysfs_read_desc_param(struct ufs_hba 
*hba,
goto out;
}
 
-   pm_runtime_get_sync(hba->dev);
+   ufshcd_rpm_get_sync(hba);
ret = ufshcd_read_desc_param(hba, desc_id, desc_index,
param_offset, desc_buf, param_size);
-   pm_runtime_put_sync(hba->dev);
+   ufshcd_rpm_put_sync(hba);
if (ret) {
ret = -EINVAL;
goto out;
@@ -678,7 +678,7 @@ static ssize_t _name##_show(struct device *dev, 
\
up(>host_sem); \
return -ENOMEM; \
}   \
-   pm_runtime_get_sync(hba->dev);  \
+   ufshcd_rpm_get_sync(hba);   \
ret = ufshcd_query_descriptor_retry(hba,\
UPIU_QUERY_OPCODE_READ_DESC, QUERY_DESC_IDN_DEVICE, \
0, 0, desc_buf, _len); \
@@ -695,7 +695,7 @@ static ssize_t _name##_show(struct device *dev, 
\
goto out;   \
ret = sysfs_emit(buf, "%s\n", desc_buf);\
 out:   \
-   pm_runtime_put_sync(hba->dev);  \
+   ufshcd_rpm_put_sync(hba);   \
kfree(desc_buf);\
up(>host_sem); \
return ret; \
@@ -744,10 +744,10 @@ static ssize_t _name##_show(struct device *dev,   
\
}   \
if (ufshcd_is_wb_flags(QUERY_FLAG_IDN##_uname)) \
index = ufshcd_wb_get_query_index(hba); \
-   pm_runtime_get_sync(hba->dev);  \
+   ufshcd_rpm_get_sync(hba);   \
ret = ufshcd_query_flag(hba, UPIU_QUERY_OPCODE_READ_FLAG,   \
QUERY_FLAG_IDN##_uname, index, );  \
-   pm_runtime_put_sync(hba->dev);  \
+   ufshcd_rpm_put_sync(hba);   \
if (ret) {  \
ret = -EINVAL;  \
goto out;   \
@@ -813,10 +813,10 @@ static ssize_t _name##_show(struct device *dev,   
\
}   \
if (ufshcd_is_wb_attrs(QUERY_ATTR_IDN##_uname)) \
index = ufshcd_wb_get_query_index(hba); \
-   pm_runtime_get_sync(hba->dev);  \
+   ufshcd_rpm_get_sync(hba);   \
ret = ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_READ_ATTR,   \
QUERY_ATTR_IDN##_uname, index, 0, );  \
-   pm_runtime_put_sync(hba->dev);  \
+   ufshcd_rpm_put_sync(hba);   \
if (ret) {  \
ret = -EINVAL;  \
goto out;   \
@@ -964,10 +964,10 @@ static ssize_t dyn_cap_needed_attribute_show(struct 
device *dev,
goto out;
}
 
-   pm_runtime_get_sync(hba->dev);
+   ufshcd_rpm_get_sync(hba);
ret = ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_READ_ATTR

[PATCH v18 1/2] scsi: ufs: Enable power management for wlun

2021-04-14 Thread Asutosh Das
During runtime-suspend of ufs host, the scsi devices are
already suspended and so are the queues associated with them.
But the ufs host sends SSU (START_STOP_UNIT) to wlun
during its runtime-suspend.
During the process blk_queue_enter checks if the queue is not in
suspended state. If so, it waits for the queue to resume, and never
comes out of it.
The commit
(d55d15a33: scsi: block: Do not accept any requests while suspended)
adds the check if the queue is in suspended state in blk_queue_enter().

Call trace:
 __switch_to+0x174/0x2c4
 __schedule+0x478/0x764
 schedule+0x9c/0xe0
 blk_queue_enter+0x158/0x228
 blk_mq_alloc_request+0x40/0xa4
 blk_get_request+0x2c/0x70
 __scsi_execute+0x60/0x1c4
 ufshcd_set_dev_pwr_mode+0x124/0x1e4
 ufshcd_suspend+0x208/0x83c
 ufshcd_runtime_suspend+0x40/0x154
 ufshcd_pltfrm_runtime_suspend+0x14/0x20
 pm_generic_runtime_suspend+0x28/0x3c
 __rpm_callback+0x80/0x2a4
 rpm_suspend+0x308/0x614
 rpm_idle+0x158/0x228
 pm_runtime_work+0x84/0xac
 process_one_work+0x1f0/0x470
 worker_thread+0x26c/0x4c8
 kthread+0x13c/0x320
 ret_from_fork+0x10/0x18

Fix this by registering ufs device wlun as a scsi driver and
registering it for block runtime-pm. Also make this as a
supplier for all other luns. That way, this device wlun
suspends after all the consumers and resumes after
hba resumes.

Co-developed-by: Can Guo 
Signed-off-by: Can Guo 
Signed-off-by: Asutosh Das 
---
 drivers/scsi/ufs/cdns-pltfrm.c |   2 +
 drivers/scsi/ufs/tc-dwc-g210-pci.c |   2 +
 drivers/scsi/ufs/ufs-debugfs.c |   6 +-
 drivers/scsi/ufs/ufs-debugfs.h |   2 +-
 drivers/scsi/ufs/ufs-exynos.c  |   2 +
 drivers/scsi/ufs/ufs-hisi.c|   2 +
 drivers/scsi/ufs/ufs-mediatek.c|  12 +-
 drivers/scsi/ufs/ufs-qcom.c|   2 +
 drivers/scsi/ufs/ufs_bsg.c |   6 +-
 drivers/scsi/ufs/ufshcd-pci.c  |  36 +-
 drivers/scsi/ufs/ufshcd.c  | 692 +
 drivers/scsi/ufs/ufshcd.h  |  21 ++
 include/trace/events/ufs.h |  20 ++
 13 files changed, 549 insertions(+), 256 deletions(-)

diff --git a/drivers/scsi/ufs/cdns-pltfrm.c b/drivers/scsi/ufs/cdns-pltfrm.c
index 13d9204..b9105e4 100644
--- a/drivers/scsi/ufs/cdns-pltfrm.c
+++ b/drivers/scsi/ufs/cdns-pltfrm.c
@@ -323,6 +323,8 @@ static const struct dev_pm_ops cdns_ufs_dev_pm_ops = {
.runtime_suspend = ufshcd_pltfrm_runtime_suspend,
.runtime_resume  = ufshcd_pltfrm_runtime_resume,
.runtime_idle= ufshcd_pltfrm_runtime_idle,
+   .prepare = ufshcd_suspend_prepare,
+   .complete   = ufshcd_resume_complete,
 };
 
 static struct platform_driver cdns_ufs_pltfrm_driver = {
diff --git a/drivers/scsi/ufs/tc-dwc-g210-pci.c 
b/drivers/scsi/ufs/tc-dwc-g210-pci.c
index 67a6a61..b01db12 100644
--- a/drivers/scsi/ufs/tc-dwc-g210-pci.c
+++ b/drivers/scsi/ufs/tc-dwc-g210-pci.c
@@ -148,6 +148,8 @@ static const struct dev_pm_ops tc_dwc_g210_pci_pm_ops = {
.runtime_suspend = tc_dwc_g210_pci_runtime_suspend,
.runtime_resume  = tc_dwc_g210_pci_runtime_resume,
.runtime_idle= tc_dwc_g210_pci_runtime_idle,
+   .prepare = ufshcd_suspend_prepare,
+   .complete   = ufshcd_resume_complete,
 };
 
 static const struct pci_device_id tc_dwc_g210_pci_tbl[] = {
diff --git a/drivers/scsi/ufs/ufs-debugfs.c b/drivers/scsi/ufs/ufs-debugfs.c
index ced9ef4..4e1ff20 100644
--- a/drivers/scsi/ufs/ufs-debugfs.c
+++ b/drivers/scsi/ufs/ufs-debugfs.c
@@ -13,7 +13,7 @@ void __init ufs_debugfs_init(void)
ufs_debugfs_root = debugfs_create_dir("ufshcd", NULL);
 }
 
-void __exit ufs_debugfs_exit(void)
+void ufs_debugfs_exit(void)
 {
debugfs_remove_recursive(ufs_debugfs_root);
 }
@@ -60,14 +60,14 @@ __acquires(>host_sem)
up(>host_sem);
return -EBUSY;
}
-   pm_runtime_get_sync(hba->dev);
+   ufshcd_rpm_get_sync(hba);
return 0;
 }
 
 static void ufs_debugfs_put_user_access(struct ufs_hba *hba)
 __releases(>host_sem)
 {
-   pm_runtime_put_sync(hba->dev);
+   ufshcd_rpm_put_sync(hba);
up(>host_sem);
 }
 
diff --git a/drivers/scsi/ufs/ufs-debugfs.h b/drivers/scsi/ufs/ufs-debugfs.h
index 3ca29d3..97548a3 100644
--- a/drivers/scsi/ufs/ufs-debugfs.h
+++ b/drivers/scsi/ufs/ufs-debugfs.h
@@ -9,7 +9,7 @@ struct ufs_hba;
 
 #ifdef CONFIG_DEBUG_FS
 void __init ufs_debugfs_init(void);
-void __exit ufs_debugfs_exit(void);
+void ufs_debugfs_exit(void);
 void ufs_debugfs_hba_init(struct ufs_hba *hba);
 void ufs_debugfs_hba_exit(struct ufs_hba *hba);
 void ufs_debugfs_exception_event(struct ufs_hba *hba, u16 status);
diff --git a/drivers/scsi/ufs/ufs-exynos.c b/drivers/scsi/ufs/ufs-exynos.c
index 70647ea..49a918c 100644
--- a/drivers/scsi/ufs/ufs-exynos.c
+++ b/drivers/scsi/ufs/ufs-exynos.c
@@ -1267,6 +1267,8 @@ static const struct dev_pm_ops exynos_ufs_pm_ops = {
.runtime_suspend = ufshcd_pltfrm_runtime_suspend,
.runtime_resume  = 

Re: [PATCH v17 1/2] scsi: ufs: Enable power management for wlun

2021-04-09 Thread Asutosh Das (asd)

On 4/9/2021 3:07 AM, Adrian Hunter wrote:

On 9/04/21 5:27 am, Daejun Park wrote:

Hi Asutosh Das,


During runtime-suspend of ufs host, the scsi devices are
already suspended and so are the queues associated with them.
But the ufs host sends SSU (START_STOP_UNIT) to wlun
during its runtime-suspend.
During the process blk_queue_enter checks if the queue is not in
suspended state. If so, it waits for the queue to resume, and never
comes out of it.
The commit
(d55d15a33: scsi: block: Do not accept any requests while suspended)
adds the check if the queue is in suspended state in blk_queue_enter().

Call trace:
__switch_to+0x174/0x2c4
__schedule+0x478/0x764
schedule+0x9c/0xe0
blk_queue_enter+0x158/0x228
blk_mq_alloc_request+0x40/0xa4
blk_get_request+0x2c/0x70
__scsi_execute+0x60/0x1c4
ufshcd_set_dev_pwr_mode+0x124/0x1e4
ufshcd_suspend+0x208/0x83c
ufshcd_runtime_suspend+0x40/0x154
ufshcd_pltfrm_runtime_suspend+0x14/0x20
pm_generic_runtime_suspend+0x28/0x3c
__rpm_callback+0x80/0x2a4
rpm_suspend+0x308/0x614
rpm_idle+0x158/0x228
pm_runtime_work+0x84/0xac
process_one_work+0x1f0/0x470
worker_thread+0x26c/0x4c8
kthread+0x13c/0x320
ret_from_fork+0x10/0x18

Fix this by registering ufs device wlun as a scsi driver and
registering it for block runtime-pm. Also make this as a
supplier for all other luns. That way, this device wlun
suspends after all the consumers and resumes after
hba resumes.

Co-developed-by: Can Guo 
Signed-off-by: Can Guo 
Signed-off-by: Asutosh Das 
---
drivers/scsi/ufs/cdns-pltfrm.c |   2 +
drivers/scsi/ufs/tc-dwc-g210-pci.c |   2 +
drivers/scsi/ufs/ufs-debugfs.c |   6 +-
drivers/scsi/ufs/ufs-debugfs.h |   2 +-
drivers/scsi/ufs/ufs-exynos.c  |   2 +
drivers/scsi/ufs/ufs-hisi.c|   2 +
drivers/scsi/ufs/ufs-mediatek.c|  12 +-
drivers/scsi/ufs/ufs-qcom.c|   2 +
drivers/scsi/ufs/ufs_bsg.c |   6 +-
drivers/scsi/ufs/ufshcd-pci.c  |  36 +--
drivers/scsi/ufs/ufshcd.c  | 642 ++---
drivers/scsi/ufs/ufshcd.h  |   6 +
include/trace/events/ufs.h |  20 ++
13 files changed, 509 insertions(+), 231 deletions(-)


In this patch, you changed pm_runtime_{get, put}_sync to scsi_autopm_{get, 
put}_device.
But, scsi_autopm_get_device() calls pm_runtime_put_sync() in case of error
of pm_runtime_get_sync(). So, pm_runtime_put_sync() can be called twice if
scsi_autopm_get_device has error.


Also it might be tidy to make wrappers e.g.

static inline int ufshcd_rpm_get_sync(struct ufs_hba *hba)
{
 return pm_runtime_get_sync(>sdev_ufs_device->sdev_gendev);
}

static inline int ufshcd_rpm_put(struct ufs_hba *hba)

{
 return pm_runtime_put(>sdev_ufs_device->sdev_gendev);
}

static inline int ufshcd_rpm_put_sync(struct ufs_hba *hba)
{
 return pm_runtime_put_sync(>sdev_ufs_device->sdev_gendev);
}

And also consider matching: e.g.

pm_runtime_put(hba->dev) to  ufshcd_rpm_put(hba)
pm_runtime_put_sync(hba->dev)to  ufshcd_rpm_put_sync(hba)





Ok, I'll push the changes shortly.

--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
Linux Foundation Collaborative Project


[PATCH v17 2/2] ufs: sysfs: Resume the proper scsi device

2021-04-08 Thread Asutosh Das
Resumes the actual scsi device the unit descriptor of which
is being accessed instead of the hba alone.

Reviewed-by: Can Guo 
Signed-off-by: Asutosh Das 
---
 drivers/scsi/ufs/ufs-sysfs.c | 30 +-
 1 file changed, 17 insertions(+), 13 deletions(-)

diff --git a/drivers/scsi/ufs/ufs-sysfs.c b/drivers/scsi/ufs/ufs-sysfs.c
index d7c3cff..fa57bac 100644
--- a/drivers/scsi/ufs/ufs-sysfs.c
+++ b/drivers/scsi/ufs/ufs-sysfs.c
@@ -245,9 +245,9 @@ static ssize_t wb_on_store(struct device *dev, struct 
device_attribute *attr,
goto out;
}
 
-   pm_runtime_get_sync(hba->dev);
+   scsi_autopm_get_device(hba->sdev_ufs_device);
res = ufshcd_wb_toggle(hba, wb_enable);
-   pm_runtime_put_sync(hba->dev);
+   scsi_autopm_put_device(hba->sdev_ufs_device);
 out:
up(>host_sem);
return res < 0 ? res : count;
@@ -297,10 +297,10 @@ static ssize_t ufs_sysfs_read_desc_param(struct ufs_hba 
*hba,
goto out;
}
 
-   pm_runtime_get_sync(hba->dev);
+   scsi_autopm_get_device(hba->sdev_ufs_device);
ret = ufshcd_read_desc_param(hba, desc_id, desc_index,
param_offset, desc_buf, param_size);
-   pm_runtime_put_sync(hba->dev);
+   scsi_autopm_put_device(hba->sdev_ufs_device);
if (ret) {
ret = -EINVAL;
goto out;
@@ -678,7 +678,7 @@ static ssize_t _name##_show(struct device *dev, 
\
up(>host_sem); \
return -ENOMEM; \
}   \
-   pm_runtime_get_sync(hba->dev);  \
+   scsi_autopm_get_device(hba->sdev_ufs_device);   \
ret = ufshcd_query_descriptor_retry(hba,\
UPIU_QUERY_OPCODE_READ_DESC, QUERY_DESC_IDN_DEVICE, \
0, 0, desc_buf, _len); \
@@ -695,7 +695,7 @@ static ssize_t _name##_show(struct device *dev, 
\
goto out;   \
ret = sysfs_emit(buf, "%s\n", desc_buf);\
 out:   \
-   pm_runtime_put_sync(hba->dev);  \
+   scsi_autopm_put_device(hba->sdev_ufs_device);   \
kfree(desc_buf);\
up(>host_sem); \
return ret; \
@@ -744,10 +744,10 @@ static ssize_t _name##_show(struct device *dev,   
\
}   \
if (ufshcd_is_wb_flags(QUERY_FLAG_IDN##_uname)) \
index = ufshcd_wb_get_query_index(hba); \
-   pm_runtime_get_sync(hba->dev);  \
+   scsi_autopm_get_device(hba->sdev_ufs_device);   \
ret = ufshcd_query_flag(hba, UPIU_QUERY_OPCODE_READ_FLAG,   \
QUERY_FLAG_IDN##_uname, index, );  \
-   pm_runtime_put_sync(hba->dev);  \
+   scsi_autopm_put_device(hba->sdev_ufs_device);   \
if (ret) {  \
ret = -EINVAL;  \
goto out;   \
@@ -813,10 +813,10 @@ static ssize_t _name##_show(struct device *dev,   
\
}   \
if (ufshcd_is_wb_attrs(QUERY_ATTR_IDN##_uname)) \
index = ufshcd_wb_get_query_index(hba); \
-   pm_runtime_get_sync(hba->dev);  \
+   scsi_autopm_get_device(hba->sdev_ufs_device);   \
ret = ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_READ_ATTR,   \
QUERY_ATTR_IDN##_uname, index, 0, );  \
-   pm_runtime_put_sync(hba->dev);  \
+   scsi_autopm_put_device(hba->sdev_ufs_device);   \
if (ret) {  \
ret = -EINVAL;  \
goto out;   \
@@ -899,11 +899,15 @@ static ssize_t _pname##_show(struct device *dev,  
\
struct scsi_device *sdev = to_scsi_device(dev); \
  

[PATCH v17 1/2] scsi: ufs: Enable power management for wlun

2021-04-08 Thread Asutosh Das
During runtime-suspend of ufs host, the scsi devices are
already suspended and so are the queues associated with them.
But the ufs host sends SSU (START_STOP_UNIT) to wlun
during its runtime-suspend.
During the process blk_queue_enter checks if the queue is not in
suspended state. If so, it waits for the queue to resume, and never
comes out of it.
The commit
(d55d15a33: scsi: block: Do not accept any requests while suspended)
adds the check if the queue is in suspended state in blk_queue_enter().

Call trace:
 __switch_to+0x174/0x2c4
 __schedule+0x478/0x764
 schedule+0x9c/0xe0
 blk_queue_enter+0x158/0x228
 blk_mq_alloc_request+0x40/0xa4
 blk_get_request+0x2c/0x70
 __scsi_execute+0x60/0x1c4
 ufshcd_set_dev_pwr_mode+0x124/0x1e4
 ufshcd_suspend+0x208/0x83c
 ufshcd_runtime_suspend+0x40/0x154
 ufshcd_pltfrm_runtime_suspend+0x14/0x20
 pm_generic_runtime_suspend+0x28/0x3c
 __rpm_callback+0x80/0x2a4
 rpm_suspend+0x308/0x614
 rpm_idle+0x158/0x228
 pm_runtime_work+0x84/0xac
 process_one_work+0x1f0/0x470
 worker_thread+0x26c/0x4c8
 kthread+0x13c/0x320
 ret_from_fork+0x10/0x18

Fix this by registering ufs device wlun as a scsi driver and
registering it for block runtime-pm. Also make this as a
supplier for all other luns. That way, this device wlun
suspends after all the consumers and resumes after
hba resumes.

Co-developed-by: Can Guo 
Signed-off-by: Can Guo 
Signed-off-by: Asutosh Das 
---
 drivers/scsi/ufs/cdns-pltfrm.c |   2 +
 drivers/scsi/ufs/tc-dwc-g210-pci.c |   2 +
 drivers/scsi/ufs/ufs-debugfs.c |   6 +-
 drivers/scsi/ufs/ufs-debugfs.h |   2 +-
 drivers/scsi/ufs/ufs-exynos.c  |   2 +
 drivers/scsi/ufs/ufs-hisi.c|   2 +
 drivers/scsi/ufs/ufs-mediatek.c|  12 +-
 drivers/scsi/ufs/ufs-qcom.c|   2 +
 drivers/scsi/ufs/ufs_bsg.c |   6 +-
 drivers/scsi/ufs/ufshcd-pci.c  |  36 +--
 drivers/scsi/ufs/ufshcd.c  | 642 ++---
 drivers/scsi/ufs/ufshcd.h  |   6 +
 include/trace/events/ufs.h |  20 ++
 13 files changed, 509 insertions(+), 231 deletions(-)

diff --git a/drivers/scsi/ufs/cdns-pltfrm.c b/drivers/scsi/ufs/cdns-pltfrm.c
index 13d9204..b9105e4 100644
--- a/drivers/scsi/ufs/cdns-pltfrm.c
+++ b/drivers/scsi/ufs/cdns-pltfrm.c
@@ -323,6 +323,8 @@ static const struct dev_pm_ops cdns_ufs_dev_pm_ops = {
.runtime_suspend = ufshcd_pltfrm_runtime_suspend,
.runtime_resume  = ufshcd_pltfrm_runtime_resume,
.runtime_idle= ufshcd_pltfrm_runtime_idle,
+   .prepare = ufshcd_suspend_prepare,
+   .complete   = ufshcd_resume_complete,
 };
 
 static struct platform_driver cdns_ufs_pltfrm_driver = {
diff --git a/drivers/scsi/ufs/tc-dwc-g210-pci.c 
b/drivers/scsi/ufs/tc-dwc-g210-pci.c
index 67a6a61..b01db12 100644
--- a/drivers/scsi/ufs/tc-dwc-g210-pci.c
+++ b/drivers/scsi/ufs/tc-dwc-g210-pci.c
@@ -148,6 +148,8 @@ static const struct dev_pm_ops tc_dwc_g210_pci_pm_ops = {
.runtime_suspend = tc_dwc_g210_pci_runtime_suspend,
.runtime_resume  = tc_dwc_g210_pci_runtime_resume,
.runtime_idle= tc_dwc_g210_pci_runtime_idle,
+   .prepare = ufshcd_suspend_prepare,
+   .complete   = ufshcd_resume_complete,
 };
 
 static const struct pci_device_id tc_dwc_g210_pci_tbl[] = {
diff --git a/drivers/scsi/ufs/ufs-debugfs.c b/drivers/scsi/ufs/ufs-debugfs.c
index ced9ef4..1e8d92b 100644
--- a/drivers/scsi/ufs/ufs-debugfs.c
+++ b/drivers/scsi/ufs/ufs-debugfs.c
@@ -13,7 +13,7 @@ void __init ufs_debugfs_init(void)
ufs_debugfs_root = debugfs_create_dir("ufshcd", NULL);
 }
 
-void __exit ufs_debugfs_exit(void)
+void ufs_debugfs_exit(void)
 {
debugfs_remove_recursive(ufs_debugfs_root);
 }
@@ -60,14 +60,14 @@ __acquires(>host_sem)
up(>host_sem);
return -EBUSY;
}
-   pm_runtime_get_sync(hba->dev);
+   scsi_autopm_get_device(hba->sdev_ufs_device);
return 0;
 }
 
 static void ufs_debugfs_put_user_access(struct ufs_hba *hba)
 __releases(>host_sem)
 {
-   pm_runtime_put_sync(hba->dev);
+   scsi_autopm_put_device(hba->sdev_ufs_device);
up(>host_sem);
 }
 
diff --git a/drivers/scsi/ufs/ufs-debugfs.h b/drivers/scsi/ufs/ufs-debugfs.h
index 3ca29d3..97548a3 100644
--- a/drivers/scsi/ufs/ufs-debugfs.h
+++ b/drivers/scsi/ufs/ufs-debugfs.h
@@ -9,7 +9,7 @@ struct ufs_hba;
 
 #ifdef CONFIG_DEBUG_FS
 void __init ufs_debugfs_init(void);
-void __exit ufs_debugfs_exit(void);
+void ufs_debugfs_exit(void);
 void ufs_debugfs_hba_init(struct ufs_hba *hba);
 void ufs_debugfs_hba_exit(struct ufs_hba *hba);
 void ufs_debugfs_exception_event(struct ufs_hba *hba, u16 status);
diff --git a/drivers/scsi/ufs/ufs-exynos.c b/drivers/scsi/ufs/ufs-exynos.c
index 70647ea..49a918c 100644
--- a/drivers/scsi/ufs/ufs-exynos.c
+++ b/drivers/scsi/ufs/ufs-exynos.c
@@ -1267,6 +1267,8 @@ static const struct dev_pm_ops exynos_ufs_pm_ops = {
.runtime_suspend = ufshcd_pltfrm_runtim

[PATCH v16 1/2] scsi: ufs: Enable power management for wlun

2021-04-07 Thread Asutosh Das
During runtime-suspend of ufs host, the scsi devices are
already suspended and so are the queues associated with them.
But the ufs host sends SSU (START_STOP_UNIT) to wlun
during its runtime-suspend.
During the process blk_queue_enter checks if the queue is not in
suspended state. If so, it waits for the queue to resume, and never
comes out of it.
The commit
(d55d15a33: scsi: block: Do not accept any requests while suspended)
adds the check if the queue is in suspended state in blk_queue_enter().

Call trace:
 __switch_to+0x174/0x2c4
 __schedule+0x478/0x764
 schedule+0x9c/0xe0
 blk_queue_enter+0x158/0x228
 blk_mq_alloc_request+0x40/0xa4
 blk_get_request+0x2c/0x70
 __scsi_execute+0x60/0x1c4
 ufshcd_set_dev_pwr_mode+0x124/0x1e4
 ufshcd_suspend+0x208/0x83c
 ufshcd_runtime_suspend+0x40/0x154
 ufshcd_pltfrm_runtime_suspend+0x14/0x20
 pm_generic_runtime_suspend+0x28/0x3c
 __rpm_callback+0x80/0x2a4
 rpm_suspend+0x308/0x614
 rpm_idle+0x158/0x228
 pm_runtime_work+0x84/0xac
 process_one_work+0x1f0/0x470
 worker_thread+0x26c/0x4c8
 kthread+0x13c/0x320
 ret_from_fork+0x10/0x18

Fix this by registering ufs device wlun as a scsi driver and
registering it for block runtime-pm. Also make this as a
supplier for all other luns. That way, this device wlun
suspends after all the consumers and resumes after
hba resumes.

Co-developed-by: Can Guo 
Signed-off-by: Can Guo 
Signed-off-by: Asutosh Das 
---
 drivers/scsi/ufs/cdns-pltfrm.c |   2 +
 drivers/scsi/ufs/tc-dwc-g210-pci.c |   2 +
 drivers/scsi/ufs/ufs-debugfs.c |   6 +-
 drivers/scsi/ufs/ufs-debugfs.h |   2 +-
 drivers/scsi/ufs/ufs-exynos.c  |   2 +
 drivers/scsi/ufs/ufs-hisi.c|   2 +
 drivers/scsi/ufs/ufs-mediatek.c|  12 +-
 drivers/scsi/ufs/ufs-qcom.c|   2 +
 drivers/scsi/ufs/ufs_bsg.c |   6 +-
 drivers/scsi/ufs/ufshcd-pci.c  |  36 +--
 drivers/scsi/ufs/ufshcd.c  | 638 ++---
 drivers/scsi/ufs/ufshcd.h  |   6 +
 include/trace/events/ufs.h |  20 ++
 13 files changed, 506 insertions(+), 230 deletions(-)

diff --git a/drivers/scsi/ufs/cdns-pltfrm.c b/drivers/scsi/ufs/cdns-pltfrm.c
index 13d9204..b9105e4 100644
--- a/drivers/scsi/ufs/cdns-pltfrm.c
+++ b/drivers/scsi/ufs/cdns-pltfrm.c
@@ -323,6 +323,8 @@ static const struct dev_pm_ops cdns_ufs_dev_pm_ops = {
.runtime_suspend = ufshcd_pltfrm_runtime_suspend,
.runtime_resume  = ufshcd_pltfrm_runtime_resume,
.runtime_idle= ufshcd_pltfrm_runtime_idle,
+   .prepare = ufshcd_suspend_prepare,
+   .complete   = ufshcd_resume_complete,
 };
 
 static struct platform_driver cdns_ufs_pltfrm_driver = {
diff --git a/drivers/scsi/ufs/tc-dwc-g210-pci.c 
b/drivers/scsi/ufs/tc-dwc-g210-pci.c
index 67a6a61..b01db12 100644
--- a/drivers/scsi/ufs/tc-dwc-g210-pci.c
+++ b/drivers/scsi/ufs/tc-dwc-g210-pci.c
@@ -148,6 +148,8 @@ static const struct dev_pm_ops tc_dwc_g210_pci_pm_ops = {
.runtime_suspend = tc_dwc_g210_pci_runtime_suspend,
.runtime_resume  = tc_dwc_g210_pci_runtime_resume,
.runtime_idle= tc_dwc_g210_pci_runtime_idle,
+   .prepare = ufshcd_suspend_prepare,
+   .complete   = ufshcd_resume_complete,
 };
 
 static const struct pci_device_id tc_dwc_g210_pci_tbl[] = {
diff --git a/drivers/scsi/ufs/ufs-debugfs.c b/drivers/scsi/ufs/ufs-debugfs.c
index ced9ef4..1e8d92b 100644
--- a/drivers/scsi/ufs/ufs-debugfs.c
+++ b/drivers/scsi/ufs/ufs-debugfs.c
@@ -13,7 +13,7 @@ void __init ufs_debugfs_init(void)
ufs_debugfs_root = debugfs_create_dir("ufshcd", NULL);
 }
 
-void __exit ufs_debugfs_exit(void)
+void ufs_debugfs_exit(void)
 {
debugfs_remove_recursive(ufs_debugfs_root);
 }
@@ -60,14 +60,14 @@ __acquires(>host_sem)
up(>host_sem);
return -EBUSY;
}
-   pm_runtime_get_sync(hba->dev);
+   scsi_autopm_get_device(hba->sdev_ufs_device);
return 0;
 }
 
 static void ufs_debugfs_put_user_access(struct ufs_hba *hba)
 __releases(>host_sem)
 {
-   pm_runtime_put_sync(hba->dev);
+   scsi_autopm_put_device(hba->sdev_ufs_device);
up(>host_sem);
 }
 
diff --git a/drivers/scsi/ufs/ufs-debugfs.h b/drivers/scsi/ufs/ufs-debugfs.h
index 3ca29d3..97548a3 100644
--- a/drivers/scsi/ufs/ufs-debugfs.h
+++ b/drivers/scsi/ufs/ufs-debugfs.h
@@ -9,7 +9,7 @@ struct ufs_hba;
 
 #ifdef CONFIG_DEBUG_FS
 void __init ufs_debugfs_init(void);
-void __exit ufs_debugfs_exit(void);
+void ufs_debugfs_exit(void);
 void ufs_debugfs_hba_init(struct ufs_hba *hba);
 void ufs_debugfs_hba_exit(struct ufs_hba *hba);
 void ufs_debugfs_exception_event(struct ufs_hba *hba, u16 status);
diff --git a/drivers/scsi/ufs/ufs-exynos.c b/drivers/scsi/ufs/ufs-exynos.c
index 70647ea..49a918c 100644
--- a/drivers/scsi/ufs/ufs-exynos.c
+++ b/drivers/scsi/ufs/ufs-exynos.c
@@ -1267,6 +1267,8 @@ static const struct dev_pm_ops exynos_ufs_pm_ops = {
.runtime_suspend = ufshcd_pltfrm_runtim

[PATCH v16 2/2] ufs: sysfs: Resume the proper scsi device

2021-04-07 Thread Asutosh Das
Resumes the actual scsi device the unit descriptor of which
is being accessed instead of the hba alone.

Reviewed-by: Can Guo 
Signed-off-by: Asutosh Das 
---
 drivers/scsi/ufs/ufs-sysfs.c | 30 +-
 1 file changed, 17 insertions(+), 13 deletions(-)

diff --git a/drivers/scsi/ufs/ufs-sysfs.c b/drivers/scsi/ufs/ufs-sysfs.c
index d7c3cff..fa57bac 100644
--- a/drivers/scsi/ufs/ufs-sysfs.c
+++ b/drivers/scsi/ufs/ufs-sysfs.c
@@ -245,9 +245,9 @@ static ssize_t wb_on_store(struct device *dev, struct 
device_attribute *attr,
goto out;
}
 
-   pm_runtime_get_sync(hba->dev);
+   scsi_autopm_get_device(hba->sdev_ufs_device);
res = ufshcd_wb_toggle(hba, wb_enable);
-   pm_runtime_put_sync(hba->dev);
+   scsi_autopm_put_device(hba->sdev_ufs_device);
 out:
up(>host_sem);
return res < 0 ? res : count;
@@ -297,10 +297,10 @@ static ssize_t ufs_sysfs_read_desc_param(struct ufs_hba 
*hba,
goto out;
}
 
-   pm_runtime_get_sync(hba->dev);
+   scsi_autopm_get_device(hba->sdev_ufs_device);
ret = ufshcd_read_desc_param(hba, desc_id, desc_index,
param_offset, desc_buf, param_size);
-   pm_runtime_put_sync(hba->dev);
+   scsi_autopm_put_device(hba->sdev_ufs_device);
if (ret) {
ret = -EINVAL;
goto out;
@@ -678,7 +678,7 @@ static ssize_t _name##_show(struct device *dev, 
\
up(>host_sem); \
return -ENOMEM; \
}   \
-   pm_runtime_get_sync(hba->dev);  \
+   scsi_autopm_get_device(hba->sdev_ufs_device);   \
ret = ufshcd_query_descriptor_retry(hba,\
UPIU_QUERY_OPCODE_READ_DESC, QUERY_DESC_IDN_DEVICE, \
0, 0, desc_buf, _len); \
@@ -695,7 +695,7 @@ static ssize_t _name##_show(struct device *dev, 
\
goto out;   \
ret = sysfs_emit(buf, "%s\n", desc_buf);\
 out:   \
-   pm_runtime_put_sync(hba->dev);  \
+   scsi_autopm_put_device(hba->sdev_ufs_device);   \
kfree(desc_buf);\
up(>host_sem); \
return ret; \
@@ -744,10 +744,10 @@ static ssize_t _name##_show(struct device *dev,   
\
}   \
if (ufshcd_is_wb_flags(QUERY_FLAG_IDN##_uname)) \
index = ufshcd_wb_get_query_index(hba); \
-   pm_runtime_get_sync(hba->dev);  \
+   scsi_autopm_get_device(hba->sdev_ufs_device);   \
ret = ufshcd_query_flag(hba, UPIU_QUERY_OPCODE_READ_FLAG,   \
QUERY_FLAG_IDN##_uname, index, );  \
-   pm_runtime_put_sync(hba->dev);  \
+   scsi_autopm_put_device(hba->sdev_ufs_device);   \
if (ret) {  \
ret = -EINVAL;  \
goto out;   \
@@ -813,10 +813,10 @@ static ssize_t _name##_show(struct device *dev,   
\
}   \
if (ufshcd_is_wb_attrs(QUERY_ATTR_IDN##_uname)) \
index = ufshcd_wb_get_query_index(hba); \
-   pm_runtime_get_sync(hba->dev);  \
+   scsi_autopm_get_device(hba->sdev_ufs_device);   \
ret = ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_READ_ATTR,   \
QUERY_ATTR_IDN##_uname, index, 0, );  \
-   pm_runtime_put_sync(hba->dev);  \
+   scsi_autopm_put_device(hba->sdev_ufs_device);   \
if (ret) {  \
ret = -EINVAL;  \
goto out;   \
@@ -899,11 +899,15 @@ static ssize_t _pname##_show(struct device *dev,  
\
struct scsi_device *sdev = to_scsi_device(dev); \
  

Re: [PATCH v15 1/2] scsi: ufs: Enable power management for wlun

2021-04-07 Thread Asutosh Das (asd)

On 4/7/2021 3:21 AM, Adrian Hunter wrote:

On 6/04/21 8:52 pm, Asutosh Das wrote:

During runtime-suspend of ufs host, the scsi devices are
already suspended and so are the queues associated with them.
But the ufs host sends SSU (START_STOP_UNIT) to wlun
during its runtime-suspend.
During the process blk_queue_enter checks if the queue is not in
suspended state. If so, it waits for the queue to resume, and never
comes out of it.
The commit
(d55d15a33: scsi: block: Do not accept any requests while suspended)
adds the check if the queue is in suspended state in blk_queue_enter().

Call trace:
  __switch_to+0x174/0x2c4
  __schedule+0x478/0x764
  schedule+0x9c/0xe0
  blk_queue_enter+0x158/0x228
  blk_mq_alloc_request+0x40/0xa4
  blk_get_request+0x2c/0x70
  __scsi_execute+0x60/0x1c4
  ufshcd_set_dev_pwr_mode+0x124/0x1e4
  ufshcd_suspend+0x208/0x83c
  ufshcd_runtime_suspend+0x40/0x154
  ufshcd_pltfrm_runtime_suspend+0x14/0x20
  pm_generic_runtime_suspend+0x28/0x3c
  __rpm_callback+0x80/0x2a4
  rpm_suspend+0x308/0x614
  rpm_idle+0x158/0x228
  pm_runtime_work+0x84/0xac
  process_one_work+0x1f0/0x470
  worker_thread+0x26c/0x4c8
  kthread+0x13c/0x320
  ret_from_fork+0x10/0x18

Fix this by registering ufs device wlun as a scsi driver and
registering it for block runtime-pm. Also make this as a
supplier for all other luns. That way, this device wlun
suspends after all the consumers and resumes after
hba resumes.

Co-developed-by: Can Guo 
Signed-off-by: Can Guo 
Signed-off-by: Asutosh Das 
---


v15 seems to be missing the updates to ufs_debugfs_get/put_user_access
that were in v14:


@@ -60,14 +60,14 @@ __acquires(>host_sem)
up(>host_sem);
return -EBUSY;
}
-   pm_runtime_get_sync(hba->dev);
+   scsi_autopm_get_device(hba->sdev_ufs_device);
return 0;
  }
  
  static void ufs_debugfs_put_user_access(struct ufs_hba *hba)

  __releases(>host_sem)
  {
-   pm_runtime_put_sync(hba->dev);
+   scsi_autopm_put_device(hba->sdev_ufs_device);
up(>host_sem);
  }
  


Also from last comments, the issue below:




+#ifdef CONFIG_PM_SLEEP
+static int ufshcd_wl_poweroff(struct device *dev)
+{
+   ufshcd_wl_shutdown(dev);


This turned out to be wrong.  This is a PM op and SCSI has already
quiesced the sdev's.  All that is needed is:

__ufshcd_wl_suspend(hba, UFS_SHUTDOWN_PM);



Yikes! Thanks, let me fix this and push the correct series.

-asd

--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
Linux Foundation Collaborative Project


[PATCH v15 2/2] ufs: sysfs: Resume the proper scsi device

2021-04-06 Thread Asutosh Das
Resumes the actual scsi device the unit descriptor of which
is being accessed instead of the hba alone.

Reviewed-by: Can Guo 
Signed-off-by: Asutosh Das 
---
 drivers/scsi/ufs/ufs-sysfs.c | 30 +-
 1 file changed, 17 insertions(+), 13 deletions(-)

diff --git a/drivers/scsi/ufs/ufs-sysfs.c b/drivers/scsi/ufs/ufs-sysfs.c
index d7c3cff..fa57bac 100644
--- a/drivers/scsi/ufs/ufs-sysfs.c
+++ b/drivers/scsi/ufs/ufs-sysfs.c
@@ -245,9 +245,9 @@ static ssize_t wb_on_store(struct device *dev, struct 
device_attribute *attr,
goto out;
}
 
-   pm_runtime_get_sync(hba->dev);
+   scsi_autopm_get_device(hba->sdev_ufs_device);
res = ufshcd_wb_toggle(hba, wb_enable);
-   pm_runtime_put_sync(hba->dev);
+   scsi_autopm_put_device(hba->sdev_ufs_device);
 out:
up(>host_sem);
return res < 0 ? res : count;
@@ -297,10 +297,10 @@ static ssize_t ufs_sysfs_read_desc_param(struct ufs_hba 
*hba,
goto out;
}
 
-   pm_runtime_get_sync(hba->dev);
+   scsi_autopm_get_device(hba->sdev_ufs_device);
ret = ufshcd_read_desc_param(hba, desc_id, desc_index,
param_offset, desc_buf, param_size);
-   pm_runtime_put_sync(hba->dev);
+   scsi_autopm_put_device(hba->sdev_ufs_device);
if (ret) {
ret = -EINVAL;
goto out;
@@ -678,7 +678,7 @@ static ssize_t _name##_show(struct device *dev, 
\
up(>host_sem); \
return -ENOMEM; \
}   \
-   pm_runtime_get_sync(hba->dev);  \
+   scsi_autopm_get_device(hba->sdev_ufs_device);   \
ret = ufshcd_query_descriptor_retry(hba,\
UPIU_QUERY_OPCODE_READ_DESC, QUERY_DESC_IDN_DEVICE, \
0, 0, desc_buf, _len); \
@@ -695,7 +695,7 @@ static ssize_t _name##_show(struct device *dev, 
\
goto out;   \
ret = sysfs_emit(buf, "%s\n", desc_buf);\
 out:   \
-   pm_runtime_put_sync(hba->dev);  \
+   scsi_autopm_put_device(hba->sdev_ufs_device);   \
kfree(desc_buf);\
up(>host_sem); \
return ret; \
@@ -744,10 +744,10 @@ static ssize_t _name##_show(struct device *dev,   
\
}   \
if (ufshcd_is_wb_flags(QUERY_FLAG_IDN##_uname)) \
index = ufshcd_wb_get_query_index(hba); \
-   pm_runtime_get_sync(hba->dev);  \
+   scsi_autopm_get_device(hba->sdev_ufs_device);   \
ret = ufshcd_query_flag(hba, UPIU_QUERY_OPCODE_READ_FLAG,   \
QUERY_FLAG_IDN##_uname, index, );  \
-   pm_runtime_put_sync(hba->dev);  \
+   scsi_autopm_put_device(hba->sdev_ufs_device);   \
if (ret) {  \
ret = -EINVAL;  \
goto out;   \
@@ -813,10 +813,10 @@ static ssize_t _name##_show(struct device *dev,   
\
}   \
if (ufshcd_is_wb_attrs(QUERY_ATTR_IDN##_uname)) \
index = ufshcd_wb_get_query_index(hba); \
-   pm_runtime_get_sync(hba->dev);  \
+   scsi_autopm_get_device(hba->sdev_ufs_device);   \
ret = ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_READ_ATTR,   \
QUERY_ATTR_IDN##_uname, index, 0, );  \
-   pm_runtime_put_sync(hba->dev);  \
+   scsi_autopm_put_device(hba->sdev_ufs_device);   \
if (ret) {  \
ret = -EINVAL;  \
goto out;   \
@@ -899,11 +899,15 @@ static ssize_t _pname##_show(struct device *dev,  
\
struct scsi_device *sdev = to_scsi_device(dev); \
  

[PATCH v15 1/2] scsi: ufs: Enable power management for wlun

2021-04-06 Thread Asutosh Das
During runtime-suspend of ufs host, the scsi devices are
already suspended and so are the queues associated with them.
But the ufs host sends SSU (START_STOP_UNIT) to wlun
during its runtime-suspend.
During the process blk_queue_enter checks if the queue is not in
suspended state. If so, it waits for the queue to resume, and never
comes out of it.
The commit
(d55d15a33: scsi: block: Do not accept any requests while suspended)
adds the check if the queue is in suspended state in blk_queue_enter().

Call trace:
 __switch_to+0x174/0x2c4
 __schedule+0x478/0x764
 schedule+0x9c/0xe0
 blk_queue_enter+0x158/0x228
 blk_mq_alloc_request+0x40/0xa4
 blk_get_request+0x2c/0x70
 __scsi_execute+0x60/0x1c4
 ufshcd_set_dev_pwr_mode+0x124/0x1e4
 ufshcd_suspend+0x208/0x83c
 ufshcd_runtime_suspend+0x40/0x154
 ufshcd_pltfrm_runtime_suspend+0x14/0x20
 pm_generic_runtime_suspend+0x28/0x3c
 __rpm_callback+0x80/0x2a4
 rpm_suspend+0x308/0x614
 rpm_idle+0x158/0x228
 pm_runtime_work+0x84/0xac
 process_one_work+0x1f0/0x470
 worker_thread+0x26c/0x4c8
 kthread+0x13c/0x320
 ret_from_fork+0x10/0x18

Fix this by registering ufs device wlun as a scsi driver and
registering it for block runtime-pm. Also make this as a
supplier for all other luns. That way, this device wlun
suspends after all the consumers and resumes after
hba resumes.

Co-developed-by: Can Guo 
Signed-off-by: Can Guo 
Signed-off-by: Asutosh Das 
---
 drivers/scsi/ufs/cdns-pltfrm.c |   2 +
 drivers/scsi/ufs/tc-dwc-g210-pci.c |   2 +
 drivers/scsi/ufs/ufs-debugfs.c |   2 +-
 drivers/scsi/ufs/ufs-debugfs.h |   2 +-
 drivers/scsi/ufs/ufs-exynos.c  |   2 +
 drivers/scsi/ufs/ufs-hisi.c|   2 +
 drivers/scsi/ufs/ufs-mediatek.c|  12 +-
 drivers/scsi/ufs/ufs-qcom.c|   2 +
 drivers/scsi/ufs/ufs_bsg.c |   6 +-
 drivers/scsi/ufs/ufshcd-pci.c  |  36 +--
 drivers/scsi/ufs/ufshcd.c  | 636 ++---
 drivers/scsi/ufs/ufshcd.h  |   6 +
 include/trace/events/ufs.h |  20 ++
 13 files changed, 502 insertions(+), 228 deletions(-)

diff --git a/drivers/scsi/ufs/cdns-pltfrm.c b/drivers/scsi/ufs/cdns-pltfrm.c
index 13d9204..b9105e4 100644
--- a/drivers/scsi/ufs/cdns-pltfrm.c
+++ b/drivers/scsi/ufs/cdns-pltfrm.c
@@ -323,6 +323,8 @@ static const struct dev_pm_ops cdns_ufs_dev_pm_ops = {
.runtime_suspend = ufshcd_pltfrm_runtime_suspend,
.runtime_resume  = ufshcd_pltfrm_runtime_resume,
.runtime_idle= ufshcd_pltfrm_runtime_idle,
+   .prepare = ufshcd_suspend_prepare,
+   .complete   = ufshcd_resume_complete,
 };
 
 static struct platform_driver cdns_ufs_pltfrm_driver = {
diff --git a/drivers/scsi/ufs/tc-dwc-g210-pci.c 
b/drivers/scsi/ufs/tc-dwc-g210-pci.c
index 67a6a61..b01db12 100644
--- a/drivers/scsi/ufs/tc-dwc-g210-pci.c
+++ b/drivers/scsi/ufs/tc-dwc-g210-pci.c
@@ -148,6 +148,8 @@ static const struct dev_pm_ops tc_dwc_g210_pci_pm_ops = {
.runtime_suspend = tc_dwc_g210_pci_runtime_suspend,
.runtime_resume  = tc_dwc_g210_pci_runtime_resume,
.runtime_idle= tc_dwc_g210_pci_runtime_idle,
+   .prepare = ufshcd_suspend_prepare,
+   .complete   = ufshcd_resume_complete,
 };
 
 static const struct pci_device_id tc_dwc_g210_pci_tbl[] = {
diff --git a/drivers/scsi/ufs/ufs-debugfs.c b/drivers/scsi/ufs/ufs-debugfs.c
index ced9ef4..8ffbd4a 100644
--- a/drivers/scsi/ufs/ufs-debugfs.c
+++ b/drivers/scsi/ufs/ufs-debugfs.c
@@ -13,7 +13,7 @@ void __init ufs_debugfs_init(void)
ufs_debugfs_root = debugfs_create_dir("ufshcd", NULL);
 }
 
-void __exit ufs_debugfs_exit(void)
+void ufs_debugfs_exit(void)
 {
debugfs_remove_recursive(ufs_debugfs_root);
 }
diff --git a/drivers/scsi/ufs/ufs-debugfs.h b/drivers/scsi/ufs/ufs-debugfs.h
index 3ca29d3..97548a3 100644
--- a/drivers/scsi/ufs/ufs-debugfs.h
+++ b/drivers/scsi/ufs/ufs-debugfs.h
@@ -9,7 +9,7 @@ struct ufs_hba;
 
 #ifdef CONFIG_DEBUG_FS
 void __init ufs_debugfs_init(void);
-void __exit ufs_debugfs_exit(void);
+void ufs_debugfs_exit(void);
 void ufs_debugfs_hba_init(struct ufs_hba *hba);
 void ufs_debugfs_hba_exit(struct ufs_hba *hba);
 void ufs_debugfs_exception_event(struct ufs_hba *hba, u16 status);
diff --git a/drivers/scsi/ufs/ufs-exynos.c b/drivers/scsi/ufs/ufs-exynos.c
index 70647ea..49a918c 100644
--- a/drivers/scsi/ufs/ufs-exynos.c
+++ b/drivers/scsi/ufs/ufs-exynos.c
@@ -1267,6 +1267,8 @@ static const struct dev_pm_ops exynos_ufs_pm_ops = {
.runtime_suspend = ufshcd_pltfrm_runtime_suspend,
.runtime_resume  = ufshcd_pltfrm_runtime_resume,
.runtime_idle= ufshcd_pltfrm_runtime_idle,
+   .prepare = ufshcd_suspend_prepare,
+   .complete   = ufshcd_resume_complete,
 };
 
 static struct platform_driver exynos_ufs_pltform = {
diff --git a/drivers/scsi/ufs/ufs-hisi.c b/drivers/scsi/ufs/ufs-hisi.c
index 0aa5813..d463b44 100644
--- a/drivers/scsi/ufs/ufs-hisi.c
+++ b/drivers/scsi/ufs/ufs-hisi.c
@@ -574,6 +574,8

Re: [PATCH v14 1/2] scsi: ufs: Enable power management for wlun

2021-03-31 Thread Asutosh Das (asd)

On 3/31/2021 11:19 AM, Adrian Hunter wrote:

On 31/03/21 1:31 am, Asutosh Das wrote:

During runtime-suspend of ufs host, the scsi devices are
already suspended and so are the queues associated with them.
But the ufs host sends SSU (START_STOP_UNIT) to wlun
during its runtime-suspend.
During the process blk_queue_enter checks if the queue is not in
suspended state. If so, it waits for the queue to resume, and never
comes out of it.
The commit
(d55d15a33: scsi: block: Do not accept any requests while suspended)
adds the check if the queue is in suspended state in blk_queue_enter().

Call trace:
  __switch_to+0x174/0x2c4
  __schedule+0x478/0x764
  schedule+0x9c/0xe0
  blk_queue_enter+0x158/0x228
  blk_mq_alloc_request+0x40/0xa4
  blk_get_request+0x2c/0x70
  __scsi_execute+0x60/0x1c4
  ufshcd_set_dev_pwr_mode+0x124/0x1e4
  ufshcd_suspend+0x208/0x83c
  ufshcd_runtime_suspend+0x40/0x154
  ufshcd_pltfrm_runtime_suspend+0x14/0x20
  pm_generic_runtime_suspend+0x28/0x3c
  __rpm_callback+0x80/0x2a4
  rpm_suspend+0x308/0x614
  rpm_idle+0x158/0x228
  pm_runtime_work+0x84/0xac
  process_one_work+0x1f0/0x470
  worker_thread+0x26c/0x4c8
  kthread+0x13c/0x320
  ret_from_fork+0x10/0x18

Fix this by registering ufs device wlun as a scsi driver and
registering it for block runtime-pm. Also make this as a
supplier for all other luns. That way, this device wlun
suspends after all the consumers and resumes after
hba resumes.

Co-developed-by: Can Guo 
Signed-off-by: Can Guo 
Signed-off-by: Asutosh Das 
---



Hi Adrian
Thanks for the comments.

Looks good but still doesn't seem to based on the latest tree.


Umm, it's based on the below:
git://git.kernel.org/pub/scm/linux/kernel/git/mkp/scsi.git
Branch: refs/heads/for-next

The top most change is e27f3c8 on 27th March'21.
Which tree are you referring to that'd be latest?


Also came across the issue below:




+#ifdef CONFIG_PM_SLEEP
+static int ufshcd_wl_poweroff(struct device *dev)
+{
+   ufshcd_wl_shutdown(dev);


This turned out to be wrong.  This is a PM op and SCSI has already
quiesced the sdev's.  All that is needed isOk. I'll fix it in the next version.




__ufshcd_wl_suspend(hba, UFS_SHUTDOWN_PM);


+   return 0;
+}
+#endif



--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
Linux Foundation Collaborative Project


Re: [PATCH V2 2/3] scsi: ufs: add a vops to configure VCC voltage level

2021-03-31 Thread Asutosh Das (asd)

On 3/21/2021 2:57 PM, Nitin Rawat wrote:

Add a vops to configure VCC voltage VCC voltage level
for platform supporting both ufs2.x and ufs 3.x devices.

Suggested-by: Stanley Chu 
Suggested-by: Asutosh Das 
Suggested-by: Bjorn Andersson 
Signed-off-by: Nitin Rawat 
Signed-off-by: Veerabhadrarao Badiganti 
---
  drivers/scsi/ufs/ufshcd.c |  4 
  drivers/scsi/ufs/ufshcd.h | 10 ++
  2 files changed, 14 insertions(+)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 633ca8e..5bfe987 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -7763,6 +7763,10 @@ static int ufshcd_add_lus(struct ufs_hba *hba)
goto out;

ufshcd_clear_ua_wluns(hba);
+   if (ufshcd_vops_setup_vcc_regulators(hba))
This would be invoked even for platforms that don't support both 2.x and 
3.x and don't need to set the voltages in the driver.
I guess platforms that support both 2.x and 3.x and can't set the 
regulator voltages from dts due to different voltage requirements of 2.x 
and 3.x, should request the driver to set the voltages. And the driver 
may do so after determining the device version.



+   dev_err(hba->dev,
+   "%s: Failed to set the VCC regulator values, continue with 
2.7v\n",
+   __func__);

/* Initialize devfreq after UFS device is detected */
if (ufshcd_is_clkscaling_supported(hba)) {
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 0db796a..8f0945d 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -324,6 +324,7 @@ struct ufs_pwr_mode_info {
   * @device_reset: called to issue a reset pulse on the UFS device
   * @program_key: program or evict an inline encryption key
   * @event_notify: called to notify important events
+ * @setup_vcc_regulators : update vcc regulator level
   */
  struct ufs_hba_variant_ops {
const char *name;
@@ -360,6 +361,7 @@ struct ufs_hba_variant_ops {
   const union ufs_crypto_cfg_entry *cfg, int slot);
void(*event_notify)(struct ufs_hba *hba,
enum ufs_event_type evt, void *data);
+   int(*setup_vcc_regulators)(struct ufs_hba *hba);
  };

  /* clock gating state  */
@@ -1269,6 +1271,14 @@ static inline void 
ufshcd_vops_config_scaling_param(struct ufs_hba *hba,
hba->vops->config_scaling_param(hba, profile, data);
  }

+static inline int ufshcd_vops_setup_vcc_regulators(struct ufs_hba *hba)
+{
+   if (hba->vops && hba->vops->setup_vcc_regulators)
+   return hba->vops->setup_vcc_regulators(hba);
+
+   return 0;
+}
+
  extern struct ufs_pm_lvl_states ufs_pm_lvl_states[];

  /*
--
2.7.4




--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
Linux Foundation Collaborative Project


[PATCH v14 1/2] scsi: ufs: Enable power management for wlun

2021-03-30 Thread Asutosh Das
During runtime-suspend of ufs host, the scsi devices are
already suspended and so are the queues associated with them.
But the ufs host sends SSU (START_STOP_UNIT) to wlun
during its runtime-suspend.
During the process blk_queue_enter checks if the queue is not in
suspended state. If so, it waits for the queue to resume, and never
comes out of it.
The commit
(d55d15a33: scsi: block: Do not accept any requests while suspended)
adds the check if the queue is in suspended state in blk_queue_enter().

Call trace:
 __switch_to+0x174/0x2c4
 __schedule+0x478/0x764
 schedule+0x9c/0xe0
 blk_queue_enter+0x158/0x228
 blk_mq_alloc_request+0x40/0xa4
 blk_get_request+0x2c/0x70
 __scsi_execute+0x60/0x1c4
 ufshcd_set_dev_pwr_mode+0x124/0x1e4
 ufshcd_suspend+0x208/0x83c
 ufshcd_runtime_suspend+0x40/0x154
 ufshcd_pltfrm_runtime_suspend+0x14/0x20
 pm_generic_runtime_suspend+0x28/0x3c
 __rpm_callback+0x80/0x2a4
 rpm_suspend+0x308/0x614
 rpm_idle+0x158/0x228
 pm_runtime_work+0x84/0xac
 process_one_work+0x1f0/0x470
 worker_thread+0x26c/0x4c8
 kthread+0x13c/0x320
 ret_from_fork+0x10/0x18

Fix this by registering ufs device wlun as a scsi driver and
registering it for block runtime-pm. Also make this as a
supplier for all other luns. That way, this device wlun
suspends after all the consumers and resumes after
hba resumes.

Co-developed-by: Can Guo 
Signed-off-by: Can Guo 
Signed-off-by: Asutosh Das 
---
 drivers/scsi/ufs/cdns-pltfrm.c |   2 +
 drivers/scsi/ufs/tc-dwc-g210-pci.c |   2 +
 drivers/scsi/ufs/ufs-debugfs.c |   6 +-
 drivers/scsi/ufs/ufs-debugfs.h |   2 +-
 drivers/scsi/ufs/ufs-exynos.c  |   2 +
 drivers/scsi/ufs/ufs-hisi.c|   2 +
 drivers/scsi/ufs/ufs-mediatek.c|  12 +-
 drivers/scsi/ufs/ufs-qcom.c|   2 +
 drivers/scsi/ufs/ufs_bsg.c |   6 +-
 drivers/scsi/ufs/ufshcd-pci.c  |  36 +--
 drivers/scsi/ufs/ufshcd.c  | 636 ++---
 drivers/scsi/ufs/ufshcd.h  |   6 +
 include/trace/events/ufs.h |  20 ++
 13 files changed, 504 insertions(+), 230 deletions(-)

diff --git a/drivers/scsi/ufs/cdns-pltfrm.c b/drivers/scsi/ufs/cdns-pltfrm.c
index 13d9204..b9105e4 100644
--- a/drivers/scsi/ufs/cdns-pltfrm.c
+++ b/drivers/scsi/ufs/cdns-pltfrm.c
@@ -323,6 +323,8 @@ static const struct dev_pm_ops cdns_ufs_dev_pm_ops = {
.runtime_suspend = ufshcd_pltfrm_runtime_suspend,
.runtime_resume  = ufshcd_pltfrm_runtime_resume,
.runtime_idle= ufshcd_pltfrm_runtime_idle,
+   .prepare = ufshcd_suspend_prepare,
+   .complete   = ufshcd_resume_complete,
 };
 
 static struct platform_driver cdns_ufs_pltfrm_driver = {
diff --git a/drivers/scsi/ufs/tc-dwc-g210-pci.c 
b/drivers/scsi/ufs/tc-dwc-g210-pci.c
index 67a6a61..b01db12 100644
--- a/drivers/scsi/ufs/tc-dwc-g210-pci.c
+++ b/drivers/scsi/ufs/tc-dwc-g210-pci.c
@@ -148,6 +148,8 @@ static const struct dev_pm_ops tc_dwc_g210_pci_pm_ops = {
.runtime_suspend = tc_dwc_g210_pci_runtime_suspend,
.runtime_resume  = tc_dwc_g210_pci_runtime_resume,
.runtime_idle= tc_dwc_g210_pci_runtime_idle,
+   .prepare = ufshcd_suspend_prepare,
+   .complete   = ufshcd_resume_complete,
 };
 
 static const struct pci_device_id tc_dwc_g210_pci_tbl[] = {
diff --git a/drivers/scsi/ufs/ufs-debugfs.c b/drivers/scsi/ufs/ufs-debugfs.c
index ced9ef4..1e8d92b 100644
--- a/drivers/scsi/ufs/ufs-debugfs.c
+++ b/drivers/scsi/ufs/ufs-debugfs.c
@@ -13,7 +13,7 @@ void __init ufs_debugfs_init(void)
ufs_debugfs_root = debugfs_create_dir("ufshcd", NULL);
 }
 
-void __exit ufs_debugfs_exit(void)
+void ufs_debugfs_exit(void)
 {
debugfs_remove_recursive(ufs_debugfs_root);
 }
@@ -60,14 +60,14 @@ __acquires(>host_sem)
up(>host_sem);
return -EBUSY;
}
-   pm_runtime_get_sync(hba->dev);
+   scsi_autopm_get_device(hba->sdev_ufs_device);
return 0;
 }
 
 static void ufs_debugfs_put_user_access(struct ufs_hba *hba)
 __releases(>host_sem)
 {
-   pm_runtime_put_sync(hba->dev);
+   scsi_autopm_put_device(hba->sdev_ufs_device);
up(>host_sem);
 }
 
diff --git a/drivers/scsi/ufs/ufs-debugfs.h b/drivers/scsi/ufs/ufs-debugfs.h
index 3ca29d3..97548a3 100644
--- a/drivers/scsi/ufs/ufs-debugfs.h
+++ b/drivers/scsi/ufs/ufs-debugfs.h
@@ -9,7 +9,7 @@ struct ufs_hba;
 
 #ifdef CONFIG_DEBUG_FS
 void __init ufs_debugfs_init(void);
-void __exit ufs_debugfs_exit(void);
+void ufs_debugfs_exit(void);
 void ufs_debugfs_hba_init(struct ufs_hba *hba);
 void ufs_debugfs_hba_exit(struct ufs_hba *hba);
 void ufs_debugfs_exception_event(struct ufs_hba *hba, u16 status);
diff --git a/drivers/scsi/ufs/ufs-exynos.c b/drivers/scsi/ufs/ufs-exynos.c
index 70647ea..49a918c 100644
--- a/drivers/scsi/ufs/ufs-exynos.c
+++ b/drivers/scsi/ufs/ufs-exynos.c
@@ -1267,6 +1267,8 @@ static const struct dev_pm_ops exynos_ufs_pm_ops = {
.runtime_suspend = ufshcd_pltfrm_runtim

[PATCH v14 2/2] ufs: sysfs: Resume the proper scsi device

2021-03-30 Thread Asutosh Das
Resumes the actual scsi device the unit descriptor of which
is being accessed instead of the hba alone.

Reviewed-by: Can Guo 
Signed-off-by: Asutosh Das 
---
 drivers/scsi/ufs/ufs-sysfs.c | 30 +-
 1 file changed, 17 insertions(+), 13 deletions(-)

diff --git a/drivers/scsi/ufs/ufs-sysfs.c b/drivers/scsi/ufs/ufs-sysfs.c
index d7c3cff..fa57bac 100644
--- a/drivers/scsi/ufs/ufs-sysfs.c
+++ b/drivers/scsi/ufs/ufs-sysfs.c
@@ -245,9 +245,9 @@ static ssize_t wb_on_store(struct device *dev, struct 
device_attribute *attr,
goto out;
}
 
-   pm_runtime_get_sync(hba->dev);
+   scsi_autopm_get_device(hba->sdev_ufs_device);
res = ufshcd_wb_toggle(hba, wb_enable);
-   pm_runtime_put_sync(hba->dev);
+   scsi_autopm_put_device(hba->sdev_ufs_device);
 out:
up(>host_sem);
return res < 0 ? res : count;
@@ -297,10 +297,10 @@ static ssize_t ufs_sysfs_read_desc_param(struct ufs_hba 
*hba,
goto out;
}
 
-   pm_runtime_get_sync(hba->dev);
+   scsi_autopm_get_device(hba->sdev_ufs_device);
ret = ufshcd_read_desc_param(hba, desc_id, desc_index,
param_offset, desc_buf, param_size);
-   pm_runtime_put_sync(hba->dev);
+   scsi_autopm_put_device(hba->sdev_ufs_device);
if (ret) {
ret = -EINVAL;
goto out;
@@ -678,7 +678,7 @@ static ssize_t _name##_show(struct device *dev, 
\
up(>host_sem); \
return -ENOMEM; \
}   \
-   pm_runtime_get_sync(hba->dev);  \
+   scsi_autopm_get_device(hba->sdev_ufs_device);   \
ret = ufshcd_query_descriptor_retry(hba,\
UPIU_QUERY_OPCODE_READ_DESC, QUERY_DESC_IDN_DEVICE, \
0, 0, desc_buf, _len); \
@@ -695,7 +695,7 @@ static ssize_t _name##_show(struct device *dev, 
\
goto out;   \
ret = sysfs_emit(buf, "%s\n", desc_buf);\
 out:   \
-   pm_runtime_put_sync(hba->dev);  \
+   scsi_autopm_put_device(hba->sdev_ufs_device);   \
kfree(desc_buf);\
up(>host_sem); \
return ret; \
@@ -744,10 +744,10 @@ static ssize_t _name##_show(struct device *dev,   
\
}   \
if (ufshcd_is_wb_flags(QUERY_FLAG_IDN##_uname)) \
index = ufshcd_wb_get_query_index(hba); \
-   pm_runtime_get_sync(hba->dev);  \
+   scsi_autopm_get_device(hba->sdev_ufs_device);   \
ret = ufshcd_query_flag(hba, UPIU_QUERY_OPCODE_READ_FLAG,   \
QUERY_FLAG_IDN##_uname, index, );  \
-   pm_runtime_put_sync(hba->dev);  \
+   scsi_autopm_put_device(hba->sdev_ufs_device);   \
if (ret) {  \
ret = -EINVAL;  \
goto out;   \
@@ -813,10 +813,10 @@ static ssize_t _name##_show(struct device *dev,   
\
}   \
if (ufshcd_is_wb_attrs(QUERY_ATTR_IDN##_uname)) \
index = ufshcd_wb_get_query_index(hba); \
-   pm_runtime_get_sync(hba->dev);  \
+   scsi_autopm_get_device(hba->sdev_ufs_device);   \
ret = ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_READ_ATTR,   \
QUERY_ATTR_IDN##_uname, index, 0, );  \
-   pm_runtime_put_sync(hba->dev);  \
+   scsi_autopm_put_device(hba->sdev_ufs_device);   \
if (ret) {  \
ret = -EINVAL;  \
goto out;   \
@@ -899,11 +899,15 @@ static ssize_t _pname##_show(struct device *dev,  
\
struct scsi_device *sdev = to_scsi_device(dev); \
  

Re: [PATCH v12 1/2] scsi: ufs: Enable power management for wlun

2021-03-24 Thread Asutosh Das (asd)

On 3/23/2021 12:19 PM, Adrian Hunter wrote:

On 23/03/21 5:13 pm, Asutosh Das (asd) wrote:

On 3/22/2021 11:12 PM, Adrian Hunter wrote:

On 22/03/21 9:53 pm, Asutosh Das (asd) wrote:

On 3/19/2021 10:47 AM, Adrian Hunter wrote:

On 19/03/21 2:35 am, Asutosh Das wrote:

During runtime-suspend of ufs host, the scsi devices are
already suspended and so are the queues associated with them.
But the ufs host sends SSU to wlun during its runtime-suspend.
During the process blk_queue_enter checks if the queue is not in
suspended state. If so, it waits for the queue to resume, and never
comes out of it.
The commit
(d55d15a33: scsi: block: Do not accept any requests while suspended)
adds the check if the queue is in suspended state in blk_queue_enter().

Call trace:
    __switch_to+0x174/0x2c4
    __schedule+0x478/0x764
    schedule+0x9c/0xe0
    blk_queue_enter+0x158/0x228
    blk_mq_alloc_request+0x40/0xa4
    blk_get_request+0x2c/0x70
    __scsi_execute+0x60/0x1c4
    ufshcd_set_dev_pwr_mode+0x124/0x1e4
    ufshcd_suspend+0x208/0x83c
    ufshcd_runtime_suspend+0x40/0x154
    ufshcd_pltfrm_runtime_suspend+0x14/0x20
    pm_generic_runtime_suspend+0x28/0x3c
    __rpm_callback+0x80/0x2a4
    rpm_suspend+0x308/0x614
    rpm_idle+0x158/0x228
    pm_runtime_work+0x84/0xac
    process_one_work+0x1f0/0x470
    worker_thread+0x26c/0x4c8
    kthread+0x13c/0x320
    ret_from_fork+0x10/0x18

Fix this by registering ufs device wlun as a scsi driver and
registering it for block runtime-pm. Also make this as a
supplier for all other luns. That way, this device wlun
suspends after all the consumers and resumes after
hba resumes.

Co-developed-by: Can Guo 
Signed-off-by: Can Guo 
Signed-off-by: Asutosh Das 


I have some more comments that may help straighten things out.

Also please look at ufs_debugfs_get_user_access() and
ufs_debugfs_put_user_access() that now need to scsi_autopm_get/put_device
sdev_ufs_device.

It would also be good if you could re-base on linux-next.



Hi Adrian
Thanks for the comments.

I agree moving the code to wlun probe and other changes.
But it looks to me that it may not fully solve the issue.

Please let me explain my understanding on this:

(Please refer to the logs in v10)
scsi_autopm_*() are invoked on a sdev.
pm_runtime_get_suppliers()/rpm_put_suppliers() are on the supplier device.

For the device wlun:
  slave_configure():
  - doesn't set the rpm_autosuspend
  - pm_runtime_getnoresume()
  scsi_sysfs_add_sdev():
  - pm_runtime_forbid()
  - scsi_autopm_get_device()
  - device_add()
  - ufshcd_wl_probe()
  - scsi_autopm_put_device()

For all other scsi devices:
  slave_alloc():
  - ufshcd_setup_links()
Say all link_add: pm_runtime_put(>sdev_ufs_device->sdev_gendev);


With DL_FLAG_RPM_ACTIVE, links will 'get' not 'put'


I'm referring to the pm_runtime_put(sdev_ufs_device) after all the links are 
setup, that you suggested to add.


Ok


  slave_configure():
  - set rpm_autosuspend
  scsi_sysfs_add_sdev():
  - scsi_autopm_get_device()
  - device_add() -> schedules an async probe()
  - scsi_autopm_put_device() - (1)

Now the rpm_put_suppliers() can be invoked *after* pm_runtime_get_suppliers() 
of the async probe(), since both are running in different contexts.


Only if the sd device suspends.


Correct. What'd stop the sd device from suspending?
We should be stopping the sd device from suspending here - imho.




Hi Adrian,
Thanks for the comments.


You mean for performance reasons.  That is something we can
look at, but let's get it working first.

Not for performance reasons. I meant to say that this issue can be fixed 
if we stop the sd devices from suspending until the sd_probe() is completed.



In that case, the usage_count of supplier would be decremented until rpm_active 
of this link becomes 1.


Right, because the sd device suspended.


Now the pm_runtime_get_suppliers() expects the link_active to be more than 1.


Not sure what you mean here. pm_runtime_*put*_suppliers() won't do anything if 
the link count is 1.

I'm referring to the logs that I pasted before:
[    6.941267][    T7] scsi 0:0:0:4: rpm_put_suppliers: [BEF] Supp 
(0:0:0:49488) usage_count: 4 rpm_active: 3

-- T196 Context comes in while T7 is running --
[    6.941466][  T196] scsi 0:0:0:4: pm_runtime_get_suppliers: (0:0:0:49488): 
supp: usage_count: 5 rpm_active: 4
--

[    7.788397][    T7] scsi 0:0:0:4: rpm_put_suppliers: [AFT] Supp 
(0:0:0:49488) usage_count: 2 rpm_active: 1

I meant to say that, if the rpm_put_suppliers() is invoked after the 
pm_runtime_get_suppliers() as is seen above then the link_active may become 1 
even *after* pm_runtime_get_suppliers() is invoked.

I'm referring to the pm_runtime_get_suppliers() invoked from:
driver_probe_device() - say for, sd 0:0:0:x
 |- pm_runtime_get_suppliers() - for

[PATCH v13 2/2] ufs: sysfs: Resume the proper scsi device

2021-03-24 Thread Asutosh Das
Resumes the actual scsi device the unit descriptor of which
is being accessed instead of the hba alone.

Reviewed-by: Can Guo 
Signed-off-by: Asutosh Das 
---
 drivers/scsi/ufs/ufs-sysfs.c | 30 +-
 1 file changed, 17 insertions(+), 13 deletions(-)

diff --git a/drivers/scsi/ufs/ufs-sysfs.c b/drivers/scsi/ufs/ufs-sysfs.c
index acc54f5..3fc182b 100644
--- a/drivers/scsi/ufs/ufs-sysfs.c
+++ b/drivers/scsi/ufs/ufs-sysfs.c
@@ -245,9 +245,9 @@ static ssize_t wb_on_store(struct device *dev, struct 
device_attribute *attr,
goto out;
}
 
-   pm_runtime_get_sync(hba->dev);
+   scsi_autopm_get_device(hba->sdev_ufs_device);
res = ufshcd_wb_ctrl(hba, wb_enable);
-   pm_runtime_put_sync(hba->dev);
+   scsi_autopm_put_device(hba->sdev_ufs_device);
 out:
up(>host_sem);
return res < 0 ? res : count;
@@ -297,10 +297,10 @@ static ssize_t ufs_sysfs_read_desc_param(struct ufs_hba 
*hba,
goto out;
}
 
-   pm_runtime_get_sync(hba->dev);
+   scsi_autopm_get_device(hba->sdev_ufs_device);
ret = ufshcd_read_desc_param(hba, desc_id, desc_index,
param_offset, desc_buf, param_size);
-   pm_runtime_put_sync(hba->dev);
+   scsi_autopm_put_device(hba->sdev_ufs_device);
if (ret) {
ret = -EINVAL;
goto out;
@@ -678,7 +678,7 @@ static ssize_t _name##_show(struct device *dev, 
\
up(>host_sem); \
return -ENOMEM; \
}   \
-   pm_runtime_get_sync(hba->dev);  \
+   scsi_autopm_get_device(hba->sdev_ufs_device);   \
ret = ufshcd_query_descriptor_retry(hba,\
UPIU_QUERY_OPCODE_READ_DESC, QUERY_DESC_IDN_DEVICE, \
0, 0, desc_buf, _len); \
@@ -695,7 +695,7 @@ static ssize_t _name##_show(struct device *dev, 
\
goto out;   \
ret = sysfs_emit(buf, "%s\n", desc_buf);\
 out:   \
-   pm_runtime_put_sync(hba->dev);  \
+   scsi_autopm_put_device(hba->sdev_ufs_device);   \
kfree(desc_buf);\
up(>host_sem); \
return ret; \
@@ -744,10 +744,10 @@ static ssize_t _name##_show(struct device *dev,   
\
}   \
if (ufshcd_is_wb_flags(QUERY_FLAG_IDN##_uname)) \
index = ufshcd_wb_get_query_index(hba); \
-   pm_runtime_get_sync(hba->dev);  \
+   scsi_autopm_get_device(hba->sdev_ufs_device);   \
ret = ufshcd_query_flag(hba, UPIU_QUERY_OPCODE_READ_FLAG,   \
QUERY_FLAG_IDN##_uname, index, );  \
-   pm_runtime_put_sync(hba->dev);  \
+   scsi_autopm_put_device(hba->sdev_ufs_device);   \
if (ret) {  \
ret = -EINVAL;  \
goto out;   \
@@ -813,10 +813,10 @@ static ssize_t _name##_show(struct device *dev,   
\
}   \
if (ufshcd_is_wb_attrs(QUERY_ATTR_IDN##_uname)) \
index = ufshcd_wb_get_query_index(hba); \
-   pm_runtime_get_sync(hba->dev);  \
+   scsi_autopm_get_device(hba->sdev_ufs_device);   \
ret = ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_READ_ATTR,   \
QUERY_ATTR_IDN##_uname, index, 0, );  \
-   pm_runtime_put_sync(hba->dev);  \
+   scsi_autopm_put_device(hba->sdev_ufs_device);   \
if (ret) {  \
ret = -EINVAL;  \
goto out;   \
@@ -899,11 +899,15 @@ static ssize_t _pname##_show(struct device *dev,  
\
struct scsi_device *sdev = to_scsi_device(dev); \
  

[PATCH v13 1/2] scsi: ufs: Enable power management for wlun

2021-03-24 Thread Asutosh Das
During runtime-suspend of ufs host, the scsi devices are
already suspended and so are the queues associated with them.
But the ufs host sends SSU (START_STOP_UNIT) to wlun
during its runtime-suspend.
During the process blk_queue_enter checks if the queue is not in
suspended state. If so, it waits for the queue to resume, and never
comes out of it.
The commit
(d55d15a33: scsi: block: Do not accept any requests while suspended)
adds the check if the queue is in suspended state in blk_queue_enter().

Call trace:
 __switch_to+0x174/0x2c4
 __schedule+0x478/0x764
 schedule+0x9c/0xe0
 blk_queue_enter+0x158/0x228
 blk_mq_alloc_request+0x40/0xa4
 blk_get_request+0x2c/0x70
 __scsi_execute+0x60/0x1c4
 ufshcd_set_dev_pwr_mode+0x124/0x1e4
 ufshcd_suspend+0x208/0x83c
 ufshcd_runtime_suspend+0x40/0x154
 ufshcd_pltfrm_runtime_suspend+0x14/0x20
 pm_generic_runtime_suspend+0x28/0x3c
 __rpm_callback+0x80/0x2a4
 rpm_suspend+0x308/0x614
 rpm_idle+0x158/0x228
 pm_runtime_work+0x84/0xac
 process_one_work+0x1f0/0x470
 worker_thread+0x26c/0x4c8
 kthread+0x13c/0x320
 ret_from_fork+0x10/0x18

Fix this by registering ufs device wlun as a scsi driver and
registering it for block runtime-pm. Also make this as a
supplier for all other luns. That way, this device wlun
suspends after all the consumers and resumes after
hba resumes.

Co-developed-by: Can Guo 
Signed-off-by: Can Guo 
Signed-off-by: Asutosh Das 
---
 drivers/scsi/ufs/cdns-pltfrm.c |   2 +
 drivers/scsi/ufs/tc-dwc-g210-pci.c |   2 +
 drivers/scsi/ufs/ufs-debugfs.c |   2 +-
 drivers/scsi/ufs/ufs-debugfs.h |   2 +-
 drivers/scsi/ufs/ufs-exynos.c  |   2 +
 drivers/scsi/ufs/ufs-hisi.c|   2 +
 drivers/scsi/ufs/ufs-mediatek.c|  12 +-
 drivers/scsi/ufs/ufs-qcom.c|   2 +
 drivers/scsi/ufs/ufs_bsg.c |   6 +-
 drivers/scsi/ufs/ufshcd-pci.c  |  36 +--
 drivers/scsi/ufs/ufshcd.c  | 627 ++---
 drivers/scsi/ufs/ufshcd.h  |   6 +
 include/trace/events/ufs.h |  20 ++
 13 files changed, 496 insertions(+), 225 deletions(-)

diff --git a/drivers/scsi/ufs/cdns-pltfrm.c b/drivers/scsi/ufs/cdns-pltfrm.c
index 149391f..3e70c23 100644
--- a/drivers/scsi/ufs/cdns-pltfrm.c
+++ b/drivers/scsi/ufs/cdns-pltfrm.c
@@ -319,6 +319,8 @@ static const struct dev_pm_ops cdns_ufs_dev_pm_ops = {
.runtime_suspend = ufshcd_pltfrm_runtime_suspend,
.runtime_resume  = ufshcd_pltfrm_runtime_resume,
.runtime_idle= ufshcd_pltfrm_runtime_idle,
+   .prepare = ufshcd_suspend_prepare,
+   .complete   = ufshcd_resume_complete,
 };
 
 static struct platform_driver cdns_ufs_pltfrm_driver = {
diff --git a/drivers/scsi/ufs/tc-dwc-g210-pci.c 
b/drivers/scsi/ufs/tc-dwc-g210-pci.c
index 67a6a61..b01db12 100644
--- a/drivers/scsi/ufs/tc-dwc-g210-pci.c
+++ b/drivers/scsi/ufs/tc-dwc-g210-pci.c
@@ -148,6 +148,8 @@ static const struct dev_pm_ops tc_dwc_g210_pci_pm_ops = {
.runtime_suspend = tc_dwc_g210_pci_runtime_suspend,
.runtime_resume  = tc_dwc_g210_pci_runtime_resume,
.runtime_idle= tc_dwc_g210_pci_runtime_idle,
+   .prepare = ufshcd_suspend_prepare,
+   .complete   = ufshcd_resume_complete,
 };
 
 static const struct pci_device_id tc_dwc_g210_pci_tbl[] = {
diff --git a/drivers/scsi/ufs/ufs-debugfs.c b/drivers/scsi/ufs/ufs-debugfs.c
index dee98dc..06457d5 100644
--- a/drivers/scsi/ufs/ufs-debugfs.c
+++ b/drivers/scsi/ufs/ufs-debugfs.c
@@ -13,7 +13,7 @@ void __init ufs_debugfs_init(void)
ufs_debugfs_root = debugfs_create_dir("ufshcd", NULL);
 }
 
-void __exit ufs_debugfs_exit(void)
+void ufs_debugfs_exit(void)
 {
debugfs_remove_recursive(ufs_debugfs_root);
 }
diff --git a/drivers/scsi/ufs/ufs-debugfs.h b/drivers/scsi/ufs/ufs-debugfs.h
index f35b39c..12c2730 100644
--- a/drivers/scsi/ufs/ufs-debugfs.h
+++ b/drivers/scsi/ufs/ufs-debugfs.h
@@ -9,7 +9,7 @@ struct ufs_hba;
 
 #ifdef CONFIG_DEBUG_FS
 void __init ufs_debugfs_init(void);
-void __exit ufs_debugfs_exit(void);
+void ufs_debugfs_exit(void);
 void ufs_debugfs_hba_init(struct ufs_hba *hba);
 void ufs_debugfs_hba_exit(struct ufs_hba *hba);
 #else
diff --git a/drivers/scsi/ufs/ufs-exynos.c b/drivers/scsi/ufs/ufs-exynos.c
index 267943a1..45c0b02 100644
--- a/drivers/scsi/ufs/ufs-exynos.c
+++ b/drivers/scsi/ufs/ufs-exynos.c
@@ -1268,6 +1268,8 @@ static const struct dev_pm_ops exynos_ufs_pm_ops = {
.runtime_suspend = ufshcd_pltfrm_runtime_suspend,
.runtime_resume  = ufshcd_pltfrm_runtime_resume,
.runtime_idle= ufshcd_pltfrm_runtime_idle,
+   .prepare = ufshcd_suspend_prepare,
+   .complete   = ufshcd_resume_complete,
 };
 
 static struct platform_driver exynos_ufs_pltform = {
diff --git a/drivers/scsi/ufs/ufs-hisi.c b/drivers/scsi/ufs/ufs-hisi.c
index 0aa5813..d463b44 100644
--- a/drivers/scsi/ufs/ufs-hisi.c
+++ b/drivers/scsi/ufs/ufs-hisi.c
@@ -574,6 +574,8 @@ static const struct dev_pm_ops ufs_h

Re: [PATCH v12 1/2] scsi: ufs: Enable power management for wlun

2021-03-23 Thread Asutosh Das (asd)

On 3/22/2021 11:12 PM, Adrian Hunter wrote:

On 22/03/21 9:53 pm, Asutosh Das (asd) wrote:

On 3/19/2021 10:47 AM, Adrian Hunter wrote:

On 19/03/21 2:35 am, Asutosh Das wrote:

During runtime-suspend of ufs host, the scsi devices are
already suspended and so are the queues associated with them.
But the ufs host sends SSU to wlun during its runtime-suspend.
During the process blk_queue_enter checks if the queue is not in
suspended state. If so, it waits for the queue to resume, and never
comes out of it.
The commit
(d55d15a33: scsi: block: Do not accept any requests while suspended)
adds the check if the queue is in suspended state in blk_queue_enter().

Call trace:
   __switch_to+0x174/0x2c4
   __schedule+0x478/0x764
   schedule+0x9c/0xe0
   blk_queue_enter+0x158/0x228
   blk_mq_alloc_request+0x40/0xa4
   blk_get_request+0x2c/0x70
   __scsi_execute+0x60/0x1c4
   ufshcd_set_dev_pwr_mode+0x124/0x1e4
   ufshcd_suspend+0x208/0x83c
   ufshcd_runtime_suspend+0x40/0x154
   ufshcd_pltfrm_runtime_suspend+0x14/0x20
   pm_generic_runtime_suspend+0x28/0x3c
   __rpm_callback+0x80/0x2a4
   rpm_suspend+0x308/0x614
   rpm_idle+0x158/0x228
   pm_runtime_work+0x84/0xac
   process_one_work+0x1f0/0x470
   worker_thread+0x26c/0x4c8
   kthread+0x13c/0x320
   ret_from_fork+0x10/0x18

Fix this by registering ufs device wlun as a scsi driver and
registering it for block runtime-pm. Also make this as a
supplier for all other luns. That way, this device wlun
suspends after all the consumers and resumes after
hba resumes.

Co-developed-by: Can Guo 
Signed-off-by: Can Guo 
Signed-off-by: Asutosh Das 


I have some more comments that may help straighten things out.

Also please look at ufs_debugfs_get_user_access() and
ufs_debugfs_put_user_access() that now need to scsi_autopm_get/put_device
sdev_ufs_device.

It would also be good if you could re-base on linux-next.



Hi Adrian
Thanks for the comments.

I agree moving the code to wlun probe and other changes.
But it looks to me that it may not fully solve the issue.

Please let me explain my understanding on this:

(Please refer to the logs in v10)
scsi_autopm_*() are invoked on a sdev.
pm_runtime_get_suppliers()/rpm_put_suppliers() are on the supplier device.

For the device wlun:
 slave_configure():
     - doesn't set the rpm_autosuspend
     - pm_runtime_getnoresume()
 scsi_sysfs_add_sdev():
     - pm_runtime_forbid()
     - scsi_autopm_get_device()
     - device_add()
     - ufshcd_wl_probe()
     - scsi_autopm_put_device()

For all other scsi devices:
 slave_alloc():
     - ufshcd_setup_links()
Say all link_add: pm_runtime_put(>sdev_ufs_device->sdev_gendev);


With DL_FLAG_RPM_ACTIVE, links will 'get' not 'put'

I'm referring to the pm_runtime_put(sdev_ufs_device) after all the links 
are setup, that you suggested to add.

 slave_configure():
     - set rpm_autosuspend
 scsi_sysfs_add_sdev():
     - scsi_autopm_get_device()
     - device_add() -> schedules an async probe()
     - scsi_autopm_put_device() - (1)

Now the rpm_put_suppliers() can be invoked *after* pm_runtime_get_suppliers() 
of the async probe(), since both are running in different contexts.


Only if the sd device suspends.


Correct. What'd stop the sd device from suspending?
We should be stopping the sd device from suspending here - imho.


In that case, the usage_count of supplier would be decremented until rpm_active 
of this link becomes 1.


Right, because the sd device suspended.


Now the pm_runtime_get_suppliers() expects the link_active to be more than 1.


Not sure what you mean here. pm_runtime_*put*_suppliers() won't do anything if 
the link count is 1.

I'm referring to the logs that I pasted before:
[6.941267][T7] scsi 0:0:0:4: rpm_put_suppliers: [BEF] Supp 
(0:0:0:49488) usage_count: 4 rpm_active: 3


-- T196 Context comes in while T7 is running --
[6.941466][  T196] scsi 0:0:0:4: pm_runtime_get_suppliers: 
(0:0:0:49488): supp: usage_count: 5 rpm_active: 4

--

[7.788397][T7] scsi 0:0:0:4: rpm_put_suppliers: [AFT] Supp 
(0:0:0:49488) usage_count: 2 rpm_active: 1


I meant to say that, if the rpm_put_suppliers() is invoked after the 
pm_runtime_get_suppliers() as is seen above then the link_active may 
become 1 even *after* pm_runtime_get_suppliers() is invoked.


I'm referring to the pm_runtime_get_suppliers() invoked from:
driver_probe_device() - say for, sd 0:0:0:x
|- pm_runtime_get_suppliers() - for sd 0:0:0:49488



Now then, there comes a time, that when sd_probe() schedules a suspend, the 
supplier usage_count becomes 0 and the link_active becomes 1.
And the supplier suspends before the consumer.


sd probe first resumes the sd device which will resume the supplier.

Correct, but it'd again schedule a suspend (since autosuspend is enabled 
now) at the end of the sd_probe().
Thereafter, pm_runtime_put_suppliers()

Re: [PATCH v12 1/2] scsi: ufs: Enable power management for wlun

2021-03-22 Thread Asutosh Das (asd)

On 3/19/2021 10:47 AM, Adrian Hunter wrote:

On 19/03/21 2:35 am, Asutosh Das wrote:

During runtime-suspend of ufs host, the scsi devices are
already suspended and so are the queues associated with them.
But the ufs host sends SSU to wlun during its runtime-suspend.
During the process blk_queue_enter checks if the queue is not in
suspended state. If so, it waits for the queue to resume, and never
comes out of it.
The commit
(d55d15a33: scsi: block: Do not accept any requests while suspended)
adds the check if the queue is in suspended state in blk_queue_enter().

Call trace:
  __switch_to+0x174/0x2c4
  __schedule+0x478/0x764
  schedule+0x9c/0xe0
  blk_queue_enter+0x158/0x228
  blk_mq_alloc_request+0x40/0xa4
  blk_get_request+0x2c/0x70
  __scsi_execute+0x60/0x1c4
  ufshcd_set_dev_pwr_mode+0x124/0x1e4
  ufshcd_suspend+0x208/0x83c
  ufshcd_runtime_suspend+0x40/0x154
  ufshcd_pltfrm_runtime_suspend+0x14/0x20
  pm_generic_runtime_suspend+0x28/0x3c
  __rpm_callback+0x80/0x2a4
  rpm_suspend+0x308/0x614
  rpm_idle+0x158/0x228
  pm_runtime_work+0x84/0xac
  process_one_work+0x1f0/0x470
  worker_thread+0x26c/0x4c8
  kthread+0x13c/0x320
  ret_from_fork+0x10/0x18

Fix this by registering ufs device wlun as a scsi driver and
registering it for block runtime-pm. Also make this as a
supplier for all other luns. That way, this device wlun
suspends after all the consumers and resumes after
hba resumes.

Co-developed-by: Can Guo 
Signed-off-by: Can Guo 
Signed-off-by: Asutosh Das 


I have some more comments that may help straighten things out.

Also please look at ufs_debugfs_get_user_access() and
ufs_debugfs_put_user_access() that now need to scsi_autopm_get/put_device
sdev_ufs_device.

It would also be good if you could re-base on linux-next.



Hi Adrian
Thanks for the comments.

I agree moving the code to wlun probe and other changes.
But it looks to me that it may not fully solve the issue.

Please let me explain my understanding on this:

(Please refer to the logs in v10)
scsi_autopm_*() are invoked on a sdev.
pm_runtime_get_suppliers()/rpm_put_suppliers() are on the supplier device.

For the device wlun:
slave_configure():
- doesn't set the rpm_autosuspend
- pm_runtime_getnoresume()
scsi_sysfs_add_sdev():
- pm_runtime_forbid()
- scsi_autopm_get_device()
- device_add()
- ufshcd_wl_probe()
- scsi_autopm_put_device()

For all other scsi devices:
slave_alloc():
- ufshcd_setup_links()
Say all link_add: pm_runtime_put(>sdev_ufs_device->sdev_gendev);
slave_configure():
- set rpm_autosuspend
scsi_sysfs_add_sdev():
- scsi_autopm_get_device()
- device_add() -> schedules an async probe()
- scsi_autopm_put_device() - (1)

Now the rpm_put_suppliers() can be invoked *after* 
pm_runtime_get_suppliers() of the async probe(), since both are running 
in different contexts.
In that case, the usage_count of supplier would be decremented until 
rpm_active of this link becomes 1.
Now the pm_runtime_get_suppliers() expects the link_active to be more 
than 1.
Now then, there comes a time, that when sd_probe() schedules a suspend, 
the supplier usage_count becomes 0 and the link_active becomes 1.

And the supplier suspends before the consumer.

So I was wondering, what'd make sure that the pm_runtime_get_suppliers() 
from driver_probe_device() is invoked after scsi_autopm_put_device() (1) 
finishes the rpm_put_suppliers().


Am not sure if I'm missing something in this.
Do you think, the current changes alone can fix the above issue?

-asd


---
  drivers/scsi/ufs/cdns-pltfrm.c |   2 +
  drivers/scsi/ufs/tc-dwc-g210-pci.c |   2 +
  drivers/scsi/ufs/ufs-debugfs.c |   2 +-
  drivers/scsi/ufs/ufs-debugfs.h |   2 +-
  drivers/scsi/ufs/ufs-exynos.c  |   2 +
  drivers/scsi/ufs/ufs-hisi.c|   2 +
  drivers/scsi/ufs/ufs-mediatek.c|  12 +-
  drivers/scsi/ufs/ufs-qcom.c|   2 +
  drivers/scsi/ufs/ufs_bsg.c |   6 +-
  drivers/scsi/ufs/ufshcd-pci.c  |  36 +--
  drivers/scsi/ufs/ufshcd.c  | 622 ++---
  drivers/scsi/ufs/ufshcd.h  |   6 +
  include/trace/events/ufs.h |  20 ++
  13 files changed, 491 insertions(+), 225 deletions(-)

diff --git a/drivers/scsi/ufs/cdns-pltfrm.c b/drivers/scsi/ufs/cdns-pltfrm.c
index 149391f..3e70c23 100644
--- a/drivers/scsi/ufs/cdns-pltfrm.c
+++ b/drivers/scsi/ufs/cdns-pltfrm.c
@@ -319,6 +319,8 @@ static const struct dev_pm_ops cdns_ufs_dev_pm_ops = {
.runtime_suspend = ufshcd_pltfrm_runtime_suspend,
.runtime_resume  = ufshcd_pltfrm_runtime_resume,
.runtime_idle= ufshcd_pltfrm_runtime_idle,
+   .prepare = ufshcd_suspend_prepare,
+   .complete   = ufshcd_resume_complete,
  };
  
  static struct platform_driver cdns_ufs_pltf

Re: [PATCH v12 1/2] scsi: ufs: Enable power management for wlun

2021-03-19 Thread Asutosh Das (asd)

On 3/18/2021 8:12 PM, Bart Van Assche wrote:

On 3/18/21 5:35 PM, Asutosh Das wrote:

During runtime-suspend of ufs host, the scsi devices are
already suspended and so are the queues associated with them.
But the ufs host sends SSU to wlun during its runtime-suspend.
During the process blk_queue_enter checks if the queue is not in
suspended state. If so, it waits for the queue to resume, and never
comes out of it.
The commit
(d55d15a33: scsi: block: Do not accept any requests while suspended)
adds the check if the queue is in suspended state in blk_queue_enter().



Hi Bart,
Thanks for the review comments.


What is the role of the WLUN during runtime suspend and why does a
command need to be sent to the WLUN during runtime suspend? Although it
is possible to derive this from the source code, please explain this in
the patch description.


Ok. Will explain it in the next version.


What does the acronym SSU stand for? This doesn't seem like a commonly
used kernel acronym to me so please expand that acronym.


START STOP UNIT.
Anyway, I'll expand it in the next version.


Fix this by registering ufs device wlun as a scsi driver and
registering it for block runtime-pm. Also make this as a
supplier for all other luns. That way, this device wlun
suspends after all the consumers and resumes after
hba resumes.


That's an interesting solution.


-void __exit ufs_debugfs_exit(void)
+void ufs_debugfs_exit(void)


Is the above change related to the rest of this patch?


Yes, it's used to handle an error in ufshcd_core_init() function.


  static struct platform_driver ufs_qcom_pltform = {
diff --git a/drivers/scsi/ufs/ufs_bsg.c b/drivers/scsi/ufs/ufs_bsg.c
index 5b2bc1a..cbb5a90 100644
--- a/drivers/scsi/ufs/ufs_bsg.c
+++ b/drivers/scsi/ufs/ufs_bsg.c
@@ -97,7 +97,7 @@ static int ufs_bsg_request(struct bsg_job *job)
  
  	bsg_reply->reply_payload_rcv_len = 0;
  
-	pm_runtime_get_sync(hba->dev);

+   scsi_autopm_get_device(hba->sdev_ufs_device);


Can the pm_runtime_get_sync() to scsi_autopm_get_device() changes be
moved into a separate patch?


I guess so. But then this patch would have issues when used independently.


+static inline bool is_rpmb_wlun(struct scsi_device *sdev)
+{
+   return (sdev->lun == ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_RPMB_WLUN));
+}


Has this patch been verified with checkpatch? Checkpatch should have
reported the following for the above code:

return is not a function, parentheses are not required


Yes, it has been verified. But I didn't see any error reports.
Below is the o/p of checkpatch:

$ ./scripts/checkpatch.pl /tmp/up/ufs-pm-v12/*
--
/tmp/up/ufs-pm-v12/-cover-letter.patch
--
WARNING: Possible unwrapped commit description (prefer a maximum 75 
chars per line)

#107:
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a 
Linux Foundation Collaborative Project.


total: 0 errors, 1 warnings, 0 lines checked

NOTE: For some of the reported defects, checkpatch may be able to
  mechanically convert to the typical style using --fix or 
--fix-inplace.


/tmp/up/ufs-pm-v12/-cover-letter.patch has style problems, please 
review.

---
/tmp/up/ufs-pm-v12/0001-scsi-ufs-Enable-power-management-for-wlun.patch
---
total: 0 errors, 0 warnings, 1180 lines checked

/tmp/up/ufs-pm-v12/0001-scsi-ufs-Enable-power-management-for-wlun.patch 
has no obvious style problems and is ready for submission.

-
/tmp/up/ufs-pm-v12/0002-ufs-sysfs-Resume-the-proper-scsi-device.patch
-
total: 0 errors, 0 warnings, 91 lines checked

/tmp/up/ufs-pm-v12/0002-ufs-sysfs-Resume-the-proper-scsi-device.patch 
has no obvious style problems and is ready for submission.


NOTE: If any of the errors are false positives, please report
  them to the maintainer, see CHECKPATCH in MAINTAINERS.



+static inline bool is_device_wlun(struct scsi_device *sdev)
+{
+   return (sdev->lun ==
+   ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_UFS_DEVICE_WLUN));
+}


Same comment here.


/*
-* Don't assume anything of pm_runtime_get_sync(), if
+* Don't assume anything of resume, if
 * resume fails, irq and clocks can be OFF, and powers
 * can be OFF or in LPM.
 */


Please make better use of the horizontal space in the above comment by
making comment lines longer.


Ok Sure.


Thanks,

Bart.



-asd

--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
Linux Foundation Collaborative Project


Re: [PATCH v10 1/2] scsi: ufs: Enable power management for wlun

2021-03-18 Thread Asutosh Das (asd)

On 3/18/2021 12:16 PM, Adrian Hunter wrote:

On 18/03/21 7:58 pm, Asutosh Das (asd) wrote:

On 3/18/2021 10:54 AM, Rafael J. Wysocki wrote:

On Thu, Mar 18, 2021 at 6:33 PM Asutosh Das (asd)
 wrote:


On 3/18/2021 7:00 AM, Rafael J. Wysocki wrote:

On Wed, Mar 17, 2021 at 7:37 AM Adrian Hunter  wrote:


On 16/03/21 10:35 pm, Asutosh Das (asd) wrote:

On 3/16/2021 12:48 AM, Adrian Hunter wrote:

On 16/03/21 12:22 am, Asutosh Das (asd) wrote:

On 3/14/2021 1:11 AM, Adrian Hunter wrote:

On 10/03/21 5:04 am, Asutosh Das (asd) wrote:

On 3/9/2021 7:56 AM, Asutosh Das (asd) wrote:

On 3/8/2021 9:17 AM, Rafael J. Wysocki wrote:

On Mon, Mar 8, 2021 at 5:21 PM Rafael J. Wysocki  wrote:


On Sat, Mar 6, 2021 at 5:17 PM Alan Stern  wrote:


On Fri, Mar 05, 2021 at 06:54:24PM -0800, Asutosh Das (asd) wrote:


Now during my testing I see a weird issue sometimes (1 in 7).
Scenario - bootups

Issue:
The supplier 'ufs_device_wlun 0:0:0:49488' goes into runtime suspend even
when one/more of its consumers are in RPM_ACTIVE state.

*Log:
[   10.056379][  T206] sd 0:0:0:1: [sdb] Synchronizing SCSI cache
[   10.062497][  T113] sd 0:0:0:5: [sdf] Synchronizing SCSI cache
[   10.356600][   T32] sd 0:0:0:7: [sdh] Synchronizing SCSI cache
[   10.362944][  T174] sd 0:0:0:3: [sdd] Synchronizing SCSI cache
[   10.696627][   T83] sd 0:0:0:2: [sdc] Synchronizing SCSI cache
[   10.704562][  T170] sd 0:0:0:6: [sdg] Synchronizing SCSI cache
[   10.980602][    T5] sd 0:0:0:0: [sda] Synchronizing SCSI cache

/** Printing all the consumer nodes of supplier **/
[   10.987327][    T5] ufs_device_wlun 0:0:0:49488: usage-count @ suspend: 0
<-- this is the usage_count
[   10.994440][    T5] ufs_rpmb_wlun 0:0:0:49476: PM state - 2
[   11.000402][    T5] scsi 0:0:0:49456: PM state - 2
[   11.005453][    T5] sd 0:0:0:0: PM state - 2
[   11.009958][    T5] sd 0:0:0:1: PM state - 2
[   11.014469][    T5] sd 0:0:0:2: PM state - 2
[   11.019072][    T5] sd 0:0:0:3: PM state - 2
[   11.023595][    T5] sd 0:0:0:4: PM state - 0 << RPM_ACTIVE
[   11.353298][    T5] sd 0:0:0:5: PM state - 2
[   11.357726][    T5] sd 0:0:0:6: PM state - 2
[   11.362155][    T5] sd 0:0:0:7: PM state - 2
[   11.366584][    T5] ufshcd-qcom 1d84000.ufshc: __ufshcd_wl_suspend - 8709
[   11.374366][    T5] ufs_device_wlun 0:0:0:49488: __ufshcd_wl_suspend -
(0) has rpm_active flags


Do you mean that rpm_active of the link between the consumer and the
supplier is greater than 0 at this point and the consumer is


I mean is rpm_active of the link greater than 1 (because 1 means "no
active references to the supplier")?

Hi Rafael:
No - it is not greater than 1.

I'm trying to understand what's going on in it; will update when I've something.




RPM_ACTIVE, but the supplier suspends successfully nevertheless?


[   11.383376][    T5] ufs_device_wlun 0:0:0:49488:
ufshcd_wl_runtime_suspend <-- Supplier suspends fine.
[   12.977318][  T174] sd 0:0:0:4: [sde] Synchronizing SCSI cache

And the the suspend of sde is stuck now:
schedule+0x9c/0xe0
schedule_timeout+0x40/0x128
io_schedule_timeout+0x44/0x68
wait_for_common_io+0x7c/0x100
wait_for_completion_io+0x14/0x20
blk_execute_rq+0x90/0xcc
__scsi_execute+0x104/0x1c4
sd_sync_cache+0xf8/0x2a0
sd_suspend_common+0x74/0x11c
sd_suspend_runtime+0x14/0x20
scsi_runtime_suspend+0x64/0x94
__rpm_callback+0x80/0x2a4
rpm_suspend+0x308/0x614
pm_runtime_work+0x98/0xa8

I added 'DL_FLAG_RPM_ACTIVE' while creating links.
    if (hba->sdev_ufs_device) {
    link = device_link_add(>sdev_gendev,
    >sdev_ufs_device->sdev_gendev,
   DL_FLAG_PM_RUNTIME|DL_FLAG_RPM_ACTIVE);
I didn't expect this to resolve the issue anyway and it didn't.

Another interesting point here is when I resume any of the above suspended
consumers, it all goes back to normal, which is kind of expected. I tried
resuming the consumer and the supplier is resumed and the supplier is
suspended when all the consumers are suspended.

Any pointers on this issue please?

@Bart/@Alan - Do you've any pointers please?


It's very noticeable that although you seem to have isolated a bug in
the power management subsystem (supplier goes into runtime suspend
even when one of its consumers is still active), you did not CC the
power management maintainer or mailing list.

I have added the appropriate CC's.


Thanks Alan!





Hello
I & Can (thanks CanG) debugged this further:

Looks like this issue can occur if the sd probe is asynchronous.

Essentially, the sd_probe() is done asynchronously and driver_probe_device() 
invokes pm_runtime_get_suppliers() before invoking sd_probe().

But scsi_probe_and_add_lun() runs in a separate context.
So the scsi_autopm_put_device() invoked from scsi_scan_host() context reduces the 
link->rpm_active to 1. And sd_probe() invokes scsi_autopm_put_device() and starts 
a timer. And then driver_probe_device() invoked from __device_atta

[PATCH v12 2/2] ufs: sysfs: Resume the proper scsi device

2021-03-18 Thread Asutosh Das
Resumes the actual scsi device the unit descriptor of which
is being accessed instead of the hba alone.

Reviewed-by: Can Guo 
Signed-off-by: Asutosh Das 
---
 drivers/scsi/ufs/ufs-sysfs.c | 30 +-
 1 file changed, 17 insertions(+), 13 deletions(-)

diff --git a/drivers/scsi/ufs/ufs-sysfs.c b/drivers/scsi/ufs/ufs-sysfs.c
index acc54f5..3fc182b 100644
--- a/drivers/scsi/ufs/ufs-sysfs.c
+++ b/drivers/scsi/ufs/ufs-sysfs.c
@@ -245,9 +245,9 @@ static ssize_t wb_on_store(struct device *dev, struct 
device_attribute *attr,
goto out;
}
 
-   pm_runtime_get_sync(hba->dev);
+   scsi_autopm_get_device(hba->sdev_ufs_device);
res = ufshcd_wb_ctrl(hba, wb_enable);
-   pm_runtime_put_sync(hba->dev);
+   scsi_autopm_put_device(hba->sdev_ufs_device);
 out:
up(>host_sem);
return res < 0 ? res : count;
@@ -297,10 +297,10 @@ static ssize_t ufs_sysfs_read_desc_param(struct ufs_hba 
*hba,
goto out;
}
 
-   pm_runtime_get_sync(hba->dev);
+   scsi_autopm_get_device(hba->sdev_ufs_device);
ret = ufshcd_read_desc_param(hba, desc_id, desc_index,
param_offset, desc_buf, param_size);
-   pm_runtime_put_sync(hba->dev);
+   scsi_autopm_put_device(hba->sdev_ufs_device);
if (ret) {
ret = -EINVAL;
goto out;
@@ -678,7 +678,7 @@ static ssize_t _name##_show(struct device *dev, 
\
up(>host_sem); \
return -ENOMEM; \
}   \
-   pm_runtime_get_sync(hba->dev);  \
+   scsi_autopm_get_device(hba->sdev_ufs_device);   \
ret = ufshcd_query_descriptor_retry(hba,\
UPIU_QUERY_OPCODE_READ_DESC, QUERY_DESC_IDN_DEVICE, \
0, 0, desc_buf, _len); \
@@ -695,7 +695,7 @@ static ssize_t _name##_show(struct device *dev, 
\
goto out;   \
ret = sysfs_emit(buf, "%s\n", desc_buf);\
 out:   \
-   pm_runtime_put_sync(hba->dev);  \
+   scsi_autopm_put_device(hba->sdev_ufs_device);   \
kfree(desc_buf);\
up(>host_sem); \
return ret; \
@@ -744,10 +744,10 @@ static ssize_t _name##_show(struct device *dev,   
\
}   \
if (ufshcd_is_wb_flags(QUERY_FLAG_IDN##_uname)) \
index = ufshcd_wb_get_query_index(hba); \
-   pm_runtime_get_sync(hba->dev);  \
+   scsi_autopm_get_device(hba->sdev_ufs_device);   \
ret = ufshcd_query_flag(hba, UPIU_QUERY_OPCODE_READ_FLAG,   \
QUERY_FLAG_IDN##_uname, index, );  \
-   pm_runtime_put_sync(hba->dev);  \
+   scsi_autopm_put_device(hba->sdev_ufs_device);   \
if (ret) {  \
ret = -EINVAL;  \
goto out;   \
@@ -813,10 +813,10 @@ static ssize_t _name##_show(struct device *dev,   
\
}   \
if (ufshcd_is_wb_attrs(QUERY_ATTR_IDN##_uname)) \
index = ufshcd_wb_get_query_index(hba); \
-   pm_runtime_get_sync(hba->dev);  \
+   scsi_autopm_get_device(hba->sdev_ufs_device);   \
ret = ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_READ_ATTR,   \
QUERY_ATTR_IDN##_uname, index, 0, );  \
-   pm_runtime_put_sync(hba->dev);  \
+   scsi_autopm_put_device(hba->sdev_ufs_device);   \
if (ret) {  \
ret = -EINVAL;  \
goto out;   \
@@ -899,11 +899,15 @@ static ssize_t _pname##_show(struct device *dev,  
\
struct scsi_device *sdev = to_scsi_device(dev); \
  

[PATCH v12 1/2] scsi: ufs: Enable power management for wlun

2021-03-18 Thread Asutosh Das
During runtime-suspend of ufs host, the scsi devices are
already suspended and so are the queues associated with them.
But the ufs host sends SSU to wlun during its runtime-suspend.
During the process blk_queue_enter checks if the queue is not in
suspended state. If so, it waits for the queue to resume, and never
comes out of it.
The commit
(d55d15a33: scsi: block: Do not accept any requests while suspended)
adds the check if the queue is in suspended state in blk_queue_enter().

Call trace:
 __switch_to+0x174/0x2c4
 __schedule+0x478/0x764
 schedule+0x9c/0xe0
 blk_queue_enter+0x158/0x228
 blk_mq_alloc_request+0x40/0xa4
 blk_get_request+0x2c/0x70
 __scsi_execute+0x60/0x1c4
 ufshcd_set_dev_pwr_mode+0x124/0x1e4
 ufshcd_suspend+0x208/0x83c
 ufshcd_runtime_suspend+0x40/0x154
 ufshcd_pltfrm_runtime_suspend+0x14/0x20
 pm_generic_runtime_suspend+0x28/0x3c
 __rpm_callback+0x80/0x2a4
 rpm_suspend+0x308/0x614
 rpm_idle+0x158/0x228
 pm_runtime_work+0x84/0xac
 process_one_work+0x1f0/0x470
 worker_thread+0x26c/0x4c8
 kthread+0x13c/0x320
 ret_from_fork+0x10/0x18

Fix this by registering ufs device wlun as a scsi driver and
registering it for block runtime-pm. Also make this as a
supplier for all other luns. That way, this device wlun
suspends after all the consumers and resumes after
hba resumes.

Co-developed-by: Can Guo 
Signed-off-by: Can Guo 
Signed-off-by: Asutosh Das 
---
 drivers/scsi/ufs/cdns-pltfrm.c |   2 +
 drivers/scsi/ufs/tc-dwc-g210-pci.c |   2 +
 drivers/scsi/ufs/ufs-debugfs.c |   2 +-
 drivers/scsi/ufs/ufs-debugfs.h |   2 +-
 drivers/scsi/ufs/ufs-exynos.c  |   2 +
 drivers/scsi/ufs/ufs-hisi.c|   2 +
 drivers/scsi/ufs/ufs-mediatek.c|  12 +-
 drivers/scsi/ufs/ufs-qcom.c|   2 +
 drivers/scsi/ufs/ufs_bsg.c |   6 +-
 drivers/scsi/ufs/ufshcd-pci.c  |  36 +--
 drivers/scsi/ufs/ufshcd.c  | 622 ++---
 drivers/scsi/ufs/ufshcd.h  |   6 +
 include/trace/events/ufs.h |  20 ++
 13 files changed, 491 insertions(+), 225 deletions(-)

diff --git a/drivers/scsi/ufs/cdns-pltfrm.c b/drivers/scsi/ufs/cdns-pltfrm.c
index 149391f..3e70c23 100644
--- a/drivers/scsi/ufs/cdns-pltfrm.c
+++ b/drivers/scsi/ufs/cdns-pltfrm.c
@@ -319,6 +319,8 @@ static const struct dev_pm_ops cdns_ufs_dev_pm_ops = {
.runtime_suspend = ufshcd_pltfrm_runtime_suspend,
.runtime_resume  = ufshcd_pltfrm_runtime_resume,
.runtime_idle= ufshcd_pltfrm_runtime_idle,
+   .prepare = ufshcd_suspend_prepare,
+   .complete   = ufshcd_resume_complete,
 };
 
 static struct platform_driver cdns_ufs_pltfrm_driver = {
diff --git a/drivers/scsi/ufs/tc-dwc-g210-pci.c 
b/drivers/scsi/ufs/tc-dwc-g210-pci.c
index 67a6a61..b01db12 100644
--- a/drivers/scsi/ufs/tc-dwc-g210-pci.c
+++ b/drivers/scsi/ufs/tc-dwc-g210-pci.c
@@ -148,6 +148,8 @@ static const struct dev_pm_ops tc_dwc_g210_pci_pm_ops = {
.runtime_suspend = tc_dwc_g210_pci_runtime_suspend,
.runtime_resume  = tc_dwc_g210_pci_runtime_resume,
.runtime_idle= tc_dwc_g210_pci_runtime_idle,
+   .prepare = ufshcd_suspend_prepare,
+   .complete   = ufshcd_resume_complete,
 };
 
 static const struct pci_device_id tc_dwc_g210_pci_tbl[] = {
diff --git a/drivers/scsi/ufs/ufs-debugfs.c b/drivers/scsi/ufs/ufs-debugfs.c
index dee98dc..06457d5 100644
--- a/drivers/scsi/ufs/ufs-debugfs.c
+++ b/drivers/scsi/ufs/ufs-debugfs.c
@@ -13,7 +13,7 @@ void __init ufs_debugfs_init(void)
ufs_debugfs_root = debugfs_create_dir("ufshcd", NULL);
 }
 
-void __exit ufs_debugfs_exit(void)
+void ufs_debugfs_exit(void)
 {
debugfs_remove_recursive(ufs_debugfs_root);
 }
diff --git a/drivers/scsi/ufs/ufs-debugfs.h b/drivers/scsi/ufs/ufs-debugfs.h
index f35b39c..12c2730 100644
--- a/drivers/scsi/ufs/ufs-debugfs.h
+++ b/drivers/scsi/ufs/ufs-debugfs.h
@@ -9,7 +9,7 @@ struct ufs_hba;
 
 #ifdef CONFIG_DEBUG_FS
 void __init ufs_debugfs_init(void);
-void __exit ufs_debugfs_exit(void);
+void ufs_debugfs_exit(void);
 void ufs_debugfs_hba_init(struct ufs_hba *hba);
 void ufs_debugfs_hba_exit(struct ufs_hba *hba);
 #else
diff --git a/drivers/scsi/ufs/ufs-exynos.c b/drivers/scsi/ufs/ufs-exynos.c
index 267943a1..45c0b02 100644
--- a/drivers/scsi/ufs/ufs-exynos.c
+++ b/drivers/scsi/ufs/ufs-exynos.c
@@ -1268,6 +1268,8 @@ static const struct dev_pm_ops exynos_ufs_pm_ops = {
.runtime_suspend = ufshcd_pltfrm_runtime_suspend,
.runtime_resume  = ufshcd_pltfrm_runtime_resume,
.runtime_idle= ufshcd_pltfrm_runtime_idle,
+   .prepare = ufshcd_suspend_prepare,
+   .complete   = ufshcd_resume_complete,
 };
 
 static struct platform_driver exynos_ufs_pltform = {
diff --git a/drivers/scsi/ufs/ufs-hisi.c b/drivers/scsi/ufs/ufs-hisi.c
index 0aa5813..d463b44 100644
--- a/drivers/scsi/ufs/ufs-hisi.c
+++ b/drivers/scsi/ufs/ufs-hisi.c
@@ -574,6 +574,8 @@ static const struct dev_pm_ops ufs_hisi_pm_ops = {
.runti

Re: [PATCH v11 1/2] scsi: ufs: Enable power management for wlun

2021-03-18 Thread Asutosh Das (asd)

On 3/15/2021 7:29 AM, Adrian Hunter wrote:

On 12/03/21 12:19 am, Asutosh Das wrote:

During runtime-suspend of ufs host, the scsi devices are
already suspended and so are the queues associated with them.
But the ufs host sends SSU to wlun during its runtime-suspend.
During the process blk_queue_enter checks if the queue is not in
suspended state. If so, it waits for the queue to resume, and never
comes out of it.
The commit
(d55d15a33: scsi: block: Do not accept any requests while suspended)
adds the check if the queue is in suspended state in blk_queue_enter().

Call trace:
  __switch_to+0x174/0x2c4
  __schedule+0x478/0x764
  schedule+0x9c/0xe0
  blk_queue_enter+0x158/0x228
  blk_mq_alloc_request+0x40/0xa4
  blk_get_request+0x2c/0x70
  __scsi_execute+0x60/0x1c4
  ufshcd_set_dev_pwr_mode+0x124/0x1e4
  ufshcd_suspend+0x208/0x83c
  ufshcd_runtime_suspend+0x40/0x154
  ufshcd_pltfrm_runtime_suspend+0x14/0x20
  pm_generic_runtime_suspend+0x28/0x3c
  __rpm_callback+0x80/0x2a4
  rpm_suspend+0x308/0x614
  rpm_idle+0x158/0x228
  pm_runtime_work+0x84/0xac
  process_one_work+0x1f0/0x470
  worker_thread+0x26c/0x4c8
  kthread+0x13c/0x320
  ret_from_fork+0x10/0x18

Fix this by registering ufs device wlun as a scsi driver and
registering it for block runtime-pm. Also make this as a
supplier for all other luns. That way, this device wlun
suspends after all the consumers and resumes after
hba resumes.


I haven't had time to try to reproduce the device-links issue, but
there are a couple of comments below, in addition to the suggestions
here:

https://lore.kernel.org/linux-scsi/b13086f3-eea1-51a7-2117-579d520f2...@intel.com/


Thanks.
I think even if the race in pm framework is fixed, the 
scsi_sysfs_add_sdev() can race with sd_probe().
IIUC that's because scsi_sysfs_add_sdev() schedules an async probe for 
the sd device and then invokes scsi_autopm_put_device().



Also, there are still ufshcd_err_handling_prepare()/unprepare()
and ufshcd_recover_pm_error(), that look like they need attention
e.g. to use scsi_autopm_get/put_device(hba->sdev_ufs_device)


Sure will address this.





Co-developed-by: Can Guo 
Signed-off-by: Can Guo 
Signed-off-by: Asutosh Das 
---
  drivers/scsi/ufs/cdns-pltfrm.c |   2 +
  drivers/scsi/ufs/tc-dwc-g210-pci.c |   2 +
  drivers/scsi/ufs/ufs-debugfs.c |   5 +
  drivers/scsi/ufs/ufs-debugfs.h |   2 +
  drivers/scsi/ufs/ufs-exynos.c  |   2 +
  drivers/scsi/ufs/ufs-hisi.c|   2 +
  drivers/scsi/ufs/ufs-mediatek.c|   2 +
  drivers/scsi/ufs/ufs-qcom.c|   2 +
  drivers/scsi/ufs/ufs_bsg.c |   6 +-
  drivers/scsi/ufs/ufshcd-pci.c  |  36 +--
  drivers/scsi/ufs/ufshcd.c  | 616 ++---
  drivers/scsi/ufs/ufshcd.h  |   7 +
  include/trace/events/ufs.h |  20 ++
  13 files changed, 498 insertions(+), 206 deletions(-)

diff --git a/drivers/scsi/ufs/cdns-pltfrm.c b/drivers/scsi/ufs/cdns-pltfrm.c
index 149391f..3e70c23 100644
--- a/drivers/scsi/ufs/cdns-pltfrm.c
+++ b/drivers/scsi/ufs/cdns-pltfrm.c
@@ -319,6 +319,8 @@ static const struct dev_pm_ops cdns_ufs_dev_pm_ops = {
.runtime_suspend = ufshcd_pltfrm_runtime_suspend,
.runtime_resume  = ufshcd_pltfrm_runtime_resume,
.runtime_idle= ufshcd_pltfrm_runtime_idle,
+   .prepare = ufshcd_suspend_prepare,
+   .complete   = ufshcd_resume_complete,
  };
  
  static struct platform_driver cdns_ufs_pltfrm_driver = {

diff --git a/drivers/scsi/ufs/tc-dwc-g210-pci.c 
b/drivers/scsi/ufs/tc-dwc-g210-pci.c
index 67a6a61..b01db12 100644
--- a/drivers/scsi/ufs/tc-dwc-g210-pci.c
+++ b/drivers/scsi/ufs/tc-dwc-g210-pci.c
@@ -148,6 +148,8 @@ static const struct dev_pm_ops tc_dwc_g210_pci_pm_ops = {
.runtime_suspend = tc_dwc_g210_pci_runtime_suspend,
.runtime_resume  = tc_dwc_g210_pci_runtime_resume,
.runtime_idle= tc_dwc_g210_pci_runtime_idle,
+   .prepare = ufshcd_suspend_prepare,
+   .complete   = ufshcd_resume_complete,
  };
  
  static const struct pci_device_id tc_dwc_g210_pci_tbl[] = {

diff --git a/drivers/scsi/ufs/ufs-debugfs.c b/drivers/scsi/ufs/ufs-debugfs.c
index dee98dc..f8ce2eb 100644
--- a/drivers/scsi/ufs/ufs-debugfs.c
+++ b/drivers/scsi/ufs/ufs-debugfs.c
@@ -54,3 +54,8 @@ void ufs_debugfs_hba_exit(struct ufs_hba *hba)
  {
debugfs_remove_recursive(hba->debugfs_root);
  }
+
+void ufs_debugfs_eh_exit(void)
+{
+   debugfs_remove_recursive(ufs_debugfs_root);
+}


This is the same as ufs_debugfs_exit() without __exit so why not
remove __exit from ufs_debugfs_exit() and use that instead?


Will change it.


diff --git a/drivers/scsi/ufs/ufs-debugfs.h b/drivers/scsi/ufs/ufs-debugfs.h
index f35b39c..3fce5a0 100644
--- a/drivers/scsi/ufs/ufs-debugfs.h
+++ b/drivers/scsi/ufs/ufs-debugfs.h
@@ -12,11 +12,13 @@ void __init ufs_debugfs_init(void);
  void __exit ufs_debugfs_exit(void);
  void ufs_debugfs_hba_init(struct ufs_hba *hba);
  void ufs_debugfs_hba_exit(

Re: [PATCH v10 1/2] scsi: ufs: Enable power management for wlun

2021-03-18 Thread Asutosh Das (asd)

On 3/18/2021 10:54 AM, Rafael J. Wysocki wrote:

On Thu, Mar 18, 2021 at 6:33 PM Asutosh Das (asd)
 wrote:


On 3/18/2021 7:00 AM, Rafael J. Wysocki wrote:

On Wed, Mar 17, 2021 at 7:37 AM Adrian Hunter  wrote:


On 16/03/21 10:35 pm, Asutosh Das (asd) wrote:

On 3/16/2021 12:48 AM, Adrian Hunter wrote:

On 16/03/21 12:22 am, Asutosh Das (asd) wrote:

On 3/14/2021 1:11 AM, Adrian Hunter wrote:

On 10/03/21 5:04 am, Asutosh Das (asd) wrote:

On 3/9/2021 7:56 AM, Asutosh Das (asd) wrote:

On 3/8/2021 9:17 AM, Rafael J. Wysocki wrote:

On Mon, Mar 8, 2021 at 5:21 PM Rafael J. Wysocki  wrote:


On Sat, Mar 6, 2021 at 5:17 PM Alan Stern  wrote:


On Fri, Mar 05, 2021 at 06:54:24PM -0800, Asutosh Das (asd) wrote:


Now during my testing I see a weird issue sometimes (1 in 7).
Scenario - bootups

Issue:
The supplier 'ufs_device_wlun 0:0:0:49488' goes into runtime suspend even
when one/more of its consumers are in RPM_ACTIVE state.

*Log:
[   10.056379][  T206] sd 0:0:0:1: [sdb] Synchronizing SCSI cache
[   10.062497][  T113] sd 0:0:0:5: [sdf] Synchronizing SCSI cache
[   10.356600][   T32] sd 0:0:0:7: [sdh] Synchronizing SCSI cache
[   10.362944][  T174] sd 0:0:0:3: [sdd] Synchronizing SCSI cache
[   10.696627][   T83] sd 0:0:0:2: [sdc] Synchronizing SCSI cache
[   10.704562][  T170] sd 0:0:0:6: [sdg] Synchronizing SCSI cache
[   10.980602][T5] sd 0:0:0:0: [sda] Synchronizing SCSI cache

/** Printing all the consumer nodes of supplier **/
[   10.987327][T5] ufs_device_wlun 0:0:0:49488: usage-count @ suspend: 0
<-- this is the usage_count
[   10.994440][T5] ufs_rpmb_wlun 0:0:0:49476: PM state - 2
[   11.000402][T5] scsi 0:0:0:49456: PM state - 2
[   11.005453][T5] sd 0:0:0:0: PM state - 2
[   11.009958][T5] sd 0:0:0:1: PM state - 2
[   11.014469][T5] sd 0:0:0:2: PM state - 2
[   11.019072][T5] sd 0:0:0:3: PM state - 2
[   11.023595][T5] sd 0:0:0:4: PM state - 0 << RPM_ACTIVE
[   11.353298][T5] sd 0:0:0:5: PM state - 2
[   11.357726][T5] sd 0:0:0:6: PM state - 2
[   11.362155][T5] sd 0:0:0:7: PM state - 2
[   11.366584][T5] ufshcd-qcom 1d84000.ufshc: __ufshcd_wl_suspend - 8709
[   11.374366][T5] ufs_device_wlun 0:0:0:49488: __ufshcd_wl_suspend -
(0) has rpm_active flags


Do you mean that rpm_active of the link between the consumer and the
supplier is greater than 0 at this point and the consumer is


I mean is rpm_active of the link greater than 1 (because 1 means "no
active references to the supplier")?

Hi Rafael:
No - it is not greater than 1.

I'm trying to understand what's going on in it; will update when I've something.




RPM_ACTIVE, but the supplier suspends successfully nevertheless?


[   11.383376][T5] ufs_device_wlun 0:0:0:49488:
ufshcd_wl_runtime_suspend <-- Supplier suspends fine.
[   12.977318][  T174] sd 0:0:0:4: [sde] Synchronizing SCSI cache

And the the suspend of sde is stuck now:
schedule+0x9c/0xe0
schedule_timeout+0x40/0x128
io_schedule_timeout+0x44/0x68
wait_for_common_io+0x7c/0x100
wait_for_completion_io+0x14/0x20
blk_execute_rq+0x90/0xcc
__scsi_execute+0x104/0x1c4
sd_sync_cache+0xf8/0x2a0
sd_suspend_common+0x74/0x11c
sd_suspend_runtime+0x14/0x20
scsi_runtime_suspend+0x64/0x94
__rpm_callback+0x80/0x2a4
rpm_suspend+0x308/0x614
pm_runtime_work+0x98/0xa8

I added 'DL_FLAG_RPM_ACTIVE' while creating links.
   if (hba->sdev_ufs_device) {
   link = device_link_add(>sdev_gendev,
   >sdev_ufs_device->sdev_gendev,
  DL_FLAG_PM_RUNTIME|DL_FLAG_RPM_ACTIVE);
I didn't expect this to resolve the issue anyway and it didn't.

Another interesting point here is when I resume any of the above suspended
consumers, it all goes back to normal, which is kind of expected. I tried
resuming the consumer and the supplier is resumed and the supplier is
suspended when all the consumers are suspended.

Any pointers on this issue please?

@Bart/@Alan - Do you've any pointers please?


It's very noticeable that although you seem to have isolated a bug in
the power management subsystem (supplier goes into runtime suspend
even when one of its consumers is still active), you did not CC the
power management maintainer or mailing list.

I have added the appropriate CC's.


Thanks Alan!





Hello
I & Can (thanks CanG) debugged this further:

Looks like this issue can occur if the sd probe is asynchronous.

Essentially, the sd_probe() is done asynchronously and driver_probe_device() 
invokes pm_runtime_get_suppliers() before invoking sd_probe().

But scsi_probe_and_add_lun() runs in a separate context.
So the scsi_autopm_put_device() invoked from scsi_scan_host() context reduces the 
link->rpm_active to 1. And sd_probe() invokes scsi_autopm_put_device() and starts 
a timer. And then driver_probe_device() invoked from __device_attach_async_helper 
context reduces the link->rpm_active to 1 thus enabling the supplier to suspend 
b

Re: [PATCH v10 1/2] scsi: ufs: Enable power management for wlun

2021-03-18 Thread Asutosh Das (asd)

On 3/18/2021 7:00 AM, Rafael J. Wysocki wrote:

On Wed, Mar 17, 2021 at 7:37 AM Adrian Hunter  wrote:


On 16/03/21 10:35 pm, Asutosh Das (asd) wrote:

On 3/16/2021 12:48 AM, Adrian Hunter wrote:

On 16/03/21 12:22 am, Asutosh Das (asd) wrote:

On 3/14/2021 1:11 AM, Adrian Hunter wrote:

On 10/03/21 5:04 am, Asutosh Das (asd) wrote:

On 3/9/2021 7:56 AM, Asutosh Das (asd) wrote:

On 3/8/2021 9:17 AM, Rafael J. Wysocki wrote:

On Mon, Mar 8, 2021 at 5:21 PM Rafael J. Wysocki  wrote:


On Sat, Mar 6, 2021 at 5:17 PM Alan Stern  wrote:


On Fri, Mar 05, 2021 at 06:54:24PM -0800, Asutosh Das (asd) wrote:


Now during my testing I see a weird issue sometimes (1 in 7).
Scenario - bootups

Issue:
The supplier 'ufs_device_wlun 0:0:0:49488' goes into runtime suspend even
when one/more of its consumers are in RPM_ACTIVE state.

*Log:
[   10.056379][  T206] sd 0:0:0:1: [sdb] Synchronizing SCSI cache
[   10.062497][  T113] sd 0:0:0:5: [sdf] Synchronizing SCSI cache
[   10.356600][   T32] sd 0:0:0:7: [sdh] Synchronizing SCSI cache
[   10.362944][  T174] sd 0:0:0:3: [sdd] Synchronizing SCSI cache
[   10.696627][   T83] sd 0:0:0:2: [sdc] Synchronizing SCSI cache
[   10.704562][  T170] sd 0:0:0:6: [sdg] Synchronizing SCSI cache
[   10.980602][T5] sd 0:0:0:0: [sda] Synchronizing SCSI cache

/** Printing all the consumer nodes of supplier **/
[   10.987327][T5] ufs_device_wlun 0:0:0:49488: usage-count @ suspend: 0
<-- this is the usage_count
[   10.994440][T5] ufs_rpmb_wlun 0:0:0:49476: PM state - 2
[   11.000402][T5] scsi 0:0:0:49456: PM state - 2
[   11.005453][T5] sd 0:0:0:0: PM state - 2
[   11.009958][T5] sd 0:0:0:1: PM state - 2
[   11.014469][T5] sd 0:0:0:2: PM state - 2
[   11.019072][T5] sd 0:0:0:3: PM state - 2
[   11.023595][T5] sd 0:0:0:4: PM state - 0 << RPM_ACTIVE
[   11.353298][T5] sd 0:0:0:5: PM state - 2
[   11.357726][T5] sd 0:0:0:6: PM state - 2
[   11.362155][T5] sd 0:0:0:7: PM state - 2
[   11.366584][T5] ufshcd-qcom 1d84000.ufshc: __ufshcd_wl_suspend - 8709
[   11.374366][T5] ufs_device_wlun 0:0:0:49488: __ufshcd_wl_suspend -
(0) has rpm_active flags


Do you mean that rpm_active of the link between the consumer and the
supplier is greater than 0 at this point and the consumer is


I mean is rpm_active of the link greater than 1 (because 1 means "no
active references to the supplier")?

Hi Rafael:
No - it is not greater than 1.

I'm trying to understand what's going on in it; will update when I've something.




RPM_ACTIVE, but the supplier suspends successfully nevertheless?


[   11.383376][T5] ufs_device_wlun 0:0:0:49488:
ufshcd_wl_runtime_suspend <-- Supplier suspends fine.
[   12.977318][  T174] sd 0:0:0:4: [sde] Synchronizing SCSI cache

And the the suspend of sde is stuck now:
schedule+0x9c/0xe0
schedule_timeout+0x40/0x128
io_schedule_timeout+0x44/0x68
wait_for_common_io+0x7c/0x100
wait_for_completion_io+0x14/0x20
blk_execute_rq+0x90/0xcc
__scsi_execute+0x104/0x1c4
sd_sync_cache+0xf8/0x2a0
sd_suspend_common+0x74/0x11c
sd_suspend_runtime+0x14/0x20
scsi_runtime_suspend+0x64/0x94
__rpm_callback+0x80/0x2a4
rpm_suspend+0x308/0x614
pm_runtime_work+0x98/0xa8

I added 'DL_FLAG_RPM_ACTIVE' while creating links.
  if (hba->sdev_ufs_device) {
  link = device_link_add(>sdev_gendev,
  >sdev_ufs_device->sdev_gendev,
 DL_FLAG_PM_RUNTIME|DL_FLAG_RPM_ACTIVE);
I didn't expect this to resolve the issue anyway and it didn't.

Another interesting point here is when I resume any of the above suspended
consumers, it all goes back to normal, which is kind of expected. I tried
resuming the consumer and the supplier is resumed and the supplier is
suspended when all the consumers are suspended.

Any pointers on this issue please?

@Bart/@Alan - Do you've any pointers please?


It's very noticeable that although you seem to have isolated a bug in
the power management subsystem (supplier goes into runtime suspend
even when one of its consumers is still active), you did not CC the
power management maintainer or mailing list.

I have added the appropriate CC's.


Thanks Alan!





Hello
I & Can (thanks CanG) debugged this further:

Looks like this issue can occur if the sd probe is asynchronous.

Essentially, the sd_probe() is done asynchronously and driver_probe_device() 
invokes pm_runtime_get_suppliers() before invoking sd_probe().

But scsi_probe_and_add_lun() runs in a separate context.
So the scsi_autopm_put_device() invoked from scsi_scan_host() context reduces the 
link->rpm_active to 1. And sd_probe() invokes scsi_autopm_put_device() and starts 
a timer. And then driver_probe_device() invoked from __device_attach_async_helper 
context reduces the link->rpm_active to 1 thus enabling the supplier to suspend 
before the consumer suspends.

So if:
Context T1:
[1] scsi_probe_and_add_lun()
[2]|- scsi_autopm_put_device()

Re: [PATCH v10 1/2] scsi: ufs: Enable power management for wlun

2021-03-16 Thread Asutosh Das (asd)

On 3/16/2021 12:48 AM, Adrian Hunter wrote:

On 16/03/21 12:22 am, Asutosh Das (asd) wrote:

On 3/14/2021 1:11 AM, Adrian Hunter wrote:

On 10/03/21 5:04 am, Asutosh Das (asd) wrote:

On 3/9/2021 7:56 AM, Asutosh Das (asd) wrote:

On 3/8/2021 9:17 AM, Rafael J. Wysocki wrote:

On Mon, Mar 8, 2021 at 5:21 PM Rafael J. Wysocki  wrote:


On Sat, Mar 6, 2021 at 5:17 PM Alan Stern  wrote:


On Fri, Mar 05, 2021 at 06:54:24PM -0800, Asutosh Das (asd) wrote:


Now during my testing I see a weird issue sometimes (1 in 7).
Scenario - bootups

Issue:
The supplier 'ufs_device_wlun 0:0:0:49488' goes into runtime suspend even
when one/more of its consumers are in RPM_ACTIVE state.

*Log:
[   10.056379][  T206] sd 0:0:0:1: [sdb] Synchronizing SCSI cache
[   10.062497][  T113] sd 0:0:0:5: [sdf] Synchronizing SCSI cache
[   10.356600][   T32] sd 0:0:0:7: [sdh] Synchronizing SCSI cache
[   10.362944][  T174] sd 0:0:0:3: [sdd] Synchronizing SCSI cache
[   10.696627][   T83] sd 0:0:0:2: [sdc] Synchronizing SCSI cache
[   10.704562][  T170] sd 0:0:0:6: [sdg] Synchronizing SCSI cache
[   10.980602][    T5] sd 0:0:0:0: [sda] Synchronizing SCSI cache

/** Printing all the consumer nodes of supplier **/
[   10.987327][    T5] ufs_device_wlun 0:0:0:49488: usage-count @ suspend: 0
<-- this is the usage_count
[   10.994440][    T5] ufs_rpmb_wlun 0:0:0:49476: PM state - 2
[   11.000402][    T5] scsi 0:0:0:49456: PM state - 2
[   11.005453][    T5] sd 0:0:0:0: PM state - 2
[   11.009958][    T5] sd 0:0:0:1: PM state - 2
[   11.014469][    T5] sd 0:0:0:2: PM state - 2
[   11.019072][    T5] sd 0:0:0:3: PM state - 2
[   11.023595][    T5] sd 0:0:0:4: PM state - 0 << RPM_ACTIVE
[   11.353298][    T5] sd 0:0:0:5: PM state - 2
[   11.357726][    T5] sd 0:0:0:6: PM state - 2
[   11.362155][    T5] sd 0:0:0:7: PM state - 2
[   11.366584][    T5] ufshcd-qcom 1d84000.ufshc: __ufshcd_wl_suspend - 8709
[   11.374366][    T5] ufs_device_wlun 0:0:0:49488: __ufshcd_wl_suspend -
(0) has rpm_active flags


Do you mean that rpm_active of the link between the consumer and the
supplier is greater than 0 at this point and the consumer is


I mean is rpm_active of the link greater than 1 (because 1 means "no
active references to the supplier")?

Hi Rafael:
No - it is not greater than 1.

I'm trying to understand what's going on in it; will update when I've something.




RPM_ACTIVE, but the supplier suspends successfully nevertheless?


[   11.383376][    T5] ufs_device_wlun 0:0:0:49488:
ufshcd_wl_runtime_suspend <-- Supplier suspends fine.
[   12.977318][  T174] sd 0:0:0:4: [sde] Synchronizing SCSI cache

And the the suspend of sde is stuck now:
schedule+0x9c/0xe0
schedule_timeout+0x40/0x128
io_schedule_timeout+0x44/0x68
wait_for_common_io+0x7c/0x100
wait_for_completion_io+0x14/0x20
blk_execute_rq+0x90/0xcc
__scsi_execute+0x104/0x1c4
sd_sync_cache+0xf8/0x2a0
sd_suspend_common+0x74/0x11c
sd_suspend_runtime+0x14/0x20
scsi_runtime_suspend+0x64/0x94
__rpm_callback+0x80/0x2a4
rpm_suspend+0x308/0x614
pm_runtime_work+0x98/0xa8

I added 'DL_FLAG_RPM_ACTIVE' while creating links.
     if (hba->sdev_ufs_device) {
     link = device_link_add(>sdev_gendev,
     >sdev_ufs_device->sdev_gendev,
    DL_FLAG_PM_RUNTIME|DL_FLAG_RPM_ACTIVE);
I didn't expect this to resolve the issue anyway and it didn't.

Another interesting point here is when I resume any of the above suspended
consumers, it all goes back to normal, which is kind of expected. I tried
resuming the consumer and the supplier is resumed and the supplier is
suspended when all the consumers are suspended.

Any pointers on this issue please?

@Bart/@Alan - Do you've any pointers please?


It's very noticeable that although you seem to have isolated a bug in
the power management subsystem (supplier goes into runtime suspend
even when one of its consumers is still active), you did not CC the
power management maintainer or mailing list.

I have added the appropriate CC's.


Thanks Alan!





Hello
I & Can (thanks CanG) debugged this further:

Looks like this issue can occur if the sd probe is asynchronous.

Essentially, the sd_probe() is done asynchronously and driver_probe_device() 
invokes pm_runtime_get_suppliers() before invoking sd_probe().

But scsi_probe_and_add_lun() runs in a separate context.
So the scsi_autopm_put_device() invoked from scsi_scan_host() context reduces the 
link->rpm_active to 1. And sd_probe() invokes scsi_autopm_put_device() and starts 
a timer. And then driver_probe_device() invoked from __device_attach_async_helper 
context reduces the link->rpm_active to 1 thus enabling the supplier to suspend 
before the consumer suspends.

So if:
Context T1:
[1] scsi_probe_and_add_lun()
[2]    |- scsi_autopm_put_device() - reduce the link->rpm_active to 1

Context T2:
__device_attach_async_helper()
  |- driver_probe_device()
  |- sd_probe()
In between [1]

Re: [PATCH v11 1/2] scsi: ufs: Enable power management for wlun

2021-03-15 Thread Asutosh Das (asd)

On 3/15/2021 7:29 AM, Adrian Hunter wrote:

On 12/03/21 12:19 am, Asutosh Das wrote:

During runtime-suspend of ufs host, the scsi devices are
already suspended and so are the queues associated with them.
But the ufs host sends SSU to wlun during its runtime-suspend.
During the process blk_queue_enter checks if the queue is not in
suspended state. If so, it waits for the queue to resume, and never
comes out of it.
The commit
(d55d15a33: scsi: block: Do not accept any requests while suspended)
adds the check if the queue is in suspended state in blk_queue_enter().

Call trace:
  __switch_to+0x174/0x2c4
  __schedule+0x478/0x764
  schedule+0x9c/0xe0
  blk_queue_enter+0x158/0x228
  blk_mq_alloc_request+0x40/0xa4
  blk_get_request+0x2c/0x70
  __scsi_execute+0x60/0x1c4
  ufshcd_set_dev_pwr_mode+0x124/0x1e4
  ufshcd_suspend+0x208/0x83c
  ufshcd_runtime_suspend+0x40/0x154
  ufshcd_pltfrm_runtime_suspend+0x14/0x20
  pm_generic_runtime_suspend+0x28/0x3c
  __rpm_callback+0x80/0x2a4
  rpm_suspend+0x308/0x614
  rpm_idle+0x158/0x228
  pm_runtime_work+0x84/0xac
  process_one_work+0x1f0/0x470
  worker_thread+0x26c/0x4c8
  kthread+0x13c/0x320
  ret_from_fork+0x10/0x18

Fix this by registering ufs device wlun as a scsi driver and
registering it for block runtime-pm. Also make this as a
supplier for all other luns. That way, this device wlun
suspends after all the consumers and resumes after
hba resumes.


I haven't had time to try to reproduce the device-links issue, but
there are a couple of comments below, in addition to the suggestions
here:

https://lore.kernel.org/linux-scsi/b13086f3-eea1-51a7-2117-579d520f2...@intel.com/

Also, there are still ufshcd_err_handling_prepare()/unprepare()
and ufshcd_recover_pm_error(), that look like they need attention
e.g. to use scsi_autopm_get/put_device(hba->sdev_ufs_device)



Hi Adrian,
Thanks for the suggestions and review.

Sorry I'd missed this mail.

Let me go through it and I'll get back.



Co-developed-by: Can Guo 
Signed-off-by: Can Guo 
Signed-off-by: Asutosh Das 
---
  drivers/scsi/ufs/cdns-pltfrm.c |   2 +
  drivers/scsi/ufs/tc-dwc-g210-pci.c |   2 +
  drivers/scsi/ufs/ufs-debugfs.c |   5 +
  drivers/scsi/ufs/ufs-debugfs.h |   2 +
  drivers/scsi/ufs/ufs-exynos.c  |   2 +
  drivers/scsi/ufs/ufs-hisi.c|   2 +
  drivers/scsi/ufs/ufs-mediatek.c|   2 +
  drivers/scsi/ufs/ufs-qcom.c|   2 +
  drivers/scsi/ufs/ufs_bsg.c |   6 +-
  drivers/scsi/ufs/ufshcd-pci.c  |  36 +--
  drivers/scsi/ufs/ufshcd.c  | 616 ++---
  drivers/scsi/ufs/ufshcd.h  |   7 +
  include/trace/events/ufs.h |  20 ++
  13 files changed, 498 insertions(+), 206 deletions(-)

diff --git a/drivers/scsi/ufs/cdns-pltfrm.c b/drivers/scsi/ufs/cdns-pltfrm.c
index 149391f..3e70c23 100644
--- a/drivers/scsi/ufs/cdns-pltfrm.c
+++ b/drivers/scsi/ufs/cdns-pltfrm.c
@@ -319,6 +319,8 @@ static const struct dev_pm_ops cdns_ufs_dev_pm_ops = {
.runtime_suspend = ufshcd_pltfrm_runtime_suspend,
.runtime_resume  = ufshcd_pltfrm_runtime_resume,
.runtime_idle= ufshcd_pltfrm_runtime_idle,
+   .prepare = ufshcd_suspend_prepare,
+   .complete   = ufshcd_resume_complete,
  };
  
  static struct platform_driver cdns_ufs_pltfrm_driver = {

diff --git a/drivers/scsi/ufs/tc-dwc-g210-pci.c 
b/drivers/scsi/ufs/tc-dwc-g210-pci.c
index 67a6a61..b01db12 100644
--- a/drivers/scsi/ufs/tc-dwc-g210-pci.c
+++ b/drivers/scsi/ufs/tc-dwc-g210-pci.c
@@ -148,6 +148,8 @@ static const struct dev_pm_ops tc_dwc_g210_pci_pm_ops = {
.runtime_suspend = tc_dwc_g210_pci_runtime_suspend,
.runtime_resume  = tc_dwc_g210_pci_runtime_resume,
.runtime_idle= tc_dwc_g210_pci_runtime_idle,
+   .prepare = ufshcd_suspend_prepare,
+   .complete   = ufshcd_resume_complete,
  };
  
  static const struct pci_device_id tc_dwc_g210_pci_tbl[] = {

diff --git a/drivers/scsi/ufs/ufs-debugfs.c b/drivers/scsi/ufs/ufs-debugfs.c
index dee98dc..f8ce2eb 100644
--- a/drivers/scsi/ufs/ufs-debugfs.c
+++ b/drivers/scsi/ufs/ufs-debugfs.c
@@ -54,3 +54,8 @@ void ufs_debugfs_hba_exit(struct ufs_hba *hba)
  {
debugfs_remove_recursive(hba->debugfs_root);
  }
+
+void ufs_debugfs_eh_exit(void)
+{
+   debugfs_remove_recursive(ufs_debugfs_root);
+}


This is the same as ufs_debugfs_exit() without __exit so why not
remove __exit from ufs_debugfs_exit() and use that instead?


diff --git a/drivers/scsi/ufs/ufs-debugfs.h b/drivers/scsi/ufs/ufs-debugfs.h
index f35b39c..3fce5a0 100644
--- a/drivers/scsi/ufs/ufs-debugfs.h
+++ b/drivers/scsi/ufs/ufs-debugfs.h
@@ -12,11 +12,13 @@ void __init ufs_debugfs_init(void);
  void __exit ufs_debugfs_exit(void);
  void ufs_debugfs_hba_init(struct ufs_hba *hba);
  void ufs_debugfs_hba_exit(struct ufs_hba *hba);
+void ufs_debugfs_eh_exit(void);
  #else
  static inline void ufs_debugfs_init(void) {}
  static inline void ufs_debugfs_exit(void) {}
  static inlin

Re: [PATCH v10 1/2] scsi: ufs: Enable power management for wlun

2021-03-15 Thread Asutosh Das (asd)

On 3/14/2021 1:11 AM, Adrian Hunter wrote:

On 10/03/21 5:04 am, Asutosh Das (asd) wrote:

On 3/9/2021 7:56 AM, Asutosh Das (asd) wrote:

On 3/8/2021 9:17 AM, Rafael J. Wysocki wrote:

On Mon, Mar 8, 2021 at 5:21 PM Rafael J. Wysocki  wrote:


On Sat, Mar 6, 2021 at 5:17 PM Alan Stern  wrote:


On Fri, Mar 05, 2021 at 06:54:24PM -0800, Asutosh Das (asd) wrote:


Now during my testing I see a weird issue sometimes (1 in 7).
Scenario - bootups

Issue:
The supplier 'ufs_device_wlun 0:0:0:49488' goes into runtime suspend even
when one/more of its consumers are in RPM_ACTIVE state.

*Log:
[   10.056379][  T206] sd 0:0:0:1: [sdb] Synchronizing SCSI cache
[   10.062497][  T113] sd 0:0:0:5: [sdf] Synchronizing SCSI cache
[   10.356600][   T32] sd 0:0:0:7: [sdh] Synchronizing SCSI cache
[   10.362944][  T174] sd 0:0:0:3: [sdd] Synchronizing SCSI cache
[   10.696627][   T83] sd 0:0:0:2: [sdc] Synchronizing SCSI cache
[   10.704562][  T170] sd 0:0:0:6: [sdg] Synchronizing SCSI cache
[   10.980602][    T5] sd 0:0:0:0: [sda] Synchronizing SCSI cache

/** Printing all the consumer nodes of supplier **/
[   10.987327][    T5] ufs_device_wlun 0:0:0:49488: usage-count @ suspend: 0
<-- this is the usage_count
[   10.994440][    T5] ufs_rpmb_wlun 0:0:0:49476: PM state - 2
[   11.000402][    T5] scsi 0:0:0:49456: PM state - 2
[   11.005453][    T5] sd 0:0:0:0: PM state - 2
[   11.009958][    T5] sd 0:0:0:1: PM state - 2
[   11.014469][    T5] sd 0:0:0:2: PM state - 2
[   11.019072][    T5] sd 0:0:0:3: PM state - 2
[   11.023595][    T5] sd 0:0:0:4: PM state - 0 << RPM_ACTIVE
[   11.353298][    T5] sd 0:0:0:5: PM state - 2
[   11.357726][    T5] sd 0:0:0:6: PM state - 2
[   11.362155][    T5] sd 0:0:0:7: PM state - 2
[   11.366584][    T5] ufshcd-qcom 1d84000.ufshc: __ufshcd_wl_suspend - 8709
[   11.374366][    T5] ufs_device_wlun 0:0:0:49488: __ufshcd_wl_suspend -
(0) has rpm_active flags


Do you mean that rpm_active of the link between the consumer and the
supplier is greater than 0 at this point and the consumer is


I mean is rpm_active of the link greater than 1 (because 1 means "no
active references to the supplier")?

Hi Rafael:
No - it is not greater than 1.

I'm trying to understand what's going on in it; will update when I've something.




RPM_ACTIVE, but the supplier suspends successfully nevertheless?


[   11.383376][    T5] ufs_device_wlun 0:0:0:49488:
ufshcd_wl_runtime_suspend <-- Supplier suspends fine.
[   12.977318][  T174] sd 0:0:0:4: [sde] Synchronizing SCSI cache

And the the suspend of sde is stuck now:
schedule+0x9c/0xe0
schedule_timeout+0x40/0x128
io_schedule_timeout+0x44/0x68
wait_for_common_io+0x7c/0x100
wait_for_completion_io+0x14/0x20
blk_execute_rq+0x90/0xcc
__scsi_execute+0x104/0x1c4
sd_sync_cache+0xf8/0x2a0
sd_suspend_common+0x74/0x11c
sd_suspend_runtime+0x14/0x20
scsi_runtime_suspend+0x64/0x94
__rpm_callback+0x80/0x2a4
rpm_suspend+0x308/0x614
pm_runtime_work+0x98/0xa8

I added 'DL_FLAG_RPM_ACTIVE' while creating links.
    if (hba->sdev_ufs_device) {
    link = device_link_add(>sdev_gendev,
    >sdev_ufs_device->sdev_gendev,
   DL_FLAG_PM_RUNTIME|DL_FLAG_RPM_ACTIVE);
I didn't expect this to resolve the issue anyway and it didn't.

Another interesting point here is when I resume any of the above suspended
consumers, it all goes back to normal, which is kind of expected. I tried
resuming the consumer and the supplier is resumed and the supplier is
suspended when all the consumers are suspended.

Any pointers on this issue please?

@Bart/@Alan - Do you've any pointers please?


It's very noticeable that although you seem to have isolated a bug in
the power management subsystem (supplier goes into runtime suspend
even when one of its consumers is still active), you did not CC the
power management maintainer or mailing list.

I have added the appropriate CC's.


Thanks Alan!





Hello
I & Can (thanks CanG) debugged this further:

Looks like this issue can occur if the sd probe is asynchronous.

Essentially, the sd_probe() is done asynchronously and driver_probe_device() 
invokes pm_runtime_get_suppliers() before invoking sd_probe().

But scsi_probe_and_add_lun() runs in a separate context.
So the scsi_autopm_put_device() invoked from scsi_scan_host() context reduces the 
link->rpm_active to 1. And sd_probe() invokes scsi_autopm_put_device() and starts 
a timer. And then driver_probe_device() invoked from __device_attach_async_helper 
context reduces the link->rpm_active to 1 thus enabling the supplier to suspend 
before the consumer suspends.

So if:
Context T1:
[1] scsi_probe_and_add_lun()
[2]    |- scsi_autopm_put_device() - reduce the link->rpm_active to 1

Context T2:
__device_attach_async_helper()
 |- driver_probe_device()
     |- sd_probe()
In between [1] and [2] say, driver_probe_device() -> sd_probe() is invoked in a 
separate context from __dev

[PATCH v11 2/2] ufs: sysfs: Resume the proper scsi device

2021-03-11 Thread Asutosh Das
Resumes the actual scsi device the unit descriptor of which
is being accessed instead of the hba alone.

Signed-off-by: Asutosh Das 
---
 drivers/scsi/ufs/ufs-sysfs.c | 30 +-
 1 file changed, 17 insertions(+), 13 deletions(-)

diff --git a/drivers/scsi/ufs/ufs-sysfs.c b/drivers/scsi/ufs/ufs-sysfs.c
index acc54f5..3fc182b 100644
--- a/drivers/scsi/ufs/ufs-sysfs.c
+++ b/drivers/scsi/ufs/ufs-sysfs.c
@@ -245,9 +245,9 @@ static ssize_t wb_on_store(struct device *dev, struct 
device_attribute *attr,
goto out;
}
 
-   pm_runtime_get_sync(hba->dev);
+   scsi_autopm_get_device(hba->sdev_ufs_device);
res = ufshcd_wb_ctrl(hba, wb_enable);
-   pm_runtime_put_sync(hba->dev);
+   scsi_autopm_put_device(hba->sdev_ufs_device);
 out:
up(>host_sem);
return res < 0 ? res : count;
@@ -297,10 +297,10 @@ static ssize_t ufs_sysfs_read_desc_param(struct ufs_hba 
*hba,
goto out;
}
 
-   pm_runtime_get_sync(hba->dev);
+   scsi_autopm_get_device(hba->sdev_ufs_device);
ret = ufshcd_read_desc_param(hba, desc_id, desc_index,
param_offset, desc_buf, param_size);
-   pm_runtime_put_sync(hba->dev);
+   scsi_autopm_put_device(hba->sdev_ufs_device);
if (ret) {
ret = -EINVAL;
goto out;
@@ -678,7 +678,7 @@ static ssize_t _name##_show(struct device *dev, 
\
up(>host_sem); \
return -ENOMEM; \
}   \
-   pm_runtime_get_sync(hba->dev);  \
+   scsi_autopm_get_device(hba->sdev_ufs_device);   \
ret = ufshcd_query_descriptor_retry(hba,\
UPIU_QUERY_OPCODE_READ_DESC, QUERY_DESC_IDN_DEVICE, \
0, 0, desc_buf, _len); \
@@ -695,7 +695,7 @@ static ssize_t _name##_show(struct device *dev, 
\
goto out;   \
ret = sysfs_emit(buf, "%s\n", desc_buf);\
 out:   \
-   pm_runtime_put_sync(hba->dev);  \
+   scsi_autopm_put_device(hba->sdev_ufs_device);   \
kfree(desc_buf);\
up(>host_sem); \
return ret; \
@@ -744,10 +744,10 @@ static ssize_t _name##_show(struct device *dev,   
\
}   \
if (ufshcd_is_wb_flags(QUERY_FLAG_IDN##_uname)) \
index = ufshcd_wb_get_query_index(hba); \
-   pm_runtime_get_sync(hba->dev);  \
+   scsi_autopm_get_device(hba->sdev_ufs_device);   \
ret = ufshcd_query_flag(hba, UPIU_QUERY_OPCODE_READ_FLAG,   \
QUERY_FLAG_IDN##_uname, index, );  \
-   pm_runtime_put_sync(hba->dev);  \
+   scsi_autopm_put_device(hba->sdev_ufs_device);   \
if (ret) {  \
ret = -EINVAL;  \
goto out;   \
@@ -813,10 +813,10 @@ static ssize_t _name##_show(struct device *dev,   
\
}   \
if (ufshcd_is_wb_attrs(QUERY_ATTR_IDN##_uname)) \
index = ufshcd_wb_get_query_index(hba); \
-   pm_runtime_get_sync(hba->dev);  \
+   scsi_autopm_get_device(hba->sdev_ufs_device);   \
ret = ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_READ_ATTR,   \
QUERY_ATTR_IDN##_uname, index, 0, );  \
-   pm_runtime_put_sync(hba->dev);  \
+   scsi_autopm_put_device(hba->sdev_ufs_device);   \
if (ret) {  \
ret = -EINVAL;  \
goto out;   \
@@ -899,11 +899,15 @@ static ssize_t _pname##_show(struct device *dev,  
\
struct scsi_device *sdev = to_scsi_device(dev); \
struct ufs_hba *hba = shost_p

[PATCH v11 1/2] scsi: ufs: Enable power management for wlun

2021-03-11 Thread Asutosh Das
During runtime-suspend of ufs host, the scsi devices are
already suspended and so are the queues associated with them.
But the ufs host sends SSU to wlun during its runtime-suspend.
During the process blk_queue_enter checks if the queue is not in
suspended state. If so, it waits for the queue to resume, and never
comes out of it.
The commit
(d55d15a33: scsi: block: Do not accept any requests while suspended)
adds the check if the queue is in suspended state in blk_queue_enter().

Call trace:
 __switch_to+0x174/0x2c4
 __schedule+0x478/0x764
 schedule+0x9c/0xe0
 blk_queue_enter+0x158/0x228
 blk_mq_alloc_request+0x40/0xa4
 blk_get_request+0x2c/0x70
 __scsi_execute+0x60/0x1c4
 ufshcd_set_dev_pwr_mode+0x124/0x1e4
 ufshcd_suspend+0x208/0x83c
 ufshcd_runtime_suspend+0x40/0x154
 ufshcd_pltfrm_runtime_suspend+0x14/0x20
 pm_generic_runtime_suspend+0x28/0x3c
 __rpm_callback+0x80/0x2a4
 rpm_suspend+0x308/0x614
 rpm_idle+0x158/0x228
 pm_runtime_work+0x84/0xac
 process_one_work+0x1f0/0x470
 worker_thread+0x26c/0x4c8
 kthread+0x13c/0x320
 ret_from_fork+0x10/0x18

Fix this by registering ufs device wlun as a scsi driver and
registering it for block runtime-pm. Also make this as a
supplier for all other luns. That way, this device wlun
suspends after all the consumers and resumes after
hba resumes.

Co-developed-by: Can Guo 
Signed-off-by: Can Guo 
Signed-off-by: Asutosh Das 
---
 drivers/scsi/ufs/cdns-pltfrm.c |   2 +
 drivers/scsi/ufs/tc-dwc-g210-pci.c |   2 +
 drivers/scsi/ufs/ufs-debugfs.c |   5 +
 drivers/scsi/ufs/ufs-debugfs.h |   2 +
 drivers/scsi/ufs/ufs-exynos.c  |   2 +
 drivers/scsi/ufs/ufs-hisi.c|   2 +
 drivers/scsi/ufs/ufs-mediatek.c|   2 +
 drivers/scsi/ufs/ufs-qcom.c|   2 +
 drivers/scsi/ufs/ufs_bsg.c |   6 +-
 drivers/scsi/ufs/ufshcd-pci.c  |  36 +--
 drivers/scsi/ufs/ufshcd.c  | 616 ++---
 drivers/scsi/ufs/ufshcd.h  |   7 +
 include/trace/events/ufs.h |  20 ++
 13 files changed, 498 insertions(+), 206 deletions(-)

diff --git a/drivers/scsi/ufs/cdns-pltfrm.c b/drivers/scsi/ufs/cdns-pltfrm.c
index 149391f..3e70c23 100644
--- a/drivers/scsi/ufs/cdns-pltfrm.c
+++ b/drivers/scsi/ufs/cdns-pltfrm.c
@@ -319,6 +319,8 @@ static const struct dev_pm_ops cdns_ufs_dev_pm_ops = {
.runtime_suspend = ufshcd_pltfrm_runtime_suspend,
.runtime_resume  = ufshcd_pltfrm_runtime_resume,
.runtime_idle= ufshcd_pltfrm_runtime_idle,
+   .prepare = ufshcd_suspend_prepare,
+   .complete   = ufshcd_resume_complete,
 };
 
 static struct platform_driver cdns_ufs_pltfrm_driver = {
diff --git a/drivers/scsi/ufs/tc-dwc-g210-pci.c 
b/drivers/scsi/ufs/tc-dwc-g210-pci.c
index 67a6a61..b01db12 100644
--- a/drivers/scsi/ufs/tc-dwc-g210-pci.c
+++ b/drivers/scsi/ufs/tc-dwc-g210-pci.c
@@ -148,6 +148,8 @@ static const struct dev_pm_ops tc_dwc_g210_pci_pm_ops = {
.runtime_suspend = tc_dwc_g210_pci_runtime_suspend,
.runtime_resume  = tc_dwc_g210_pci_runtime_resume,
.runtime_idle= tc_dwc_g210_pci_runtime_idle,
+   .prepare = ufshcd_suspend_prepare,
+   .complete   = ufshcd_resume_complete,
 };
 
 static const struct pci_device_id tc_dwc_g210_pci_tbl[] = {
diff --git a/drivers/scsi/ufs/ufs-debugfs.c b/drivers/scsi/ufs/ufs-debugfs.c
index dee98dc..f8ce2eb 100644
--- a/drivers/scsi/ufs/ufs-debugfs.c
+++ b/drivers/scsi/ufs/ufs-debugfs.c
@@ -54,3 +54,8 @@ void ufs_debugfs_hba_exit(struct ufs_hba *hba)
 {
debugfs_remove_recursive(hba->debugfs_root);
 }
+
+void ufs_debugfs_eh_exit(void)
+{
+   debugfs_remove_recursive(ufs_debugfs_root);
+}
diff --git a/drivers/scsi/ufs/ufs-debugfs.h b/drivers/scsi/ufs/ufs-debugfs.h
index f35b39c..3fce5a0 100644
--- a/drivers/scsi/ufs/ufs-debugfs.h
+++ b/drivers/scsi/ufs/ufs-debugfs.h
@@ -12,11 +12,13 @@ void __init ufs_debugfs_init(void);
 void __exit ufs_debugfs_exit(void);
 void ufs_debugfs_hba_init(struct ufs_hba *hba);
 void ufs_debugfs_hba_exit(struct ufs_hba *hba);
+void ufs_debugfs_eh_exit(void);
 #else
 static inline void ufs_debugfs_init(void) {}
 static inline void ufs_debugfs_exit(void) {}
 static inline void ufs_debugfs_hba_init(struct ufs_hba *hba) {}
 static inline void ufs_debugfs_hba_exit(struct ufs_hba *hba) {}
+static inline void ufs_debugfs_eh_exit(void) {}
 #endif
 
 #endif
diff --git a/drivers/scsi/ufs/ufs-exynos.c b/drivers/scsi/ufs/ufs-exynos.c
index 267943a1..45c0b02 100644
--- a/drivers/scsi/ufs/ufs-exynos.c
+++ b/drivers/scsi/ufs/ufs-exynos.c
@@ -1268,6 +1268,8 @@ static const struct dev_pm_ops exynos_ufs_pm_ops = {
.runtime_suspend = ufshcd_pltfrm_runtime_suspend,
.runtime_resume  = ufshcd_pltfrm_runtime_resume,
.runtime_idle= ufshcd_pltfrm_runtime_idle,
+   .prepare = ufshcd_suspend_prepare,
+   .complete   = ufshcd_resume_complete,
 };
 
 static struct platform_driver exynos_ufs_pltform = {
diff --git a/drivers/scsi/ufs/ufs-hisi.c b/driv

Re: [PATCH v10 1/2] scsi: ufs: Enable power management for wlun

2021-03-10 Thread Asutosh Das (asd)

On 3/10/2021 8:27 AM, Alan Stern wrote:

On Tue, Mar 09, 2021 at 08:04:53PM -0800, Asutosh Das (asd) wrote:

On 3/9/2021 7:14 PM, Alan Stern wrote:

On Tue, Mar 09, 2021 at 07:04:34PM -0800, Asutosh Das (asd) wrote:

Hello
I & Can (thanks CanG) debugged this further:

Looks like this issue can occur if the sd probe is asynchronous.

Essentially, the sd_probe() is done asynchronously and driver_probe_device()
invokes pm_runtime_get_suppliers() before invoking sd_probe().

But scsi_probe_and_add_lun() runs in a separate context.
So the scsi_autopm_put_device() invoked from scsi_scan_host() context
reduces the link->rpm_active to 1. And sd_probe() invokes
scsi_autopm_put_device() and starts a timer. And then driver_probe_device()
invoked from __device_attach_async_helper context reduces the
link->rpm_active to 1 thus enabling the supplier to suspend before the
consumer suspends.



I don't see a way around this. Please let me know if you
(@Alan/@Bart/@Adrian) have any thoughts on this.


How about changing the SCSI core so that it does a runtime_get before
starting an async probe, and the async probe routine does a
runtime_put when it is finished?  In other words, don't allow a device
to go into runtime suspend while it is waiting to be probed.

I don't think that would be too intrusive.

Alan Stern



Hi Alan
Thanks for the suggestion.

Am trying to understand:

Do you mean something like this:

int scsi_sysfs_add_sdev(struct scsi_device *sdev)
{

scsi_autopm_get_device(sdev);
pm_runtime_get_noresume(>sdev_gendev);
[...]
scsi_autopm_put_device(sdev);
[...]
}

static int sd_probe(struct device *dev)
{
[...]
pm_runtime_put_noidle(dev);
scsi_autopm_put_device(sdp);
[...]
}

This may work (I'm limited by my imagination in scsi layer :) ).


I'm not sure about this.  To be honest, I did not read the entirety of
your last message; it had way too much detail.  THere's a time and place
for that, but when you're brainstorming to figure out the underlying
cause of a problem and come up with a strategy to fix it, you want to
concentrate on the overall picture, not the details.

As I understand the situation, you've get a SCSI target with multiple
logical units, let's say A and B, and you need to make sure that A never
goes into runtime suspend unless B is already suspended.  In other
words, B always has to suspend before A and resume after A.

To do this, you register a device link with A as the supplier and B as
the consumer.  Then the PM core takes care of the ordering for you.

But I don't understand when you set up the device link.  If the timing
is wrong then, thanks to async SCSI probing, you may have a situation
where A is registered before B and before the link is set up.  Then
there's temporarily nothing to stop A from suspending before B.

You also need to prevent each device from suspending before it is
probed.  That's the easy part I was trying to address before (although
it may not be so easy if the drivers are in loadable modules and not
present in the kernel).

You need to think through these issues before proposing actual changes.


But the pm_runtime_put_noidle() would have to be added to all registered
scsi_driver{}, perhaps? Or may be I can check for sdp->type?


Like this; it's too early to worry about this sort of thing.

Alan Stern


Hi Alan
Thanks. Understood.

I will check the details and see if I can come up with something.
I'll propose an alternate fix otherwise and drop this change altogether.

Thanks!
-asd

--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
Linux Foundation Collaborative Project


Re: [PATCH v10 1/2] scsi: ufs: Enable power management for wlun

2021-03-09 Thread Asutosh Das (asd)

On 3/9/2021 7:14 PM, Alan Stern wrote:

On Tue, Mar 09, 2021 at 07:04:34PM -0800, Asutosh Das (asd) wrote:

Hello
I & Can (thanks CanG) debugged this further:

Looks like this issue can occur if the sd probe is asynchronous.

Essentially, the sd_probe() is done asynchronously and driver_probe_device()
invokes pm_runtime_get_suppliers() before invoking sd_probe().

But scsi_probe_and_add_lun() runs in a separate context.
So the scsi_autopm_put_device() invoked from scsi_scan_host() context
reduces the link->rpm_active to 1. And sd_probe() invokes
scsi_autopm_put_device() and starts a timer. And then driver_probe_device()
invoked from __device_attach_async_helper context reduces the
link->rpm_active to 1 thus enabling the supplier to suspend before the
consumer suspends.



I don't see a way around this. Please let me know if you
(@Alan/@Bart/@Adrian) have any thoughts on this.


How about changing the SCSI core so that it does a runtime_get before
starting an async probe, and the async probe routine does a
runtime_put when it is finished?  In other words, don't allow a device
to go into runtime suspend while it is waiting to be probed.

I don't think that would be too intrusive.

Alan Stern



Hi Alan
Thanks for the suggestion.

Am trying to understand:

Do you mean something like this:

int scsi_sysfs_add_sdev(struct scsi_device *sdev)
{

scsi_autopm_get_device(sdev);
pm_runtime_get_noresume(>sdev_gendev);
[...]
scsi_autopm_put_device(sdev);
[...]
}

static int sd_probe(struct device *dev)
{
[...]
pm_runtime_put_noidle(dev);
scsi_autopm_put_device(sdp);
[...]
}

This may work (I'm limited by my imagination in scsi layer :) ).

But the pm_runtime_put_noidle() would have to be added to all registered 
scsi_driver{}, perhaps? Or may be I can check for sdp->type?


-asd

--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
Linux Foundation Collaborative Project


Re: [PATCH v10 1/2] scsi: ufs: Enable power management for wlun

2021-03-09 Thread Asutosh Das (asd)

On 3/9/2021 7:56 AM, Asutosh Das (asd) wrote:

On 3/8/2021 9:17 AM, Rafael J. Wysocki wrote:
On Mon, Mar 8, 2021 at 5:21 PM Rafael J. Wysocki  
wrote:


On Sat, Mar 6, 2021 at 5:17 PM Alan Stern  
wrote:


On Fri, Mar 05, 2021 at 06:54:24PM -0800, Asutosh Das (asd) wrote:


Now during my testing I see a weird issue sometimes (1 in 7).
Scenario - bootups

Issue:
The supplier 'ufs_device_wlun 0:0:0:49488' goes into runtime 
suspend even

when one/more of its consumers are in RPM_ACTIVE state.

*Log:
[   10.056379][  T206] sd 0:0:0:1: [sdb] Synchronizing SCSI cache
[   10.062497][  T113] sd 0:0:0:5: [sdf] Synchronizing SCSI cache
[   10.356600][   T32] sd 0:0:0:7: [sdh] Synchronizing SCSI cache
[   10.362944][  T174] sd 0:0:0:3: [sdd] Synchronizing SCSI cache
[   10.696627][   T83] sd 0:0:0:2: [sdc] Synchronizing SCSI cache
[   10.704562][  T170] sd 0:0:0:6: [sdg] Synchronizing SCSI cache
[   10.980602][    T5] sd 0:0:0:0: [sda] Synchronizing SCSI cache

/** Printing all the consumer nodes of supplier **/
[   10.987327][    T5] ufs_device_wlun 0:0:0:49488: usage-count @ 
suspend: 0

<-- this is the usage_count
[   10.994440][    T5] ufs_rpmb_wlun 0:0:0:49476: PM state - 2
[   11.000402][    T5] scsi 0:0:0:49456: PM state - 2
[   11.005453][    T5] sd 0:0:0:0: PM state - 2
[   11.009958][    T5] sd 0:0:0:1: PM state - 2
[   11.014469][    T5] sd 0:0:0:2: PM state - 2
[   11.019072][    T5] sd 0:0:0:3: PM state - 2
[   11.023595][    T5] sd 0:0:0:4: PM state - 0 << RPM_ACTIVE
[   11.353298][    T5] sd 0:0:0:5: PM state - 2
[   11.357726][    T5] sd 0:0:0:6: PM state - 2
[   11.362155][    T5] sd 0:0:0:7: PM state - 2
[   11.366584][    T5] ufshcd-qcom 1d84000.ufshc: 
__ufshcd_wl_suspend - 8709
[   11.374366][    T5] ufs_device_wlun 0:0:0:49488: 
__ufshcd_wl_suspend -

(0) has rpm_active flags


Do you mean that rpm_active of the link between the consumer and the
supplier is greater than 0 at this point and the consumer is


I mean is rpm_active of the link greater than 1 (because 1 means "no
active references to the supplier")?

Hi Rafael:
No - it is not greater than 1.

I'm trying to understand what's going on in it; will update when I've 
something.





RPM_ACTIVE, but the supplier suspends successfully nevertheless?


[   11.383376][    T5] ufs_device_wlun 0:0:0:49488:
ufshcd_wl_runtime_suspend <-- Supplier suspends fine.
[   12.977318][  T174] sd 0:0:0:4: [sde] Synchronizing SCSI cache

And the the suspend of sde is stuck now:
schedule+0x9c/0xe0
schedule_timeout+0x40/0x128
io_schedule_timeout+0x44/0x68
wait_for_common_io+0x7c/0x100
wait_for_completion_io+0x14/0x20
blk_execute_rq+0x90/0xcc
__scsi_execute+0x104/0x1c4
sd_sync_cache+0xf8/0x2a0
sd_suspend_common+0x74/0x11c
sd_suspend_runtime+0x14/0x20
scsi_runtime_suspend+0x64/0x94
__rpm_callback+0x80/0x2a4
rpm_suspend+0x308/0x614
pm_runtime_work+0x98/0xa8

I added 'DL_FLAG_RPM_ACTIVE' while creating links.
   if (hba->sdev_ufs_device) {
   link = device_link_add(>sdev_gendev,
   >sdev_ufs_device->sdev_gendev,
  
DL_FLAG_PM_RUNTIME|DL_FLAG_RPM_ACTIVE);

I didn't expect this to resolve the issue anyway and it didn't.

Another interesting point here is when I resume any of the above 
suspended
consumers, it all goes back to normal, which is kind of expected. I 
tried

resuming the consumer and the supplier is resumed and the supplier is
suspended when all the consumers are suspended.

Any pointers on this issue please?

@Bart/@Alan - Do you've any pointers please?


It's very noticeable that although you seem to have isolated a bug in
the power management subsystem (supplier goes into runtime suspend
even when one of its consumers is still active), you did not CC the
power management maintainer or mailing list.

I have added the appropriate CC's.


Thanks Alan!





Hello
I & Can (thanks CanG) debugged this further:

Looks like this issue can occur if the sd probe is asynchronous.

Essentially, the sd_probe() is done asynchronously and 
driver_probe_device() invokes pm_runtime_get_suppliers() before invoking 
sd_probe().


But scsi_probe_and_add_lun() runs in a separate context.
So the scsi_autopm_put_device() invoked from scsi_scan_host() context 
reduces the link->rpm_active to 1. And sd_probe() invokes 
scsi_autopm_put_device() and starts a timer. And then 
driver_probe_device() invoked from __device_attach_async_helper context 
reduces the link->rpm_active to 1 thus enabling the supplier to suspend 
before the consumer suspends.


So if:
Context T1:
[1] scsi_probe_and_add_lun()
[2] |- scsi_autopm_put_device() - reduce the link->rpm_active to 1

Context T2:
__device_attach_async_helper()
|- driver_probe_device()
|- sd_probe()
In between [1] and [2] say, driver_probe_device() -> sd_probe() is 
invoked in a separate context from __device_attach_async_helper().
The driver_probe_device() -> pm_runtime_g

Re: [PATCH v10 1/2] scsi: ufs: Enable power management for wlun

2021-03-09 Thread Asutosh Das (asd)

On 3/8/2021 9:17 AM, Rafael J. Wysocki wrote:

On Mon, Mar 8, 2021 at 5:21 PM Rafael J. Wysocki  wrote:


On Sat, Mar 6, 2021 at 5:17 PM Alan Stern  wrote:


On Fri, Mar 05, 2021 at 06:54:24PM -0800, Asutosh Das (asd) wrote:


Now during my testing I see a weird issue sometimes (1 in 7).
Scenario - bootups

Issue:
The supplier 'ufs_device_wlun 0:0:0:49488' goes into runtime suspend even
when one/more of its consumers are in RPM_ACTIVE state.

*Log:
[   10.056379][  T206] sd 0:0:0:1: [sdb] Synchronizing SCSI cache
[   10.062497][  T113] sd 0:0:0:5: [sdf] Synchronizing SCSI cache
[   10.356600][   T32] sd 0:0:0:7: [sdh] Synchronizing SCSI cache
[   10.362944][  T174] sd 0:0:0:3: [sdd] Synchronizing SCSI cache
[   10.696627][   T83] sd 0:0:0:2: [sdc] Synchronizing SCSI cache
[   10.704562][  T170] sd 0:0:0:6: [sdg] Synchronizing SCSI cache
[   10.980602][T5] sd 0:0:0:0: [sda] Synchronizing SCSI cache

/** Printing all the consumer nodes of supplier **/
[   10.987327][T5] ufs_device_wlun 0:0:0:49488: usage-count @ suspend: 0
<-- this is the usage_count
[   10.994440][T5] ufs_rpmb_wlun 0:0:0:49476: PM state - 2
[   11.000402][T5] scsi 0:0:0:49456: PM state - 2
[   11.005453][T5] sd 0:0:0:0: PM state - 2
[   11.009958][T5] sd 0:0:0:1: PM state - 2
[   11.014469][T5] sd 0:0:0:2: PM state - 2
[   11.019072][T5] sd 0:0:0:3: PM state - 2
[   11.023595][T5] sd 0:0:0:4: PM state - 0 << RPM_ACTIVE
[   11.353298][T5] sd 0:0:0:5: PM state - 2
[   11.357726][T5] sd 0:0:0:6: PM state - 2
[   11.362155][T5] sd 0:0:0:7: PM state - 2
[   11.366584][T5] ufshcd-qcom 1d84000.ufshc: __ufshcd_wl_suspend - 8709
[   11.374366][T5] ufs_device_wlun 0:0:0:49488: __ufshcd_wl_suspend -
(0) has rpm_active flags


Do you mean that rpm_active of the link between the consumer and the
supplier is greater than 0 at this point and the consumer is


I mean is rpm_active of the link greater than 1 (because 1 means "no
active references to the supplier")?

Hi Rafael:
No - it is not greater than 1.

I'm trying to understand what's going on in it; will update when I've 
something.





RPM_ACTIVE, but the supplier suspends successfully nevertheless?


[   11.383376][T5] ufs_device_wlun 0:0:0:49488:
ufshcd_wl_runtime_suspend <-- Supplier suspends fine.
[   12.977318][  T174] sd 0:0:0:4: [sde] Synchronizing SCSI cache

And the the suspend of sde is stuck now:
schedule+0x9c/0xe0
schedule_timeout+0x40/0x128
io_schedule_timeout+0x44/0x68
wait_for_common_io+0x7c/0x100
wait_for_completion_io+0x14/0x20
blk_execute_rq+0x90/0xcc
__scsi_execute+0x104/0x1c4
sd_sync_cache+0xf8/0x2a0
sd_suspend_common+0x74/0x11c
sd_suspend_runtime+0x14/0x20
scsi_runtime_suspend+0x64/0x94
__rpm_callback+0x80/0x2a4
rpm_suspend+0x308/0x614
pm_runtime_work+0x98/0xa8

I added 'DL_FLAG_RPM_ACTIVE' while creating links.
   if (hba->sdev_ufs_device) {
   link = device_link_add(>sdev_gendev,
   >sdev_ufs_device->sdev_gendev,
  DL_FLAG_PM_RUNTIME|DL_FLAG_RPM_ACTIVE);
I didn't expect this to resolve the issue anyway and it didn't.

Another interesting point here is when I resume any of the above suspended
consumers, it all goes back to normal, which is kind of expected. I tried
resuming the consumer and the supplier is resumed and the supplier is
suspended when all the consumers are suspended.

Any pointers on this issue please?

@Bart/@Alan - Do you've any pointers please?


It's very noticeable that although you seem to have isolated a bug in
the power management subsystem (supplier goes into runtime suspend
even when one of its consumers is still active), you did not CC the
power management maintainer or mailing list.

I have added the appropriate CC's.


Thanks Alan!



--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
Linux Foundation Collaborative Project


Re: [PATCH v10 1/2] scsi: ufs: Enable power management for wlun

2021-03-05 Thread Asutosh Das (asd)

On 3/4/2021 7:35 AM, Adrian Hunter wrote:

On 3/03/21 12:52 am, Asutosh Das wrote:

During runtime-suspend of ufs host, the scsi devices are
already suspended and so are the queues associated with them.
But the ufs host sends SSU to wlun during its runtime-suspend.
During the process blk_queue_enter checks if the queue is not in
suspended state. If so, it waits for the queue to resume, and never
comes out of it.
The commit
(d55d15a33: scsi: block: Do not accept any requests while suspended)
adds the check if the queue is in suspended state in blk_queue_enter().

Call trace:
  __switch_to+0x174/0x2c4
  __schedule+0x478/0x764
  schedule+0x9c/0xe0
  blk_queue_enter+0x158/0x228
  blk_mq_alloc_request+0x40/0xa4
  blk_get_request+0x2c/0x70
  __scsi_execute+0x60/0x1c4
  ufshcd_set_dev_pwr_mode+0x124/0x1e4
  ufshcd_suspend+0x208/0x83c
  ufshcd_runtime_suspend+0x40/0x154
  ufshcd_pltfrm_runtime_suspend+0x14/0x20
  pm_generic_runtime_suspend+0x28/0x3c
  __rpm_callback+0x80/0x2a4
  rpm_suspend+0x308/0x614
  rpm_idle+0x158/0x228
  pm_runtime_work+0x84/0xac
  process_one_work+0x1f0/0x470
  worker_thread+0x26c/0x4c8
  kthread+0x13c/0x320
  ret_from_fork+0x10/0x18

Fix this by registering ufs device wlun as a scsi driver and
registering it for block runtime-pm. Also make this as a
supplier for all other luns. That way, this device wlun
suspends after all the consumers and resumes after
hba resumes.

Co-developed-by: Can Guo 
Signed-off-by: Can Guo 
Signed-off-by: Asutosh Das 


It looks good, but still a few further comments below.

Also, do you think ufshcd_err_handling_prepare()/unprepare()
need changes?  And ufshcd_recover_pm_error()?

And maybe ufshcd_auto_hibern8_update() when it is called from ufs_sysfs.c?


Hi Adrian
Sure, I'll fix it in the next version.

Now during my testing I see a weird issue sometimes (1 in 7).
Scenario - bootups

Issue:
The supplier 'ufs_device_wlun 0:0:0:49488' goes into runtime suspend 
even when one/more of its consumers are in RPM_ACTIVE state.


*Log:
[   10.056379][  T206] sd 0:0:0:1: [sdb] Synchronizing SCSI cache
[   10.062497][  T113] sd 0:0:0:5: [sdf] Synchronizing SCSI cache
[   10.356600][   T32] sd 0:0:0:7: [sdh] Synchronizing SCSI cache
[   10.362944][  T174] sd 0:0:0:3: [sdd] Synchronizing SCSI cache
[   10.696627][   T83] sd 0:0:0:2: [sdc] Synchronizing SCSI cache
[   10.704562][  T170] sd 0:0:0:6: [sdg] Synchronizing SCSI cache
[   10.980602][T5] sd 0:0:0:0: [sda] Synchronizing SCSI cache

/** Printing all the consumer nodes of supplier **/
[   10.987327][T5] ufs_device_wlun 0:0:0:49488: usage-count @ 
suspend: 0 <-- this is the usage_count

[   10.994440][T5] ufs_rpmb_wlun 0:0:0:49476: PM state - 2
[   11.000402][T5] scsi 0:0:0:49456: PM state - 2
[   11.005453][T5] sd 0:0:0:0: PM state - 2
[   11.009958][T5] sd 0:0:0:1: PM state - 2
[   11.014469][T5] sd 0:0:0:2: PM state - 2
[   11.019072][T5] sd 0:0:0:3: PM state - 2
[   11.023595][T5] sd 0:0:0:4: PM state - 0 << RPM_ACTIVE
[   11.353298][T5] sd 0:0:0:5: PM state - 2
[   11.357726][T5] sd 0:0:0:6: PM state - 2
[   11.362155][T5] sd 0:0:0:7: PM state - 2
[   11.366584][T5] ufshcd-qcom 1d84000.ufshc: __ufshcd_wl_suspend - 8709
[   11.374366][T5] ufs_device_wlun 0:0:0:49488: __ufshcd_wl_suspend 
- (0) has rpm_active flags
[   11.383376][T5] ufs_device_wlun 0:0:0:49488: 
ufshcd_wl_runtime_suspend <-- Supplier suspends fine.

[   12.977318][  T174] sd 0:0:0:4: [sde] Synchronizing SCSI cache

And the the suspend of sde is stuck now:
schedule+0x9c/0xe0
schedule_timeout+0x40/0x128
io_schedule_timeout+0x44/0x68
wait_for_common_io+0x7c/0x100
wait_for_completion_io+0x14/0x20
blk_execute_rq+0x90/0xcc
__scsi_execute+0x104/0x1c4
sd_sync_cache+0xf8/0x2a0
sd_suspend_common+0x74/0x11c
sd_suspend_runtime+0x14/0x20
scsi_runtime_suspend+0x64/0x94
__rpm_callback+0x80/0x2a4
rpm_suspend+0x308/0x614
pm_runtime_work+0x98/0xa8

I added 'DL_FLAG_RPM_ACTIVE' while creating links.
  if (hba->sdev_ufs_device) {
  link = device_link_add(>sdev_gendev,
  >sdev_ufs_device->sdev_gendev,
 DL_FLAG_PM_RUNTIME|DL_FLAG_RPM_ACTIVE);
I didn't expect this to resolve the issue anyway and it didn't.

Another interesting point here is when I resume any of the above 
suspended consumers, it all goes back to normal, which is kind of 
expected. I tried resuming the consumer and the supplier is resumed and 
the supplier is suspended when all the consumers are suspended.


Any pointers on this issue please?

@Bart/@Alan - Do you've any pointers please?

Thanks,
AsutoshD





---
  drivers/scsi/ufs/cdns-pltfrm.c |   2 +
  drivers/scsi/ufs/tc-dwc-g210-pci.c |   2 +
  drivers/scsi/ufs/ufs-exynos.c  |   2 +
  drivers/scsi/ufs/ufs-hisi.c|   2 +
  drivers/scsi/ufs/ufs-mediatek.c|   2 +
  drivers/scsi/ufs/ufs-qcom.c|   2 +
  drivers/scsi/ufs/ufs_bsg.c |   6 +-
  drivers/scsi/ufs

Re: [PATCH v10 2/2] ufs: sysfs: Resume the proper scsi device

2021-03-04 Thread Asutosh Das

On Thu, Mar 04 2021 at 23:45 -0800, Adrian Hunter wrote:

On 3/03/21 12:52 am, Asutosh Das wrote:

Resumes the actual scsi device the unit descriptor of which
is being accessed instead of the hba alone.


Since "scsi: ufs: ufs-debugfs: Add user-defined exception_event_mask"
is now in linux-next, a similar change is needed for ufs-debugfs.c.
Probably best it is a separate patch though.


Ok Sure, I'll push a separate patch.
If there're not any other concerns, please can you ack these changes.

Thanks,
-asd


[PATCH v10 2/2] ufs: sysfs: Resume the proper scsi device

2021-03-03 Thread Asutosh Das
Resumes the actual scsi device the unit descriptor of which
is being accessed instead of the hba alone.

Signed-off-by: Asutosh Das 
---
 drivers/scsi/ufs/ufs-sysfs.c | 30 +-
 1 file changed, 17 insertions(+), 13 deletions(-)

diff --git a/drivers/scsi/ufs/ufs-sysfs.c b/drivers/scsi/ufs/ufs-sysfs.c
index acc54f5..3fc182b 100644
--- a/drivers/scsi/ufs/ufs-sysfs.c
+++ b/drivers/scsi/ufs/ufs-sysfs.c
@@ -245,9 +245,9 @@ static ssize_t wb_on_store(struct device *dev, struct 
device_attribute *attr,
goto out;
}
 
-   pm_runtime_get_sync(hba->dev);
+   scsi_autopm_get_device(hba->sdev_ufs_device);
res = ufshcd_wb_ctrl(hba, wb_enable);
-   pm_runtime_put_sync(hba->dev);
+   scsi_autopm_put_device(hba->sdev_ufs_device);
 out:
up(>host_sem);
return res < 0 ? res : count;
@@ -297,10 +297,10 @@ static ssize_t ufs_sysfs_read_desc_param(struct ufs_hba 
*hba,
goto out;
}
 
-   pm_runtime_get_sync(hba->dev);
+   scsi_autopm_get_device(hba->sdev_ufs_device);
ret = ufshcd_read_desc_param(hba, desc_id, desc_index,
param_offset, desc_buf, param_size);
-   pm_runtime_put_sync(hba->dev);
+   scsi_autopm_put_device(hba->sdev_ufs_device);
if (ret) {
ret = -EINVAL;
goto out;
@@ -678,7 +678,7 @@ static ssize_t _name##_show(struct device *dev, 
\
up(>host_sem); \
return -ENOMEM; \
}   \
-   pm_runtime_get_sync(hba->dev);  \
+   scsi_autopm_get_device(hba->sdev_ufs_device);   \
ret = ufshcd_query_descriptor_retry(hba,\
UPIU_QUERY_OPCODE_READ_DESC, QUERY_DESC_IDN_DEVICE, \
0, 0, desc_buf, _len); \
@@ -695,7 +695,7 @@ static ssize_t _name##_show(struct device *dev, 
\
goto out;   \
ret = sysfs_emit(buf, "%s\n", desc_buf);\
 out:   \
-   pm_runtime_put_sync(hba->dev);  \
+   scsi_autopm_put_device(hba->sdev_ufs_device);   \
kfree(desc_buf);\
up(>host_sem); \
return ret; \
@@ -744,10 +744,10 @@ static ssize_t _name##_show(struct device *dev,   
\
}   \
if (ufshcd_is_wb_flags(QUERY_FLAG_IDN##_uname)) \
index = ufshcd_wb_get_query_index(hba); \
-   pm_runtime_get_sync(hba->dev);  \
+   scsi_autopm_get_device(hba->sdev_ufs_device);   \
ret = ufshcd_query_flag(hba, UPIU_QUERY_OPCODE_READ_FLAG,   \
QUERY_FLAG_IDN##_uname, index, );  \
-   pm_runtime_put_sync(hba->dev);  \
+   scsi_autopm_put_device(hba->sdev_ufs_device);   \
if (ret) {  \
ret = -EINVAL;  \
goto out;   \
@@ -813,10 +813,10 @@ static ssize_t _name##_show(struct device *dev,   
\
}   \
if (ufshcd_is_wb_attrs(QUERY_ATTR_IDN##_uname)) \
index = ufshcd_wb_get_query_index(hba); \
-   pm_runtime_get_sync(hba->dev);  \
+   scsi_autopm_get_device(hba->sdev_ufs_device);   \
ret = ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_READ_ATTR,   \
QUERY_ATTR_IDN##_uname, index, 0, );  \
-   pm_runtime_put_sync(hba->dev);  \
+   scsi_autopm_put_device(hba->sdev_ufs_device);   \
if (ret) {  \
ret = -EINVAL;  \
goto out;   \
@@ -899,11 +899,15 @@ static ssize_t _pname##_show(struct device *dev,  
\
struct scsi_device *sdev = to_scsi_device(dev); \
struct ufs_hba *hba = shost_p

[PATCH v10 1/2] scsi: ufs: Enable power management for wlun

2021-03-03 Thread Asutosh Das
During runtime-suspend of ufs host, the scsi devices are
already suspended and so are the queues associated with them.
But the ufs host sends SSU to wlun during its runtime-suspend.
During the process blk_queue_enter checks if the queue is not in
suspended state. If so, it waits for the queue to resume, and never
comes out of it.
The commit
(d55d15a33: scsi: block: Do not accept any requests while suspended)
adds the check if the queue is in suspended state in blk_queue_enter().

Call trace:
 __switch_to+0x174/0x2c4
 __schedule+0x478/0x764
 schedule+0x9c/0xe0
 blk_queue_enter+0x158/0x228
 blk_mq_alloc_request+0x40/0xa4
 blk_get_request+0x2c/0x70
 __scsi_execute+0x60/0x1c4
 ufshcd_set_dev_pwr_mode+0x124/0x1e4
 ufshcd_suspend+0x208/0x83c
 ufshcd_runtime_suspend+0x40/0x154
 ufshcd_pltfrm_runtime_suspend+0x14/0x20
 pm_generic_runtime_suspend+0x28/0x3c
 __rpm_callback+0x80/0x2a4
 rpm_suspend+0x308/0x614
 rpm_idle+0x158/0x228
 pm_runtime_work+0x84/0xac
 process_one_work+0x1f0/0x470
 worker_thread+0x26c/0x4c8
 kthread+0x13c/0x320
 ret_from_fork+0x10/0x18

Fix this by registering ufs device wlun as a scsi driver and
registering it for block runtime-pm. Also make this as a
supplier for all other luns. That way, this device wlun
suspends after all the consumers and resumes after
hba resumes.

Co-developed-by: Can Guo 
Signed-off-by: Can Guo 
Signed-off-by: Asutosh Das 
---
 drivers/scsi/ufs/cdns-pltfrm.c |   2 +
 drivers/scsi/ufs/tc-dwc-g210-pci.c |   2 +
 drivers/scsi/ufs/ufs-exynos.c  |   2 +
 drivers/scsi/ufs/ufs-hisi.c|   2 +
 drivers/scsi/ufs/ufs-mediatek.c|   2 +
 drivers/scsi/ufs/ufs-qcom.c|   2 +
 drivers/scsi/ufs/ufs_bsg.c |   6 +-
 drivers/scsi/ufs/ufshcd-pci.c  |  32 +-
 drivers/scsi/ufs/ufshcd.c  | 583 +++--
 drivers/scsi/ufs/ufshcd.h  |   7 +
 include/trace/events/ufs.h |  20 ++
 11 files changed, 478 insertions(+), 182 deletions(-)

diff --git a/drivers/scsi/ufs/cdns-pltfrm.c b/drivers/scsi/ufs/cdns-pltfrm.c
index 149391f..3e70c23 100644
--- a/drivers/scsi/ufs/cdns-pltfrm.c
+++ b/drivers/scsi/ufs/cdns-pltfrm.c
@@ -319,6 +319,8 @@ static const struct dev_pm_ops cdns_ufs_dev_pm_ops = {
.runtime_suspend = ufshcd_pltfrm_runtime_suspend,
.runtime_resume  = ufshcd_pltfrm_runtime_resume,
.runtime_idle= ufshcd_pltfrm_runtime_idle,
+   .prepare = ufshcd_suspend_prepare,
+   .complete   = ufshcd_resume_complete,
 };
 
 static struct platform_driver cdns_ufs_pltfrm_driver = {
diff --git a/drivers/scsi/ufs/tc-dwc-g210-pci.c 
b/drivers/scsi/ufs/tc-dwc-g210-pci.c
index 67a6a61..b01db12 100644
--- a/drivers/scsi/ufs/tc-dwc-g210-pci.c
+++ b/drivers/scsi/ufs/tc-dwc-g210-pci.c
@@ -148,6 +148,8 @@ static const struct dev_pm_ops tc_dwc_g210_pci_pm_ops = {
.runtime_suspend = tc_dwc_g210_pci_runtime_suspend,
.runtime_resume  = tc_dwc_g210_pci_runtime_resume,
.runtime_idle= tc_dwc_g210_pci_runtime_idle,
+   .prepare = ufshcd_suspend_prepare,
+   .complete   = ufshcd_resume_complete,
 };
 
 static const struct pci_device_id tc_dwc_g210_pci_tbl[] = {
diff --git a/drivers/scsi/ufs/ufs-exynos.c b/drivers/scsi/ufs/ufs-exynos.c
index 267943a1..45c0b02 100644
--- a/drivers/scsi/ufs/ufs-exynos.c
+++ b/drivers/scsi/ufs/ufs-exynos.c
@@ -1268,6 +1268,8 @@ static const struct dev_pm_ops exynos_ufs_pm_ops = {
.runtime_suspend = ufshcd_pltfrm_runtime_suspend,
.runtime_resume  = ufshcd_pltfrm_runtime_resume,
.runtime_idle= ufshcd_pltfrm_runtime_idle,
+   .prepare = ufshcd_suspend_prepare,
+   .complete   = ufshcd_resume_complete,
 };
 
 static struct platform_driver exynos_ufs_pltform = {
diff --git a/drivers/scsi/ufs/ufs-hisi.c b/drivers/scsi/ufs/ufs-hisi.c
index 0aa5813..d463b44 100644
--- a/drivers/scsi/ufs/ufs-hisi.c
+++ b/drivers/scsi/ufs/ufs-hisi.c
@@ -574,6 +574,8 @@ static const struct dev_pm_ops ufs_hisi_pm_ops = {
.runtime_suspend = ufshcd_pltfrm_runtime_suspend,
.runtime_resume  = ufshcd_pltfrm_runtime_resume,
.runtime_idle= ufshcd_pltfrm_runtime_idle,
+   .prepare = ufshcd_suspend_prepare,
+   .complete   = ufshcd_resume_complete,
 };
 
 static struct platform_driver ufs_hisi_pltform = {
diff --git a/drivers/scsi/ufs/ufs-mediatek.c b/drivers/scsi/ufs/ufs-mediatek.c
index c55202b..df1eabb 100644
--- a/drivers/scsi/ufs/ufs-mediatek.c
+++ b/drivers/scsi/ufs/ufs-mediatek.c
@@ -1097,6 +1097,8 @@ static const struct dev_pm_ops ufs_mtk_pm_ops = {
.runtime_suspend = ufshcd_pltfrm_runtime_suspend,
.runtime_resume  = ufshcd_pltfrm_runtime_resume,
.runtime_idle= ufshcd_pltfrm_runtime_idle,
+   .prepare = ufshcd_suspend_prepare,
+   .complete   = ufshcd_resume_complete,
 };
 
 static struct platform_driver ufs_mtk_pltform = {
diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index f97d7b0

Re: [PATCH v9 1/2] scsi: ufs: Enable power management for wlun

2021-03-02 Thread Asutosh Das

On Tue, Mar 02 2021 at 06:14 -0800, Adrian Hunter wrote:

On 2/03/21 5:21 am, Asutosh Das wrote:

During runtime-suspend of ufs host, the scsi devices are
already suspended and so are the queues associated with them.
But the ufs host sends SSU to wlun during its runtime-suspend.
During the process blk_queue_enter checks if the queue is not in
suspended state. If so, it waits for the queue to resume, and never
comes out of it.
The commit
(d55d15a33: scsi: block: Do not accept any requests while suspended)
adds the check if the queue is in suspended state in blk_queue_enter().

Call trace:
 __switch_to+0x174/0x2c4
 __schedule+0x478/0x764
 schedule+0x9c/0xe0
 blk_queue_enter+0x158/0x228
 blk_mq_alloc_request+0x40/0xa4
 blk_get_request+0x2c/0x70
 __scsi_execute+0x60/0x1c4
 ufshcd_set_dev_pwr_mode+0x124/0x1e4
 ufshcd_suspend+0x208/0x83c
 ufshcd_runtime_suspend+0x40/0x154
 ufshcd_pltfrm_runtime_suspend+0x14/0x20
 pm_generic_runtime_suspend+0x28/0x3c
 __rpm_callback+0x80/0x2a4
 rpm_suspend+0x308/0x614
 rpm_idle+0x158/0x228
 pm_runtime_work+0x84/0xac
 process_one_work+0x1f0/0x470
 worker_thread+0x26c/0x4c8
 kthread+0x13c/0x320
 ret_from_fork+0x10/0x18

Fix this by registering ufs device wlun as a scsi driver and
registering it for block runtime-pm. Also make this as a
supplier for all other luns. That way, this device wlun
suspends after all the consumers and resumes after
hba resumes.

Co-developed-by: Can Guo 
Signed-off-by: Can Guo 
Signed-off-by: Asutosh Das 
---


Now we need either to move the suspend/resume vops from
ufshcd_suspend/resume to __ufshcd_wl_suspend/resume, assuming that
would work for existing implementations of those callbacks,
or otherwise create new vops ->wl_suspend() / ->wl_resume(), and
then split the existing implementations of those callbacks.

ufs_intel_resume() now needs to be invoked from __ufshcd_wl_resume().
I am not sure about the others:

exynos_ufs_suspend()
exynos_ufs_resume()
ufs_hisi_suspend()
ufs_hisi_resume()
ufs_mtk_suspend()
ufs_mtk_resume()
ufs_qcom_suspend()
ufs_qcom_resume()



Thanks. I'll change this in the next version.

-asd


[PATCH v9 2/2] ufs: sysfs: Resume the proper scsi device

2021-03-01 Thread Asutosh Das
Resumes the actual scsi device the unit descriptor of which
is being accessed instead of the hba alone.

Signed-off-by: Asutosh Das 
---
 drivers/scsi/ufs/ufs-sysfs.c | 26 +++---
 1 file changed, 15 insertions(+), 11 deletions(-)

diff --git a/drivers/scsi/ufs/ufs-sysfs.c b/drivers/scsi/ufs/ufs-sysfs.c
index acc54f5..34481e3 100644
--- a/drivers/scsi/ufs/ufs-sysfs.c
+++ b/drivers/scsi/ufs/ufs-sysfs.c
@@ -297,10 +297,10 @@ static ssize_t ufs_sysfs_read_desc_param(struct ufs_hba 
*hba,
goto out;
}
 
-   pm_runtime_get_sync(hba->dev);
+   scsi_autopm_get_device(hba->sdev_ufs_device);
ret = ufshcd_read_desc_param(hba, desc_id, desc_index,
param_offset, desc_buf, param_size);
-   pm_runtime_put_sync(hba->dev);
+   scsi_autopm_put_device(hba->sdev_ufs_device);
if (ret) {
ret = -EINVAL;
goto out;
@@ -678,7 +678,7 @@ static ssize_t _name##_show(struct device *dev, 
\
up(>host_sem); \
return -ENOMEM; \
}   \
-   pm_runtime_get_sync(hba->dev);  \
+   scsi_autopm_get_device(hba->sdev_ufs_device);   \
ret = ufshcd_query_descriptor_retry(hba,\
UPIU_QUERY_OPCODE_READ_DESC, QUERY_DESC_IDN_DEVICE, \
0, 0, desc_buf, _len); \
@@ -695,7 +695,7 @@ static ssize_t _name##_show(struct device *dev, 
\
goto out;   \
ret = sysfs_emit(buf, "%s\n", desc_buf);\
 out:   \
-   pm_runtime_put_sync(hba->dev);  \
+   scsi_autopm_put_device(hba->sdev_ufs_device);   \
kfree(desc_buf);\
up(>host_sem); \
return ret; \
@@ -744,10 +744,10 @@ static ssize_t _name##_show(struct device *dev,   
\
}   \
if (ufshcd_is_wb_flags(QUERY_FLAG_IDN##_uname)) \
index = ufshcd_wb_get_query_index(hba); \
-   pm_runtime_get_sync(hba->dev);  \
+   scsi_autopm_get_device(hba->sdev_ufs_device);   \
ret = ufshcd_query_flag(hba, UPIU_QUERY_OPCODE_READ_FLAG,   \
QUERY_FLAG_IDN##_uname, index, );  \
-   pm_runtime_put_sync(hba->dev);  \
+   scsi_autopm_put_device(hba->sdev_ufs_device);   \
if (ret) {  \
ret = -EINVAL;  \
goto out;   \
@@ -813,10 +813,10 @@ static ssize_t _name##_show(struct device *dev,   
\
}   \
if (ufshcd_is_wb_attrs(QUERY_ATTR_IDN##_uname)) \
index = ufshcd_wb_get_query_index(hba); \
-   pm_runtime_get_sync(hba->dev);  \
+   scsi_autopm_get_device(hba->sdev_ufs_device);   \
ret = ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_READ_ATTR,   \
QUERY_ATTR_IDN##_uname, index, 0, );  \
-   pm_runtime_put_sync(hba->dev);  \
+   scsi_autopm_put_device(hba->sdev_ufs_device);   \
if (ret) {  \
ret = -EINVAL;  \
goto out;   \
@@ -899,11 +899,15 @@ static ssize_t _pname##_show(struct device *dev,  
\
struct scsi_device *sdev = to_scsi_device(dev); \
struct ufs_hba *hba = shost_priv(sdev->host);   \
u8 lun = ufshcd_scsi_to_upiu_lun(sdev->lun);\
+   int ret;\
if (!ufs_is_valid_unit_desc_lun(>dev_info, lun,\
_duname##_DESC_PARAM##_puname)) \
return -EINVAL; \
-   return ufs_sysfs_read_desc_p

[PATCH v9 1/2] scsi: ufs: Enable power management for wlun

2021-03-01 Thread Asutosh Das
During runtime-suspend of ufs host, the scsi devices are
already suspended and so are the queues associated with them.
But the ufs host sends SSU to wlun during its runtime-suspend.
During the process blk_queue_enter checks if the queue is not in
suspended state. If so, it waits for the queue to resume, and never
comes out of it.
The commit
(d55d15a33: scsi: block: Do not accept any requests while suspended)
adds the check if the queue is in suspended state in blk_queue_enter().

Call trace:
 __switch_to+0x174/0x2c4
 __schedule+0x478/0x764
 schedule+0x9c/0xe0
 blk_queue_enter+0x158/0x228
 blk_mq_alloc_request+0x40/0xa4
 blk_get_request+0x2c/0x70
 __scsi_execute+0x60/0x1c4
 ufshcd_set_dev_pwr_mode+0x124/0x1e4
 ufshcd_suspend+0x208/0x83c
 ufshcd_runtime_suspend+0x40/0x154
 ufshcd_pltfrm_runtime_suspend+0x14/0x20
 pm_generic_runtime_suspend+0x28/0x3c
 __rpm_callback+0x80/0x2a4
 rpm_suspend+0x308/0x614
 rpm_idle+0x158/0x228
 pm_runtime_work+0x84/0xac
 process_one_work+0x1f0/0x470
 worker_thread+0x26c/0x4c8
 kthread+0x13c/0x320
 ret_from_fork+0x10/0x18

Fix this by registering ufs device wlun as a scsi driver and
registering it for block runtime-pm. Also make this as a
supplier for all other luns. That way, this device wlun
suspends after all the consumers and resumes after
hba resumes.

Co-developed-by: Can Guo 
Signed-off-by: Can Guo 
Signed-off-by: Asutosh Das 
---
 drivers/scsi/ufs/cdns-pltfrm.c |   2 +
 drivers/scsi/ufs/tc-dwc-g210-pci.c |   2 +
 drivers/scsi/ufs/ufs-exynos.c  |   2 +
 drivers/scsi/ufs/ufs-hisi.c|   2 +
 drivers/scsi/ufs/ufs-mediatek.c|   2 +
 drivers/scsi/ufs/ufs-qcom.c|   2 +
 drivers/scsi/ufs/ufshcd-pci.c  |  32 +-
 drivers/scsi/ufs/ufshcd.c  | 609 +++--
 drivers/scsi/ufs/ufshcd.h  |   7 +
 include/trace/events/ufs.h |  20 ++
 10 files changed, 493 insertions(+), 187 deletions(-)

diff --git a/drivers/scsi/ufs/cdns-pltfrm.c b/drivers/scsi/ufs/cdns-pltfrm.c
index 149391f..3e70c23 100644
--- a/drivers/scsi/ufs/cdns-pltfrm.c
+++ b/drivers/scsi/ufs/cdns-pltfrm.c
@@ -319,6 +319,8 @@ static const struct dev_pm_ops cdns_ufs_dev_pm_ops = {
.runtime_suspend = ufshcd_pltfrm_runtime_suspend,
.runtime_resume  = ufshcd_pltfrm_runtime_resume,
.runtime_idle= ufshcd_pltfrm_runtime_idle,
+   .prepare = ufshcd_suspend_prepare,
+   .complete   = ufshcd_resume_complete,
 };
 
 static struct platform_driver cdns_ufs_pltfrm_driver = {
diff --git a/drivers/scsi/ufs/tc-dwc-g210-pci.c 
b/drivers/scsi/ufs/tc-dwc-g210-pci.c
index 67a6a61..b01db12 100644
--- a/drivers/scsi/ufs/tc-dwc-g210-pci.c
+++ b/drivers/scsi/ufs/tc-dwc-g210-pci.c
@@ -148,6 +148,8 @@ static const struct dev_pm_ops tc_dwc_g210_pci_pm_ops = {
.runtime_suspend = tc_dwc_g210_pci_runtime_suspend,
.runtime_resume  = tc_dwc_g210_pci_runtime_resume,
.runtime_idle= tc_dwc_g210_pci_runtime_idle,
+   .prepare = ufshcd_suspend_prepare,
+   .complete   = ufshcd_resume_complete,
 };
 
 static const struct pci_device_id tc_dwc_g210_pci_tbl[] = {
diff --git a/drivers/scsi/ufs/ufs-exynos.c b/drivers/scsi/ufs/ufs-exynos.c
index 267943a1..45c0b02 100644
--- a/drivers/scsi/ufs/ufs-exynos.c
+++ b/drivers/scsi/ufs/ufs-exynos.c
@@ -1268,6 +1268,8 @@ static const struct dev_pm_ops exynos_ufs_pm_ops = {
.runtime_suspend = ufshcd_pltfrm_runtime_suspend,
.runtime_resume  = ufshcd_pltfrm_runtime_resume,
.runtime_idle= ufshcd_pltfrm_runtime_idle,
+   .prepare = ufshcd_suspend_prepare,
+   .complete   = ufshcd_resume_complete,
 };
 
 static struct platform_driver exynos_ufs_pltform = {
diff --git a/drivers/scsi/ufs/ufs-hisi.c b/drivers/scsi/ufs/ufs-hisi.c
index 0aa5813..d463b44 100644
--- a/drivers/scsi/ufs/ufs-hisi.c
+++ b/drivers/scsi/ufs/ufs-hisi.c
@@ -574,6 +574,8 @@ static const struct dev_pm_ops ufs_hisi_pm_ops = {
.runtime_suspend = ufshcd_pltfrm_runtime_suspend,
.runtime_resume  = ufshcd_pltfrm_runtime_resume,
.runtime_idle= ufshcd_pltfrm_runtime_idle,
+   .prepare = ufshcd_suspend_prepare,
+   .complete   = ufshcd_resume_complete,
 };
 
 static struct platform_driver ufs_hisi_pltform = {
diff --git a/drivers/scsi/ufs/ufs-mediatek.c b/drivers/scsi/ufs/ufs-mediatek.c
index c55202b..df1eabb 100644
--- a/drivers/scsi/ufs/ufs-mediatek.c
+++ b/drivers/scsi/ufs/ufs-mediatek.c
@@ -1097,6 +1097,8 @@ static const struct dev_pm_ops ufs_mtk_pm_ops = {
.runtime_suspend = ufshcd_pltfrm_runtime_suspend,
.runtime_resume  = ufshcd_pltfrm_runtime_resume,
.runtime_idle= ufshcd_pltfrm_runtime_idle,
+   .prepare = ufshcd_suspend_prepare,
+   .complete   = ufshcd_resume_complete,
 };
 
 static struct platform_driver ufs_mtk_pltform = {
diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index f97d7b0..9aa098a 100644
--- a/drivers/scsi/ufs/ufs

Re: [PATCH] scsi: ufs: Fix incorrect ufshcd_state after ufshcd_reset_and_restore()

2021-03-01 Thread Asutosh Das

On Mon, Mar 01 2021 at 11:19 -0800, Adrian Hunter wrote:

If ufshcd_probe_hba() fails it sets ufshcd_state to UFSHCD_STATE_ERROR,
however, if it is called again, as it is within a loop in
ufshcd_reset_and_restore(), and succeeds, then it will not set the state
back to UFSHCD_STATE_OPERATIONAL unless the state was
UFSHCD_STATE_RESET.

That can result in the state being UFSHCD_STATE_ERROR even though
ufshcd_reset_and_restore() is successful and returns zero.

Fix by initializing the state to UFSHCD_STATE_RESET in the start of each
loop in ufshcd_reset_and_restore().  If there is an error,
ufshcd_reset_and_restore() will change the state to UFSHCD_STATE_ERROR,
otherwise ufshcd_probe_hba() will have set the state appropriately.

Fixes: 4db7a2360597 ("scsi: ufs: Fix concurrency of error handler and other error 
recovery paths")
Signed-off-by: Adrian Hunter 
---


Reviewed-by: Asutosh Das 


drivers/scsi/ufs/ufshcd.c | 2 ++
1 file changed, 2 insertions(+)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 77161750c9fb..91a403afe038 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -7031,6 +7031,8 @@ static int ufshcd_reset_and_restore(struct ufs_hba *hba)
spin_unlock_irqrestore(hba->host->host_lock, flags);

do {
+   hba->ufshcd_state = UFSHCD_STATE_RESET;
+
/* Reset the attached device */
ufshcd_device_reset(hba);

--
2.17.1



Re: [PATCH v8 1/2] scsi: ufs: Enable power management for wlun

2021-03-01 Thread Asutosh Das

On Mon, Mar 01 2021 at 05:23 -0800, Adrian Hunter wrote:

Hi

A couple of minor things, but also a potential issue with when link state
transitions are done.  Please see comments below.

On 26/02/21 1:37 am, Asutosh Das wrote:


Hi Adrian
Thanks for your comments.


During runtime-suspend of ufs host, the scsi devices are
already suspended and so are the queues associated with them.
But the ufs host sends SSU to wlun during its runtime-suspend.
During the process blk_queue_enter checks if the queue is not in
suspended state. If so, it waits for the queue to resume, and never
comes out of it.
The commit
(d55d15a33: scsi: block: Do not accept any requests while suspended)
adds the check if the queue is in suspended state in blk_queue_enter().

Call trace:
 __switch_to+0x174/0x2c4
 __schedule+0x478/0x764
 schedule+0x9c/0xe0
 blk_queue_enter+0x158/0x228
 blk_mq_alloc_request+0x40/0xa4
 blk_get_request+0x2c/0x70
 __scsi_execute+0x60/0x1c4
 ufshcd_set_dev_pwr_mode+0x124/0x1e4
 ufshcd_suspend+0x208/0x83c
 ufshcd_runtime_suspend+0x40/0x154
 ufshcd_pltfrm_runtime_suspend+0x14/0x20
 pm_generic_runtime_suspend+0x28/0x3c
 __rpm_callback+0x80/0x2a4
 rpm_suspend+0x308/0x614
 rpm_idle+0x158/0x228
 pm_runtime_work+0x84/0xac
 process_one_work+0x1f0/0x470
 worker_thread+0x26c/0x4c8
 kthread+0x13c/0x320
 ret_from_fork+0x10/0x18

Fix this by registering ufs device wlun as a scsi driver and
registering it for block runtime-pm. Also make this as a
supplier for all other luns. That way, this device wlun
suspends after all the consumers and resumes after
hba resumes.

Co-developed-by: Can Guo 
Signed-off-by: Can Guo 
Signed-off-by: Asutosh Das 
---
 drivers/scsi/ufs/cdns-pltfrm.c |   2 +
 drivers/scsi/ufs/tc-dwc-g210-pci.c |   2 +
 drivers/scsi/ufs/ufs-exynos.c  |   2 +
 drivers/scsi/ufs/ufs-hisi.c|   2 +
 drivers/scsi/ufs/ufs-mediatek.c|   2 +
 drivers/scsi/ufs/ufs-qcom.c|   2 +
 drivers/scsi/ufs/ufshcd-pci.c  |  26 +-
 drivers/scsi/ufs/ufshcd.c  | 540 ++---
 drivers/scsi/ufs/ufshcd.h  |   7 +
 include/trace/events/ufs.h |  20 ++
 10 files changed, 483 insertions(+), 122 deletions(-)

diff --git a/drivers/scsi/ufs/cdns-pltfrm.c b/drivers/scsi/ufs/cdns-pltfrm.c
index 149391f..3e70c23 100644
--- a/drivers/scsi/ufs/cdns-pltfrm.c
+++ b/drivers/scsi/ufs/cdns-pltfrm.c
@@ -319,6 +319,8 @@ static const struct dev_pm_ops cdns_ufs_dev_pm_ops = {
.runtime_suspend = ufshcd_pltfrm_runtime_suspend,
.runtime_resume  = ufshcd_pltfrm_runtime_resume,
.runtime_idle= ufshcd_pltfrm_runtime_idle,
+   .prepare = ufshcd_suspend_prepare,
+   .complete   = ufshcd_resume_complete,
 };

 static struct platform_driver cdns_ufs_pltfrm_driver = {
diff --git a/drivers/scsi/ufs/tc-dwc-g210-pci.c 
b/drivers/scsi/ufs/tc-dwc-g210-pci.c
index 67a6a61..b01db12 100644
--- a/drivers/scsi/ufs/tc-dwc-g210-pci.c
+++ b/drivers/scsi/ufs/tc-dwc-g210-pci.c
@@ -148,6 +148,8 @@ static const struct dev_pm_ops tc_dwc_g210_pci_pm_ops = {
.runtime_suspend = tc_dwc_g210_pci_runtime_suspend,
.runtime_resume  = tc_dwc_g210_pci_runtime_resume,
.runtime_idle= tc_dwc_g210_pci_runtime_idle,
+   .prepare = ufshcd_suspend_prepare,
+   .complete   = ufshcd_resume_complete,
 };

 static const struct pci_device_id tc_dwc_g210_pci_tbl[] = {
diff --git a/drivers/scsi/ufs/ufs-exynos.c b/drivers/scsi/ufs/ufs-exynos.c
index 267943a1..45c0b02 100644
--- a/drivers/scsi/ufs/ufs-exynos.c
+++ b/drivers/scsi/ufs/ufs-exynos.c
@@ -1268,6 +1268,8 @@ static const struct dev_pm_ops exynos_ufs_pm_ops = {
.runtime_suspend = ufshcd_pltfrm_runtime_suspend,
.runtime_resume  = ufshcd_pltfrm_runtime_resume,
.runtime_idle= ufshcd_pltfrm_runtime_idle,
+   .prepare = ufshcd_suspend_prepare,
+   .complete   = ufshcd_resume_complete,
 };

 static struct platform_driver exynos_ufs_pltform = {
diff --git a/drivers/scsi/ufs/ufs-hisi.c b/drivers/scsi/ufs/ufs-hisi.c
index 0aa5813..d463b44 100644
--- a/drivers/scsi/ufs/ufs-hisi.c
+++ b/drivers/scsi/ufs/ufs-hisi.c
@@ -574,6 +574,8 @@ static const struct dev_pm_ops ufs_hisi_pm_ops = {
.runtime_suspend = ufshcd_pltfrm_runtime_suspend,
.runtime_resume  = ufshcd_pltfrm_runtime_resume,
.runtime_idle= ufshcd_pltfrm_runtime_idle,
+   .prepare = ufshcd_suspend_prepare,
+   .complete   = ufshcd_resume_complete,
 };

 static struct platform_driver ufs_hisi_pltform = {
diff --git a/drivers/scsi/ufs/ufs-mediatek.c b/drivers/scsi/ufs/ufs-mediatek.c
index c55202b..df1eabb 100644
--- a/drivers/scsi/ufs/ufs-mediatek.c
+++ b/drivers/scsi/ufs/ufs-mediatek.c
@@ -1097,6 +1097,8 @@ static const struct dev_pm_ops ufs_mtk_pm_ops = {
.runtime_suspend = ufshcd_pltfrm_runtime_suspend,
.runtime_resume  = ufshcd_pltfrm_runtime_resume,
.runtime_idle= ufshcd_pltfrm_runtime_idle,
+   .prepare

[PATCH v8 2/2] ufs: sysfs: Resume the proper scsi device

2021-02-25 Thread Asutosh Das
Resumes the actual scsi device the unit descriptor of which
is being accessed instead of the hba alone.

Signed-off-by: Asutosh Das 
---
 drivers/scsi/ufs/ufs-sysfs.c | 26 +++---
 1 file changed, 15 insertions(+), 11 deletions(-)

diff --git a/drivers/scsi/ufs/ufs-sysfs.c b/drivers/scsi/ufs/ufs-sysfs.c
index acc54f5..34481e3 100644
--- a/drivers/scsi/ufs/ufs-sysfs.c
+++ b/drivers/scsi/ufs/ufs-sysfs.c
@@ -297,10 +297,10 @@ static ssize_t ufs_sysfs_read_desc_param(struct ufs_hba 
*hba,
goto out;
}
 
-   pm_runtime_get_sync(hba->dev);
+   scsi_autopm_get_device(hba->sdev_ufs_device);
ret = ufshcd_read_desc_param(hba, desc_id, desc_index,
param_offset, desc_buf, param_size);
-   pm_runtime_put_sync(hba->dev);
+   scsi_autopm_put_device(hba->sdev_ufs_device);
if (ret) {
ret = -EINVAL;
goto out;
@@ -678,7 +678,7 @@ static ssize_t _name##_show(struct device *dev, 
\
up(>host_sem); \
return -ENOMEM; \
}   \
-   pm_runtime_get_sync(hba->dev);  \
+   scsi_autopm_get_device(hba->sdev_ufs_device);   \
ret = ufshcd_query_descriptor_retry(hba,\
UPIU_QUERY_OPCODE_READ_DESC, QUERY_DESC_IDN_DEVICE, \
0, 0, desc_buf, _len); \
@@ -695,7 +695,7 @@ static ssize_t _name##_show(struct device *dev, 
\
goto out;   \
ret = sysfs_emit(buf, "%s\n", desc_buf);\
 out:   \
-   pm_runtime_put_sync(hba->dev);  \
+   scsi_autopm_put_device(hba->sdev_ufs_device);   \
kfree(desc_buf);\
up(>host_sem); \
return ret; \
@@ -744,10 +744,10 @@ static ssize_t _name##_show(struct device *dev,   
\
}   \
if (ufshcd_is_wb_flags(QUERY_FLAG_IDN##_uname)) \
index = ufshcd_wb_get_query_index(hba); \
-   pm_runtime_get_sync(hba->dev);  \
+   scsi_autopm_get_device(hba->sdev_ufs_device);   \
ret = ufshcd_query_flag(hba, UPIU_QUERY_OPCODE_READ_FLAG,   \
QUERY_FLAG_IDN##_uname, index, );  \
-   pm_runtime_put_sync(hba->dev);  \
+   scsi_autopm_put_device(hba->sdev_ufs_device);   \
if (ret) {  \
ret = -EINVAL;  \
goto out;   \
@@ -813,10 +813,10 @@ static ssize_t _name##_show(struct device *dev,   
\
}   \
if (ufshcd_is_wb_attrs(QUERY_ATTR_IDN##_uname)) \
index = ufshcd_wb_get_query_index(hba); \
-   pm_runtime_get_sync(hba->dev);  \
+   scsi_autopm_get_device(hba->sdev_ufs_device);   \
ret = ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_READ_ATTR,   \
QUERY_ATTR_IDN##_uname, index, 0, );  \
-   pm_runtime_put_sync(hba->dev);  \
+   scsi_autopm_put_device(hba->sdev_ufs_device);   \
if (ret) {  \
ret = -EINVAL;  \
goto out;   \
@@ -899,11 +899,15 @@ static ssize_t _pname##_show(struct device *dev,  
\
struct scsi_device *sdev = to_scsi_device(dev); \
struct ufs_hba *hba = shost_priv(sdev->host);   \
u8 lun = ufshcd_scsi_to_upiu_lun(sdev->lun);\
+   int ret;\
if (!ufs_is_valid_unit_desc_lun(>dev_info, lun,\
_duname##_DESC_PARAM##_puname)) \
return -EINVAL; \
-   return ufs_sysfs_read_desc_p

[PATCH v8 1/2] scsi: ufs: Enable power management for wlun

2021-02-25 Thread Asutosh Das
During runtime-suspend of ufs host, the scsi devices are
already suspended and so are the queues associated with them.
But the ufs host sends SSU to wlun during its runtime-suspend.
During the process blk_queue_enter checks if the queue is not in
suspended state. If so, it waits for the queue to resume, and never
comes out of it.
The commit
(d55d15a33: scsi: block: Do not accept any requests while suspended)
adds the check if the queue is in suspended state in blk_queue_enter().

Call trace:
 __switch_to+0x174/0x2c4
 __schedule+0x478/0x764
 schedule+0x9c/0xe0
 blk_queue_enter+0x158/0x228
 blk_mq_alloc_request+0x40/0xa4
 blk_get_request+0x2c/0x70
 __scsi_execute+0x60/0x1c4
 ufshcd_set_dev_pwr_mode+0x124/0x1e4
 ufshcd_suspend+0x208/0x83c
 ufshcd_runtime_suspend+0x40/0x154
 ufshcd_pltfrm_runtime_suspend+0x14/0x20
 pm_generic_runtime_suspend+0x28/0x3c
 __rpm_callback+0x80/0x2a4
 rpm_suspend+0x308/0x614
 rpm_idle+0x158/0x228
 pm_runtime_work+0x84/0xac
 process_one_work+0x1f0/0x470
 worker_thread+0x26c/0x4c8
 kthread+0x13c/0x320
 ret_from_fork+0x10/0x18

Fix this by registering ufs device wlun as a scsi driver and
registering it for block runtime-pm. Also make this as a
supplier for all other luns. That way, this device wlun
suspends after all the consumers and resumes after
hba resumes.

Co-developed-by: Can Guo 
Signed-off-by: Can Guo 
Signed-off-by: Asutosh Das 
---
 drivers/scsi/ufs/cdns-pltfrm.c |   2 +
 drivers/scsi/ufs/tc-dwc-g210-pci.c |   2 +
 drivers/scsi/ufs/ufs-exynos.c  |   2 +
 drivers/scsi/ufs/ufs-hisi.c|   2 +
 drivers/scsi/ufs/ufs-mediatek.c|   2 +
 drivers/scsi/ufs/ufs-qcom.c|   2 +
 drivers/scsi/ufs/ufshcd-pci.c  |  26 +-
 drivers/scsi/ufs/ufshcd.c  | 540 ++---
 drivers/scsi/ufs/ufshcd.h  |   7 +
 include/trace/events/ufs.h |  20 ++
 10 files changed, 483 insertions(+), 122 deletions(-)

diff --git a/drivers/scsi/ufs/cdns-pltfrm.c b/drivers/scsi/ufs/cdns-pltfrm.c
index 149391f..3e70c23 100644
--- a/drivers/scsi/ufs/cdns-pltfrm.c
+++ b/drivers/scsi/ufs/cdns-pltfrm.c
@@ -319,6 +319,8 @@ static const struct dev_pm_ops cdns_ufs_dev_pm_ops = {
.runtime_suspend = ufshcd_pltfrm_runtime_suspend,
.runtime_resume  = ufshcd_pltfrm_runtime_resume,
.runtime_idle= ufshcd_pltfrm_runtime_idle,
+   .prepare = ufshcd_suspend_prepare,
+   .complete   = ufshcd_resume_complete,
 };
 
 static struct platform_driver cdns_ufs_pltfrm_driver = {
diff --git a/drivers/scsi/ufs/tc-dwc-g210-pci.c 
b/drivers/scsi/ufs/tc-dwc-g210-pci.c
index 67a6a61..b01db12 100644
--- a/drivers/scsi/ufs/tc-dwc-g210-pci.c
+++ b/drivers/scsi/ufs/tc-dwc-g210-pci.c
@@ -148,6 +148,8 @@ static const struct dev_pm_ops tc_dwc_g210_pci_pm_ops = {
.runtime_suspend = tc_dwc_g210_pci_runtime_suspend,
.runtime_resume  = tc_dwc_g210_pci_runtime_resume,
.runtime_idle= tc_dwc_g210_pci_runtime_idle,
+   .prepare = ufshcd_suspend_prepare,
+   .complete   = ufshcd_resume_complete,
 };
 
 static const struct pci_device_id tc_dwc_g210_pci_tbl[] = {
diff --git a/drivers/scsi/ufs/ufs-exynos.c b/drivers/scsi/ufs/ufs-exynos.c
index 267943a1..45c0b02 100644
--- a/drivers/scsi/ufs/ufs-exynos.c
+++ b/drivers/scsi/ufs/ufs-exynos.c
@@ -1268,6 +1268,8 @@ static const struct dev_pm_ops exynos_ufs_pm_ops = {
.runtime_suspend = ufshcd_pltfrm_runtime_suspend,
.runtime_resume  = ufshcd_pltfrm_runtime_resume,
.runtime_idle= ufshcd_pltfrm_runtime_idle,
+   .prepare = ufshcd_suspend_prepare,
+   .complete   = ufshcd_resume_complete,
 };
 
 static struct platform_driver exynos_ufs_pltform = {
diff --git a/drivers/scsi/ufs/ufs-hisi.c b/drivers/scsi/ufs/ufs-hisi.c
index 0aa5813..d463b44 100644
--- a/drivers/scsi/ufs/ufs-hisi.c
+++ b/drivers/scsi/ufs/ufs-hisi.c
@@ -574,6 +574,8 @@ static const struct dev_pm_ops ufs_hisi_pm_ops = {
.runtime_suspend = ufshcd_pltfrm_runtime_suspend,
.runtime_resume  = ufshcd_pltfrm_runtime_resume,
.runtime_idle= ufshcd_pltfrm_runtime_idle,
+   .prepare = ufshcd_suspend_prepare,
+   .complete   = ufshcd_resume_complete,
 };
 
 static struct platform_driver ufs_hisi_pltform = {
diff --git a/drivers/scsi/ufs/ufs-mediatek.c b/drivers/scsi/ufs/ufs-mediatek.c
index c55202b..df1eabb 100644
--- a/drivers/scsi/ufs/ufs-mediatek.c
+++ b/drivers/scsi/ufs/ufs-mediatek.c
@@ -1097,6 +1097,8 @@ static const struct dev_pm_ops ufs_mtk_pm_ops = {
.runtime_suspend = ufshcd_pltfrm_runtime_suspend,
.runtime_resume  = ufshcd_pltfrm_runtime_resume,
.runtime_idle= ufshcd_pltfrm_runtime_idle,
+   .prepare = ufshcd_suspend_prepare,
+   .complete   = ufshcd_resume_complete,
 };
 
 static struct platform_driver ufs_mtk_pltform = {
diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index f97d7b0..9aa098a 100644
--- a/drivers/scsi/ufs/ufs

Re: [PATCH v7 1/2] scsi: ufs: Enable power management for wlun

2021-02-25 Thread Asutosh Das

On Thu, Feb 25 2021 at 07:55 -0800, Adrian Hunter wrote:

On 25/02/21 5:00 am, Asutosh Das wrote:

During runtime-suspend of ufs host, the scsi devices are
already suspended and so are the queues associated with them.
But the ufs host sends SSU to wlun during its runtime-suspend.
During the process blk_queue_enter checks if the queue is not in
suspended state. If so, it waits for the queue to resume, and never
comes out of it.
The commit
(d55d15a33: scsi: block: Do not accept any requests while suspended)
adds the check if the queue is in suspended state in blk_queue_enter().

Call trace:
 __switch_to+0x174/0x2c4
 __schedule+0x478/0x764
 schedule+0x9c/0xe0
 blk_queue_enter+0x158/0x228
 blk_mq_alloc_request+0x40/0xa4
 blk_get_request+0x2c/0x70
 __scsi_execute+0x60/0x1c4
 ufshcd_set_dev_pwr_mode+0x124/0x1e4
 ufshcd_suspend+0x208/0x83c
 ufshcd_runtime_suspend+0x40/0x154
 ufshcd_pltfrm_runtime_suspend+0x14/0x20
 pm_generic_runtime_suspend+0x28/0x3c
 __rpm_callback+0x80/0x2a4
 rpm_suspend+0x308/0x614
 rpm_idle+0x158/0x228
 pm_runtime_work+0x84/0xac
 process_one_work+0x1f0/0x470
 worker_thread+0x26c/0x4c8
 kthread+0x13c/0x320
 ret_from_fork+0x10/0x18

Fix this by registering ufs device wlun as a scsi driver and
registering it for block runtime-pm. Also make this as a
supplier for all other luns. That way, this device wlun
suspends after all the consumers and resumes after
hba resumes.

Co-developed-by: Can Guo 
Signed-off-by: Can Guo 
Signed-off-by: Asutosh Das 
---
 drivers/scsi/ufs/cdns-pltfrm.c |   2 +
 drivers/scsi/ufs/tc-dwc-g210-pci.c |   2 +
 drivers/scsi/ufs/ufs-exynos.c  |   2 +
 drivers/scsi/ufs/ufs-hisi.c|   2 +
 drivers/scsi/ufs/ufs-mediatek.c|   2 +
 drivers/scsi/ufs/ufs-qcom.c|   2 +
 drivers/scsi/ufs/ufshcd-pci.c  |  26 +-
 drivers/scsi/ufs/ufshcd.c  | 532 ++---
 drivers/scsi/ufs/ufshcd.h  |   7 +
 include/trace/events/ufs.h |  20 ++
 10 files changed, 476 insertions(+), 121 deletions(-)

diff --git a/drivers/scsi/ufs/cdns-pltfrm.c b/drivers/scsi/ufs/cdns-pltfrm.c
index 149391f..3e70c23 100644
--- a/drivers/scsi/ufs/cdns-pltfrm.c
+++ b/drivers/scsi/ufs/cdns-pltfrm.c
@@ -319,6 +319,8 @@ static const struct dev_pm_ops cdns_ufs_dev_pm_ops = {
.runtime_suspend = ufshcd_pltfrm_runtime_suspend,
.runtime_resume  = ufshcd_pltfrm_runtime_resume,
.runtime_idle= ufshcd_pltfrm_runtime_idle,
+   .prepare = ufshcd_suspend_prepare,
+   .complete   = ufshcd_resume_complete,
 };

 static struct platform_driver cdns_ufs_pltfrm_driver = {
diff --git a/drivers/scsi/ufs/tc-dwc-g210-pci.c 
b/drivers/scsi/ufs/tc-dwc-g210-pci.c
index 67a6a61..b01db12 100644
--- a/drivers/scsi/ufs/tc-dwc-g210-pci.c
+++ b/drivers/scsi/ufs/tc-dwc-g210-pci.c
@@ -148,6 +148,8 @@ static const struct dev_pm_ops tc_dwc_g210_pci_pm_ops = {
.runtime_suspend = tc_dwc_g210_pci_runtime_suspend,
.runtime_resume  = tc_dwc_g210_pci_runtime_resume,
.runtime_idle= tc_dwc_g210_pci_runtime_idle,
+   .prepare = ufshcd_suspend_prepare,
+   .complete   = ufshcd_resume_complete,
 };

 static const struct pci_device_id tc_dwc_g210_pci_tbl[] = {
diff --git a/drivers/scsi/ufs/ufs-exynos.c b/drivers/scsi/ufs/ufs-exynos.c
index 267943a1..45c0b02 100644
--- a/drivers/scsi/ufs/ufs-exynos.c
+++ b/drivers/scsi/ufs/ufs-exynos.c
@@ -1268,6 +1268,8 @@ static const struct dev_pm_ops exynos_ufs_pm_ops = {
.runtime_suspend = ufshcd_pltfrm_runtime_suspend,
.runtime_resume  = ufshcd_pltfrm_runtime_resume,
.runtime_idle= ufshcd_pltfrm_runtime_idle,
+   .prepare = ufshcd_suspend_prepare,
+   .complete   = ufshcd_resume_complete,
 };

 static struct platform_driver exynos_ufs_pltform = {
diff --git a/drivers/scsi/ufs/ufs-hisi.c b/drivers/scsi/ufs/ufs-hisi.c
index 0aa5813..d463b44 100644
--- a/drivers/scsi/ufs/ufs-hisi.c
+++ b/drivers/scsi/ufs/ufs-hisi.c
@@ -574,6 +574,8 @@ static const struct dev_pm_ops ufs_hisi_pm_ops = {
.runtime_suspend = ufshcd_pltfrm_runtime_suspend,
.runtime_resume  = ufshcd_pltfrm_runtime_resume,
.runtime_idle= ufshcd_pltfrm_runtime_idle,
+   .prepare = ufshcd_suspend_prepare,
+   .complete   = ufshcd_resume_complete,
 };

 static struct platform_driver ufs_hisi_pltform = {
diff --git a/drivers/scsi/ufs/ufs-mediatek.c b/drivers/scsi/ufs/ufs-mediatek.c
index c55202b..df1eabb 100644
--- a/drivers/scsi/ufs/ufs-mediatek.c
+++ b/drivers/scsi/ufs/ufs-mediatek.c
@@ -1097,6 +1097,8 @@ static const struct dev_pm_ops ufs_mtk_pm_ops = {
.runtime_suspend = ufshcd_pltfrm_runtime_suspend,
.runtime_resume  = ufshcd_pltfrm_runtime_resume,
.runtime_idle= ufshcd_pltfrm_runtime_idle,
+   .prepare = ufshcd_suspend_prepare,
+   .complete   = ufshcd_resume_complete,
 };

 static struct platform_driver ufs_mtk_pltform = {
diff --git a/drivers/scsi/ufs/ufs

[PATCH v7 1/2] scsi: ufs: Enable power management for wlun

2021-02-24 Thread Asutosh Das
During runtime-suspend of ufs host, the scsi devices are
already suspended and so are the queues associated with them.
But the ufs host sends SSU to wlun during its runtime-suspend.
During the process blk_queue_enter checks if the queue is not in
suspended state. If so, it waits for the queue to resume, and never
comes out of it.
The commit
(d55d15a33: scsi: block: Do not accept any requests while suspended)
adds the check if the queue is in suspended state in blk_queue_enter().

Call trace:
 __switch_to+0x174/0x2c4
 __schedule+0x478/0x764
 schedule+0x9c/0xe0
 blk_queue_enter+0x158/0x228
 blk_mq_alloc_request+0x40/0xa4
 blk_get_request+0x2c/0x70
 __scsi_execute+0x60/0x1c4
 ufshcd_set_dev_pwr_mode+0x124/0x1e4
 ufshcd_suspend+0x208/0x83c
 ufshcd_runtime_suspend+0x40/0x154
 ufshcd_pltfrm_runtime_suspend+0x14/0x20
 pm_generic_runtime_suspend+0x28/0x3c
 __rpm_callback+0x80/0x2a4
 rpm_suspend+0x308/0x614
 rpm_idle+0x158/0x228
 pm_runtime_work+0x84/0xac
 process_one_work+0x1f0/0x470
 worker_thread+0x26c/0x4c8
 kthread+0x13c/0x320
 ret_from_fork+0x10/0x18

Fix this by registering ufs device wlun as a scsi driver and
registering it for block runtime-pm. Also make this as a
supplier for all other luns. That way, this device wlun
suspends after all the consumers and resumes after
hba resumes.

Co-developed-by: Can Guo 
Signed-off-by: Can Guo 
Signed-off-by: Asutosh Das 
---
 drivers/scsi/ufs/cdns-pltfrm.c |   2 +
 drivers/scsi/ufs/tc-dwc-g210-pci.c |   2 +
 drivers/scsi/ufs/ufs-exynos.c  |   2 +
 drivers/scsi/ufs/ufs-hisi.c|   2 +
 drivers/scsi/ufs/ufs-mediatek.c|   2 +
 drivers/scsi/ufs/ufs-qcom.c|   2 +
 drivers/scsi/ufs/ufshcd-pci.c  |  26 +-
 drivers/scsi/ufs/ufshcd.c  | 532 ++---
 drivers/scsi/ufs/ufshcd.h  |   7 +
 include/trace/events/ufs.h |  20 ++
 10 files changed, 476 insertions(+), 121 deletions(-)

diff --git a/drivers/scsi/ufs/cdns-pltfrm.c b/drivers/scsi/ufs/cdns-pltfrm.c
index 149391f..3e70c23 100644
--- a/drivers/scsi/ufs/cdns-pltfrm.c
+++ b/drivers/scsi/ufs/cdns-pltfrm.c
@@ -319,6 +319,8 @@ static const struct dev_pm_ops cdns_ufs_dev_pm_ops = {
.runtime_suspend = ufshcd_pltfrm_runtime_suspend,
.runtime_resume  = ufshcd_pltfrm_runtime_resume,
.runtime_idle= ufshcd_pltfrm_runtime_idle,
+   .prepare = ufshcd_suspend_prepare,
+   .complete   = ufshcd_resume_complete,
 };
 
 static struct platform_driver cdns_ufs_pltfrm_driver = {
diff --git a/drivers/scsi/ufs/tc-dwc-g210-pci.c 
b/drivers/scsi/ufs/tc-dwc-g210-pci.c
index 67a6a61..b01db12 100644
--- a/drivers/scsi/ufs/tc-dwc-g210-pci.c
+++ b/drivers/scsi/ufs/tc-dwc-g210-pci.c
@@ -148,6 +148,8 @@ static const struct dev_pm_ops tc_dwc_g210_pci_pm_ops = {
.runtime_suspend = tc_dwc_g210_pci_runtime_suspend,
.runtime_resume  = tc_dwc_g210_pci_runtime_resume,
.runtime_idle= tc_dwc_g210_pci_runtime_idle,
+   .prepare = ufshcd_suspend_prepare,
+   .complete   = ufshcd_resume_complete,
 };
 
 static const struct pci_device_id tc_dwc_g210_pci_tbl[] = {
diff --git a/drivers/scsi/ufs/ufs-exynos.c b/drivers/scsi/ufs/ufs-exynos.c
index 267943a1..45c0b02 100644
--- a/drivers/scsi/ufs/ufs-exynos.c
+++ b/drivers/scsi/ufs/ufs-exynos.c
@@ -1268,6 +1268,8 @@ static const struct dev_pm_ops exynos_ufs_pm_ops = {
.runtime_suspend = ufshcd_pltfrm_runtime_suspend,
.runtime_resume  = ufshcd_pltfrm_runtime_resume,
.runtime_idle= ufshcd_pltfrm_runtime_idle,
+   .prepare = ufshcd_suspend_prepare,
+   .complete   = ufshcd_resume_complete,
 };
 
 static struct platform_driver exynos_ufs_pltform = {
diff --git a/drivers/scsi/ufs/ufs-hisi.c b/drivers/scsi/ufs/ufs-hisi.c
index 0aa5813..d463b44 100644
--- a/drivers/scsi/ufs/ufs-hisi.c
+++ b/drivers/scsi/ufs/ufs-hisi.c
@@ -574,6 +574,8 @@ static const struct dev_pm_ops ufs_hisi_pm_ops = {
.runtime_suspend = ufshcd_pltfrm_runtime_suspend,
.runtime_resume  = ufshcd_pltfrm_runtime_resume,
.runtime_idle= ufshcd_pltfrm_runtime_idle,
+   .prepare = ufshcd_suspend_prepare,
+   .complete   = ufshcd_resume_complete,
 };
 
 static struct platform_driver ufs_hisi_pltform = {
diff --git a/drivers/scsi/ufs/ufs-mediatek.c b/drivers/scsi/ufs/ufs-mediatek.c
index c55202b..df1eabb 100644
--- a/drivers/scsi/ufs/ufs-mediatek.c
+++ b/drivers/scsi/ufs/ufs-mediatek.c
@@ -1097,6 +1097,8 @@ static const struct dev_pm_ops ufs_mtk_pm_ops = {
.runtime_suspend = ufshcd_pltfrm_runtime_suspend,
.runtime_resume  = ufshcd_pltfrm_runtime_resume,
.runtime_idle= ufshcd_pltfrm_runtime_idle,
+   .prepare = ufshcd_suspend_prepare,
+   .complete   = ufshcd_resume_complete,
 };
 
 static struct platform_driver ufs_mtk_pltform = {
diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index f97d7b0..9aa098a 100644
--- a/drivers/scsi/ufs/ufs

[PATCH v7 2/2] ufs: sysfs: Resume the proper scsi device

2021-02-24 Thread Asutosh Das
Resumes the actual scsi device the unit descriptor of which
is being accessed instead of the hba alone.

Signed-off-by: Asutosh Das 
---
 drivers/scsi/ufs/ufs-sysfs.c | 26 +++---
 1 file changed, 15 insertions(+), 11 deletions(-)

diff --git a/drivers/scsi/ufs/ufs-sysfs.c b/drivers/scsi/ufs/ufs-sysfs.c
index acc54f5..34481e3 100644
--- a/drivers/scsi/ufs/ufs-sysfs.c
+++ b/drivers/scsi/ufs/ufs-sysfs.c
@@ -297,10 +297,10 @@ static ssize_t ufs_sysfs_read_desc_param(struct ufs_hba 
*hba,
goto out;
}
 
-   pm_runtime_get_sync(hba->dev);
+   scsi_autopm_get_device(hba->sdev_ufs_device);
ret = ufshcd_read_desc_param(hba, desc_id, desc_index,
param_offset, desc_buf, param_size);
-   pm_runtime_put_sync(hba->dev);
+   scsi_autopm_put_device(hba->sdev_ufs_device);
if (ret) {
ret = -EINVAL;
goto out;
@@ -678,7 +678,7 @@ static ssize_t _name##_show(struct device *dev, 
\
up(>host_sem); \
return -ENOMEM; \
}   \
-   pm_runtime_get_sync(hba->dev);  \
+   scsi_autopm_get_device(hba->sdev_ufs_device);   \
ret = ufshcd_query_descriptor_retry(hba,\
UPIU_QUERY_OPCODE_READ_DESC, QUERY_DESC_IDN_DEVICE, \
0, 0, desc_buf, _len); \
@@ -695,7 +695,7 @@ static ssize_t _name##_show(struct device *dev, 
\
goto out;   \
ret = sysfs_emit(buf, "%s\n", desc_buf);\
 out:   \
-   pm_runtime_put_sync(hba->dev);  \
+   scsi_autopm_put_device(hba->sdev_ufs_device);   \
kfree(desc_buf);\
up(>host_sem); \
return ret; \
@@ -744,10 +744,10 @@ static ssize_t _name##_show(struct device *dev,   
\
}   \
if (ufshcd_is_wb_flags(QUERY_FLAG_IDN##_uname)) \
index = ufshcd_wb_get_query_index(hba); \
-   pm_runtime_get_sync(hba->dev);  \
+   scsi_autopm_get_device(hba->sdev_ufs_device);   \
ret = ufshcd_query_flag(hba, UPIU_QUERY_OPCODE_READ_FLAG,   \
QUERY_FLAG_IDN##_uname, index, );  \
-   pm_runtime_put_sync(hba->dev);  \
+   scsi_autopm_put_device(hba->sdev_ufs_device);   \
if (ret) {  \
ret = -EINVAL;  \
goto out;   \
@@ -813,10 +813,10 @@ static ssize_t _name##_show(struct device *dev,   
\
}   \
if (ufshcd_is_wb_attrs(QUERY_ATTR_IDN##_uname)) \
index = ufshcd_wb_get_query_index(hba); \
-   pm_runtime_get_sync(hba->dev);  \
+   scsi_autopm_get_device(hba->sdev_ufs_device);   \
ret = ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_READ_ATTR,   \
QUERY_ATTR_IDN##_uname, index, 0, );  \
-   pm_runtime_put_sync(hba->dev);  \
+   scsi_autopm_put_device(hba->sdev_ufs_device);   \
if (ret) {  \
ret = -EINVAL;  \
goto out;   \
@@ -899,11 +899,15 @@ static ssize_t _pname##_show(struct device *dev,  
\
struct scsi_device *sdev = to_scsi_device(dev); \
struct ufs_hba *hba = shost_priv(sdev->host);   \
u8 lun = ufshcd_scsi_to_upiu_lun(sdev->lun);\
+   int ret;\
if (!ufs_is_valid_unit_desc_lun(>dev_info, lun,\
_duname##_DESC_PARAM##_puname)) \
return -EINVAL; \
-   return ufs_sysfs_read_desc_p

[PATCH v6 1/2] scsi: ufs: Enable power management for wlun

2021-02-24 Thread Asutosh Das
During runtime-suspend of ufs host, the scsi devices are
already suspended and so are the queues associated with them.
But the ufs host sends SSU to wlun during its runtime-suspend.
During the process blk_queue_enter checks if the queue is not in
suspended state. If so, it waits for the queue to resume, and never
comes out of it.
The commit
(d55d15a33: scsi: block: Do not accept any requests while suspended)
adds the check if the queue is in suspended state in blk_queue_enter().

Call trace:
 __switch_to+0x174/0x2c4
 __schedule+0x478/0x764
 schedule+0x9c/0xe0
 blk_queue_enter+0x158/0x228
 blk_mq_alloc_request+0x40/0xa4
 blk_get_request+0x2c/0x70
 __scsi_execute+0x60/0x1c4
 ufshcd_set_dev_pwr_mode+0x124/0x1e4
 ufshcd_suspend+0x208/0x83c
 ufshcd_runtime_suspend+0x40/0x154
 ufshcd_pltfrm_runtime_suspend+0x14/0x20
 pm_generic_runtime_suspend+0x28/0x3c
 __rpm_callback+0x80/0x2a4
 rpm_suspend+0x308/0x614
 rpm_idle+0x158/0x228
 pm_runtime_work+0x84/0xac
 process_one_work+0x1f0/0x470
 worker_thread+0x26c/0x4c8
 kthread+0x13c/0x320
 ret_from_fork+0x10/0x18

Fix this by registering ufs device wlun as a scsi driver and
registering it for block runtime-pm. Also make this as a
supplier for all other luns. That way, this device wlun
suspends after all the consumers and resumes after
hba resumes.

Co-developed-by: Can Guo 
Signed-off-by: Can Guo 
Signed-off-by: Asutosh Das 
---
 drivers/scsi/ufs/cdns-pltfrm.c |   2 +
 drivers/scsi/ufs/tc-dwc-g210-pci.c |   2 +
 drivers/scsi/ufs/ufs-exynos.c  |   2 +
 drivers/scsi/ufs/ufs-hisi.c|   2 +
 drivers/scsi/ufs/ufs-mediatek.c|   2 +
 drivers/scsi/ufs/ufs-qcom.c|   2 +
 drivers/scsi/ufs/ufshcd-pci.c  |  26 +-
 drivers/scsi/ufs/ufshcd.c  | 530 ++---
 drivers/scsi/ufs/ufshcd.h  |   7 +
 include/trace/events/ufs.h |  20 ++
 10 files changed, 474 insertions(+), 121 deletions(-)

diff --git a/drivers/scsi/ufs/cdns-pltfrm.c b/drivers/scsi/ufs/cdns-pltfrm.c
index 149391f..3e70c23 100644
--- a/drivers/scsi/ufs/cdns-pltfrm.c
+++ b/drivers/scsi/ufs/cdns-pltfrm.c
@@ -319,6 +319,8 @@ static const struct dev_pm_ops cdns_ufs_dev_pm_ops = {
.runtime_suspend = ufshcd_pltfrm_runtime_suspend,
.runtime_resume  = ufshcd_pltfrm_runtime_resume,
.runtime_idle= ufshcd_pltfrm_runtime_idle,
+   .prepare = ufshcd_suspend_prepare,
+   .complete   = ufshcd_resume_complete,
 };
 
 static struct platform_driver cdns_ufs_pltfrm_driver = {
diff --git a/drivers/scsi/ufs/tc-dwc-g210-pci.c 
b/drivers/scsi/ufs/tc-dwc-g210-pci.c
index 67a6a61..b01db12 100644
--- a/drivers/scsi/ufs/tc-dwc-g210-pci.c
+++ b/drivers/scsi/ufs/tc-dwc-g210-pci.c
@@ -148,6 +148,8 @@ static const struct dev_pm_ops tc_dwc_g210_pci_pm_ops = {
.runtime_suspend = tc_dwc_g210_pci_runtime_suspend,
.runtime_resume  = tc_dwc_g210_pci_runtime_resume,
.runtime_idle= tc_dwc_g210_pci_runtime_idle,
+   .prepare = ufshcd_suspend_prepare,
+   .complete   = ufshcd_resume_complete,
 };
 
 static const struct pci_device_id tc_dwc_g210_pci_tbl[] = {
diff --git a/drivers/scsi/ufs/ufs-exynos.c b/drivers/scsi/ufs/ufs-exynos.c
index 267943a1..45c0b02 100644
--- a/drivers/scsi/ufs/ufs-exynos.c
+++ b/drivers/scsi/ufs/ufs-exynos.c
@@ -1268,6 +1268,8 @@ static const struct dev_pm_ops exynos_ufs_pm_ops = {
.runtime_suspend = ufshcd_pltfrm_runtime_suspend,
.runtime_resume  = ufshcd_pltfrm_runtime_resume,
.runtime_idle= ufshcd_pltfrm_runtime_idle,
+   .prepare = ufshcd_suspend_prepare,
+   .complete   = ufshcd_resume_complete,
 };
 
 static struct platform_driver exynos_ufs_pltform = {
diff --git a/drivers/scsi/ufs/ufs-hisi.c b/drivers/scsi/ufs/ufs-hisi.c
index 0aa5813..d463b44 100644
--- a/drivers/scsi/ufs/ufs-hisi.c
+++ b/drivers/scsi/ufs/ufs-hisi.c
@@ -574,6 +574,8 @@ static const struct dev_pm_ops ufs_hisi_pm_ops = {
.runtime_suspend = ufshcd_pltfrm_runtime_suspend,
.runtime_resume  = ufshcd_pltfrm_runtime_resume,
.runtime_idle= ufshcd_pltfrm_runtime_idle,
+   .prepare = ufshcd_suspend_prepare,
+   .complete   = ufshcd_resume_complete,
 };
 
 static struct platform_driver ufs_hisi_pltform = {
diff --git a/drivers/scsi/ufs/ufs-mediatek.c b/drivers/scsi/ufs/ufs-mediatek.c
index c55202b..df1eabb 100644
--- a/drivers/scsi/ufs/ufs-mediatek.c
+++ b/drivers/scsi/ufs/ufs-mediatek.c
@@ -1097,6 +1097,8 @@ static const struct dev_pm_ops ufs_mtk_pm_ops = {
.runtime_suspend = ufshcd_pltfrm_runtime_suspend,
.runtime_resume  = ufshcd_pltfrm_runtime_resume,
.runtime_idle= ufshcd_pltfrm_runtime_idle,
+   .prepare = ufshcd_suspend_prepare,
+   .complete   = ufshcd_resume_complete,
 };
 
 static struct platform_driver ufs_mtk_pltform = {
diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index f97d7b0..9aa098a 100644
--- a/drivers/scsi/ufs/ufs

[PATCH v6 2/2] ufs: sysfs: Resume the proper scsi device

2021-02-24 Thread Asutosh Das
Resumes the actual scsi device the unit descriptor of which
is being accessed instead of the hba alone.

Signed-off-by: Asutosh Das 
---
 drivers/scsi/ufs/ufs-sysfs.c | 26 +++---
 1 file changed, 15 insertions(+), 11 deletions(-)

diff --git a/drivers/scsi/ufs/ufs-sysfs.c b/drivers/scsi/ufs/ufs-sysfs.c
index acc54f5..34481e3 100644
--- a/drivers/scsi/ufs/ufs-sysfs.c
+++ b/drivers/scsi/ufs/ufs-sysfs.c
@@ -297,10 +297,10 @@ static ssize_t ufs_sysfs_read_desc_param(struct ufs_hba 
*hba,
goto out;
}
 
-   pm_runtime_get_sync(hba->dev);
+   scsi_autopm_get_device(hba->sdev_ufs_device);
ret = ufshcd_read_desc_param(hba, desc_id, desc_index,
param_offset, desc_buf, param_size);
-   pm_runtime_put_sync(hba->dev);
+   scsi_autopm_put_device(hba->sdev_ufs_device);
if (ret) {
ret = -EINVAL;
goto out;
@@ -678,7 +678,7 @@ static ssize_t _name##_show(struct device *dev, 
\
up(>host_sem); \
return -ENOMEM; \
}   \
-   pm_runtime_get_sync(hba->dev);  \
+   scsi_autopm_get_device(hba->sdev_ufs_device);   \
ret = ufshcd_query_descriptor_retry(hba,\
UPIU_QUERY_OPCODE_READ_DESC, QUERY_DESC_IDN_DEVICE, \
0, 0, desc_buf, _len); \
@@ -695,7 +695,7 @@ static ssize_t _name##_show(struct device *dev, 
\
goto out;   \
ret = sysfs_emit(buf, "%s\n", desc_buf);\
 out:   \
-   pm_runtime_put_sync(hba->dev);  \
+   scsi_autopm_put_device(hba->sdev_ufs_device);   \
kfree(desc_buf);\
up(>host_sem); \
return ret; \
@@ -744,10 +744,10 @@ static ssize_t _name##_show(struct device *dev,   
\
}   \
if (ufshcd_is_wb_flags(QUERY_FLAG_IDN##_uname)) \
index = ufshcd_wb_get_query_index(hba); \
-   pm_runtime_get_sync(hba->dev);  \
+   scsi_autopm_get_device(hba->sdev_ufs_device);   \
ret = ufshcd_query_flag(hba, UPIU_QUERY_OPCODE_READ_FLAG,   \
QUERY_FLAG_IDN##_uname, index, );  \
-   pm_runtime_put_sync(hba->dev);  \
+   scsi_autopm_put_device(hba->sdev_ufs_device);   \
if (ret) {  \
ret = -EINVAL;  \
goto out;   \
@@ -813,10 +813,10 @@ static ssize_t _name##_show(struct device *dev,   
\
}   \
if (ufshcd_is_wb_attrs(QUERY_ATTR_IDN##_uname)) \
index = ufshcd_wb_get_query_index(hba); \
-   pm_runtime_get_sync(hba->dev);  \
+   scsi_autopm_get_device(hba->sdev_ufs_device);   \
ret = ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_READ_ATTR,   \
QUERY_ATTR_IDN##_uname, index, 0, );  \
-   pm_runtime_put_sync(hba->dev);  \
+   scsi_autopm_put_device(hba->sdev_ufs_device);   \
if (ret) {  \
ret = -EINVAL;  \
goto out;   \
@@ -899,11 +899,15 @@ static ssize_t _pname##_show(struct device *dev,  
\
struct scsi_device *sdev = to_scsi_device(dev); \
struct ufs_hba *hba = shost_priv(sdev->host);   \
u8 lun = ufshcd_scsi_to_upiu_lun(sdev->lun);\
+   int ret;\
if (!ufs_is_valid_unit_desc_lun(>dev_info, lun,\
_duname##_DESC_PARAM##_puname)) \
return -EINVAL; \
-   return ufs_sysfs_read_desc_p

Re: [PATCH v5 1/2] scsi: ufs: Enable power management for wlun

2021-02-24 Thread Asutosh Das

On Wed, Feb 24 2021 at 06:34 -0800, Adrian Hunter wrote:

On 24/02/21 7:13 am, Asutosh Das wrote:

During runtime-suspend of ufs host, the scsi devices are
already suspended and so are the queues associated with them.
But the ufs host sends SSU to wlun during its runtime-suspend.
During the process blk_queue_enter checks if the queue is not in
suspended state. If so, it waits for the queue to resume, and never
comes out of it.
The commit
(d55d15a33: scsi: block: Do not accept any requests while suspended)
adds the check if the queue is in suspended state in blk_queue_enter().

Call trace:
 __switch_to+0x174/0x2c4
 __schedule+0x478/0x764
 schedule+0x9c/0xe0
 blk_queue_enter+0x158/0x228
 blk_mq_alloc_request+0x40/0xa4
 blk_get_request+0x2c/0x70
 __scsi_execute+0x60/0x1c4
 ufshcd_set_dev_pwr_mode+0x124/0x1e4
 ufshcd_suspend+0x208/0x83c
 ufshcd_runtime_suspend+0x40/0x154
 ufshcd_pltfrm_runtime_suspend+0x14/0x20
 pm_generic_runtime_suspend+0x28/0x3c
 __rpm_callback+0x80/0x2a4
 rpm_suspend+0x308/0x614
 rpm_idle+0x158/0x228
 pm_runtime_work+0x84/0xac
 process_one_work+0x1f0/0x470
 worker_thread+0x26c/0x4c8
 kthread+0x13c/0x320
 ret_from_fork+0x10/0x18

Fix this by registering ufs device wlun as a scsi driver and
registering it for block runtime-pm. Also make this as a
supplier for all other luns. That way, this device wlun
suspends after all the consumers and resumes after
hba resumes.

Co-developed-by: Can Guo 
Signed-off-by: Can Guo 
Signed-off-by: Asutosh Das 
---
 drivers/scsi/ufs/ufs-qcom.c  |   2 +
 drivers/scsi/ufs/ufshcd-pci.c|  24 --
 drivers/scsi/ufs/ufshcd-pltfrm.c |  29 +++
 drivers/scsi/ufs/ufshcd-pltfrm.h |   4 +
 drivers/scsi/ufs/ufshcd.c| 491 +++
 drivers/scsi/ufs/ufshcd.h|   5 +
 include/trace/events/ufs.h   |  20 ++
 7 files changed, 454 insertions(+), 121 deletions(-)

diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index f97d7b0..8cd8cfd 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -1546,6 +1546,8 @@ static const struct dev_pm_ops ufs_qcom_pm_ops = {
.runtime_suspend = ufshcd_pltfrm_runtime_suspend,
.runtime_resume  = ufshcd_pltfrm_runtime_resume,
.runtime_idle= ufshcd_pltfrm_runtime_idle,
+   .prepare= ufshcd_pltfrm_prepare,
+   .resume_early   = ufshcd_pltfrm_resume_early,


Hi Adrian,
Thanks for the detailed review and code pointers.
Appreciate it.



The pair for the "prepare" callback is the "complete" callback rather than
"resume_early"


Ok. I'll check the complete. The idea was to enable runtime-pm before resuming.


Presumably all drivers will need this kind of change.


 };

Yes. I'll make the changes.



 static struct platform_driver ufs_qcom_pltform = {
diff --git a/drivers/scsi/ufs/ufshcd-pci.c b/drivers/scsi/ufs/ufshcd-pci.c
index fadd566..ab84d56 100644
--- a/drivers/scsi/ufs/ufshcd-pci.c
+++ b/drivers/scsi/ufs/ufshcd-pci.c
@@ -247,29 +247,6 @@ static int ufshcd_pci_resume(struct device *dev)
return ufshcd_system_resume(dev_get_drvdata(dev));
 }

-/**
- * ufshcd_pci_poweroff - suspend-to-disk poweroff function
- * @dev: pointer to PCI device handle
- *
- * Returns 0 if successful
- * Returns non-zero otherwise
- */
-static int ufshcd_pci_poweroff(struct device *dev)
-{
-   struct ufs_hba *hba = dev_get_drvdata(dev);
-   int spm_lvl = hba->spm_lvl;
-   int ret;
-
-   /*
-* For poweroff we need to set the UFS device to PowerDown mode.
-* Force spm_lvl to ensure that.
-*/
-   hba->spm_lvl = 5;
-   ret = ufshcd_system_suspend(hba);
-   hba->spm_lvl = spm_lvl;
-   return ret;
-}
-
 #endif /* !CONFIG_PM_SLEEP */

 #ifdef CONFIG_PM
@@ -370,7 +347,6 @@ static const struct dev_pm_ops ufshcd_pci_pm_ops = {
.resume = ufshcd_pci_resume,
.freeze = ufshcd_pci_suspend,
.thaw   = ufshcd_pci_resume,
-   .poweroff   = ufshcd_pci_poweroff,
.restore= ufshcd_pci_resume,
 #endif
SET_RUNTIME_PM_OPS(ufshcd_pci_runtime_suspend,
diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
index 1a69949..84550dc 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -217,6 +217,35 @@ int ufshcd_pltfrm_runtime_idle(struct device *dev)
 }
 EXPORT_SYMBOL_GPL(ufshcd_pltfrm_runtime_idle);

+int ufshcd_pltfrm_prepare(struct device *dev)
+{
+   struct ufs_hba *hba = dev_get_drvdata(dev);
+
+   /*
+* SCSI assumes that runtime-pm and system-pm for scsi drivers
+* are same. And it doesn't wake up the device for system-suspend
+* if it's runtime suspended. But ufs doesn't follow that.
+* The rpm-lvl and spm-lvl can be different in ufs.
+* Force it to honor system-suspend.


Presumably we could check whether the current power mode is different from
the spm_lvl target po

[PATCH v5 2/2] ufs: sysfs: Resume the proper scsi device

2021-02-23 Thread Asutosh Das
Resumes the actual scsi device the unit descriptor of which
is being accessed instead of the hba alone.

Signed-off-by: Asutosh Das 
---
 drivers/scsi/ufs/ufs-sysfs.c | 26 +++---
 1 file changed, 15 insertions(+), 11 deletions(-)

diff --git a/drivers/scsi/ufs/ufs-sysfs.c b/drivers/scsi/ufs/ufs-sysfs.c
index acc54f5..34481e3 100644
--- a/drivers/scsi/ufs/ufs-sysfs.c
+++ b/drivers/scsi/ufs/ufs-sysfs.c
@@ -297,10 +297,10 @@ static ssize_t ufs_sysfs_read_desc_param(struct ufs_hba 
*hba,
goto out;
}
 
-   pm_runtime_get_sync(hba->dev);
+   scsi_autopm_get_device(hba->sdev_ufs_device);
ret = ufshcd_read_desc_param(hba, desc_id, desc_index,
param_offset, desc_buf, param_size);
-   pm_runtime_put_sync(hba->dev);
+   scsi_autopm_put_device(hba->sdev_ufs_device);
if (ret) {
ret = -EINVAL;
goto out;
@@ -678,7 +678,7 @@ static ssize_t _name##_show(struct device *dev, 
\
up(>host_sem); \
return -ENOMEM; \
}   \
-   pm_runtime_get_sync(hba->dev);  \
+   scsi_autopm_get_device(hba->sdev_ufs_device);   \
ret = ufshcd_query_descriptor_retry(hba,\
UPIU_QUERY_OPCODE_READ_DESC, QUERY_DESC_IDN_DEVICE, \
0, 0, desc_buf, _len); \
@@ -695,7 +695,7 @@ static ssize_t _name##_show(struct device *dev, 
\
goto out;   \
ret = sysfs_emit(buf, "%s\n", desc_buf);\
 out:   \
-   pm_runtime_put_sync(hba->dev);  \
+   scsi_autopm_put_device(hba->sdev_ufs_device);   \
kfree(desc_buf);\
up(>host_sem); \
return ret; \
@@ -744,10 +744,10 @@ static ssize_t _name##_show(struct device *dev,   
\
}   \
if (ufshcd_is_wb_flags(QUERY_FLAG_IDN##_uname)) \
index = ufshcd_wb_get_query_index(hba); \
-   pm_runtime_get_sync(hba->dev);  \
+   scsi_autopm_get_device(hba->sdev_ufs_device);   \
ret = ufshcd_query_flag(hba, UPIU_QUERY_OPCODE_READ_FLAG,   \
QUERY_FLAG_IDN##_uname, index, );  \
-   pm_runtime_put_sync(hba->dev);  \
+   scsi_autopm_put_device(hba->sdev_ufs_device);   \
if (ret) {  \
ret = -EINVAL;  \
goto out;   \
@@ -813,10 +813,10 @@ static ssize_t _name##_show(struct device *dev,   
\
}   \
if (ufshcd_is_wb_attrs(QUERY_ATTR_IDN##_uname)) \
index = ufshcd_wb_get_query_index(hba); \
-   pm_runtime_get_sync(hba->dev);  \
+   scsi_autopm_get_device(hba->sdev_ufs_device);   \
ret = ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_READ_ATTR,   \
QUERY_ATTR_IDN##_uname, index, 0, );  \
-   pm_runtime_put_sync(hba->dev);  \
+   scsi_autopm_put_device(hba->sdev_ufs_device);   \
if (ret) {  \
ret = -EINVAL;  \
goto out;   \
@@ -899,11 +899,15 @@ static ssize_t _pname##_show(struct device *dev,  
\
struct scsi_device *sdev = to_scsi_device(dev); \
struct ufs_hba *hba = shost_priv(sdev->host);   \
u8 lun = ufshcd_scsi_to_upiu_lun(sdev->lun);\
+   int ret;\
if (!ufs_is_valid_unit_desc_lun(>dev_info, lun,\
_duname##_DESC_PARAM##_puname)) \
return -EINVAL; \
-   return ufs_sysfs_read_desc_p

[PATCH v5 1/2] scsi: ufs: Enable power management for wlun

2021-02-23 Thread Asutosh Das
During runtime-suspend of ufs host, the scsi devices are
already suspended and so are the queues associated with them.
But the ufs host sends SSU to wlun during its runtime-suspend.
During the process blk_queue_enter checks if the queue is not in
suspended state. If so, it waits for the queue to resume, and never
comes out of it.
The commit
(d55d15a33: scsi: block: Do not accept any requests while suspended)
adds the check if the queue is in suspended state in blk_queue_enter().

Call trace:
 __switch_to+0x174/0x2c4
 __schedule+0x478/0x764
 schedule+0x9c/0xe0
 blk_queue_enter+0x158/0x228
 blk_mq_alloc_request+0x40/0xa4
 blk_get_request+0x2c/0x70
 __scsi_execute+0x60/0x1c4
 ufshcd_set_dev_pwr_mode+0x124/0x1e4
 ufshcd_suspend+0x208/0x83c
 ufshcd_runtime_suspend+0x40/0x154
 ufshcd_pltfrm_runtime_suspend+0x14/0x20
 pm_generic_runtime_suspend+0x28/0x3c
 __rpm_callback+0x80/0x2a4
 rpm_suspend+0x308/0x614
 rpm_idle+0x158/0x228
 pm_runtime_work+0x84/0xac
 process_one_work+0x1f0/0x470
 worker_thread+0x26c/0x4c8
 kthread+0x13c/0x320
 ret_from_fork+0x10/0x18

Fix this by registering ufs device wlun as a scsi driver and
registering it for block runtime-pm. Also make this as a
supplier for all other luns. That way, this device wlun
suspends after all the consumers and resumes after
hba resumes.

Co-developed-by: Can Guo 
Signed-off-by: Can Guo 
Signed-off-by: Asutosh Das 
---
 drivers/scsi/ufs/ufs-qcom.c  |   2 +
 drivers/scsi/ufs/ufshcd-pci.c|  24 --
 drivers/scsi/ufs/ufshcd-pltfrm.c |  29 +++
 drivers/scsi/ufs/ufshcd-pltfrm.h |   4 +
 drivers/scsi/ufs/ufshcd.c| 491 +++
 drivers/scsi/ufs/ufshcd.h|   5 +
 include/trace/events/ufs.h   |  20 ++
 7 files changed, 454 insertions(+), 121 deletions(-)

diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index f97d7b0..8cd8cfd 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -1546,6 +1546,8 @@ static const struct dev_pm_ops ufs_qcom_pm_ops = {
.runtime_suspend = ufshcd_pltfrm_runtime_suspend,
.runtime_resume  = ufshcd_pltfrm_runtime_resume,
.runtime_idle= ufshcd_pltfrm_runtime_idle,
+   .prepare= ufshcd_pltfrm_prepare,
+   .resume_early   = ufshcd_pltfrm_resume_early,
 };
 
 static struct platform_driver ufs_qcom_pltform = {
diff --git a/drivers/scsi/ufs/ufshcd-pci.c b/drivers/scsi/ufs/ufshcd-pci.c
index fadd566..ab84d56 100644
--- a/drivers/scsi/ufs/ufshcd-pci.c
+++ b/drivers/scsi/ufs/ufshcd-pci.c
@@ -247,29 +247,6 @@ static int ufshcd_pci_resume(struct device *dev)
return ufshcd_system_resume(dev_get_drvdata(dev));
 }
 
-/**
- * ufshcd_pci_poweroff - suspend-to-disk poweroff function
- * @dev: pointer to PCI device handle
- *
- * Returns 0 if successful
- * Returns non-zero otherwise
- */
-static int ufshcd_pci_poweroff(struct device *dev)
-{
-   struct ufs_hba *hba = dev_get_drvdata(dev);
-   int spm_lvl = hba->spm_lvl;
-   int ret;
-
-   /*
-* For poweroff we need to set the UFS device to PowerDown mode.
-* Force spm_lvl to ensure that.
-*/
-   hba->spm_lvl = 5;
-   ret = ufshcd_system_suspend(hba);
-   hba->spm_lvl = spm_lvl;
-   return ret;
-}
-
 #endif /* !CONFIG_PM_SLEEP */
 
 #ifdef CONFIG_PM
@@ -370,7 +347,6 @@ static const struct dev_pm_ops ufshcd_pci_pm_ops = {
.resume = ufshcd_pci_resume,
.freeze = ufshcd_pci_suspend,
.thaw   = ufshcd_pci_resume,
-   .poweroff   = ufshcd_pci_poweroff,
.restore= ufshcd_pci_resume,
 #endif
SET_RUNTIME_PM_OPS(ufshcd_pci_runtime_suspend,
diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
index 1a69949..84550dc 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -217,6 +217,35 @@ int ufshcd_pltfrm_runtime_idle(struct device *dev)
 }
 EXPORT_SYMBOL_GPL(ufshcd_pltfrm_runtime_idle);
 
+int ufshcd_pltfrm_prepare(struct device *dev)
+{
+   struct ufs_hba *hba = dev_get_drvdata(dev);
+
+   /*
+* SCSI assumes that runtime-pm and system-pm for scsi drivers
+* are same. And it doesn't wake up the device for system-suspend
+* if it's runtime suspended. But ufs doesn't follow that.
+* The rpm-lvl and spm-lvl can be different in ufs.
+* Force it to honor system-suspend.
+*/
+   scsi_autopm_get_device(hba->sdev_ufs_device);
+   /* Refer ufshcd_pltfrm_resume_early() */
+   pm_runtime_get_noresume(>sdev_ufs_device->sdev_gendev);
+   scsi_autopm_put_device(hba->sdev_ufs_device);
+
+   return 0;
+}
+EXPORT_SYMBOL_GPL(ufshcd_pltfrm_prepare);
+
+int ufshcd_pltfrm_resume_early(struct device *dev)
+{
+   struct ufs_hba *hba = dev_get_drvdata(dev);
+
+   pm_runtime_put_noidle(>sdev_ufs_device->sdev_gendev);
+
+   return 0;
+}
+EXPORT_SYMBOL_GPL(ufshcd_pltfrm_resume_early);
 #en

Re: [PATCH v4 1/2] scsi: ufs: Enable power management for wlun

2021-02-23 Thread Asutosh Das

On Tue, Feb 23 2021 at 12:23 -0800, Adrian Hunter wrote:

On 23/02/21 1:04 am, Asutosh Das wrote:

During runtime-suspend of ufs host, the scsi devices are
already suspended and so are the queues associated with them.
But the ufs host sends SSU to wlun during its runtime-suspend.
During the process blk_queue_enter checks if the queue is not in
suspended state. If so, it waits for the queue to resume, and never
comes out of it.
The commit
(d55d15a33: scsi: block: Do not accept any requests while suspended)
adds the check if the queue is in suspended state in blk_queue_enter().

Call trace:
 __switch_to+0x174/0x2c4
 __schedule+0x478/0x764
 schedule+0x9c/0xe0
 blk_queue_enter+0x158/0x228
 blk_mq_alloc_request+0x40/0xa4
 blk_get_request+0x2c/0x70
 __scsi_execute+0x60/0x1c4
 ufshcd_set_dev_pwr_mode+0x124/0x1e4
 ufshcd_suspend+0x208/0x83c
 ufshcd_runtime_suspend+0x40/0x154
 ufshcd_pltfrm_runtime_suspend+0x14/0x20
 pm_generic_runtime_suspend+0x28/0x3c
 __rpm_callback+0x80/0x2a4
 rpm_suspend+0x308/0x614
 rpm_idle+0x158/0x228
 pm_runtime_work+0x84/0xac
 process_one_work+0x1f0/0x470
 worker_thread+0x26c/0x4c8
 kthread+0x13c/0x320
 ret_from_fork+0x10/0x18

Fix this by registering ufs device wlun as a scsi driver and
registering it for block runtime-pm. Also make this as a
supplier for all other luns. That way, this device wlun
suspends after all the consumers and resumes after
hba resumes.


Hi

I have a few more questions and comments.

At a glance it looked to me like the SCSI bus will leave a SCSI device
runtime suspended at system suspend, but UFS device spm_lvl and rpm_lvl need
not be the same.  Do you know how SCSI handles that case?



Co-developed-by: Can Guo 
Signed-off-by: Can Guo 
Signed-off-by: Asutosh Das 
---
 drivers/scsi/ufs/ufshcd.c  | 455 +++--
 drivers/scsi/ufs/ufshcd.h  |   4 +
 include/trace/events/ufs.h |  20 ++
 3 files changed, 382 insertions(+), 97 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 45624c7..1d8044a 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -16,6 +16,7 @@
 #include 
 #include 
 #include 
+#include 
 #include "ufshcd.h"
 #include "ufs_quirks.h"
 #include "unipro.h"
@@ -251,6 +252,11 @@ static int ufshcd_wb_toggle_flush_during_h8(struct ufs_hba 
*hba, bool set);
 static inline int ufshcd_wb_toggle_flush(struct ufs_hba *hba, bool enable);
 static void ufshcd_hba_vreg_set_lpm(struct ufs_hba *hba);
 static void ufshcd_hba_vreg_set_hpm(struct ufs_hba *hba);
+static int ufshcd_wl_runtime_suspend(struct device *dev);
+static int ufshcd_wl_runtime_resume(struct device *dev);
+static int ufshcd_wl_suspend(struct device *dev);
+static int ufshcd_wl_resume(struct device *dev);
+static void ufshcd_wl_shutdown(struct device *dev);

 static inline bool ufshcd_valid_tag(struct ufs_hba *hba, int tag)
 {
@@ -1556,7 +1562,7 @@ static ssize_t ufshcd_clkscale_enable_store(struct device 
*dev,
if (value == hba->clk_scaling.is_enabled)
goto out;

-   pm_runtime_get_sync(hba->dev);
+   scsi_autopm_get_device(hba->sdev_ufs_device);
ufshcd_hold(hba, false);

hba->clk_scaling.is_enabled = value;
@@ -1572,7 +1578,7 @@ static ssize_t ufshcd_clkscale_enable_store(struct device 
*dev,
}

ufshcd_release(hba);
-   pm_runtime_put_sync(hba->dev);
+   scsi_autopm_put_device(hba->sdev_ufs_device);
 out:
up(>host_sem);
return err ? err : count;
@@ -2572,6 +2578,17 @@ static inline u16 ufshcd_upiu_wlun_to_scsi_wlun(u8 
upiu_wlun_id)
return (upiu_wlun_id & ~UFS_UPIU_WLUN_ID) | SCSI_W_LUN_BASE;
 }

+static inline bool is_rpmb_wlun(struct scsi_device *sdev)
+{
+   return (sdev->lun == ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_RPMB_WLUN));
+}
+
+static inline bool is_device_wlun(struct scsi_device *sdev)
+{
+   return (sdev->lun ==
+   ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_UFS_DEVICE_WLUN));
+}
+
 static void ufshcd_init_lrb(struct ufs_hba *hba, struct ufshcd_lrb *lrb, int i)
 {
struct utp_transfer_cmd_desc *cmd_descp = hba->ucdl_base_addr;
@@ -4808,6 +4825,41 @@ static inline void 
ufshcd_get_lu_power_on_wp_status(struct ufs_hba *hba,
 }

 /**
+ * ufshcd_setup_links - associate link b/w device wlun and other luns
+ * @sdev: pointer to SCSI device
+ * @hba: pointer to ufs hba
+ */
+static void ufshcd_setup_links(struct ufs_hba *hba, struct scsi_device *sdev)
+{
+   struct device_link *link;
+
+   /*
+* device wlun is the supplier & rest of the luns are consumers
+* This ensures that device wlun suspends after all other luns.
+*/
+   if (hba->sdev_ufs_device) {
+   link = device_link_add(>sdev_gendev,
+  >sdev_ufs_device->sdev_gendev,
+  DL_FLAG_PM_RUNTIME);
+   if (!link) {

Re: [PATCH v4 1/2] scsi: ufs: Enable power management for wlun

2021-02-23 Thread Asutosh Das

On Tue, Feb 23 2021 at 12:23 -0800, Adrian Hunter wrote:

On 23/02/21 1:04 am, Asutosh Das wrote:

During runtime-suspend of ufs host, the scsi devices are
already suspended and so are the queues associated with them.
But the ufs host sends SSU to wlun during its runtime-suspend.
During the process blk_queue_enter checks if the queue is not in
suspended state. If so, it waits for the queue to resume, and never
comes out of it.
The commit
(d55d15a33: scsi: block: Do not accept any requests while suspended)
adds the check if the queue is in suspended state in blk_queue_enter().

Call trace:
 __switch_to+0x174/0x2c4
 __schedule+0x478/0x764
 schedule+0x9c/0xe0
 blk_queue_enter+0x158/0x228
 blk_mq_alloc_request+0x40/0xa4
 blk_get_request+0x2c/0x70
 __scsi_execute+0x60/0x1c4
 ufshcd_set_dev_pwr_mode+0x124/0x1e4
 ufshcd_suspend+0x208/0x83c
 ufshcd_runtime_suspend+0x40/0x154
 ufshcd_pltfrm_runtime_suspend+0x14/0x20
 pm_generic_runtime_suspend+0x28/0x3c
 __rpm_callback+0x80/0x2a4
 rpm_suspend+0x308/0x614
 rpm_idle+0x158/0x228
 pm_runtime_work+0x84/0xac
 process_one_work+0x1f0/0x470
 worker_thread+0x26c/0x4c8
 kthread+0x13c/0x320
 ret_from_fork+0x10/0x18

Fix this by registering ufs device wlun as a scsi driver and
registering it for block runtime-pm. Also make this as a
supplier for all other luns. That way, this device wlun
suspends after all the consumers and resumes after
hba resumes.


Hi


Hi Adrian

I have a few more questions and comments.


Thanks for the review.
I'll go through your comments and fix it in the next version.


At a glance it looked to me like the SCSI bus will leave a SCSI device
runtime suspended at system suspend, but UFS device spm_lvl and rpm_lvl need
not be the same.  Do you know how SCSI handles that case?



Good point.

Yes, it says that:
/*
 * All the high-level SCSI drivers that implement runtime
 * PM treat runtime suspend, system suspend, and system
 * hibernate nearly identically. In all cases the requirements
 * for runtime suspension are stricter.
 */

It's not true in case of ufs.

I can think of a couple of approaches:

Adding a couple of more cb() to ufs device wlun:
1. .prepare() -> runtime resume the ufs device -> pm_runtime_get_noresume()
2. .resume_early() -> pm_runtime_put_noidle()

Or,

Add a check to SCSI pm such that, should a device expose a capability saying
that it's runtime-pm differs from its system-pm, scsi-pm invokes the said 
device's
system-pm cb(). I'm not sure if this approach would violate any underlying 
assumptions.

Also, I'm not sure which would be a better approach or if there's another 
approach entirely.
Appreciate any insights.



Co-developed-by: Can Guo 
Signed-off-by: Can Guo 
Signed-off-by: Asutosh Das 
---
 drivers/scsi/ufs/ufshcd.c  | 455 +++--
 drivers/scsi/ufs/ufshcd.h  |   4 +
 include/trace/events/ufs.h |  20 ++
 3 files changed, 382 insertions(+), 97 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 45624c7..1d8044a 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -16,6 +16,7 @@
 #include 
 #include 
 #include 
+#include 
 #include "ufshcd.h"
 #include "ufs_quirks.h"
 #include "unipro.h"
@@ -251,6 +252,11 @@ static int ufshcd_wb_toggle_flush_during_h8(struct ufs_hba 
*hba, bool set);
 static inline int ufshcd_wb_toggle_flush(struct ufs_hba *hba, bool enable);
 static void ufshcd_hba_vreg_set_lpm(struct ufs_hba *hba);
 static void ufshcd_hba_vreg_set_hpm(struct ufs_hba *hba);
+static int ufshcd_wl_runtime_suspend(struct device *dev);
+static int ufshcd_wl_runtime_resume(struct device *dev);
+static int ufshcd_wl_suspend(struct device *dev);
+static int ufshcd_wl_resume(struct device *dev);
+static void ufshcd_wl_shutdown(struct device *dev);

 static inline bool ufshcd_valid_tag(struct ufs_hba *hba, int tag)
 {
@@ -1556,7 +1562,7 @@ static ssize_t ufshcd_clkscale_enable_store(struct device 
*dev,
if (value == hba->clk_scaling.is_enabled)
goto out;

-   pm_runtime_get_sync(hba->dev);
+   scsi_autopm_get_device(hba->sdev_ufs_device);
ufshcd_hold(hba, false);

hba->clk_scaling.is_enabled = value;
@@ -1572,7 +1578,7 @@ static ssize_t ufshcd_clkscale_enable_store(struct device 
*dev,
}

ufshcd_release(hba);
-   pm_runtime_put_sync(hba->dev);
+   scsi_autopm_put_device(hba->sdev_ufs_device);
 out:
up(>host_sem);
return err ? err : count;
@@ -2572,6 +2578,17 @@ static inline u16 ufshcd_upiu_wlun_to_scsi_wlun(u8 
upiu_wlun_id)
return (upiu_wlun_id & ~UFS_UPIU_WLUN_ID) | SCSI_W_LUN_BASE;
 }

+static inline bool is_rpmb_wlun(struct scsi_device *sdev)
+{
+   return (sdev->lun == ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_RPMB_WLUN));
+}
+
+static inline bool is_device_wlun(struct scsi_device *sdev)
+{
+   return (sdev->lun ==
+   ufshcd_upiu_wlun_to_scsi_wlun(UFS_UP

[PATCH v4 2/2] ufs: sysfs: Resume the proper scsi device

2021-02-22 Thread Asutosh Das
Resumes the actual scsi device the unit descriptor of which
is being accessed instead of the hba alone.

Signed-off-by: Asutosh Das 
---
 drivers/scsi/ufs/ufs-sysfs.c | 26 +++---
 1 file changed, 15 insertions(+), 11 deletions(-)

diff --git a/drivers/scsi/ufs/ufs-sysfs.c b/drivers/scsi/ufs/ufs-sysfs.c
index acc54f5..34481e3 100644
--- a/drivers/scsi/ufs/ufs-sysfs.c
+++ b/drivers/scsi/ufs/ufs-sysfs.c
@@ -297,10 +297,10 @@ static ssize_t ufs_sysfs_read_desc_param(struct ufs_hba 
*hba,
goto out;
}
 
-   pm_runtime_get_sync(hba->dev);
+   scsi_autopm_get_device(hba->sdev_ufs_device);
ret = ufshcd_read_desc_param(hba, desc_id, desc_index,
param_offset, desc_buf, param_size);
-   pm_runtime_put_sync(hba->dev);
+   scsi_autopm_put_device(hba->sdev_ufs_device);
if (ret) {
ret = -EINVAL;
goto out;
@@ -678,7 +678,7 @@ static ssize_t _name##_show(struct device *dev, 
\
up(>host_sem); \
return -ENOMEM; \
}   \
-   pm_runtime_get_sync(hba->dev);  \
+   scsi_autopm_get_device(hba->sdev_ufs_device);   \
ret = ufshcd_query_descriptor_retry(hba,\
UPIU_QUERY_OPCODE_READ_DESC, QUERY_DESC_IDN_DEVICE, \
0, 0, desc_buf, _len); \
@@ -695,7 +695,7 @@ static ssize_t _name##_show(struct device *dev, 
\
goto out;   \
ret = sysfs_emit(buf, "%s\n", desc_buf);\
 out:   \
-   pm_runtime_put_sync(hba->dev);  \
+   scsi_autopm_put_device(hba->sdev_ufs_device);   \
kfree(desc_buf);\
up(>host_sem); \
return ret; \
@@ -744,10 +744,10 @@ static ssize_t _name##_show(struct device *dev,   
\
}   \
if (ufshcd_is_wb_flags(QUERY_FLAG_IDN##_uname)) \
index = ufshcd_wb_get_query_index(hba); \
-   pm_runtime_get_sync(hba->dev);  \
+   scsi_autopm_get_device(hba->sdev_ufs_device);   \
ret = ufshcd_query_flag(hba, UPIU_QUERY_OPCODE_READ_FLAG,   \
QUERY_FLAG_IDN##_uname, index, );  \
-   pm_runtime_put_sync(hba->dev);  \
+   scsi_autopm_put_device(hba->sdev_ufs_device);   \
if (ret) {  \
ret = -EINVAL;  \
goto out;   \
@@ -813,10 +813,10 @@ static ssize_t _name##_show(struct device *dev,   
\
}   \
if (ufshcd_is_wb_attrs(QUERY_ATTR_IDN##_uname)) \
index = ufshcd_wb_get_query_index(hba); \
-   pm_runtime_get_sync(hba->dev);  \
+   scsi_autopm_get_device(hba->sdev_ufs_device);   \
ret = ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_READ_ATTR,   \
QUERY_ATTR_IDN##_uname, index, 0, );  \
-   pm_runtime_put_sync(hba->dev);  \
+   scsi_autopm_put_device(hba->sdev_ufs_device);   \
if (ret) {  \
ret = -EINVAL;  \
goto out;   \
@@ -899,11 +899,15 @@ static ssize_t _pname##_show(struct device *dev,  
\
struct scsi_device *sdev = to_scsi_device(dev); \
struct ufs_hba *hba = shost_priv(sdev->host);   \
u8 lun = ufshcd_scsi_to_upiu_lun(sdev->lun);\
+   int ret;\
if (!ufs_is_valid_unit_desc_lun(>dev_info, lun,\
_duname##_DESC_PARAM##_puname)) \
return -EINVAL; \
-   return ufs_sysfs_read_desc_p

[PATCH v4 1/2] scsi: ufs: Enable power management for wlun

2021-02-22 Thread Asutosh Das
During runtime-suspend of ufs host, the scsi devices are
already suspended and so are the queues associated with them.
But the ufs host sends SSU to wlun during its runtime-suspend.
During the process blk_queue_enter checks if the queue is not in
suspended state. If so, it waits for the queue to resume, and never
comes out of it.
The commit
(d55d15a33: scsi: block: Do not accept any requests while suspended)
adds the check if the queue is in suspended state in blk_queue_enter().

Call trace:
 __switch_to+0x174/0x2c4
 __schedule+0x478/0x764
 schedule+0x9c/0xe0
 blk_queue_enter+0x158/0x228
 blk_mq_alloc_request+0x40/0xa4
 blk_get_request+0x2c/0x70
 __scsi_execute+0x60/0x1c4
 ufshcd_set_dev_pwr_mode+0x124/0x1e4
 ufshcd_suspend+0x208/0x83c
 ufshcd_runtime_suspend+0x40/0x154
 ufshcd_pltfrm_runtime_suspend+0x14/0x20
 pm_generic_runtime_suspend+0x28/0x3c
 __rpm_callback+0x80/0x2a4
 rpm_suspend+0x308/0x614
 rpm_idle+0x158/0x228
 pm_runtime_work+0x84/0xac
 process_one_work+0x1f0/0x470
 worker_thread+0x26c/0x4c8
 kthread+0x13c/0x320
 ret_from_fork+0x10/0x18

Fix this by registering ufs device wlun as a scsi driver and
registering it for block runtime-pm. Also make this as a
supplier for all other luns. That way, this device wlun
suspends after all the consumers and resumes after
hba resumes.

Co-developed-by: Can Guo 
Signed-off-by: Can Guo 
Signed-off-by: Asutosh Das 
---
 drivers/scsi/ufs/ufshcd.c  | 455 +++--
 drivers/scsi/ufs/ufshcd.h  |   4 +
 include/trace/events/ufs.h |  20 ++
 3 files changed, 382 insertions(+), 97 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 45624c7..1d8044a 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -16,6 +16,7 @@
 #include 
 #include 
 #include 
+#include 
 #include "ufshcd.h"
 #include "ufs_quirks.h"
 #include "unipro.h"
@@ -251,6 +252,11 @@ static int ufshcd_wb_toggle_flush_during_h8(struct ufs_hba 
*hba, bool set);
 static inline int ufshcd_wb_toggle_flush(struct ufs_hba *hba, bool enable);
 static void ufshcd_hba_vreg_set_lpm(struct ufs_hba *hba);
 static void ufshcd_hba_vreg_set_hpm(struct ufs_hba *hba);
+static int ufshcd_wl_runtime_suspend(struct device *dev);
+static int ufshcd_wl_runtime_resume(struct device *dev);
+static int ufshcd_wl_suspend(struct device *dev);
+static int ufshcd_wl_resume(struct device *dev);
+static void ufshcd_wl_shutdown(struct device *dev);
 
 static inline bool ufshcd_valid_tag(struct ufs_hba *hba, int tag)
 {
@@ -1556,7 +1562,7 @@ static ssize_t ufshcd_clkscale_enable_store(struct device 
*dev,
if (value == hba->clk_scaling.is_enabled)
goto out;
 
-   pm_runtime_get_sync(hba->dev);
+   scsi_autopm_get_device(hba->sdev_ufs_device);
ufshcd_hold(hba, false);
 
hba->clk_scaling.is_enabled = value;
@@ -1572,7 +1578,7 @@ static ssize_t ufshcd_clkscale_enable_store(struct device 
*dev,
}
 
ufshcd_release(hba);
-   pm_runtime_put_sync(hba->dev);
+   scsi_autopm_put_device(hba->sdev_ufs_device);
 out:
up(>host_sem);
return err ? err : count;
@@ -2572,6 +2578,17 @@ static inline u16 ufshcd_upiu_wlun_to_scsi_wlun(u8 
upiu_wlun_id)
return (upiu_wlun_id & ~UFS_UPIU_WLUN_ID) | SCSI_W_LUN_BASE;
 }
 
+static inline bool is_rpmb_wlun(struct scsi_device *sdev)
+{
+   return (sdev->lun == ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_RPMB_WLUN));
+}
+
+static inline bool is_device_wlun(struct scsi_device *sdev)
+{
+   return (sdev->lun ==
+   ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_UFS_DEVICE_WLUN));
+}
+
 static void ufshcd_init_lrb(struct ufs_hba *hba, struct ufshcd_lrb *lrb, int i)
 {
struct utp_transfer_cmd_desc *cmd_descp = hba->ucdl_base_addr;
@@ -4808,6 +4825,41 @@ static inline void 
ufshcd_get_lu_power_on_wp_status(struct ufs_hba *hba,
 }
 
 /**
+ * ufshcd_setup_links - associate link b/w device wlun and other luns
+ * @sdev: pointer to SCSI device
+ * @hba: pointer to ufs hba
+ */
+static void ufshcd_setup_links(struct ufs_hba *hba, struct scsi_device *sdev)
+{
+   struct device_link *link;
+
+   /*
+* device wlun is the supplier & rest of the luns are consumers
+* This ensures that device wlun suspends after all other luns.
+*/
+   if (hba->sdev_ufs_device) {
+   link = device_link_add(>sdev_gendev,
+  >sdev_ufs_device->sdev_gendev,
+  DL_FLAG_PM_RUNTIME);
+   if (!link) {
+   dev_err(>sdev_gendev, "Failed establishing link - 
%s\n",
+   dev_name(>sdev_ufs_device->sdev_gendev));
+   return;
+   }
+   hba->luns_avail--;
+   /* Ignore REPORT_LUN wlun probing */
+   if (hba->luns_avail !=

Re: [RFC PATCH v3 1/1] scsi: ufs: Enable power management for wlun

2021-02-19 Thread Asutosh Das

On Fri, Feb 19 2021 at 00:35 -0800, Adrian Hunter wrote:

On 11/02/21 9:18 pm, Asutosh Das wrote:

During runtime-suspend of ufs host, the scsi devices are
already suspended and so are the queues associated with them.
But the ufs host sends SSU to wlun during its runtime-suspend.
During the process blk_queue_enter checks if the queue is not in
suspended state. If so, it waits for the queue to resume, and never
comes out of it.
The commit
(d55d15a33: scsi: block: Do not accept any requests while suspended)
adds the check if the queue is in suspended state in blk_queue_enter().

Call trace:
 __switch_to+0x174/0x2c4
 __schedule+0x478/0x764
 schedule+0x9c/0xe0
 blk_queue_enter+0x158/0x228
 blk_mq_alloc_request+0x40/0xa4
 blk_get_request+0x2c/0x70
 __scsi_execute+0x60/0x1c4
 ufshcd_set_dev_pwr_mode+0x124/0x1e4
 ufshcd_suspend+0x208/0x83c
 ufshcd_runtime_suspend+0x40/0x154
 ufshcd_pltfrm_runtime_suspend+0x14/0x20
 pm_generic_runtime_suspend+0x28/0x3c
 __rpm_callback+0x80/0x2a4
 rpm_suspend+0x308/0x614
 rpm_idle+0x158/0x228
 pm_runtime_work+0x84/0xac
 process_one_work+0x1f0/0x470
 worker_thread+0x26c/0x4c8
 kthread+0x13c/0x320
 ret_from_fork+0x10/0x18

Fix this by registering ufs device wlun as a scsi driver and
registering it for block runtime-pm. Also make this as a
supplier for all other luns. That way, this device wlun
suspends after all the consumers and resumes after
hba resumes.


Sounds reasonable.  Thanks for doing this.  Some comments below.



Co-developed-by: Can Guo 
Signed-off-by: Can Guo 
Signed-off-by: Asutosh Das 
---
 drivers/scsi/ufs/ufshcd.c  | 415 +
 drivers/scsi/ufs/ufshcd.h  |   4 +
 include/trace/events/ufs.h |  20 +++
 3 files changed, 364 insertions(+), 75 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 45624c7..e92dbde 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -16,6 +16,7 @@
 #include 
 #include 
 #include 
+#include 
 #include "ufshcd.h"
 #include "ufs_quirks.h"
 #include "unipro.h"
@@ -251,6 +252,13 @@ static int ufshcd_wb_toggle_flush_during_h8(struct ufs_hba 
*hba, bool set);
 static inline int ufshcd_wb_toggle_flush(struct ufs_hba *hba, bool enable);
 static void ufshcd_hba_vreg_set_lpm(struct ufs_hba *hba);
 static void ufshcd_hba_vreg_set_hpm(struct ufs_hba *hba);
+static int __ufshcd_wl_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op);
+static int __ufshcd_wl_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op);
+static int ufshcd_wl_runtime_suspend(struct device *dev);
+static int ufshcd_wl_runtime_resume(struct device *dev);
+static int ufshcd_wl_suspend(struct device *dev);
+static int ufshcd_wl_resume(struct device *dev);
+static void ufshcd_wl_shutdown(struct device *dev);


Please try to reduce the number of forward declarations.


Done, I think I can reduce a couple of these.



 static inline bool ufshcd_valid_tag(struct ufs_hba *hba, int tag)
 {
@@ -2572,6 +2580,17 @@ static inline u16 ufshcd_upiu_wlun_to_scsi_wlun(u8 
upiu_wlun_id)
return (upiu_wlun_id & ~UFS_UPIU_WLUN_ID) | SCSI_W_LUN_BASE;
 }

+static inline bool is_rpmb_wlun(struct scsi_device *sdev)
+{
+   return (sdev->lun == ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_RPMB_WLUN));
+}
+
+static inline bool is_device_wlun(struct scsi_device *sdev)
+{
+   return (sdev->lun ==
+   ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_UFS_DEVICE_WLUN));
+}
+
 static void ufshcd_init_lrb(struct ufs_hba *hba, struct ufshcd_lrb *lrb, int i)
 {
struct utp_transfer_cmd_desc *cmd_descp = hba->ucdl_base_addr;
@@ -4808,6 +4827,43 @@ static inline void 
ufshcd_get_lu_power_on_wp_status(struct ufs_hba *hba,
 }

 /**
+ * ufshcd_setup_links - associate link b/w device wlun and other luns
+ * @sdev: pointer to SCSI device
+ * @hba: pointer to ufs hba
+ *
+ * Returns void
+ */
+static void ufshcd_setup_links(struct ufs_hba *hba, struct scsi_device *sdev)
+{
+   struct device_link *link;
+
+   /*
+* device wlun is the supplier & rest of the luns are consumers
+* This ensures that device wlun suspends after all other luns.
+*/
+   if (hba->sdev_ufs_device) {
+   link = device_link_add(>sdev_gendev,
+  >sdev_ufs_device->sdev_gendev,
+  DL_FLAG_PM_RUNTIME);
+   if (!link) {
+   dev_err(>sdev_gendev, "Failed establishing link - 
%s\n",
+   dev_name(>sdev_ufs_device->sdev_gendev));
+   return;
+   }
+   hba->luns_avail--;
+   /* Ignore REPORT_LUN wlun probing */
+   if (hba->luns_avail != 1)
+   return;
+
+   pm_runtime_put_noidle(>sdev_ufs_device->sdev_gendev);
+   pm_runtime_mark_last_busy(>sdev_ufs_device->sdev_gende

Re: [RFC PATCH v3 1/1] scsi: ufs: Enable power management for wlun

2021-02-17 Thread Asutosh Das

On Tue, Feb 16 2021 at 09:44 -0800, Asutosh Das wrote:

On Sat, Feb 13 2021 at 13:37 -0800, Avri Altman wrote:

+   } else {

Is it possible to get here?
Scsi_scan_host is called only after successful add_wluns


It looks so.
scsi 0:0:0:49488: Link setup for lun - ufshcd_setup_links
[...]
Call trace:
dump_backtrace+0x0/0x1d4
show_stack+0x18/0x24
dump_stack+0xc4/0x144
ufshcd_setup_links+0xd8/0x100
ufshcd_slave_alloc+0x134/0x1a0
scsi_alloc_sdev+0x1c0/0x230
scsi_probe_and_add_lun+0xc0/0xd48
__scsi_add_device+0xc0/0x138
ufshcd_scsi_add_wlus+0x30/0x1c0
ufshcd_async_scan+0x58/0x240
async_run_entry_fn+0x48/0x128
process_one_work+0x1f0/0x470
worker_thread+0x26c/0x4c8
kthread+0x13c/0x320
ret_from_fork+0x10/0x18




+   /* device wlun is probed */
+   hba->luns_avail--;
+   }
+}
+





/**
@@ -7254,6 +7312,14 @@ static int ufshcd_scsi_add_wlus(struct ufs_hba
*hba)
   goto out;
   }
   ufshcd_blk_pm_runtime_init(hba->sdev_ufs_device);
+   /*
+* A pm_runtime_put_sync is invoked when this device enables
blk_pm_runtime
+* & would suspend the device-wlun upon timer expiry.
+* But suspending device wlun _may_ put the ufs device in the 
pre-defined
+* low power mode (SSU ). Probing of other luns may fail then.
+* Don't allow this suspend until all the luns have been probed.

Maybe add one more sentence: see pm_runtime_mark_last_busy in ufshcd_setup_links

Done.






-   ufshcd_clear_ua_wluns(hba);

Are there any callers left to ufshcd_clear_ua_wluns?
Can it be removed?

Let me check.


I don't think this can be removed.
The reasoning behind this call as per the commit message indicates that if
there's a reset this request_sense is needed to clear uac.

In pm level 5, the reset would still happen. So I guess this is needed.
Please let me know if I'm missing something here.
The commit message didn't have much details otherwise.








+   if (hba->wlun_dev_clr_ua)
+   ufshcd_clear_ua_wlun(hba, UFS_UPIU_UFS_DEVICE_WLUN);

   cmd[4] = pwr_mode << 4;


Re: [RFC PATCH v3 1/1] scsi: ufs: Enable power management for wlun

2021-02-16 Thread Asutosh Das

On Fri, Feb 12 2021 at 19:25 -0800, Bart Van Assche wrote:

On 2/11/21 11:18 AM, Asutosh Das wrote:

+static inline bool is_rpmb_wlun(struct scsi_device *sdev)
+{
+   return (sdev->lun == ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_RPMB_WLUN));
+}
+
+static inline bool is_device_wlun(struct scsi_device *sdev)
+{
+   return (sdev->lun ==
+   ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_UFS_DEVICE_WLUN));
+}


A minor comment: checkpatch should have reported that "return is not a
function" for the above code.


 /**
+ * ufshcd_setup_links - associate link b/w device wlun and other luns
+ * @sdev: pointer to SCSI device
+ * @hba: pointer to ufs hba
+ *
+ * Returns void
+ */


Please leave out "Returns void".


+static int ufshcd_wl_suspend(struct device *dev)
+{
+   struct scsi_device *sdev = to_scsi_device(dev);
+   struct ufs_hba *hba;
+   int ret;
+   ktime_t start = ktime_get();
+
+   if (is_rpmb_wlun(sdev))
+   return 0;
+   hba = shost_priv(sdev->host);
+   ret = __ufshcd_wl_suspend(hba, UFS_SYSTEM_PM);
+   if (ret)
+   dev_err(>sdev_gendev, "%s failed: %d\n", __func__,  ret);
+
+   trace_ufshcd_wl_suspend(dev_name(dev), ret,
+   ktime_to_us(ktime_sub(ktime_get(), start)),
+   hba->curr_dev_pwr_mode, hba->uic_link_state);
+
+   return ret;
+
+}


Please remove the blank line after the return statement.

Otherwise this patch looks good to me. Hence:

Reviewed-by: Bart Van Assche 



Done.

Thanks,
-asd


Re: [RFC PATCH v3 1/1] scsi: ufs: Enable power management for wlun

2021-02-16 Thread Asutosh Das

On Sat, Feb 13 2021 at 13:37 -0800, Avri Altman wrote:

+   } else {

Is it possible to get here?
Scsi_scan_host is called only after successful add_wluns


It looks so.
scsi 0:0:0:49488: Link setup for lun - ufshcd_setup_links
[...]
Call trace:
dump_backtrace+0x0/0x1d4
show_stack+0x18/0x24
dump_stack+0xc4/0x144
ufshcd_setup_links+0xd8/0x100
ufshcd_slave_alloc+0x134/0x1a0
scsi_alloc_sdev+0x1c0/0x230
scsi_probe_and_add_lun+0xc0/0xd48
__scsi_add_device+0xc0/0x138
ufshcd_scsi_add_wlus+0x30/0x1c0
ufshcd_async_scan+0x58/0x240
async_run_entry_fn+0x48/0x128
process_one_work+0x1f0/0x470
worker_thread+0x26c/0x4c8
kthread+0x13c/0x320
ret_from_fork+0x10/0x18




+   /* device wlun is probed */
+   hba->luns_avail--;
+   }
+}
+





 /**
@@ -7254,6 +7312,14 @@ static int ufshcd_scsi_add_wlus(struct ufs_hba
*hba)
goto out;
}
ufshcd_blk_pm_runtime_init(hba->sdev_ufs_device);
+   /*
+* A pm_runtime_put_sync is invoked when this device enables
blk_pm_runtime
+* & would suspend the device-wlun upon timer expiry.
+* But suspending device wlun _may_ put the ufs device in the 
pre-defined
+* low power mode (SSU ). Probing of other luns may fail then.
+* Don't allow this suspend until all the luns have been probed.

Maybe add one more sentence: see pm_runtime_mark_last_busy in ufshcd_setup_links

Done.






-   ufshcd_clear_ua_wluns(hba);

Are there any callers left to ufshcd_clear_ua_wluns?
Can it be removed?

Let me check.




+   if (hba->wlun_dev_clr_ua)
+   ufshcd_clear_ua_wlun(hba, UFS_UPIU_UFS_DEVICE_WLUN);

cmd[4] = pwr_mode << 4;


[RFC PATCH v3 1/1] scsi: ufs: Enable power management for wlun

2021-02-11 Thread Asutosh Das
During runtime-suspend of ufs host, the scsi devices are
already suspended and so are the queues associated with them.
But the ufs host sends SSU to wlun during its runtime-suspend.
During the process blk_queue_enter checks if the queue is not in
suspended state. If so, it waits for the queue to resume, and never
comes out of it.
The commit
(d55d15a33: scsi: block: Do not accept any requests while suspended)
adds the check if the queue is in suspended state in blk_queue_enter().

Call trace:
 __switch_to+0x174/0x2c4
 __schedule+0x478/0x764
 schedule+0x9c/0xe0
 blk_queue_enter+0x158/0x228
 blk_mq_alloc_request+0x40/0xa4
 blk_get_request+0x2c/0x70
 __scsi_execute+0x60/0x1c4
 ufshcd_set_dev_pwr_mode+0x124/0x1e4
 ufshcd_suspend+0x208/0x83c
 ufshcd_runtime_suspend+0x40/0x154
 ufshcd_pltfrm_runtime_suspend+0x14/0x20
 pm_generic_runtime_suspend+0x28/0x3c
 __rpm_callback+0x80/0x2a4
 rpm_suspend+0x308/0x614
 rpm_idle+0x158/0x228
 pm_runtime_work+0x84/0xac
 process_one_work+0x1f0/0x470
 worker_thread+0x26c/0x4c8
 kthread+0x13c/0x320
 ret_from_fork+0x10/0x18

Fix this by registering ufs device wlun as a scsi driver and
registering it for block runtime-pm. Also make this as a
supplier for all other luns. That way, this device wlun
suspends after all the consumers and resumes after
hba resumes.

Co-developed-by: Can Guo 
Signed-off-by: Can Guo 
Signed-off-by: Asutosh Das 
---
 drivers/scsi/ufs/ufshcd.c  | 415 +
 drivers/scsi/ufs/ufshcd.h  |   4 +
 include/trace/events/ufs.h |  20 +++
 3 files changed, 364 insertions(+), 75 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 45624c7..e92dbde 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -16,6 +16,7 @@
 #include 
 #include 
 #include 
+#include 
 #include "ufshcd.h"
 #include "ufs_quirks.h"
 #include "unipro.h"
@@ -251,6 +252,13 @@ static int ufshcd_wb_toggle_flush_during_h8(struct ufs_hba 
*hba, bool set);
 static inline int ufshcd_wb_toggle_flush(struct ufs_hba *hba, bool enable);
 static void ufshcd_hba_vreg_set_lpm(struct ufs_hba *hba);
 static void ufshcd_hba_vreg_set_hpm(struct ufs_hba *hba);
+static int __ufshcd_wl_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op);
+static int __ufshcd_wl_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op);
+static int ufshcd_wl_runtime_suspend(struct device *dev);
+static int ufshcd_wl_runtime_resume(struct device *dev);
+static int ufshcd_wl_suspend(struct device *dev);
+static int ufshcd_wl_resume(struct device *dev);
+static void ufshcd_wl_shutdown(struct device *dev);
 
 static inline bool ufshcd_valid_tag(struct ufs_hba *hba, int tag)
 {
@@ -2572,6 +2580,17 @@ static inline u16 ufshcd_upiu_wlun_to_scsi_wlun(u8 
upiu_wlun_id)
return (upiu_wlun_id & ~UFS_UPIU_WLUN_ID) | SCSI_W_LUN_BASE;
 }
 
+static inline bool is_rpmb_wlun(struct scsi_device *sdev)
+{
+   return (sdev->lun == ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_RPMB_WLUN));
+}
+
+static inline bool is_device_wlun(struct scsi_device *sdev)
+{
+   return (sdev->lun ==
+   ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_UFS_DEVICE_WLUN));
+}
+
 static void ufshcd_init_lrb(struct ufs_hba *hba, struct ufshcd_lrb *lrb, int i)
 {
struct utp_transfer_cmd_desc *cmd_descp = hba->ucdl_base_addr;
@@ -4808,6 +4827,43 @@ static inline void 
ufshcd_get_lu_power_on_wp_status(struct ufs_hba *hba,
 }
 
 /**
+ * ufshcd_setup_links - associate link b/w device wlun and other luns
+ * @sdev: pointer to SCSI device
+ * @hba: pointer to ufs hba
+ *
+ * Returns void
+ */
+static void ufshcd_setup_links(struct ufs_hba *hba, struct scsi_device *sdev)
+{
+   struct device_link *link;
+
+   /*
+* device wlun is the supplier & rest of the luns are consumers
+* This ensures that device wlun suspends after all other luns.
+*/
+   if (hba->sdev_ufs_device) {
+   link = device_link_add(>sdev_gendev,
+  >sdev_ufs_device->sdev_gendev,
+  DL_FLAG_PM_RUNTIME);
+   if (!link) {
+   dev_err(>sdev_gendev, "Failed establishing link - 
%s\n",
+   dev_name(>sdev_ufs_device->sdev_gendev));
+   return;
+   }
+   hba->luns_avail--;
+   /* Ignore REPORT_LUN wlun probing */
+   if (hba->luns_avail != 1)
+   return;
+
+   pm_runtime_put_noidle(>sdev_ufs_device->sdev_gendev);
+   pm_runtime_mark_last_busy(>sdev_ufs_device->sdev_gendev);
+   } else {
+   /* device wlun is probed */
+   hba->luns_avail--;
+   }
+}
+
+/**
  * ufshcd_slave_alloc - handle initial SCSI device configurations
  * @sdev: pointer to SCSI device
  *
@@ -4838,6 +4894,8 @@ static in

Re: [RFC PATCH v2 2/2] scsi: ufs: Fix deadlock while suspending ufs host

2021-01-28 Thread Asutosh Das

On Thu, Jan 28 2021 at 04:21 -0800, Avri Altman wrote:


During runtime-suspend of ufs host, the scsi devices are
already suspended and so are the queues associated with them.
But the ufs host sends SSU to wlun during its runtime-suspend.

Do you possible meant: "sends request-sense while clearing UAC to"



The idea was to show that there's a scsi command that's sent during
suspend which may deadlock.

Yes, I agree to your comment and would change the message to reflect it in
the next version.



Thanks,
Avri


[RFC PATCH v2 2/2] scsi: ufs: Fix deadlock while suspending ufs host

2021-01-27 Thread Asutosh Das
During runtime-suspend of ufs host, the scsi devices are
already suspended and so are the queues associated with them.
But the ufs host sends SSU to wlun during its runtime-suspend.
During the process blk_queue_enter checks if the queue is not in
suspended state. If so, it waits for the queue to resume, and never
comes out of it.
The commit
(d55d15a33: scsi: block: Do not accept any requests while suspended)
adds the check if the queue is in suspended state in blk_queue_enter().

Fix this, by decoupling wlun scsi devices from block layer pm.
The runtime-pm for these devices would be managed by bsg and sg drivers.

Call trace:
 __switch_to+0x174/0x2c4
 __schedule+0x478/0x764
 schedule+0x9c/0xe0
 blk_queue_enter+0x158/0x228
 blk_mq_alloc_request+0x40/0xa4
 blk_get_request+0x2c/0x70
 __scsi_execute+0x60/0x1c4
 ufshcd_set_dev_pwr_mode+0x124/0x1e4
 ufshcd_suspend+0x208/0x83c
 ufshcd_runtime_suspend+0x40/0x154
 ufshcd_pltfrm_runtime_suspend+0x14/0x20
 pm_generic_runtime_suspend+0x28/0x3c
 __rpm_callback+0x80/0x2a4
 rpm_suspend+0x308/0x614
 rpm_idle+0x158/0x228
 pm_runtime_work+0x84/0xac
 process_one_work+0x1f0/0x470
 worker_thread+0x26c/0x4c8
 kthread+0x13c/0x320
 ret_from_fork+0x10/0x18

Signed-off-by: Asutosh Das 
Signed-off-by: Can Guo 
Signed-off-by: Bao D. Nguyen 
---
 drivers/scsi/ufs/ufshcd.c | 18 ++
 1 file changed, 2 insertions(+), 16 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 9c691e4..b7e7f81 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -7217,16 +7217,6 @@ static void ufshcd_set_active_icc_lvl(struct ufs_hba 
*hba)
kfree(desc_buf);
 }
 
-static inline void ufshcd_blk_pm_runtime_init(struct scsi_device *sdev)
-{
-   scsi_autopm_get_device(sdev);
-   blk_pm_runtime_init(sdev->request_queue, >sdev_gendev);
-   if (sdev->rpm_autosuspend)
-   pm_runtime_set_autosuspend_delay(>sdev_gendev,
-RPM_AUTOSUSPEND_DELAY_MS);
-   scsi_autopm_put_device(sdev);
-}
-
 /**
  * ufshcd_scsi_add_wlus - Adds required W-LUs
  * @hba: per-adapter instance
@@ -7265,7 +7255,6 @@ static int ufshcd_scsi_add_wlus(struct ufs_hba *hba)
hba->sdev_ufs_device = NULL;
goto out;
}
-   ufshcd_blk_pm_runtime_init(hba->sdev_ufs_device);
scsi_device_put(hba->sdev_ufs_device);
 
hba->sdev_rpmb = __scsi_add_device(hba->host, 0, 0,
@@ -7274,17 +7263,14 @@ static int ufshcd_scsi_add_wlus(struct ufs_hba *hba)
ret = PTR_ERR(hba->sdev_rpmb);
goto remove_sdev_ufs_device;
}
-   ufshcd_blk_pm_runtime_init(hba->sdev_rpmb);
scsi_device_put(hba->sdev_rpmb);
 
sdev_boot = __scsi_add_device(hba->host, 0, 0,
ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_BOOT_WLUN), NULL);
-   if (IS_ERR(sdev_boot)) {
+   if (IS_ERR(sdev_boot))
dev_err(hba->dev, "%s: BOOT WLUN not found\n", __func__);
-   } else {
-   ufshcd_blk_pm_runtime_init(sdev_boot);
+   else
scsi_device_put(sdev_boot);
-   }
goto out;
 
 remove_sdev_ufs_device:
-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux 
Foundation Collaborative Project.



[RFC PATCH v2 1/2] block: bsg: resume platform device before accessing

2021-01-27 Thread Asutosh Das
It may happen that the underlying device's runtime-pm is
not controlled by block-pm. So it's possible that when
commands are sent to the device, it's suspended and may not
be resumed by blk-pm. Hence explicitly resume the parent
which is the platform device.

Signed-off-by: Asutosh Das 
Signed-off-by: Can Guo 
Signed-off-by: Bao D. Nguyen 
---
 block/bsg.c | 8 
 1 file changed, 8 insertions(+)

diff --git a/block/bsg.c b/block/bsg.c
index d7bae94..e9fc896 100644
--- a/block/bsg.c
+++ b/block/bsg.c
@@ -12,6 +12,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include 
 #include 
@@ -306,12 +307,15 @@ static struct bsg_device *bsg_get_device(struct inode 
*inode, struct file *file)
 static int bsg_open(struct inode *inode, struct file *file)
 {
struct bsg_device *bd;
+   struct bsg_class_device *bcd;
 
bd = bsg_get_device(inode, file);
 
if (IS_ERR(bd))
return PTR_ERR(bd);
 
+   bcd = >queue->bsg_dev;
+   pm_runtime_get_sync(bcd->class_dev->parent);
file->private_data = bd;
return 0;
 }
@@ -319,8 +323,12 @@ static int bsg_open(struct inode *inode, struct file *file)
 static int bsg_release(struct inode *inode, struct file *file)
 {
struct bsg_device *bd = file->private_data;
+   struct bsg_class_device *bcd;
 
file->private_data = NULL;
+
+   bcd = >queue->bsg_dev;
+   pm_runtime_put_sync(bcd->class_dev->parent);
return bsg_put_device(bd);
 }
 
-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux 
Foundation Collaborative Project.



[RFC PATCH v1 2/2] scsi: ufs: Fix deadlock while suspending ufs host

2021-01-26 Thread Asutosh Das
During runtime-suspend of ufs host, the scsi devices are
already suspended and so are the queues associated with them.
But the ufs host sends SSU to wlun during its runtime-suspend.
During the process blk_queue_enter checks if the queue is not in
suspended state. If so, it waits for the queue to resume, and never
comes out of it.
The commit
(d55d15a33: scsi: block: Do not accept any requests while suspended)
adds the check if the queue is in suspended state in blk_queue_enter().

Fix this, by decoupling wlun scsi devices from block layer pm.
The runtime-pm for these devices would be managed by bsg and sg drivers.

Call trace:
 __switch_to+0x174/0x2c4
 __schedule+0x478/0x764
 schedule+0x9c/0xe0
 blk_queue_enter+0x158/0x228
 blk_mq_alloc_request+0x40/0xa4
 blk_get_request+0x2c/0x70
 __scsi_execute+0x60/0x1c4
 ufshcd_set_dev_pwr_mode+0x124/0x1e4
 ufshcd_suspend+0x208/0x83c
 ufshcd_runtime_suspend+0x40/0x154
 ufshcd_pltfrm_runtime_suspend+0x14/0x20
 pm_generic_runtime_suspend+0x28/0x3c
 __rpm_callback+0x80/0x2a4
 rpm_suspend+0x308/0x614
 rpm_idle+0x158/0x228
 pm_runtime_work+0x84/0xac
 process_one_work+0x1f0/0x470
 worker_thread+0x26c/0x4c8
 kthread+0x13c/0x320
 ret_from_fork+0x10/0x18

Change-Id: Id777fd52493c8b5522d1ebcad73cd30dac33e8a4
Signed-off-by: Asutosh Das 
Signed-off-by: Can Guo 
Signed-off-by: Bao D. Nguyen 
---
 drivers/scsi/ufs/ufshcd.c | 18 ++
 1 file changed, 2 insertions(+), 16 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 9c691e4..b7e7f81 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -7217,16 +7217,6 @@ static void ufshcd_set_active_icc_lvl(struct ufs_hba 
*hba)
kfree(desc_buf);
 }
 
-static inline void ufshcd_blk_pm_runtime_init(struct scsi_device *sdev)
-{
-   scsi_autopm_get_device(sdev);
-   blk_pm_runtime_init(sdev->request_queue, >sdev_gendev);
-   if (sdev->rpm_autosuspend)
-   pm_runtime_set_autosuspend_delay(>sdev_gendev,
-RPM_AUTOSUSPEND_DELAY_MS);
-   scsi_autopm_put_device(sdev);
-}
-
 /**
  * ufshcd_scsi_add_wlus - Adds required W-LUs
  * @hba: per-adapter instance
@@ -7265,7 +7255,6 @@ static int ufshcd_scsi_add_wlus(struct ufs_hba *hba)
hba->sdev_ufs_device = NULL;
goto out;
}
-   ufshcd_blk_pm_runtime_init(hba->sdev_ufs_device);
scsi_device_put(hba->sdev_ufs_device);
 
hba->sdev_rpmb = __scsi_add_device(hba->host, 0, 0,
@@ -7274,17 +7263,14 @@ static int ufshcd_scsi_add_wlus(struct ufs_hba *hba)
ret = PTR_ERR(hba->sdev_rpmb);
goto remove_sdev_ufs_device;
}
-   ufshcd_blk_pm_runtime_init(hba->sdev_rpmb);
scsi_device_put(hba->sdev_rpmb);
 
sdev_boot = __scsi_add_device(hba->host, 0, 0,
ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_BOOT_WLUN), NULL);
-   if (IS_ERR(sdev_boot)) {
+   if (IS_ERR(sdev_boot))
dev_err(hba->dev, "%s: BOOT WLUN not found\n", __func__);
-   } else {
-   ufshcd_blk_pm_runtime_init(sdev_boot);
+   else
scsi_device_put(sdev_boot);
-   }
goto out;
 
 remove_sdev_ufs_device:
-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux 
Foundation Collaborative Project.



[RFC PATCH v1 1/2] block: bsg: resume scsi device before accessing

2021-01-26 Thread Asutosh Das
Resumes the scsi device before accessing it.

Change-Id: I2929af60f2a92c89704a582fcdb285d35b429fde
Signed-off-by: Asutosh Das 
Signed-off-by: Can Guo 
Signed-off-by: Bao D. Nguyen 
---
 block/bsg.c | 8 
 1 file changed, 8 insertions(+)

diff --git a/block/bsg.c b/block/bsg.c
index d7bae94..f4c197f 100644
--- a/block/bsg.c
+++ b/block/bsg.c
@@ -306,12 +306,16 @@ static struct bsg_device *bsg_get_device(struct inode 
*inode, struct file *file)
 static int bsg_open(struct inode *inode, struct file *file)
 {
struct bsg_device *bd;
+   struct scsi_device *sd;
 
bd = bsg_get_device(inode, file);
 
if (IS_ERR(bd))
return PTR_ERR(bd);
 
+   sd = (struct scsi_device *) bd->queue->queuedata;
+   if (scsi_autopm_get_device(sd))
+   return -EIO;
file->private_data = bd;
return 0;
 }
@@ -319,8 +323,12 @@ static int bsg_open(struct inode *inode, struct file *file)
 static int bsg_release(struct inode *inode, struct file *file)
 {
struct bsg_device *bd = file->private_data;
+   struct scsi_device *sd;
 
file->private_data = NULL;
+   sd = (struct scsi_device *) bd->queue->queuedata;
+   scsi_autopm_put_device(sd);
+
return bsg_put_device(bd);
 }
 
-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux 
Foundation Collaborative Project.



Re: [PATCH v1] scsi: ufs-mediatek: Enable UFSHCI_QUIRK_SKIP_MANUAL_WB_FLUSH_CTRL

2020-12-27 Thread Asutosh Das (asd)

On 12/24/2020 5:47 AM, Stanley Chu wrote:

Hi Avri, Bean,

On Thu, 2020-12-24 at 13:01 +0100, Bean Huo wrote:

On Thu, 2020-12-24 at 11:03 +, Avri Altman wrote:

Do you see any substantial benefit of having
fWriteBoosterBufferFlushEn
disabled?


1. The definition of fWriteBoosterBufferFlushEn is that host allows
device to do flush in anytime after fWriteBoosterBufferFlushEn is
set as
on. This is not what we want.

Just Like BKOP, We do not want flush happening beyond host's
expected
timing that device performance may be "randomly" dropped.


Explicit flush takes place only when the device is idle:
if fWriteBoosterBufferFlushEn is set, the device is idle, and before
h8 received.
If a request arrives, the flush operation should be halted.
So no performance degradation is expected.


Hi Stanley

Avri's comment is correct, fWriteBoosterBufferFlushEn==1, device will
flush only when it is in idle, once there is new incoming request, the
flush will be suspended. You should be very careful when you want to
skip this stetting of this flag.


Very appreciate your the clarification.

However similar to "Background Operations Termination Latency", while
the next request comes, device may need some time to suspend on-going
flush operations. This delay may "randomly" degrade the performance
right?



Have you actually seen this happening? I've not come across any random 
performance degradation concerns, hence asking.


From what I've observed is the handling of WB buffer flush depends on 
how flash vendors implement it. Some vendors that I've seen just create 
a separate WB buffer in an instant. I don't know the intricacies of 
their implementation, but I guess the new WB buffer handles the requests 
while the previous one is being flushed.
Anyway, for Qualcomm platforms we plan to have 
fWriteBoosterBufferFlushEn=1 by default.



Since the configuration, i.e., enable
fWriteBoosterBufferFlushDuringHibernate only with
fWriteBoosterBufferFlushEn disabled, has been applied in many of our
mass-produced products these yeas, we would like to keep it unless the
new setting has obvious benefits.

Thanks,
Stanley Chu



Bean






--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
Linux Foundation Collaborative Project


Re: [PATCH v2 2/2] scsi: ufs: Uninline ufshcd_vops_device_reset function

2020-12-15 Thread Asutosh Das (asd)

On 12/8/2020 5:56 AM, Stanley Chu wrote:

Since more and more statements showing up in ufshcd_vops_device_reset(),
uninline it to allow compiler making possibly better optimization.

Signed-off-by: Stanley Chu 
---


Reviewed-by: Asutosh Das 


  drivers/scsi/ufs/ufshcd.c | 27 ++-
  drivers/scsi/ufs/ufshcd.h | 19 +--
  2 files changed, 27 insertions(+), 19 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index c1c401b2b69d..b2ca1a6ad426 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -580,6 +580,23 @@ static void ufshcd_print_pwr_info(struct ufs_hba *hba)
 hba->pwr_info.hs_rate);
  }
  
+static void ufshcd_device_reset(struct ufs_hba *hba)

+{
+   int err;
+
+   err = ufshcd_vops_device_reset(hba);
+
+   if (!err) {
+   ufshcd_set_ufs_dev_active(hba);
+   if (ufshcd_is_wb_allowed(hba)) {
+   hba->wb_enabled = false;
+   hba->wb_buf_flush_enabled = false;
+   }
+   }
+   if (err != -EOPNOTSUPP)
+   ufshcd_update_evt_hist(hba, UFS_EVT_DEV_RESET, err);
+}
+
  void ufshcd_delay_us(unsigned long us, unsigned long tolerance)
  {
if (!us)
@@ -3932,7 +3949,7 @@ int ufshcd_link_recovery(struct ufs_hba *hba)
spin_unlock_irqrestore(hba->host->host_lock, flags);
  
  	/* Reset the attached device */

-   ufshcd_vops_device_reset(hba);
+   ufshcd_device_reset(hba);
  
  	ret = ufshcd_host_reset_and_restore(hba);
  
@@ -6933,7 +6950,7 @@ static int ufshcd_reset_and_restore(struct ufs_hba *hba)
  
  	do {

/* Reset the attached device */
-   ufshcd_vops_device_reset(hba);
+   ufshcd_device_reset(hba);
  
  		err = ufshcd_host_reset_and_restore(hba);

} while (err && --retries);
@@ -8712,7 +8729,7 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum 
ufs_pm_op pm_op)
 * further below.
 */
if (ufshcd_is_ufs_dev_deepsleep(hba)) {
-   ufshcd_vops_device_reset(hba);
+   ufshcd_device_reset(hba);
WARN_ON(!ufshcd_is_link_off(hba));
}
if (ufshcd_is_link_hibern8(hba) && !ufshcd_uic_hibern8_exit(hba))
@@ -8722,7 +8739,7 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum 
ufs_pm_op pm_op)
  set_dev_active:
/* Can also get here needing to exit DeepSleep */
if (ufshcd_is_ufs_dev_deepsleep(hba)) {
-   ufshcd_vops_device_reset(hba);
+   ufshcd_device_reset(hba);
ufshcd_host_reset_and_restore(hba);
}
if (!ufshcd_set_dev_pwr_mode(hba, UFS_ACTIVE_PWR_MODE))
@@ -9321,7 +9338,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem 
*mmio_base, unsigned int irq)
}
  
  	/* Reset the attached device */

-   ufshcd_vops_device_reset(hba);
+   ufshcd_device_reset(hba);
  
  	ufshcd_init_crypto(hba);
  
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h

index 36d367eb8139..9bb5f0ed4124 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -1216,21 +1216,12 @@ static inline void ufshcd_vops_dbg_register_dump(struct 
ufs_hba *hba)
hba->vops->dbg_register_dump(hba);
  }
  
-static inline void ufshcd_vops_device_reset(struct ufs_hba *hba)

+static inline int ufshcd_vops_device_reset(struct ufs_hba *hba)
  {
-   if (hba->vops && hba->vops->device_reset) {
-   int err = hba->vops->device_reset(hba);
-
-   if (!err) {
-   ufshcd_set_ufs_dev_active(hba);
-   if (ufshcd_is_wb_allowed(hba)) {
-   hba->wb_enabled = false;
-   hba->wb_buf_flush_enabled = false;
-   }
-   }
-   if (err != -EOPNOTSUPP)
-   ufshcd_update_evt_hist(hba, UFS_EVT_DEV_RESET, err);
-   }
+   if (hba->vops && hba->vops->device_reset)
+   return hba->vops->device_reset(hba);
+
+   return -EOPNOTSUPP;
  }
  
  static inline void ufshcd_vops_config_scaling_param(struct ufs_hba *hba,





--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
Linux Foundation Collaborative Project


Re: [PATCH v1 0/3] Refine error history and introduce notify_event vop

2020-12-04 Thread Asutosh Das (asd)

On 11/25/2020 9:38 PM, Stanley Chu wrote:

Hi,
This series refines error history functions and introduce a new notify_event 
vop to allow vendor to get notified of important events.

Stanley Chu (3):
   scsi: ufs: Add error history for abort event in UFS Device W-LUN
   scsi: ufs: Refine error history functions
   scsi: ufs: Introduce notify_event variant function

  drivers/scsi/ufs/ufshcd.c | 122 ++
  drivers/scsi/ufs/ufshcd.h |  82 -
  2 files changed, 112 insertions(+), 92 deletions(-)



Hi Stanley,

Reviewed-by: Asutosh Das 

Please add to the series.


--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
Linux Foundation Collaborative Project


Re: [PATCH 1/3] scsi: ufs: Add "wb_on" sysfs node to control WB on/off

2020-12-02 Thread Asutosh Das (asd)

On 12/2/2020 8:20 AM, Bean Huo wrote:

On Mon, 2020-11-30 at 15:19 -0800, Asutosh Das (asd) wrote:

+ return -EINVAL;
+
+ pm_runtime_get_sync(hba->dev);
+ res = ufshcd_wb_ctrl(hba, wb_enable);


Say, a platform supports clock-scaling and this bit is toggled.
The control goes into ufshcd_wb_ctrl for both this sysfs and
clock-scaling contexts. The clock-scaling context passes all checks
and
blocks on waiting for this wb control to be disabled and then tries
to
enable wb when it's already disabled. Perhaps that's a race there?


Hi Asutosh
Appreciate your review.
There is only inconsistent problem between clock-scaling and sysfs,
since hba->dev_cmd.lock can garantee there is only one can change
fWriteBoosterEn. But this is only happening on user willfully wants to
control WB through sysfs even they know the platform supports clock-
scaling.

Since this is for the platform which doesn't support clock-scaling, I
think based on your comments, it should be acceptable for you like
this:


Or a synchronization primitive b/w the 2 contexts would work just as 
well. However, I don't have an issue if the user is denied toggling of 
wb anyway. LGTM.





+static ssize_t wb_on_store(struct device *dev, struct device_attribute
*attr,
+  const char *buf, size_t count)
+{
+   struct ufs_hba *hba = dev_get_drvdata(dev);
+   unsigned int wb_enable;
+   ssize_t res;
+
+   if (ufshcd_is_clkscaling_supported(hba)) {
+  dev_err(dev, "supports dynamic clk scaling, control WB
+   through sysfs is not allowed!");
+  return -EOPNOTSUPP;
+   }
+   if (!ufshcd_is_wb_allowed(hba))
+   return -EOPNOTSUPP;
+
+   if (kstrtouint(buf, 0, _enable))
+   return -EINVAL;
+
+   if (wb_enable != 0 && wb_enable != 1)
+   return -EINVAL;
+
+   pm_runtime_get_sync(hba->dev);
+   res = ufshcd_wb_ctrl(hba, wb_enable);
+   pm_runtime_put_sync(hba->dev);
+
+   return res < 0 ? res : count;
+}

thanks,
Bean





--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
Linux Foundation Collaborative Project


Re: [PATCH v3 1/2] scsi: ufs: Refactor ufshcd_setup_clocks() to remove skip_ref_clk

2020-12-01 Thread Asutosh Das (asd)

On 11/30/2020 7:11 PM, Can Guo wrote:

On 2020-12-01 07:01, Asutosh Das (asd) wrote:

On 11/25/2020 6:01 PM, Can Guo wrote:
Remove the param skip_ref_clk from __ufshcd_setup_clocks(), but keep 
a flag
in struct ufs_clk_info to tell whether a clock can be disabled or not 
while

the link is active.

Reviewed-by: Hongwu Su
Reviewed-by: Bean Huo 
Reviewed-by: Stanley Chu 
Signed-off-by: Can Guo 
---
  drivers/scsi/ufs/ufshcd-pltfrm.c |  2 ++
  drivers/scsi/ufs/ufshcd.c    | 29 +
  drivers/scsi/ufs/ufshcd.h    |  3 +++
  3 files changed, 14 insertions(+), 20 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c 
b/drivers/scsi/ufs/ufshcd-pltfrm.c

index 3db0af6..873ef14 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -92,6 +92,8 @@ static int ufshcd_parse_clock_info(struct ufs_hba 
*hba)

  clki->min_freq = clkfreq[i];
  clki->max_freq = clkfreq[i+1];
  clki->name = kstrdup(name, GFP_KERNEL);
+    if (!strcmp(name, "ref_clk"))
+    clki->keep_link_active = true;
  dev_dbg(dev, "%s: min %u max %u name %s\n", "freq-table-hz",
  clki->min_freq, clki->max_freq, clki->name);
  list_add_tail(>list, >clk_list_head);
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index a7857f6..44254c9 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -221,8 +221,6 @@ 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_probe_hba(struct ufs_hba *hba, bool async);
-static int __ufshcd_setup_clocks(struct ufs_hba *hba, bool on,
- bool skip_ref_clk);
  static int ufshcd_setup_clocks(struct ufs_hba *hba, bool on);
  static int ufshcd_uic_hibern8_enter(struct ufs_hba *hba);
  static inline void ufshcd_add_delay_before_dme_cmd(struct ufs_hba 
*hba);
@@ -1707,11 +1705,7 @@ static void ufshcd_gate_work(struct 
work_struct *work)

    ufshcd_disable_irq(hba);
  -    if (!ufshcd_is_link_active(hba))
-    ufshcd_setup_clocks(hba, false);
-    else
-    /* If link is active, device ref_clk can't be switched off */
-    __ufshcd_setup_clocks(hba, false, true);
+    ufshcd_setup_clocks(hba, false);
    /*
   * In case you are here to cancel this work the gating state
@@ -7990,8 +7984,7 @@ static int ufshcd_init_hba_vreg(struct ufs_hba 
*hba)

  return 0;
  }
  -static int __ufshcd_setup_clocks(struct ufs_hba *hba, bool on,
-    bool skip_ref_clk)
+static int ufshcd_setup_clocks(struct ufs_hba *hba, bool on)
  {
  int ret = 0;
  struct ufs_clk_info *clki;
@@ -8009,7 +8002,12 @@ static int __ufshcd_setup_clocks(struct 
ufs_hba *hba, bool on,

    list_for_each_entry(clki, head, list) {
  if (!IS_ERR_OR_NULL(clki->clk)) {
-    if (skip_ref_clk && !strcmp(clki->name, "ref_clk"))
+    /*
+ * Don't disable clocks which are needed
+ * to keep the link active.
+ */
+    if (ufshcd_is_link_active(hba) &&
+    clki->keep_link_active)
  continue;
    clk_state_changed = on ^ clki->enabled;
@@ -8054,11 +8052,6 @@ static int __ufshcd_setup_clocks(struct 
ufs_hba *hba, bool on,

  return ret;
  }
  -static int ufshcd_setup_clocks(struct ufs_hba *hba, bool on)
-{
-    return  __ufshcd_setup_clocks(hba, on, false);
-}
-
  static int ufshcd_init_clocks(struct ufs_hba *hba)
  {
  int ret = 0;
@@ -8577,11 +8570,7 @@ static int ufshcd_suspend(struct ufs_hba *hba, 
enum ufs_pm_op pm_op)

   */
  ufshcd_disable_irq(hba);
  -    if (!ufshcd_is_link_active(hba))
-    ufshcd_setup_clocks(hba, false);
-    else
-    /* If link is active, device ref_clk can't be switched off */
-    __ufshcd_setup_clocks(hba, false, true);
+    ufshcd_setup_clocks(hba, false);
    if (ufshcd_is_clkgating_allowed(hba)) {
  hba->clk_gating.state = CLKS_OFF;
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 66e5338..6f0f2d4 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -229,6 +229,8 @@ struct ufs_dev_cmd {
   * @max_freq: maximum frequency supported by the clock
   * @min_freq: min frequency that can be used for clock scaling
   * @curr_freq: indicates the current frequency that it is set to
+ * @keep_link_active: indicates that the clk should not be disabled if
+  link is active
   * @enabled: variable to check against multiple enable/disable
   */
  struct ufs_clk_info {
@@ -238,6 +240,7 @@ struct ufs_clk_info {
  u32 max_freq;
  u32 min_freq;
  u32 curr_freq;
+    bool keep_link_active;


Nitpick - How about 'always-on' instead of 'keep_link_active'?


Hi Asutosh,

B

Re: [PATCH v2] scsi: ufs: Remove pre-defined initial voltage values of device powers

2020-12-01 Thread Asutosh Das (asd)

On 11/30/2020 10:51 PM, Stanley Chu wrote:

UFS specficication allows different VCC configurations for UFS devices,
for example,
(1). 2.70V - 3.60V (Activated by default in UFS core driver)
(2). 1.70V - 1.95V (Activated if "vcc-supply-1p8" is declared in
   device tree)
(3). 2.40V - 2.70V (Supported since UFS 3.x)

With the introduction of UFS 3.x products, an issue is happening that
UFS driver will use wrong "min_uV-max_uV" values to configure the
voltage of VCC regulator on UFU 3.x products with the configuration (3)
used.

To solve this issue, we simply remove pre-defined initial VCC voltage
values in UFS core driver with below reasons,

1. UFS specifications do not define how to detect the VCC configuration
supported by attached device.

2. Device tree already supports standard regulator properties.

Therefore VCC voltage shall be defined correctly in device tree, and
shall not changed by UFS driver. What UFS driver needs to do is simply
enable or disable the VCC regulator only.

Similar change is applied to VCCQ and VCCQ2 as well.

Note that we keep struct ufs_vreg unchanged. This is allow vendors to
configure proper min_uV and max_uV of any regulators to make
regulator_set_voltage() works during regulator toggling flow.
Without specific vendor configurations, min_uV and max_uV will be NULL
by default and UFS core driver will enable or disable the regulator
only without adjusting its voltage.

Reviewed-by: Bjorn Andersson 
Signed-off-by: Stanley Chu 
---


Reviewed-by: Asutosh Das 


  drivers/scsi/ufs/ufshcd-pltfrm.c | 16 
  1 file changed, 16 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
index a6f76399b3ae..09e2f04bf4f6 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -133,22 +133,6 @@ static int ufshcd_populate_vreg(struct device *dev, const 
char *name,
vreg->max_uA = 0;
}
  
-	if (!strcmp(name, "vcc")) {

-   if (of_property_read_bool(np, "vcc-supply-1p8")) {
-   vreg->min_uV = UFS_VREG_VCC_1P8_MIN_UV;
-   vreg->max_uV = UFS_VREG_VCC_1P8_MAX_UV;
-   } else {
-   vreg->min_uV = UFS_VREG_VCC_MIN_UV;
-   vreg->max_uV = UFS_VREG_VCC_MAX_UV;
-   }
-   } else if (!strcmp(name, "vccq")) {
-   vreg->min_uV = UFS_VREG_VCCQ_MIN_UV;
-   vreg->max_uV = UFS_VREG_VCCQ_MAX_UV;
-   } else if (!strcmp(name, "vccq2")) {
-   vreg->min_uV = UFS_VREG_VCCQ2_MIN_UV;
-   vreg->max_uV = UFS_VREG_VCCQ2_MAX_UV;
-   }
-
goto out;
  
  out:





--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
Linux Foundation Collaborative Project


Re: [RFC PATCH v1] scsi: ufs: Remove pre-defined initial VCC voltage values

2020-11-30 Thread Asutosh Das (asd)

On 11/30/2020 6:53 PM, Bjorn Andersson wrote:

On Mon 30 Nov 17:54 CST 2020, Asutosh Das (asd) wrote:


On 11/30/2020 3:14 PM, Bjorn Andersson wrote:

On Mon 30 Nov 16:51 CST 2020, Asutosh Das (asd) wrote:


On 11/30/2020 1:16 AM, Stanley Chu wrote:

UFS specficication allows different VCC configurations for UFS devices,
for example,
(1). 2.70V - 3.60V (By default)
(2). 1.70V - 1.95V (Activated if "vcc-supply-1p8" is declared in
 device tree)
(3). 2.40V - 2.70V (Supported since UFS 3.x)

With the introduction of UFS 3.x products, an issue is happening that
UFS driver will use wrong "min_uV/max_uV" configuration to toggle VCC
regulator on UFU 3.x products with VCC configuration (3) used.

To solve this issue, we simply remove pre-defined initial VCC voltage
values in UFS driver with below reasons,

1. UFS specifications do not define how to detect the VCC configuration
  supported by attached device.

2. Device tree already supports standard regulator properties.

Therefore VCC voltage shall be defined correctly in device tree, and
shall not be changed by UFS driver. What UFS driver needs to do is simply
enabling or disabling the VCC regulator only.

This is a RFC conceptional patch. Please help review this and feel
free to feedback any ideas. Once this concept is accepted, and then
I would post a more completed patch series to fix this issue.

Signed-off-by: Stanley Chu 
---
drivers/scsi/ufs/ufshcd-pltfrm.c | 10 +-
1 file changed, 1 insertion(+), 9 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
index a6f76399b3ae..3965be03c136 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -133,15 +133,7 @@ static int ufshcd_populate_vreg(struct device *dev, const 
char *name,
vreg->max_uA = 0;
}
-   if (!strcmp(name, "vcc")) {
-   if (of_property_read_bool(np, "vcc-supply-1p8")) {
-   vreg->min_uV = UFS_VREG_VCC_1P8_MIN_UV;
-   vreg->max_uV = UFS_VREG_VCC_1P8_MAX_UV;
-   } else {
-   vreg->min_uV = UFS_VREG_VCC_MIN_UV;
-   vreg->max_uV = UFS_VREG_VCC_MAX_UV;
-   }
-   } else if (!strcmp(name, "vccq")) {
+   if (!strcmp(name, "vccq")) {
vreg->min_uV = UFS_VREG_VCCQ_MIN_UV;
vreg->max_uV = UFS_VREG_VCCQ_MAX_UV;
} else if (!strcmp(name, "vccq2")) {



Hi Stanley

Thanks for the patch. Bao (nguyenb) was also working towards something
similar.
Would it be possible for you to take into account the scenario in which the
same platform supports both 2.x and 3.x UFS devices?

These've different voltage requirements, 2.4v-3.6v.
I'm not sure if standard dts regulator properties can support this.



What is the actual voltage requirement for these devices and how does
the software know what voltage to pick in this range?

Regards,
Bjorn


-asd


--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
Linux Foundation Collaborative Project


For platforms that support both 2.x (2.7v-3.6v) and 3.x (2.4v-2.7v), the
voltage requirements (Vcc) are 2.4v-3.6v. The software initializes the ufs
device at 2.95v & reads the version and if the device is 3.x, it may do the
following:
- Set the device power mode to SLEEP
- Disable the Vcc
- Enable the Vcc and set it to 2.5v
- Set the device power mode to ACTIVE

All of the above may be done at HS-G1 & moved to max supported gear based on
the device version, perhaps?

Am open to other ideas though.



But that means that for a board where we don't know (don't want to know)
if we have a 2.x or 3.x device we need to set:

   regulator-min-microvolt = <2.4V>
   regulator-max-microvolt = <3.6V>

And the 2.5V and the two ranges should be hard coded into the ufshcd (in
particular if they come from the specification).

For devices with only 2.x or 3.x devices, regulator-{min,max}-microvolt
should be adjusted accordingly.

Note that driving the regulators outside these ranges will either damage
the hardware or cause it to misbehave, so these values should be defined
in the board.dts anyways.

Also note that regulator_set_voltage(2.4V, 3.6V) won't give you "a
voltage between 2.4V and 3.6V, it will most likely give either 2.4V or
any more specific voltage that we've specified in the board file because
the regulator happens to be shared with some other consumer and changing
it in runtime would be bad.

Regards,
Bjorn



Understood.
I also understand that assumptions on the regulator limits in the driver 
is a bad idea. I'm not sure how it's designed, but I should think the 
power-grid design should take care of regulator sharing; if it's being 
shared and the platform supports both 2.x and 3.x. Perhaps, such 
platforms be iden

Re: [RFC PATCH v1] scsi: ufs: Remove pre-defined initial VCC voltage values

2020-11-30 Thread Asutosh Das (asd)

On 11/30/2020 5:25 PM, Stanley Chu wrote:

On Mon, 2020-11-30 at 15:54 -0800, Asutosh Das (asd) wrote:

On 11/30/2020 3:14 PM, Bjorn Andersson wrote:

On Mon 30 Nov 16:51 CST 2020, Asutosh Das (asd) wrote:


On 11/30/2020 1:16 AM, Stanley Chu wrote:

UFS specficication allows different VCC configurations for UFS devices,
for example,
(1). 2.70V - 3.60V (By default)
(2). 1.70V - 1.95V (Activated if "vcc-supply-1p8" is declared in
 device tree)
(3). 2.40V - 2.70V (Supported since UFS 3.x)

With the introduction of UFS 3.x products, an issue is happening that
UFS driver will use wrong "min_uV/max_uV" configuration to toggle VCC
regulator on UFU 3.x products with VCC configuration (3) used.

To solve this issue, we simply remove pre-defined initial VCC voltage
values in UFS driver with below reasons,

1. UFS specifications do not define how to detect the VCC configuration
  supported by attached device.

2. Device tree already supports standard regulator properties.

Therefore VCC voltage shall be defined correctly in device tree, and
shall not be changed by UFS driver. What UFS driver needs to do is simply
enabling or disabling the VCC regulator only.

This is a RFC conceptional patch. Please help review this and feel
free to feedback any ideas. Once this concept is accepted, and then
I would post a more completed patch series to fix this issue.

Signed-off-by: Stanley Chu 
---
drivers/scsi/ufs/ufshcd-pltfrm.c | 10 +-
1 file changed, 1 insertion(+), 9 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
index a6f76399b3ae..3965be03c136 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -133,15 +133,7 @@ static int ufshcd_populate_vreg(struct device *dev, const 
char *name,
vreg->max_uA = 0;
}
-   if (!strcmp(name, "vcc")) {
-   if (of_property_read_bool(np, "vcc-supply-1p8")) {
-   vreg->min_uV = UFS_VREG_VCC_1P8_MIN_UV;
-   vreg->max_uV = UFS_VREG_VCC_1P8_MAX_UV;
-   } else {
-   vreg->min_uV = UFS_VREG_VCC_MIN_UV;
-   vreg->max_uV = UFS_VREG_VCC_MAX_UV;
-   }
-   } else if (!strcmp(name, "vccq")) {
+   if (!strcmp(name, "vccq")) {
vreg->min_uV = UFS_VREG_VCCQ_MIN_UV;
vreg->max_uV = UFS_VREG_VCCQ_MAX_UV;
} else if (!strcmp(name, "vccq2")) {



Hi Stanley

Thanks for the patch. Bao (nguyenb) was also working towards something
similar.
Would it be possible for you to take into account the scenario in which the
same platform supports both 2.x and 3.x UFS devices?

These've different voltage requirements, 2.4v-3.6v.
I'm not sure if standard dts regulator properties can support this.



What is the actual voltage requirement for these devices and how does
the software know what voltage to pick in this range?

Regards,
Bjorn


-asd


--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
Linux Foundation Collaborative Project


For platforms that support both 2.x (2.7v-3.6v) and 3.x (2.4v-2.7v), the
voltage requirements (Vcc) are 2.4v-3.6v. The software initializes the
ufs device at 2.95v & reads the version and if the device is 3.x, it may
do the following:
- Set the device power mode to SLEEP
- Disable the Vcc
- Enable the Vcc and set it to 2.5v
- Set the device power mode to ACTIVE

All of the above may be done at HS-G1 & moved to max supported gear
based on the device version, perhaps?


Hi Asutosh,

Thanks for sharing this idea.

1. I did not see above flow defined in UFS specifications, please
correct me if I was wrong.

2. For above flow, the concern is that I am not sure if all devices
supporting VCC (2.4v - 2.7v) can accept higher voltage, say 2.95v, for
version detection.

3. For version detection, another concern is that I am not sure if all
3.x devices support VCC (2.4v - 2.7v) only, or in other words, I am not
sure if all 2.x devices support VCC (2.7v - 3.6v) only. The above rule
will break any devices not obeying this "conventions".

For platforms that support both 2.x (2.7v-3.6v) and 3.x (2.4v-2.7v),

It would be good for UFS drivers detecting the correct voltage if the
protocol is well-defined in specifications. Until that day, any
"non-standard" way may be better implemented in vendor's ops?

If the vop concept works on your platform, we could still keep struct
ufs_vreg and allow vendors to configure proper min_uV and max_uV to make
regulator_set_voltage() works during VCC toggling flow. Without specific
vendor configurations, min_uV and max_uV would be NULL by default and
UFS core driver will only enable/disasble VCC regulator only without
adjusting its voltage.



I think this would work. Do you plan to implement t

Re: [PATCH v3 2/3] scsi: ufs: Fix a racing problem between ufshcd_abort and eh_work

2020-11-30 Thread Asutosh Das (asd)

On 11/16/2020 11:04 PM, Can Guo wrote:

In current task abort routine, if task abort happens to the device W-LU,
the code directly jumps to ufshcd_eh_host_reset_handler() to perform a
full reset and restore then returns FAIL or SUCCESS. Commands sent to the
device W-LU are most likely the SSU cmds sent during UFS PM operations. If
such SSU cmd enters task abort routine, when ufshcd_eh_host_reset_handler()
flushes eh_work, there will be racing because err_handler is serialized
with any PM operations.

Since the main idea of aborting one cmd to the device W-LU is to perform
a full reset and restore, in order to resolve the racing problem, we merely
clean up the lrb taken by this cmd, queue the eh_work and abort the cmd.
Since the cmd has been aborted, the PM operation which sends the cmd simply
errors out, thus err_handler will not be blocked by ongoing PM operations
and err_handler can also recover PM error if any, which comes as another
benefit of this change.

Because such cmd is aborted even before it is actually cleared from HW, set
the lrb->in_use flag to prevent subsequent cmds, including SCSI cmds and
dev cmds, from taking the lrb released by this cmd. Flag lrb->in_use shall
evetually be cleared in __ufshcd_transfer_req_compl() invoked by the full
reset and restore from err_handler.

Signed-off-by: Can Guo 
---


Reviewed-by: Asutosh Das 


  drivers/scsi/ufs/ufshcd.c | 55 ---
  drivers/scsi/ufs/ufshcd.h |  2 ++
  2 files changed, 45 insertions(+), 12 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 7e764e8..cd7394e 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -2539,6 +2539,14 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, 
struct scsi_cmnd *cmd)
(hba->clk_gating.state != CLKS_ON));
  
  	lrbp = >lrb[tag];

+   if (unlikely(lrbp->in_use)) {
+   if (hba->pm_op_in_progress)
+   set_host_byte(cmd, DID_BAD_TARGET);
+   else
+   err = SCSI_MLQUEUE_HOST_BUSY;
+   ufshcd_release(hba);
+   goto out;
+   }
  
  	WARN_ON(lrbp->cmd);

lrbp->cmd = cmd;
@@ -2781,6 +2789,11 @@ static int ufshcd_exec_dev_cmd(struct ufs_hba *hba,
  
  	init_completion();

lrbp = >lrb[tag];
+   if (unlikely(lrbp->in_use)) {
+   err = -EBUSY;
+   goto out;
+   }
+
WARN_ON(lrbp->cmd);
err = ufshcd_compose_dev_cmd(hba, lrbp, cmd_type, tag);
if (unlikely(err))
@@ -2797,6 +2810,7 @@ static int ufshcd_exec_dev_cmd(struct ufs_hba *hba,
  
  	err = ufshcd_wait_for_dev_cmd(hba, lrbp, timeout);
  
+out:

ufshcd_add_query_upiu_trace(hba, tag,
err ? "query_complete_err" : "query_complete");
  
@@ -4932,6 +4946,7 @@ static void __ufshcd_transfer_req_compl(struct ufs_hba *hba,
  
  	for_each_set_bit(index, _reqs, hba->nutrs) {

lrbp = >lrb[index];
+   lrbp->in_use = false;
lrbp->compl_time_stamp = ktime_get();
cmd = lrbp->cmd;
if (cmd) {
@@ -6374,8 +6389,12 @@ static int ufshcd_issue_devman_upiu_cmd(struct ufs_hba 
*hba,
  
  	init_completion();

lrbp = >lrb[tag];
-   WARN_ON(lrbp->cmd);
+   if (unlikely(lrbp->in_use)) {
+   err = -EBUSY;
+   goto out;
+   }
  
+	WARN_ON(lrbp->cmd);

lrbp->cmd = NULL;
lrbp->sense_bufflen = 0;
lrbp->sense_buffer = NULL;
@@ -6447,6 +6466,7 @@ static int ufshcd_issue_devman_upiu_cmd(struct ufs_hba 
*hba,
}
}
  
+out:

blk_put_request(req);
  out_unlock:
up_read(>clk_scaling_lock);
@@ -6696,16 +6716,6 @@ static int ufshcd_abort(struct scsi_cmnd *cmd)
BUG();
}
  
-	/*

-* Task abort to the device W-LUN is illegal. When this command
-* will fail, due to spec violation, scsi err handling next step
-* will be to send LU reset which, again, is a spec violation.
-* To avoid these unnecessary/illegal step we skip to the last error
-* handling stage: reset and restore.
-*/
-   if (lrbp->lun == UFS_UPIU_UFS_DEVICE_WLUN)
-   return ufshcd_eh_host_reset_handler(cmd);
-
ufshcd_hold(hba, false);
reg = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
/* If command is already aborted/completed, return SUCCESS */
@@ -6726,7 +6736,7 @@ static int ufshcd_abort(struct scsi_cmnd *cmd)
 * to reduce repeated printouts. For other aborted requests only print
 * basic details.
 */
-   scsi_print_command(hba->lrb[tag].cmd);
+   scsi_print_command(cmd);
if (!hba->req_abort_count) {
ufshcd_update_reg_hist(>ufs_stats.task_abort, 0);
ufshcd_print_ho

Re: [PATCH v3 1/3] scsi: ufs: Serialize eh_work with system PM events and async scan

2020-11-30 Thread Asutosh Das (asd)

On 11/16/2020 11:04 PM, Can Guo wrote:

Serialize eh_work with system PM events and async scan to make sure eh_work
does not run in parallel with them.

Signed-off-by: Can Guo 
---


Reviewed-by: Asutosh Das 


  drivers/scsi/ufs/ufshcd.c | 64 +--
  drivers/scsi/ufs/ufshcd.h |  1 +
  2 files changed, 41 insertions(+), 24 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 1d8134e..7e764e8 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -5597,7 +5597,9 @@ static inline void ufshcd_schedule_eh_work(struct ufs_hba 
*hba)
  static void ufshcd_err_handling_prepare(struct ufs_hba *hba)
  {
pm_runtime_get_sync(hba->dev);
-   if (pm_runtime_suspended(hba->dev)) {
+   if (pm_runtime_status_suspended(hba->dev) || hba->is_sys_suspended) {
+   enum ufs_pm_op pm_op;
+
/*
 * Don't assume anything of pm_runtime_get_sync(), if
 * resume fails, irq and clocks can be OFF, and powers
@@ -5612,7 +5614,8 @@ static void ufshcd_err_handling_prepare(struct ufs_hba 
*hba)
if (!ufshcd_is_clkgating_allowed(hba))
ufshcd_setup_clocks(hba, true);
ufshcd_release(hba);
-   ufshcd_vops_resume(hba, UFS_RUNTIME_PM);
+   pm_op = hba->is_sys_suspended ? UFS_RUNTIME_PM : UFS_SYSTEM_PM;
+   ufshcd_vops_resume(hba, pm_op);
} else {
ufshcd_hold(hba, false);
if (hba->clk_scaling.is_allowed) {
@@ -5633,7 +5636,7 @@ static void ufshcd_err_handling_unprepare(struct ufs_hba 
*hba)
  
  static inline bool ufshcd_err_handling_should_stop(struct ufs_hba *hba)

  {
-   return (hba->ufshcd_state == UFSHCD_STATE_ERROR ||
+   return (!hba->is_powered || hba->ufshcd_state == UFSHCD_STATE_ERROR ||
(!(hba->saved_err || hba->saved_uic_err || hba->force_reset ||
ufshcd_is_link_broken(hba;
  }
@@ -5646,6 +5649,7 @@ static void ufshcd_recover_pm_error(struct ufs_hba *hba)
struct request_queue *q;
int ret;
  
+	hba->is_sys_suspended = false;

/*
 * Set RPM status of hba device to RPM_ACTIVE,
 * this also clears its runtime error.
@@ -5704,11 +5708,13 @@ static void ufshcd_err_handler(struct work_struct *work)
  
  	hba = container_of(work, struct ufs_hba, eh_work);
  
+	down(>eh_sem);

spin_lock_irqsave(hba->host->host_lock, flags);
if (ufshcd_err_handling_should_stop(hba)) {
if (hba->ufshcd_state != UFSHCD_STATE_ERROR)
hba->ufshcd_state = UFSHCD_STATE_OPERATIONAL;
spin_unlock_irqrestore(hba->host->host_lock, flags);
+   up(>eh_sem);
return;
}
ufshcd_set_eh_in_progress(hba);
@@ -5716,20 +5722,18 @@ static void ufshcd_err_handler(struct work_struct *work)
ufshcd_err_handling_prepare(hba);
spin_lock_irqsave(hba->host->host_lock, flags);
ufshcd_scsi_block_requests(hba);
-   /*
-* A full reset and restore might have happened after preparation
-* is finished, double check whether we should stop.
-*/
-   if (ufshcd_err_handling_should_stop(hba)) {
-   if (hba->ufshcd_state != UFSHCD_STATE_ERROR)
-   hba->ufshcd_state = UFSHCD_STATE_OPERATIONAL;
-   goto out;
-   }
hba->ufshcd_state = UFSHCD_STATE_RESET;
  
  	/* Complete requests that have door-bell cleared by h/w */

ufshcd_complete_requests(hba);
  
+	/*

+* A full reset and restore might have happened after preparation
+* is finished, double check whether we should stop.
+*/
+   if (ufshcd_err_handling_should_stop(hba))
+   goto skip_err_handling;
+
if (hba->dev_quirks & UFS_DEVICE_QUIRK_RECOVERY_FROM_DL_NAC_ERRORS) {
bool ret;
  
@@ -5737,17 +5741,10 @@ static void ufshcd_err_handler(struct work_struct *work)

/* release the lock as ufshcd_quirk_dl_nac_errors() may sleep */
ret = ufshcd_quirk_dl_nac_errors(hba);
spin_lock_irqsave(hba->host->host_lock, flags);
-   if (!ret && !hba->force_reset && ufshcd_is_link_active(hba))
+   if (!ret && ufshcd_err_handling_should_stop(hba))
goto skip_err_handling;
}
  
-	if (hba->force_reset || ufshcd_is_link_broken(hba) ||

-   ufshcd_is_saved_err_fatal(hba) ||
-   ((hba->saved_err & UIC_ERROR) &&
-(hba->saved_uic_err & (UFSHCD_UIC_DL_NAC_RECEIVED_ERROR |
-   UFSHCD_UIC_DL_TCx_REPLAY_ERROR
-   needs_reset = true;
-
if ((hba->saved_err & (INT_FATAL_ER

Re: [PATCH v3 2/2] scsi: ufs-qcom: Keep core_clk_unipro ON while link is active

2020-11-30 Thread Asutosh Das (asd)

On 11/25/2020 6:01 PM, Can Guo wrote:

If we want to disable clocks to save power but still keep the link active,
core_clk_unipro, as same as ref_clk, should not be the one being disabled.

Reviewed-by: Hongwu Su
Signed-off-by: Can Guo 
---


Reviewed-by: Asutosh Das 


  drivers/scsi/ufs/ufs-qcom.c | 6 ++
  1 file changed, 6 insertions(+)

diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index f9d6ef3..8a7fc62 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -977,6 +977,7 @@ static int ufs_qcom_init(struct ufs_hba *hba)
struct platform_device *pdev = to_platform_device(dev);
struct ufs_qcom_host *host;
struct resource *res;
+   struct ufs_clk_info *clki;
  
  	if (strlen(android_boot_dev) && strcmp(android_boot_dev, dev_name(dev)))

return -ENODEV;
@@ -1075,6 +1076,11 @@ static int ufs_qcom_init(struct ufs_hba *hba)
}
}
  
+	list_for_each_entry(clki, >clk_list_head, list) {

+   if (!strcmp(clki->name, "core_clk_unipro"))
+   clki->keep_link_active = true;
+   }
+
err = ufs_qcom_init_lane_clks(host);
if (err)
goto out_variant_clear;




--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
Linux Foundation Collaborative Project


Re: [RFC PATCH v1] scsi: ufs: Remove pre-defined initial VCC voltage values

2020-11-30 Thread Asutosh Das (asd)

On 11/30/2020 3:14 PM, Bjorn Andersson wrote:

On Mon 30 Nov 16:51 CST 2020, Asutosh Das (asd) wrote:


On 11/30/2020 1:16 AM, Stanley Chu wrote:

UFS specficication allows different VCC configurations for UFS devices,
for example,
(1). 2.70V - 3.60V (By default)
(2). 1.70V - 1.95V (Activated if "vcc-supply-1p8" is declared in
device tree)
(3). 2.40V - 2.70V (Supported since UFS 3.x)

With the introduction of UFS 3.x products, an issue is happening that
UFS driver will use wrong "min_uV/max_uV" configuration to toggle VCC
regulator on UFU 3.x products with VCC configuration (3) used.

To solve this issue, we simply remove pre-defined initial VCC voltage
values in UFS driver with below reasons,

1. UFS specifications do not define how to detect the VCC configuration
 supported by attached device.

2. Device tree already supports standard regulator properties.

Therefore VCC voltage shall be defined correctly in device tree, and
shall not be changed by UFS driver. What UFS driver needs to do is simply
enabling or disabling the VCC regulator only.

This is a RFC conceptional patch. Please help review this and feel
free to feedback any ideas. Once this concept is accepted, and then
I would post a more completed patch series to fix this issue.

Signed-off-by: Stanley Chu 
---
   drivers/scsi/ufs/ufshcd-pltfrm.c | 10 +-
   1 file changed, 1 insertion(+), 9 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
index a6f76399b3ae..3965be03c136 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -133,15 +133,7 @@ static int ufshcd_populate_vreg(struct device *dev, const 
char *name,
vreg->max_uA = 0;
}
-   if (!strcmp(name, "vcc")) {
-   if (of_property_read_bool(np, "vcc-supply-1p8")) {
-   vreg->min_uV = UFS_VREG_VCC_1P8_MIN_UV;
-   vreg->max_uV = UFS_VREG_VCC_1P8_MAX_UV;
-   } else {
-   vreg->min_uV = UFS_VREG_VCC_MIN_UV;
-   vreg->max_uV = UFS_VREG_VCC_MAX_UV;
-   }
-   } else if (!strcmp(name, "vccq")) {
+   if (!strcmp(name, "vccq")) {
vreg->min_uV = UFS_VREG_VCCQ_MIN_UV;
vreg->max_uV = UFS_VREG_VCCQ_MAX_UV;
} else if (!strcmp(name, "vccq2")) {



Hi Stanley

Thanks for the patch. Bao (nguyenb) was also working towards something
similar.
Would it be possible for you to take into account the scenario in which the
same platform supports both 2.x and 3.x UFS devices?

These've different voltage requirements, 2.4v-3.6v.
I'm not sure if standard dts regulator properties can support this.



What is the actual voltage requirement for these devices and how does
the software know what voltage to pick in this range?

Regards,
Bjorn


-asd


--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
Linux Foundation Collaborative Project


For platforms that support both 2.x (2.7v-3.6v) and 3.x (2.4v-2.7v), the 
voltage requirements (Vcc) are 2.4v-3.6v. The software initializes the 
ufs device at 2.95v & reads the version and if the device is 3.x, it may 
do the following:

- Set the device power mode to SLEEP
- Disable the Vcc
- Enable the Vcc and set it to 2.5v
- Set the device power mode to ACTIVE

All of the above may be done at HS-G1 & moved to max supported gear 
based on the device version, perhaps?


Am open to other ideas though.

-asd

--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
Linux Foundation Collaborative Project


Re: [PATCH 1/3] scsi: ufs: Add "wb_on" sysfs node to control WB on/off

2020-11-30 Thread Asutosh Das (asd)

On 11/30/2020 10:11 AM, Bean Huo wrote:

From: Bean Huo 

Currently we let UFS WriteBooster driver use clock scaling
up/down to set WB on/off, for the platform which doesn't
support UFSHCD_CAP_CLK_SCALING, WB will be always on. Provide
a sysfs attribute to enable/disable WB during runtime.

Signed-off-by: Bean Huo 
---
  drivers/scsi/ufs/ufs-sysfs.c | 33 +
  drivers/scsi/ufs/ufshcd.c|  3 +--
  drivers/scsi/ufs/ufshcd.h|  2 ++
  3 files changed, 36 insertions(+), 2 deletions(-)

diff --git a/drivers/scsi/ufs/ufs-sysfs.c b/drivers/scsi/ufs/ufs-sysfs.c
index 08e72b7eef6a..e41d8eb779ec 100644
--- a/drivers/scsi/ufs/ufs-sysfs.c
+++ b/drivers/scsi/ufs/ufs-sysfs.c
@@ -189,6 +189,37 @@ static ssize_t auto_hibern8_store(struct device *dev,
return count;
  }
  
+static ssize_t wb_on_show(struct device *dev, struct device_attribute *attr,

+ char *buf)
+{
+   struct ufs_hba *hba = dev_get_drvdata(dev);
+
+   return scnprintf(buf, PAGE_SIZE, "%d\n", hba->wb_enabled);
+}
+
+static ssize_t wb_on_store(struct device *dev, struct device_attribute *attr,
+  const char *buf, size_t count)
+{
+   struct ufs_hba *hba = dev_get_drvdata(dev);
+   unsigned int wb_enable;
+   ssize_t res;
+
+   if (!ufshcd_is_wb_allowed(hba))
+   return -EOPNOTSUPP;
+
+   if (kstrtouint(buf, 0, _enable))
+   return -EINVAL;
+
+   if (wb_enable != 0 && wb_enable != 1)
+   return -EINVAL;
+
+   pm_runtime_get_sync(hba->dev);
+   res = ufshcd_wb_ctrl(hba, wb_enable);


Say, a platform supports clock-scaling and this bit is toggled.
The control goes into ufshcd_wb_ctrl for both this sysfs and 
clock-scaling contexts. The clock-scaling context passes all checks and 
blocks on waiting for this wb control to be disabled and then tries to 
enable wb when it's already disabled. Perhaps that's a race there?



+   pm_runtime_put_sync(hba->dev);
+
+   return res < 0 ? res : count;
+}
+
  static DEVICE_ATTR_RW(rpm_lvl);
  static DEVICE_ATTR_RO(rpm_target_dev_state);
  static DEVICE_ATTR_RO(rpm_target_link_state);
@@ -196,6 +227,7 @@ static DEVICE_ATTR_RW(spm_lvl);
  static DEVICE_ATTR_RO(spm_target_dev_state);
  static DEVICE_ATTR_RO(spm_target_link_state);
  static DEVICE_ATTR_RW(auto_hibern8);
+static DEVICE_ATTR_RW(wb_on);
  
  static struct attribute *ufs_sysfs_ufshcd_attrs[] = {

_attr_rpm_lvl.attr,
@@ -205,6 +237,7 @@ static struct attribute *ufs_sysfs_ufshcd_attrs[] = {
_attr_spm_target_dev_state.attr,
_attr_spm_target_link_state.attr,
_attr_auto_hibern8.attr,
+   _attr_wb_on.attr,
NULL
  };
  
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c

index d169db41ee16..639ba9d1ccbb 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -247,7 +247,6 @@ static inline int ufshcd_config_vreg_hpm(struct ufs_hba 
*hba,
  static int ufshcd_try_to_abort_task(struct ufs_hba *hba, int tag);
  static int ufshcd_wb_buf_flush_enable(struct ufs_hba *hba);
  static int ufshcd_wb_buf_flush_disable(struct ufs_hba *hba);
-static int ufshcd_wb_ctrl(struct ufs_hba *hba, bool enable);
  static int ufshcd_wb_toggle_flush_during_h8(struct ufs_hba *hba, bool set);
  static inline void ufshcd_wb_toggle_flush(struct ufs_hba *hba, bool enable);
  static void ufshcd_hba_vreg_set_lpm(struct ufs_hba *hba);
@@ -5299,7 +5298,7 @@ static void ufshcd_bkops_exception_event_handler(struct 
ufs_hba *hba)
__func__, err);
  }
  
-static int ufshcd_wb_ctrl(struct ufs_hba *hba, bool enable)

+int ufshcd_wb_ctrl(struct ufs_hba *hba, bool enable)
  {
int ret;
u8 index;
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index d0b68df07eef..c7bb61a4e484 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -1067,6 +1067,8 @@ int ufshcd_exec_raw_upiu_cmd(struct ufs_hba *hba,
 u8 *desc_buff, int *buff_len,
 enum query_opcode desc_op);
  
+int ufshcd_wb_ctrl(struct ufs_hba *hba, bool enable);

+
  /* Wrapper functions for safely calling variant operations */
  static inline const char *ufshcd_get_var_name(struct ufs_hba *hba)
  {




--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
Linux Foundation Collaborative Project


Re: [PATCH v3 1/2] scsi: ufs: Refactor ufshcd_setup_clocks() to remove skip_ref_clk

2020-11-30 Thread Asutosh Das (asd)

On 11/25/2020 6:01 PM, Can Guo wrote:

Remove the param skip_ref_clk from __ufshcd_setup_clocks(), but keep a flag
in struct ufs_clk_info to tell whether a clock can be disabled or not while
the link is active.

Reviewed-by: Hongwu Su
Reviewed-by: Bean Huo 
Reviewed-by: Stanley Chu 
Signed-off-by: Can Guo 
---
  drivers/scsi/ufs/ufshcd-pltfrm.c |  2 ++
  drivers/scsi/ufs/ufshcd.c| 29 +
  drivers/scsi/ufs/ufshcd.h|  3 +++
  3 files changed, 14 insertions(+), 20 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
index 3db0af6..873ef14 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -92,6 +92,8 @@ static int ufshcd_parse_clock_info(struct ufs_hba *hba)
clki->min_freq = clkfreq[i];
clki->max_freq = clkfreq[i+1];
clki->name = kstrdup(name, GFP_KERNEL);
+   if (!strcmp(name, "ref_clk"))
+   clki->keep_link_active = true;
dev_dbg(dev, "%s: min %u max %u name %s\n", "freq-table-hz",
clki->min_freq, clki->max_freq, clki->name);
list_add_tail(>list, >clk_list_head);
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index a7857f6..44254c9 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -221,8 +221,6 @@ 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_probe_hba(struct ufs_hba *hba, bool async);
-static int __ufshcd_setup_clocks(struct ufs_hba *hba, bool on,
-bool skip_ref_clk);
  static int ufshcd_setup_clocks(struct ufs_hba *hba, bool on);
  static int ufshcd_uic_hibern8_enter(struct ufs_hba *hba);
  static inline void ufshcd_add_delay_before_dme_cmd(struct ufs_hba *hba);
@@ -1707,11 +1705,7 @@ static void ufshcd_gate_work(struct work_struct *work)
  
  	ufshcd_disable_irq(hba);
  
-	if (!ufshcd_is_link_active(hba))

-   ufshcd_setup_clocks(hba, false);
-   else
-   /* If link is active, device ref_clk can't be switched off */
-   __ufshcd_setup_clocks(hba, false, true);
+   ufshcd_setup_clocks(hba, false);
  
  	/*

 * In case you are here to cancel this work the gating state
@@ -7990,8 +7984,7 @@ static int ufshcd_init_hba_vreg(struct ufs_hba *hba)
return 0;
  }
  
-static int __ufshcd_setup_clocks(struct ufs_hba *hba, bool on,

-   bool skip_ref_clk)
+static int ufshcd_setup_clocks(struct ufs_hba *hba, bool on)
  {
int ret = 0;
struct ufs_clk_info *clki;
@@ -8009,7 +8002,12 @@ static int __ufshcd_setup_clocks(struct ufs_hba *hba, 
bool on,
  
  	list_for_each_entry(clki, head, list) {

if (!IS_ERR_OR_NULL(clki->clk)) {
-   if (skip_ref_clk && !strcmp(clki->name, "ref_clk"))
+   /*
+* Don't disable clocks which are needed
+* to keep the link active.
+*/
+   if (ufshcd_is_link_active(hba) &&
+   clki->keep_link_active)
continue;
  
  			clk_state_changed = on ^ clki->enabled;

@@ -8054,11 +8052,6 @@ static int __ufshcd_setup_clocks(struct ufs_hba *hba, 
bool on,
return ret;
  }
  
-static int ufshcd_setup_clocks(struct ufs_hba *hba, bool on)

-{
-   return  __ufshcd_setup_clocks(hba, on, false);
-}
-
  static int ufshcd_init_clocks(struct ufs_hba *hba)
  {
int ret = 0;
@@ -8577,11 +8570,7 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum 
ufs_pm_op pm_op)
 */
ufshcd_disable_irq(hba);
  
-	if (!ufshcd_is_link_active(hba))

-   ufshcd_setup_clocks(hba, false);
-   else
-   /* If link is active, device ref_clk can't be switched off */
-   __ufshcd_setup_clocks(hba, false, true);
+   ufshcd_setup_clocks(hba, false);
  
  	if (ufshcd_is_clkgating_allowed(hba)) {

hba->clk_gating.state = CLKS_OFF;
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 66e5338..6f0f2d4 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -229,6 +229,8 @@ struct ufs_dev_cmd {
   * @max_freq: maximum frequency supported by the clock
   * @min_freq: min frequency that can be used for clock scaling
   * @curr_freq: indicates the current frequency that it is set to
+ * @keep_link_active: indicates that the clk should not be disabled if
+ link is active
   * @enabled: variable to check against multiple enable/disable
   */
  struct ufs_clk_info {
@@ -238,6 +240,7 @@ struct ufs_clk_info {
u32 max_freq;
u32 min_freq;
u32 curr_freq;
+   bool keep_link_active;



Re: [PATCH 1/1] scsi: ufs: Remove scale down gear hard code

2020-11-30 Thread Asutosh Das (asd)

On 11/26/2020 5:58 PM, Can Guo wrote:

Instead of making the scale down gear a hard code, make it a member of
ufs_clk_scaling struct.

Signed-off-by: Can Guo 
---


Reviewed-by: Asutosh Das 


  drivers/scsi/ufs/ufshcd.c | 12 +++-
  drivers/scsi/ufs/ufshcd.h |  2 ++
  2 files changed, 9 insertions(+), 5 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 44254c9..1789df3 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -1100,7 +1100,6 @@ static int ufshcd_wait_for_doorbell_clr(struct ufs_hba 
*hba,
   */
  static int ufshcd_scale_gear(struct ufs_hba *hba, bool scale_up)
  {
-   #define UFS_MIN_GEAR_TO_SCALE_DOWN  UFS_HS_G1
int ret = 0;
struct ufs_pa_layer_attr new_pwr_info;
  
@@ -,16 +1110,16 @@ static int ufshcd_scale_gear(struct ufs_hba *hba, bool scale_up)

memcpy(_pwr_info, >pwr_info,
   sizeof(struct ufs_pa_layer_attr));
  
-		if (hba->pwr_info.gear_tx > UFS_MIN_GEAR_TO_SCALE_DOWN

-   || hba->pwr_info.gear_rx > UFS_MIN_GEAR_TO_SCALE_DOWN) {
+   if (hba->pwr_info.gear_tx > hba->clk_scaling.min_gear ||
+   hba->pwr_info.gear_rx > hba->clk_scaling.min_gear) {
/* save the current power mode */
memcpy(>clk_scaling.saved_pwr_info.info,
>pwr_info,
sizeof(struct ufs_pa_layer_attr));
  
  			/* scale down gear */

-   new_pwr_info.gear_tx = UFS_MIN_GEAR_TO_SCALE_DOWN;
-   new_pwr_info.gear_rx = UFS_MIN_GEAR_TO_SCALE_DOWN;
+   new_pwr_info.gear_tx = hba->clk_scaling.min_gear;
+   new_pwr_info.gear_rx = hba->clk_scaling.min_gear;
}
}
  
@@ -1824,6 +1823,9 @@ static void ufshcd_init_clk_scaling(struct ufs_hba *hba)

if (!ufshcd_is_clkscaling_supported(hba))
return;
  
+	if (!hba->clk_scaling.min_gear)

+   hba->clk_scaling.min_gear = UFS_HS_G1;
+
INIT_WORK(>clk_scaling.suspend_work,
  ufshcd_clk_scaling_suspend_work);
INIT_WORK(>clk_scaling.resume_work,
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 6f0f2d4..bdab23e 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -385,6 +385,7 @@ struct ufs_saved_pwr_info {
   * @workq: workqueue to schedule devfreq suspend/resume work
   * @suspend_work: worker to suspend devfreq
   * @resume_work: worker to resume devfreq
+ * @min_gear: lowest HS gear to scale down to
   * @is_allowed: tracks if scaling is currently allowed or not
   * @is_busy_started: tracks if busy period has started or not
   * @is_suspended: tracks if devfreq is suspended or not
@@ -399,6 +400,7 @@ struct ufs_clk_scaling {
struct workqueue_struct *workq;
struct work_struct suspend_work;
struct work_struct resume_work;
+   u32 min_gear;
bool is_allowed;
bool is_busy_started;
bool is_suspended;




--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
Linux Foundation Collaborative Project


Re: [RFC PATCH v1] scsi: ufs: Remove pre-defined initial VCC voltage values

2020-11-30 Thread Asutosh Das (asd)

On 11/30/2020 1:16 AM, Stanley Chu wrote:

UFS specficication allows different VCC configurations for UFS devices,
for example,
(1). 2.70V - 3.60V (By default)
(2). 1.70V - 1.95V (Activated if "vcc-supply-1p8" is declared in
   device tree)
(3). 2.40V - 2.70V (Supported since UFS 3.x)

With the introduction of UFS 3.x products, an issue is happening that
UFS driver will use wrong "min_uV/max_uV" configuration to toggle VCC
regulator on UFU 3.x products with VCC configuration (3) used.

To solve this issue, we simply remove pre-defined initial VCC voltage
values in UFS driver with below reasons,

1. UFS specifications do not define how to detect the VCC configuration
supported by attached device.

2. Device tree already supports standard regulator properties.

Therefore VCC voltage shall be defined correctly in device tree, and
shall not be changed by UFS driver. What UFS driver needs to do is simply
enabling or disabling the VCC regulator only.

This is a RFC conceptional patch. Please help review this and feel
free to feedback any ideas. Once this concept is accepted, and then
I would post a more completed patch series to fix this issue.

Signed-off-by: Stanley Chu 
---
  drivers/scsi/ufs/ufshcd-pltfrm.c | 10 +-
  1 file changed, 1 insertion(+), 9 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
index a6f76399b3ae..3965be03c136 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -133,15 +133,7 @@ static int ufshcd_populate_vreg(struct device *dev, const 
char *name,
vreg->max_uA = 0;
}
  
-	if (!strcmp(name, "vcc")) {

-   if (of_property_read_bool(np, "vcc-supply-1p8")) {
-   vreg->min_uV = UFS_VREG_VCC_1P8_MIN_UV;
-   vreg->max_uV = UFS_VREG_VCC_1P8_MAX_UV;
-   } else {
-   vreg->min_uV = UFS_VREG_VCC_MIN_UV;
-   vreg->max_uV = UFS_VREG_VCC_MAX_UV;
-   }
-   } else if (!strcmp(name, "vccq")) {
+   if (!strcmp(name, "vccq")) {
vreg->min_uV = UFS_VREG_VCCQ_MIN_UV;
vreg->max_uV = UFS_VREG_VCCQ_MAX_UV;
} else if (!strcmp(name, "vccq2")) {



Hi Stanley

Thanks for the patch. Bao (nguyenb) was also working towards something 
similar.
Would it be possible for you to take into account the scenario in which 
the same platform supports both 2.x and 3.x UFS devices?


These've different voltage requirements, 2.4v-3.6v.
I'm not sure if standard dts regulator properties can support this.

-asd


--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
Linux Foundation Collaborative Project


Re: [PATCH v3 3/3] scsi: ufs: Print host regs in IRQ handler when AH8 error happens

2020-11-17 Thread Asutosh Das (asd)

On 11/16/2020 11:04 PM, Can Guo wrote:

When AH8 error happens, all the regs and states are dumped in err handler.
Sometime we need to look into host regs right after AH8 error happens,
which is before leaving the IRQ handler.

Signed-off-by: Can Guo 
---


Reviewed-by: Asutosh Das 


  drivers/scsi/ufs/ufshcd.c | 3 ++-
  1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index cd7394e..a7857f6 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -6057,7 +6057,8 @@ static irqreturn_t ufshcd_check_errors(struct ufs_hba 
*hba)
hba->saved_uic_err |= hba->uic_error;
  
  		/* dump controller state before resetting */

-   if ((hba->saved_err & (INT_FATAL_ERRORS)) ||
+   if ((hba->saved_err &
+(INT_FATAL_ERRORS | UFSHCD_UIC_HIBERN8_MASK)) ||
(hba->saved_uic_err &&
 (hba->saved_uic_err != UFSHCD_UIC_PA_GENERIC_ERROR))) {
dev_err(hba->dev, "%s: saved_err 0x%x saved_uic_err 
0x%x\n",




--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
Linux Foundation Collaborative Project


Re: [PATCH v1 1/2] scsi: ufs: Fix unbalanced scsi_block_reqs_cnt caused by ufshcd_hold()

2020-11-11 Thread Asutosh Das (asd)

On 11/2/2020 10:24 PM, Can Guo wrote:

The scsi_block_reqs_cnt increased in ufshcd_hold() is supposed to be
decreased back in ufshcd_ungate_work() in a paired way. However, if
specific ufshcd_hold/release sequences are met, it is possible that
scsi_block_reqs_cnt is increased twice but only one ungate work is
queued. To make sure scsi_block_reqs_cnt is handled by ufshcd_hold() and
ufshcd_ungate_work() in a paired way, increase it only if queue_work()
returns true.

Signed-off-by: Can Guo 
Reviewed-by: Hongwu Su 
---


Reviewed-by: Asutosh Das 


  drivers/scsi/ufs/ufshcd.c | 6 +++---
  1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 847f355..efa7d86 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -1634,12 +1634,12 @@ int ufshcd_hold(struct ufs_hba *hba, bool async)
 */
/* fallthrough */
case CLKS_OFF:
-   ufshcd_scsi_block_requests(hba);
hba->clk_gating.state = REQ_CLKS_ON;
trace_ufshcd_clk_gating(dev_name(hba->dev),
hba->clk_gating.state);
-   queue_work(hba->clk_gating.clk_gating_workq,
-  >clk_gating.ungate_work);
+   if (queue_work(hba->clk_gating.clk_gating_workq,
+  >clk_gating.ungate_work))
+   ufshcd_scsi_block_requests(hba);
/*
 * fall through to check if we should wait for this
 * work to be done or not.




--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
Linux Foundation Collaborative Project


Re: [PATCH v2 1/1] scsi: ufs: Fix unexpected values get from ufshcd_read_desc_param()

2020-11-10 Thread Asutosh Das (asd)

On 10/21/2020 10:59 PM, Can Guo wrote:

Since WB feature has been added, WB related sysfs entries can be accessed
even when an UFS device does not support WB feature. In that case, the
descriptors which are not supported by the UFS device may be wrongly
reported when they are accessed from their corrsponding sysfs entries.
Fix it by adding a sanity check of parameter offset against the actual
decriptor length.

Signed-off-by: Can Guo 
---


Reviewed-by: Asutosh Das 


  drivers/scsi/ufs/ufshcd.c | 24 +++-
  1 file changed, 15 insertions(+), 9 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index a2ebcc8..aeec10d 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -3184,13 +3184,19 @@ int ufshcd_read_desc_param(struct ufs_hba *hba,
/* Get the length of descriptor */
ufshcd_map_desc_id_to_length(hba, desc_id, _len);
if (!buff_len) {
-   dev_err(hba->dev, "%s: Failed to get desc length", __func__);
+   dev_err(hba->dev, "%s: Failed to get desc length\n", __func__);
+   return -EINVAL;
+   }
+
+   if (param_offset >= buff_len) {
+   dev_err(hba->dev, "%s: Invalid offset 0x%x in descriptor IDN 0x%x, 
length 0x%x\n",
+   __func__, param_offset, desc_id, buff_len);
return -EINVAL;
}
  
  	/* Check whether we need temp memory */

if (param_offset != 0 || param_size < buff_len) {
-   desc_buf = kmalloc(buff_len, GFP_KERNEL);
+   desc_buf = kzalloc(buff_len, GFP_KERNEL);
if (!desc_buf)
return -ENOMEM;
} else {
@@ -3204,14 +3210,14 @@ int ufshcd_read_desc_param(struct ufs_hba *hba,
desc_buf, _len);
  
  	if (ret) {

-   dev_err(hba->dev, "%s: Failed reading descriptor. desc_id %d, 
desc_index %d, param_offset %d, ret %d",
+   dev_err(hba->dev, "%s: Failed reading descriptor. desc_id %d, 
desc_index %d, param_offset %d, ret %d\n",
__func__, desc_id, desc_index, param_offset, ret);
goto out;
}
  
  	/* Sanity check */

if (desc_buf[QUERY_DESC_DESC_TYPE_OFFSET] != desc_id) {
-   dev_err(hba->dev, "%s: invalid desc_id %d in descriptor header",
+   dev_err(hba->dev, "%s: invalid desc_id %d in descriptor 
header\n",
__func__, desc_buf[QUERY_DESC_DESC_TYPE_OFFSET]);
ret = -EINVAL;
goto out;
@@ -3221,12 +3227,12 @@ int ufshcd_read_desc_param(struct ufs_hba *hba,
buff_len = desc_buf[QUERY_DESC_LENGTH_OFFSET];
ufshcd_update_desc_length(hba, desc_id, desc_index, buff_len);
  
-	/* Check wherher we will not copy more data, than available */

-   if (is_kmalloc && (param_offset + param_size) > buff_len)
-   param_size = buff_len - param_offset;
-
-   if (is_kmalloc)
+   if (is_kmalloc) {
+   /* Make sure we don't copy more data than available */
+   if (param_offset + param_size > buff_len)
+   param_size = buff_len - param_offset;
memcpy(param_read_buf, _buf[param_offset], param_size);
+   }
  out:
if (is_kmalloc)
kfree(desc_buf);




--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
Linux Foundation Collaborative Project


Re: [PATCH v2] scsi: ufshcd: fix missing destroy_workqueue()

2020-11-10 Thread Asutosh Das (asd)

On 11/9/2020 11:42 PM, Qinglang Miao wrote:

Add the missing destroy_workqueue() before return from
ufshcd_init in the error handling case as well as in
ufshcd_remove.

Fixes: 4db7a2360597 ("scsi: ufs: Fix concurrency of error handler and other error 
recovery paths")
Suggested-by: Avri Altman 
Signed-off-by: Qinglang Miao 
---


Reviewed-by: Asutosh Das 


  v2: consider missing destroy_workqueue ufshcd_remove either.

  drivers/scsi/ufs/ufshcd.c | 2 ++
  1 file changed, 2 insertions(+)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index b8f573a02713..adbdda4f556b 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -8906,6 +8906,7 @@ void ufshcd_remove(struct ufs_hba *hba)
blk_mq_free_tag_set(>tmf_tag_set);
blk_cleanup_queue(hba->cmd_queue);
scsi_remove_host(hba->host);
+   destroy_workqueue(hba->eh_wq);
/* disable interrupts */
ufshcd_disable_intr(hba, hba->intr_mask);
ufshcd_hba_stop(hba);
@@ -9206,6 +9207,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem 
*mmio_base, unsigned int irq)
  exit_gating:
ufshcd_exit_clk_scaling(hba);
ufshcd_exit_clk_gating(hba);
+   destroy_workqueue(hba->eh_wq);
  out_disable:
hba->is_irq_enabled = false;
ufshcd_hba_exit(hba);




--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
Linux Foundation Collaborative Project


Re: [PATCH V4 1/2] scsi: ufs: Add DeepSleep feature

2020-11-04 Thread Asutosh Das (asd)

On 11/3/2020 6:14 AM, Adrian Hunter wrote:

DeepSleep is a UFS v3.1 feature that achieves the lowest power consumption
of the device, apart from power off.

In DeepSleep mode, no commands are accepted, and the only way to exit is
using a hardware reset or power cycle.

This patch assumes that if a power cycle was an option, then power off
would be preferable, so only exit via a hardware reset is supported.

Drivers that wish to support DeepSleep need to set a new capability flag
UFSHCD_CAP_DEEPSLEEP and provide a hardware reset via the existing
  ->device_reset() callback.

It is assumed that UFS devices with wspecversion >= 0x310 support
DeepSleep.

Signed-off-by: Adrian Hunter 
---


Reviewed-by: Asutosh Das 



  Documentation/ABI/testing/sysfs-driver-ufs | 34 +++
  drivers/scsi/ufs/ufs-sysfs.c   |  7 
  drivers/scsi/ufs/ufs.h |  1 +
  drivers/scsi/ufs/ufshcd.c  | 39 --
  drivers/scsi/ufs/ufshcd.h  | 17 +-
  include/trace/events/ufs.h |  3 +-
  6 files changed, 83 insertions(+), 18 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-driver-ufs 
b/Documentation/ABI/testing/sysfs-driver-ufs
index adc0d0e91607..e77fa784d6d8 100644
--- a/Documentation/ABI/testing/sysfs-driver-ufs
+++ b/Documentation/ABI/testing/sysfs-driver-ufs
@@ -916,21 +916,24 @@ Date: September 2014
  Contact:  Subhash Jadavani 
  Description:  This entry could be used to set or show the UFS device
runtime power management level. The current driver
-   implementation supports 6 levels with next target states:
+   implementation supports 7 levels with next target states:
  
  		==  

-   0   an UFS device will stay active, an UIC link will
+   0   UFS device will stay active, UIC link will
stay active
-   1   an UFS device will stay active, an UIC link will
+   1   UFS device will stay active, UIC link will
hibernate
-   2   an UFS device will moved to sleep, an UIC link will
+   2   UFS device will be moved to sleep, UIC link will
stay active
-   3   an UFS device will moved to sleep, an UIC link will
+   3   UFS device will be moved to sleep, UIC link will
hibernate
-   4   an UFS device will be powered off, an UIC link will
+   4   UFS device will be powered off, UIC link will
hibernate
-   5   an UFS device will be powered off, an UIC link will
+   5   UFS device will be powered off, UIC link will
be powered off
+   6   UFS device will be moved to deep sleep, UIC link
+   will be powered off. Note, deep sleep might not be
+   supported in which case this value will not be accepted
==  
  
  What:		/sys/bus/platform/drivers/ufshcd/*/rpm_target_dev_state

@@ -954,21 +957,24 @@ Date: September 2014
  Contact:  Subhash Jadavani 
  Description:  This entry could be used to set or show the UFS device
system power management level. The current driver
-   implementation supports 6 levels with next target states:
+   implementation supports 7 levels with next target states:
  
  		==  

-   0   an UFS device will stay active, an UIC link will
+   0   UFS device will stay active, UIC link will
stay active
-   1   an UFS device will stay active, an UIC link will
+   1   UFS device will stay active, UIC link will
hibernate
-   2   an UFS device will moved to sleep, an UIC link will
+   2   UFS device will be moved to sleep, UIC link will
stay active
-   3   an UFS device will moved to sleep, an UIC link will
+   3   UFS device will be moved to sleep, UIC link will
hibernate
-   4   an UFS device will be powered off, an UIC link will
+   4   UFS device will be powered off, UIC link will
hibernate
-   5   an UFS device will be powered off, an UIC link will
+   5   UFS device will be powered off, UIC link will
be powered off
+   6   UFS device will be moved to deep sleep, UIC link
+   will be powered off. Note, deep sleep might not be
+   supported in which case this value will not be accepted
==  
  
  What:		/sys/bus/platform/drivers/ufshcd/*/spm_target_dev_state

diff

Re: [PATCH V4 2/2] scsi: ufs: Allow an error return value from ->device_reset()

2020-11-04 Thread Asutosh Das (asd)

On 11/3/2020 6:14 AM, Adrian Hunter wrote:

It is simpler for drivers to provide a ->device_reset() callback
irrespective of whether the GPIO, or firmware interface necessary to do the
reset, is discovered during probe.

Change ->device_reset() to return an error code.  Drivers that provide
the callback, but do not do the reset operation should return -EOPNOTSUPP.

Signed-off-by: Adrian Hunter 


Reviewed-by: Asutosh Das 


---
  drivers/scsi/ufs/ufs-mediatek.c |  4 +++-
  drivers/scsi/ufs/ufs-qcom.c |  6 --
  drivers/scsi/ufs/ufshcd.h   | 11 +++
  3 files changed, 14 insertions(+), 7 deletions(-)

diff --git a/drivers/scsi/ufs/ufs-mediatek.c b/drivers/scsi/ufs/ufs-mediatek.c
index 8df73bc2f8cb..914a827a93ee 100644
--- a/drivers/scsi/ufs/ufs-mediatek.c
+++ b/drivers/scsi/ufs/ufs-mediatek.c
@@ -743,7 +743,7 @@ static int ufs_mtk_link_startup_notify(struct ufs_hba *hba,
return ret;
  }
  
-static void ufs_mtk_device_reset(struct ufs_hba *hba)

+static int ufs_mtk_device_reset(struct ufs_hba *hba)
  {
struct arm_smccc_res res;
  
@@ -764,6 +764,8 @@ static void ufs_mtk_device_reset(struct ufs_hba *hba)

usleep_range(1, 15000);
  
  	dev_info(hba->dev, "device reset done\n");

+
+   return 0;
  }
  
  static int ufs_mtk_link_set_hpm(struct ufs_hba *hba)

diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index 9a19c6d15d3b..357c3b49321d 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -1422,13 +1422,13 @@ static void ufs_qcom_dump_dbg_regs(struct ufs_hba *hba)
   *
   * Toggles the (optional) reset line to reset the attached device.
   */
-static void ufs_qcom_device_reset(struct ufs_hba *hba)
+static int ufs_qcom_device_reset(struct ufs_hba *hba)
  {
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
  
  	/* reset gpio is optional */

if (!host->device_reset)
-   return;
+   return -EOPNOTSUPP;
  
  	/*

 * The UFS device shall detect reset pulses of 1us, sleep for 10us to
@@ -1439,6 +1439,8 @@ static void ufs_qcom_device_reset(struct ufs_hba *hba)
  
  	gpiod_set_value_cansleep(host->device_reset, 0);

usleep_range(10, 15);
+
+   return 0;
  }
  
  #if IS_ENABLED(CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND)

diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 213be0667b59..5191d87f6263 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -323,7 +323,7 @@ struct ufs_hba_variant_ops {
int (*resume)(struct ufs_hba *, enum ufs_pm_op);
void(*dbg_register_dump)(struct ufs_hba *hba);
int (*phy_initialization)(struct ufs_hba *);
-   void(*device_reset)(struct ufs_hba *hba);
+   int (*device_reset)(struct ufs_hba *hba);
void(*config_scaling_param)(struct ufs_hba *hba,
struct devfreq_dev_profile *profile,
void *data);
@@ -1207,9 +1207,12 @@ static inline void ufshcd_vops_dbg_register_dump(struct 
ufs_hba *hba)
  static inline void ufshcd_vops_device_reset(struct ufs_hba *hba)
  {
if (hba->vops && hba->vops->device_reset) {
-   hba->vops->device_reset(hba);
-   ufshcd_set_ufs_dev_active(hba);
-   ufshcd_update_reg_hist(>ufs_stats.dev_reset, 0);
+   int err = hba->vops->device_reset(hba);
+
+   if (!err)
+   ufshcd_set_ufs_dev_active(hba);
+   if (err != -EOPNOTSUPP)
+   ufshcd_update_reg_hist(>ufs_stats.dev_reset, err);
}
  }
  




--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
Linux Foundation Collaborative Project


[PATCH v2 2/2] ufs: qcom: Enable aggressive power collapse for ufs hba

2020-10-27 Thread Asutosh Das
Enabling this capability to let hba power-collapse
more often to save power.

Reviewed-by: Can Guo 
Signed-off-by: Asutosh Das 
---
 drivers/scsi/ufs/ufs-qcom.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index f9d6ef3..9a19c6d 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -863,6 +863,7 @@ static void ufs_qcom_set_caps(struct ufs_hba *hba)
hba->caps |= UFSHCD_CAP_AUTO_BKOPS_SUSPEND;
hba->caps |= UFSHCD_CAP_WB_EN;
hba->caps |= UFSHCD_CAP_CRYPTO;
+   hba->caps |= UFSHCD_CAP_AGGR_POWER_COLLAPSE;
 
if (host->hw_ver.major >= 0x2) {
host->caps = UFS_QCOM_CAP_QUNIPRO |
-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux 
Foundation Collaborative Project.



[PATCH v2 1/2] scsi: ufs: Put hba into LPM during clk gating

2020-10-27 Thread Asutosh Das
From: Can Guo 

During clock gating, after clocks are disabled,
put hba into LPM to save more power.

Acked-by: Stanley Chu 
Signed-off-by: Can Guo 
Signed-off-by: Asutosh Das 
---
 drivers/scsi/ufs/ufshcd.c |  9 +++--
 drivers/scsi/ufs/ufshcd.h | 13 +
 2 files changed, 20 insertions(+), 2 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 47c544d..9fc1bac 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -245,6 +245,8 @@ static int ufshcd_wb_buf_flush_disable(struct ufs_hba *hba);
 static int ufshcd_wb_ctrl(struct ufs_hba *hba, bool enable);
 static int ufshcd_wb_toggle_flush_during_h8(struct ufs_hba *hba, bool set);
 static inline void ufshcd_wb_toggle_flush(struct ufs_hba *hba, bool enable);
+static void ufshcd_hba_vreg_set_lpm(struct ufs_hba *hba);
+static void ufshcd_hba_vreg_set_hpm(struct ufs_hba *hba);
 
 static inline bool ufshcd_valid_tag(struct ufs_hba *hba, int tag)
 {
@@ -1548,6 +1550,7 @@ static void ufshcd_ungate_work(struct work_struct *work)
}
 
spin_unlock_irqrestore(hba->host->host_lock, flags);
+   ufshcd_hba_vreg_set_hpm(hba);
ufshcd_setup_clocks(hba, true);
 
ufshcd_enable_irq(hba);
@@ -1713,6 +1716,8 @@ static void ufshcd_gate_work(struct work_struct *work)
/* If link is active, device ref_clk can't be switched off */
__ufshcd_setup_clocks(hba, false, true);
 
+   /* Put the host controller in low power mode if possible */
+   ufshcd_hba_vreg_set_lpm(hba);
/*
 * In case you are here to cancel this work the gating state
 * would be marked as REQ_CLKS_ON. In this case keep the state
@@ -8405,13 +8410,13 @@ static int ufshcd_vreg_set_hpm(struct ufs_hba *hba)
 
 static void ufshcd_hba_vreg_set_lpm(struct ufs_hba *hba)
 {
-   if (ufshcd_is_link_off(hba))
+   if (ufshcd_is_link_off(hba) || ufshcd_can_aggressive_pc(hba))
ufshcd_setup_hba_vreg(hba, false);
 }
 
 static void ufshcd_hba_vreg_set_hpm(struct ufs_hba *hba)
 {
-   if (ufshcd_is_link_off(hba))
+   if (ufshcd_is_link_off(hba) || ufshcd_can_aggressive_pc(hba))
ufshcd_setup_hba_vreg(hba, true);
 }
 
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 47eb143..0fbb735 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -592,6 +592,13 @@ enum ufshcd_caps {
 * inline crypto engine, if it is present
 */
UFSHCD_CAP_CRYPTO   = 1 << 8,
+
+   /*
+* This capability allows the controller regulators to be put into
+* lpm mode aggressively during clock gating.
+* This would increase power savings.
+*/
+   UFSHCD_CAP_AGGR_POWER_COLLAPSE  = 1 << 9,
 };
 
 struct ufs_hba_variant_params {
@@ -829,6 +836,12 @@ return true;
 #endif
 }
 
+static inline bool ufshcd_can_aggressive_pc(struct ufs_hba *hba)
+{
+   return !!(ufshcd_is_link_hibern8(hba) &&
+ (hba->caps & UFSHCD_CAP_AGGR_POWER_COLLAPSE));
+}
+
 static inline bool ufshcd_is_auto_hibern8_supported(struct ufs_hba *hba)
 {
return (hba->capabilities & MASK_AUTO_HIBERN8_SUPPORT) &&
-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux 
Foundation Collaborative Project.



[PATCH v1 2/2] ufs: qcom: Enable aggressive power collapse for ufs hba

2020-10-26 Thread Asutosh Das
Enabling this capability to let hba power-collapse
more often to save power.

Signed-off-by: Asutosh Das 
---
 drivers/scsi/ufs/ufs-qcom.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index f9d6ef3..9a19c6d 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -863,6 +863,7 @@ static void ufs_qcom_set_caps(struct ufs_hba *hba)
hba->caps |= UFSHCD_CAP_AUTO_BKOPS_SUSPEND;
hba->caps |= UFSHCD_CAP_WB_EN;
hba->caps |= UFSHCD_CAP_CRYPTO;
+   hba->caps |= UFSHCD_CAP_AGGR_POWER_COLLAPSE;
 
if (host->hw_ver.major >= 0x2) {
host->caps = UFS_QCOM_CAP_QUNIPRO |
-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux 
Foundation Collaborative Project.



[PATCH v1 1/2] scsi: ufs: Put hba into LPM during clk gating

2020-10-26 Thread Asutosh Das
From: Can Guo 

During clock gating, after clocks are disabled,
put hba into LPM to save more power.

Signed-off-by: Can Guo 
Signed-off-by: Asutosh Das 
---
 drivers/scsi/ufs/ufshcd.c |  7 +--
 drivers/scsi/ufs/ufshcd.h | 13 +
 2 files changed, 18 insertions(+), 2 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 47c544d..55ca8c6 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -1548,6 +1548,7 @@ static void ufshcd_ungate_work(struct work_struct *work)
}
 
spin_unlock_irqrestore(hba->host->host_lock, flags);
+   ufshcd_hba_vreg_set_hpm(hba);
ufshcd_setup_clocks(hba, true);
 
ufshcd_enable_irq(hba);
@@ -1713,6 +1714,8 @@ static void ufshcd_gate_work(struct work_struct *work)
/* If link is active, device ref_clk can't be switched off */
__ufshcd_setup_clocks(hba, false, true);
 
+   /* Put the host controller in low power mode if possible */
+   ufshcd_hba_vreg_set_lpm(hba);
/*
 * In case you are here to cancel this work the gating state
 * would be marked as REQ_CLKS_ON. In this case keep the state
@@ -8405,13 +8408,13 @@ static int ufshcd_vreg_set_hpm(struct ufs_hba *hba)
 
 static void ufshcd_hba_vreg_set_lpm(struct ufs_hba *hba)
 {
-   if (ufshcd_is_link_off(hba))
+   if (ufshcd_is_link_off(hba) || ufshcd_can_aggressive_pc(hba))
ufshcd_setup_hba_vreg(hba, false);
 }
 
 static void ufshcd_hba_vreg_set_hpm(struct ufs_hba *hba)
 {
-   if (ufshcd_is_link_off(hba))
+   if (ufshcd_is_link_off(hba) || ufshcd_can_aggressive_pc(hba))
ufshcd_setup_hba_vreg(hba, true);
 }
 
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 47eb143..0fbb735 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -592,6 +592,13 @@ enum ufshcd_caps {
 * inline crypto engine, if it is present
 */
UFSHCD_CAP_CRYPTO   = 1 << 8,
+
+   /*
+* This capability allows the controller regulators to be put into
+* lpm mode aggressively during clock gating.
+* This would increase power savings.
+*/
+   UFSHCD_CAP_AGGR_POWER_COLLAPSE  = 1 << 9,
 };
 
 struct ufs_hba_variant_params {
@@ -829,6 +836,12 @@ return true;
 #endif
 }
 
+static inline bool ufshcd_can_aggressive_pc(struct ufs_hba *hba)
+{
+   return !!(ufshcd_is_link_hibern8(hba) &&
+ (hba->caps & UFSHCD_CAP_AGGR_POWER_COLLAPSE));
+}
+
 static inline bool ufshcd_is_auto_hibern8_supported(struct ufs_hba *hba)
 {
return (hba->capabilities & MASK_AUTO_HIBERN8_SUPPORT) &&
-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux 
Foundation Collaborative Project.



  1   2   3   >