* [PATCH 1/7] ufs: core: Change the type of an ufshcd_clkgate_delay_set() argument
2026-01-16 18:26 [PATCH 0/7] ufs: Remove the clock gating code Bart Van Assche
@ 2026-01-16 18:26 ` Bart Van Assche
2026-01-16 18:26 ` [PATCH 2/7] ufs: host: mediatek: Use ufshcd_clkgate_delay_set() Bart Van Assche
` (6 subsequent siblings)
7 siblings, 0 replies; 16+ messages in thread
From: Bart Van Assche @ 2026-01-16 18:26 UTC (permalink / raw)
To: Martin K . Petersen
Cc: linux-scsi, Bart Van Assche, James E.J. Bottomley, Peter Wang,
Avri Altman, Bean Huo, Adrian Hunter, Bao D. Nguyen
Prepare for introducing a second ufshcd_clkgate_delay_set() caller and
also for modifying the implementation of ufshcd_clkgate_delay_set(). No
functionality has been changed.
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
---
drivers/ufs/core/ufshcd.c | 7 +++----
include/ufs/ufshcd.h | 2 +-
2 files changed, 4 insertions(+), 5 deletions(-)
diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c
index 057678f4c50a..2ee1947af797 100644
--- a/drivers/ufs/core/ufshcd.c
+++ b/drivers/ufs/core/ufshcd.c
@@ -2115,10 +2115,8 @@ static ssize_t ufshcd_clkgate_delay_show(struct device *dev,
return sysfs_emit(buf, "%lu\n", hba->clk_gating.delay_ms);
}
-void ufshcd_clkgate_delay_set(struct device *dev, unsigned long value)
+void ufshcd_clkgate_delay_set(struct ufs_hba *hba, unsigned long value)
{
- struct ufs_hba *hba = dev_get_drvdata(dev);
-
guard(spinlock_irqsave)(&hba->clk_gating.lock);
hba->clk_gating.delay_ms = value;
}
@@ -2127,12 +2125,13 @@ EXPORT_SYMBOL_GPL(ufshcd_clkgate_delay_set);
static ssize_t ufshcd_clkgate_delay_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
+ struct ufs_hba *hba = dev_get_drvdata(dev);
unsigned long value;
if (kstrtoul(buf, 0, &value))
return -EINVAL;
- ufshcd_clkgate_delay_set(dev, value);
+ ufshcd_clkgate_delay_set(hba, value);
return count;
}
diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h
index 19154228780b..b4aef7acd351 100644
--- a/include/ufs/ufshcd.h
+++ b/include/ufs/ufshcd.h
@@ -1433,7 +1433,7 @@ void ufshcd_fixup_dev_quirks(struct ufs_hba *hba,
void ufshcd_hold(struct ufs_hba *hba);
void ufshcd_release(struct ufs_hba *hba);
-void ufshcd_clkgate_delay_set(struct device *dev, unsigned long value);
+void ufshcd_clkgate_delay_set(struct ufs_hba *hba, unsigned long value);
int ufshcd_get_vreg(struct device *dev, struct ufs_vreg *vreg);
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH 2/7] ufs: host: mediatek: Use ufshcd_clkgate_delay_set()
2026-01-16 18:26 [PATCH 0/7] ufs: Remove the clock gating code Bart Van Assche
2026-01-16 18:26 ` [PATCH 1/7] ufs: core: Change the type of an ufshcd_clkgate_delay_set() argument Bart Van Assche
@ 2026-01-16 18:26 ` Bart Van Assche
2026-01-16 18:26 ` [PATCH 3/7] ufs: core: Redirect clock gating to RPM Bart Van Assche
` (5 subsequent siblings)
7 siblings, 0 replies; 16+ messages in thread
From: Bart Van Assche @ 2026-01-16 18:26 UTC (permalink / raw)
To: Martin K . Petersen
Cc: linux-scsi, Bart Van Assche, Peter Wang, Chaotian Jing,
James E.J. Bottomley, Matthias Brugger,
AngeloGioacchino Del Regno
Prepare for modifying the implementation of ufshcd_clkgate_delay_set().
No functionality has been changed.
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
---
drivers/ufs/host/ufs-mediatek.c | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c
index ecbbf52bf734..75cfa18be88b 100644
--- a/drivers/ufs/host/ufs-mediatek.c
+++ b/drivers/ufs/host/ufs-mediatek.c
@@ -1109,7 +1109,6 @@ static void ufs_mtk_vreg_fix_vccqx(struct ufs_hba *hba)
static void ufs_mtk_setup_clk_gating(struct ufs_hba *hba)
{
- unsigned long flags;
u32 ah_ms = 10;
u32 ah_scale, ah_timer;
u32 scale_us[] = {1, 10, 100, 1000, 10000, 100000};
@@ -1124,9 +1123,7 @@ static void ufs_mtk_setup_clk_gating(struct ufs_hba *hba)
ah_ms = ah_timer * scale_us[ah_scale] / 1000;
}
- spin_lock_irqsave(hba->host->host_lock, flags);
- hba->clk_gating.delay_ms = max(ah_ms, 10U);
- spin_unlock_irqrestore(hba->host->host_lock, flags);
+ ufshcd_clkgate_delay_set(hba, max(ah_ms, 10U));
}
}
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH 3/7] ufs: core: Redirect clock gating to RPM
2026-01-16 18:26 [PATCH 0/7] ufs: Remove the clock gating code Bart Van Assche
2026-01-16 18:26 ` [PATCH 1/7] ufs: core: Change the type of an ufshcd_clkgate_delay_set() argument Bart Van Assche
2026-01-16 18:26 ` [PATCH 2/7] ufs: host: mediatek: Use ufshcd_clkgate_delay_set() Bart Van Assche
@ 2026-01-16 18:26 ` Bart Van Assche
2026-01-17 2:05 ` kernel test robot
2026-01-17 2:16 ` kernel test robot
2026-01-16 18:26 ` [PATCH 4/7] ufs: core: Switch from " Bart Van Assche
` (4 subsequent siblings)
7 siblings, 2 replies; 16+ messages in thread
From: Bart Van Assche @ 2026-01-16 18:26 UTC (permalink / raw)
To: Martin K . Petersen
Cc: linux-scsi, Bart Van Assche, James E.J. Bottomley, Peter Wang,
Avri Altman, Bean Huo, Adrian Hunter, Bao D. Nguyen
Let the clkgate_enable and clkgate_delay_ms sysfs attributes control
runtime power management instead of clock gating. Enable runtime power
management if either UFSHCD_CAP_RPM_AUTOSUSPEND or UFSHCD_CAP_CLK_GATING
have been set.
This patch prepares for removing the clock gating code because:
- The functionality of the clock gating code is identical to the runtime
power management code. Both track the number of SCSI commands that are in
progress, gate clocks, disable VCC and VCCQ and trigger link hibernation
after a delay if no commands are in progress.
- The runtime power management code is more efficient because it uses a
per-CPU counter while the clock gating code uses a single counter that
is protected by a spinlock. Every spinlock in the I/O path has a
measurable performance impact. Additionally, the clock gating code
sets the BLK_MQ_F_BLOCKING flag for all SCSI request queues. This flag
increases the amount of time spent in the block layer on processing
requests.
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
---
drivers/ufs/core/ufshcd.c | 49 +++++++++++++++++++++++++--------------
include/ufs/ufshcd.h | 2 +-
2 files changed, 32 insertions(+), 19 deletions(-)
diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c
index 2ee1947af797..900b945444d1 100644
--- a/drivers/ufs/core/ufshcd.c
+++ b/drivers/ufs/core/ufshcd.c
@@ -2107,18 +2107,31 @@ void ufshcd_release(struct ufs_hba *hba)
}
EXPORT_SYMBOL_GPL(ufshcd_release);
+/* The struct device instance that controls RPM for the UFS device. */
+static inline struct device *ufs_rpm_dev(struct ufs_hba *hba)
+{
+ return &hba->ufs_device_wlun->sdev_gendev;
+}
+
static ssize_t ufshcd_clkgate_delay_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct ufs_hba *hba = dev_get_drvdata(dev);
+ struct device *rpm_dev = ufs_rpm_dev(hba);
- return sysfs_emit(buf, "%lu\n", hba->clk_gating.delay_ms);
+ if (!rpm_dev->power.use_autosuspend)
+ return -EIO;
+
+ return sysfs_emit(buf, "%u\n", rpm_dev->power.autosuspend_delay);
}
void ufshcd_clkgate_delay_set(struct ufs_hba *hba, unsigned long value)
{
- guard(spinlock_irqsave)(&hba->clk_gating.lock);
- hba->clk_gating.delay_ms = value;
+ struct device *rpm_dev = ufs_rpm_dev(hba);
+
+ device_lock(rpm_dev);
+ pm_runtime_set_autosuspend_delay(rpm_dev, value);
+ device_unlock(rpm_dev);
}
EXPORT_SYMBOL_GPL(ufshcd_clkgate_delay_set);
@@ -2126,8 +2139,12 @@ static ssize_t ufshcd_clkgate_delay_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct ufs_hba *hba = dev_get_drvdata(dev);
+ struct device *rpm_dev = ufs_rpm_dev(hba);
unsigned long value;
+ if (!rpm_dev->power.use_autosuspend)
+ return -EIO;
+
if (kstrtoul(buf, 0, &value))
return -EINVAL;
@@ -2140,31 +2157,27 @@ static ssize_t ufshcd_clkgate_enable_show(struct device *dev,
{
struct ufs_hba *hba = dev_get_drvdata(dev);
- return sysfs_emit(buf, "%d\n", hba->clk_gating.is_enabled);
+ return sysfs_emit(buf, "%d\n", ufs_rpm_dev(hba)->power.runtime_auto);
}
static ssize_t ufshcd_clkgate_enable_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct ufs_hba *hba = dev_get_drvdata(dev);
- u32 value;
-
- if (kstrtou32(buf, 0, &value))
- return -EINVAL;
-
- value = !!value;
-
- guard(spinlock_irqsave)(&hba->clk_gating.lock);
+ struct device *rpm_dev = ufs_rpm_dev(hba);
+ bool value;
+ int err;
- if (value == hba->clk_gating.is_enabled)
- return count;
+ err = kstrtobool(buf, &value);
+ if (err)
+ return err;
+ device_lock(rpm_dev);
if (value)
- __ufshcd_release(hba);
+ pm_runtime_allow(rpm_dev);
else
- hba->clk_gating.active_reqs++;
-
- hba->clk_gating.is_enabled = value;
+ pm_runtime_forbid(rpm_dev);
+ device_unlock(rpm_dev);
return count;
}
diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h
index b4aef7acd351..dac07a5cd998 100644
--- a/include/ufs/ufshcd.h
+++ b/include/ufs/ufshcd.h
@@ -1224,7 +1224,7 @@ static inline bool ufshcd_can_autobkops_during_suspend(struct ufs_hba *hba)
}
static inline bool ufshcd_is_rpm_autosuspend_allowed(struct ufs_hba *hba)
{
- return hba->caps & UFSHCD_CAP_RPM_AUTOSUSPEND;
+ return hba->caps & (UFSHCD_CAP_RPM_AUTOSUSPEND | UFSHCD_CAP_CLK_GATING);
}
static inline bool ufshcd_is_intr_aggr_allowed(struct ufs_hba *hba)
^ permalink raw reply related [flat|nested] 16+ messages in thread* Re: [PATCH 3/7] ufs: core: Redirect clock gating to RPM
2026-01-16 18:26 ` [PATCH 3/7] ufs: core: Redirect clock gating to RPM Bart Van Assche
@ 2026-01-17 2:05 ` kernel test robot
2026-01-17 2:16 ` kernel test robot
1 sibling, 0 replies; 16+ messages in thread
From: kernel test robot @ 2026-01-17 2:05 UTC (permalink / raw)
To: Bart Van Assche, Martin K . Petersen
Cc: llvm, oe-kbuild-all, linux-scsi, Bart Van Assche,
James E.J. Bottomley, Peter Wang, Avri Altman, Bean Huo,
Adrian Hunter, Bao D. Nguyen
Hi Bart,
kernel test robot noticed the following build errors:
[auto build test ERROR on jejb-scsi/for-next]
[also build test ERROR on mkp-scsi/for-next linus/master v6.19-rc5 next-20260116]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Bart-Van-Assche/ufs-core-Change-the-type-of-an-ufshcd_clkgate_delay_set-argument/20260117-022907
base: https://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi.git for-next
patch link: https://lore.kernel.org/r/20260116182628.3255116-4-bvanassche%40acm.org
patch subject: [PATCH 3/7] ufs: core: Redirect clock gating to RPM
config: hexagon-randconfig-002-20260117 (https://download.01.org/0day-ci/archive/20260117/202601170903.r8uLs14E-lkp@intel.com/config)
compiler: clang version 22.0.0git (https://github.com/llvm/llvm-project 9b8addffa70cee5b2acc5454712d9cf78ce45710)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260117/202601170903.r8uLs14E-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202601170903.r8uLs14E-lkp@intel.com/
All errors (new ones prefixed by >>):
>> drivers/ufs/core/ufshcd.c:2120:22: error: no member named 'use_autosuspend' in 'struct dev_pm_info'
2120 | if (!rpm_dev->power.use_autosuspend)
| ~~~~~~~~~~~~~~ ^
>> drivers/ufs/core/ufshcd.c:2123:48: error: no member named 'autosuspend_delay' in 'struct dev_pm_info'
2123 | return sysfs_emit(buf, "%u\n", rpm_dev->power.autosuspend_delay);
| ~~~~~~~~~~~~~~ ^
drivers/ufs/core/ufshcd.c:2143:22: error: no member named 'use_autosuspend' in 'struct dev_pm_info'
2143 | if (!rpm_dev->power.use_autosuspend)
| ~~~~~~~~~~~~~~ ^
>> drivers/ufs/core/ufshcd.c:2158:57: error: no member named 'runtime_auto' in 'struct dev_pm_info'
2158 | return sysfs_emit(buf, "%d\n", ufs_rpm_dev(hba)->power.runtime_auto);
| ~~~~~~~~~~~~~~~~~~~~~~~ ^
drivers/ufs/core/ufshcd.c:10656:44: warning: shift count >= width of type [-Wshift-count-overflow]
10656 | if (!dma_set_mask_and_coherent(hba->dev, DMA_BIT_MASK(64)))
| ^~~~~~~~~~~~~~~~
include/linux/dma-mapping.h:93:54: note: expanded from macro 'DMA_BIT_MASK'
93 | #define DMA_BIT_MASK(n) (((n) == 64) ? ~0ULL : ((1ULL<<(n))-1))
| ^ ~~~
1 warning and 4 errors generated.
vim +2120 drivers/ufs/core/ufshcd.c
2113
2114 static ssize_t ufshcd_clkgate_delay_show(struct device *dev,
2115 struct device_attribute *attr, char *buf)
2116 {
2117 struct ufs_hba *hba = dev_get_drvdata(dev);
2118 struct device *rpm_dev = ufs_rpm_dev(hba);
2119
> 2120 if (!rpm_dev->power.use_autosuspend)
2121 return -EIO;
2122
> 2123 return sysfs_emit(buf, "%u\n", rpm_dev->power.autosuspend_delay);
2124 }
2125
2126 void ufshcd_clkgate_delay_set(struct ufs_hba *hba, unsigned long value)
2127 {
2128 struct device *rpm_dev = ufs_rpm_dev(hba);
2129
2130 device_lock(rpm_dev);
2131 pm_runtime_set_autosuspend_delay(rpm_dev, value);
2132 device_unlock(rpm_dev);
2133 }
2134 EXPORT_SYMBOL_GPL(ufshcd_clkgate_delay_set);
2135
2136 static ssize_t ufshcd_clkgate_delay_store(struct device *dev,
2137 struct device_attribute *attr, const char *buf, size_t count)
2138 {
2139 struct ufs_hba *hba = dev_get_drvdata(dev);
2140 struct device *rpm_dev = ufs_rpm_dev(hba);
2141 unsigned long value;
2142
2143 if (!rpm_dev->power.use_autosuspend)
2144 return -EIO;
2145
2146 if (kstrtoul(buf, 0, &value))
2147 return -EINVAL;
2148
2149 ufshcd_clkgate_delay_set(hba, value);
2150 return count;
2151 }
2152
2153 static ssize_t ufshcd_clkgate_enable_show(struct device *dev,
2154 struct device_attribute *attr, char *buf)
2155 {
2156 struct ufs_hba *hba = dev_get_drvdata(dev);
2157
> 2158 return sysfs_emit(buf, "%d\n", ufs_rpm_dev(hba)->power.runtime_auto);
2159 }
2160
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 16+ messages in thread* Re: [PATCH 3/7] ufs: core: Redirect clock gating to RPM
2026-01-16 18:26 ` [PATCH 3/7] ufs: core: Redirect clock gating to RPM Bart Van Assche
2026-01-17 2:05 ` kernel test robot
@ 2026-01-17 2:16 ` kernel test robot
1 sibling, 0 replies; 16+ messages in thread
From: kernel test robot @ 2026-01-17 2:16 UTC (permalink / raw)
To: Bart Van Assche, Martin K . Petersen
Cc: oe-kbuild-all, linux-scsi, Bart Van Assche, James E.J. Bottomley,
Peter Wang, Avri Altman, Bean Huo, Adrian Hunter, Bao D. Nguyen
Hi Bart,
kernel test robot noticed the following build warnings:
[auto build test WARNING on jejb-scsi/for-next]
[also build test WARNING on mkp-scsi/for-next linus/master v6.19-rc5 next-20260116]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Bart-Van-Assche/ufs-core-Change-the-type-of-an-ufshcd_clkgate_delay_set-argument/20260117-022907
base: https://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi.git for-next
patch link: https://lore.kernel.org/r/20260116182628.3255116-4-bvanassche%40acm.org
patch subject: [PATCH 3/7] ufs: core: Redirect clock gating to RPM
config: sparc-randconfig-002-20260117 (https://download.01.org/0day-ci/archive/20260117/202601170923.kY23MUEg-lkp@intel.com/config)
compiler: sparc64-linux-gcc (GCC) 8.5.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260117/202601170923.kY23MUEg-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202601170923.kY23MUEg-lkp@intel.com/
All warnings (new ones prefixed by >>):
drivers/ufs/core/ufshcd.c: In function 'ufshcd_clkgate_delay_show':
drivers/ufs/core/ufshcd.c:2120:22: error: 'struct dev_pm_info' has no member named 'use_autosuspend'; did you mean 'async_suspend'?
if (!rpm_dev->power.use_autosuspend)
^~~~~~~~~~~~~~~
async_suspend
drivers/ufs/core/ufshcd.c:2123:47: error: 'struct dev_pm_info' has no member named 'autosuspend_delay'
return sysfs_emit(buf, "%u\n", rpm_dev->power.autosuspend_delay);
^
drivers/ufs/core/ufshcd.c: In function 'ufshcd_clkgate_delay_store':
drivers/ufs/core/ufshcd.c:2143:22: error: 'struct dev_pm_info' has no member named 'use_autosuspend'; did you mean 'async_suspend'?
if (!rpm_dev->power.use_autosuspend)
^~~~~~~~~~~~~~~
async_suspend
drivers/ufs/core/ufshcd.c: In function 'ufshcd_clkgate_enable_show':
drivers/ufs/core/ufshcd.c:2158:56: error: 'struct dev_pm_info' has no member named 'runtime_auto'
return sysfs_emit(buf, "%d\n", ufs_rpm_dev(hba)->power.runtime_auto);
^
>> drivers/ufs/core/ufshcd.c:2159:1: warning: control reaches end of non-void function [-Wreturn-type]
}
^
drivers/ufs/core/ufshcd.c: In function 'ufshcd_clkgate_delay_show':
drivers/ufs/core/ufshcd.c:2124:1: warning: control reaches end of non-void function [-Wreturn-type]
}
^
vim +2159 drivers/ufs/core/ufshcd.c
1ab27c9cf8b63d drivers/scsi/ufs/ufshcd.c Sahitya Tummala 2014-09-25 2152
b427411abb3d61 drivers/scsi/ufs/ufshcd.c Sahitya Tummala 2016-12-22 2153 static ssize_t ufshcd_clkgate_enable_show(struct device *dev,
b427411abb3d61 drivers/scsi/ufs/ufshcd.c Sahitya Tummala 2016-12-22 2154 struct device_attribute *attr, char *buf)
b427411abb3d61 drivers/scsi/ufs/ufshcd.c Sahitya Tummala 2016-12-22 2155 {
b427411abb3d61 drivers/scsi/ufs/ufshcd.c Sahitya Tummala 2016-12-22 2156 struct ufs_hba *hba = dev_get_drvdata(dev);
b427411abb3d61 drivers/scsi/ufs/ufshcd.c Sahitya Tummala 2016-12-22 2157
c24e59ff9dfa8d drivers/ufs/core/ufshcd.c Bart Van Assche 2026-01-16 2158 return sysfs_emit(buf, "%d\n", ufs_rpm_dev(hba)->power.runtime_auto);
b427411abb3d61 drivers/scsi/ufs/ufshcd.c Sahitya Tummala 2016-12-22 @2159 }
b427411abb3d61 drivers/scsi/ufs/ufshcd.c Sahitya Tummala 2016-12-22 2160
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH 4/7] ufs: core: Switch from clock gating to RPM
2026-01-16 18:26 [PATCH 0/7] ufs: Remove the clock gating code Bart Van Assche
` (2 preceding siblings ...)
2026-01-16 18:26 ` [PATCH 3/7] ufs: core: Redirect clock gating to RPM Bart Van Assche
@ 2026-01-16 18:26 ` Bart Van Assche
2026-01-16 18:26 ` [PATCH 5/7] ufs: core: Remove unused code and data structures Bart Van Assche
` (3 subsequent siblings)
7 siblings, 0 replies; 16+ messages in thread
From: Bart Van Assche @ 2026-01-16 18:26 UTC (permalink / raw)
To: Martin K . Petersen
Cc: linux-scsi, Bart Van Assche, James E.J. Bottomley, Peter Wang,
Avri Altman, Bean Huo, Adrian Hunter, Bao D. Nguyen
Make ufshcd_hold() and ufshcd_release() call RPM functions instead of
controlling clock gating directly. This patch does not change the power
consumption of systems with UFS devices: both clock gating and RPM
switch to the same low power state if the UFS device is not in use.
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
---
drivers/ufs/core/ufshcd.c | 103 +++-----------------------------------
1 file changed, 8 insertions(+), 95 deletions(-)
diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c
index 900b945444d1..b3d75152abd9 100644
--- a/drivers/ufs/core/ufshcd.c
+++ b/drivers/ufs/core/ufshcd.c
@@ -1936,72 +1936,10 @@ static void ufshcd_ungate_work(struct work_struct *work)
*/
void ufshcd_hold(struct ufs_hba *hba)
{
- bool flush_result;
- unsigned long flags;
-
- if (!ufshcd_is_clkgating_allowed(hba) ||
- !hba->clk_gating.is_initialized)
- return;
- spin_lock_irqsave(&hba->clk_gating.lock, flags);
- hba->clk_gating.active_reqs++;
-
-start:
- switch (hba->clk_gating.state) {
- case CLKS_ON:
- /*
- * Wait for the ungate work to complete if in progress.
- * Though the clocks may be in ON state, the link could
- * still be in hibner8 state if hibern8 is allowed
- * during clock gating.
- * Make sure we exit hibern8 state also in addition to
- * clocks being ON.
- */
- if (ufshcd_can_hibern8_during_gating(hba) &&
- ufshcd_is_link_hibern8(hba)) {
- spin_unlock_irqrestore(&hba->clk_gating.lock, flags);
- flush_result = flush_work(&hba->clk_gating.ungate_work);
- if (hba->clk_gating.is_suspended && !flush_result)
- return;
- spin_lock_irqsave(&hba->clk_gating.lock, flags);
- goto start;
- }
- break;
- case REQ_CLKS_OFF:
- if (cancel_delayed_work(&hba->clk_gating.gate_work)) {
- hba->clk_gating.state = CLKS_ON;
- trace_ufshcd_clk_gating(hba,
- hba->clk_gating.state);
- break;
- }
- /*
- * If we are here, it means gating work is either done or
- * currently running. Hence, fall through to cancel gating
- * work and to enable clocks.
- */
- fallthrough;
- case CLKS_OFF:
- hba->clk_gating.state = REQ_CLKS_ON;
- trace_ufshcd_clk_gating(hba,
- hba->clk_gating.state);
- queue_work(hba->clk_gating.clk_gating_workq,
- &hba->clk_gating.ungate_work);
- /*
- * fall through to check if we should wait for this
- * work to be done or not.
- */
- fallthrough;
- case REQ_CLKS_ON:
- spin_unlock_irqrestore(&hba->clk_gating.lock, flags);
- flush_work(&hba->clk_gating.ungate_work);
- /* Make sure state is CLKS_ON before returning */
- spin_lock_irqsave(&hba->clk_gating.lock, flags);
- goto start;
- default:
- dev_err(hba->dev, "%s: clk gating is in invalid state %d\n",
- __func__, hba->clk_gating.state);
- break;
- }
- spin_unlock_irqrestore(&hba->clk_gating.lock, flags);
+ /* blk_pm_runtime_init() sets q->dev */
+ if (hba->ufs_device_wlun && hba->ufs_device_wlun->request_queue->dev &&
+ !hba->pm_op_in_progress)
+ ufshcd_rpm_get_sync(hba);
}
EXPORT_SYMBOL_GPL(ufshcd_hold);
@@ -2073,37 +2011,12 @@ static void ufshcd_gate_work(struct work_struct *work)
}
}
-static void __ufshcd_release(struct ufs_hba *hba)
-{
- lockdep_assert_held(&hba->clk_gating.lock);
-
- if (!ufshcd_is_clkgating_allowed(hba))
- return;
-
- hba->clk_gating.active_reqs--;
-
- if (hba->clk_gating.active_reqs || hba->clk_gating.is_suspended ||
- !hba->clk_gating.is_initialized ||
- hba->clk_gating.state == CLKS_OFF)
- return;
-
- scoped_guard(spinlock_irqsave, hba->host->host_lock) {
- if (ufshcd_has_pending_tasks(hba) ||
- hba->ufshcd_state != UFSHCD_STATE_OPERATIONAL)
- return;
- }
-
- hba->clk_gating.state = REQ_CLKS_OFF;
- trace_ufshcd_clk_gating(hba, hba->clk_gating.state);
- queue_delayed_work(hba->clk_gating.clk_gating_workq,
- &hba->clk_gating.gate_work,
- msecs_to_jiffies(hba->clk_gating.delay_ms));
-}
-
void ufshcd_release(struct ufs_hba *hba)
{
- guard(spinlock_irqsave)(&hba->clk_gating.lock);
- __ufshcd_release(hba);
+ /* blk_pm_runtime_init() sets q->dev */
+ if (hba->ufs_device_wlun && hba->ufs_device_wlun->request_queue->dev &&
+ !hba->pm_op_in_progress)
+ ufshcd_rpm_put(hba);
}
EXPORT_SYMBOL_GPL(ufshcd_release);
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH 5/7] ufs: core: Remove unused code and data structures
2026-01-16 18:26 [PATCH 0/7] ufs: Remove the clock gating code Bart Van Assche
` (3 preceding siblings ...)
2026-01-16 18:26 ` [PATCH 4/7] ufs: core: Switch from " Bart Van Assche
@ 2026-01-16 18:26 ` Bart Van Assche
2026-01-17 2:16 ` kernel test robot
2026-01-16 18:26 ` [PATCH 6/7] ufs: core: Remove superfluous ufshcd_{hold,release}() calls Bart Van Assche
` (2 subsequent siblings)
7 siblings, 1 reply; 16+ messages in thread
From: Bart Van Assche @ 2026-01-16 18:26 UTC (permalink / raw)
To: Martin K . Petersen
Cc: linux-scsi, Bart Van Assche, James E.J. Bottomley, Peter Wang,
Avri Altman, Bean Huo, Adrian Hunter, Bao D. Nguyen
Remove the code and data structures that are no longer used due to patch
"ufs: core: Switch from clock gating to RPM".
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
---
drivers/ufs/core/ufs_trace.h | 27 -------
drivers/ufs/core/ufshcd.c | 152 +----------------------------------
include/ufs/ufshcd.h | 33 --------
3 files changed, 4 insertions(+), 208 deletions(-)
diff --git a/drivers/ufs/core/ufs_trace.h b/drivers/ufs/core/ufs_trace.h
index 309ae51b4906..a8395d97ad77 100644
--- a/drivers/ufs/core/ufs_trace.h
+++ b/drivers/ufs/core/ufs_trace.h
@@ -63,7 +63,6 @@
UFS_LINK_STATES;
UFS_PWR_MODES;
-UFSCHD_CLK_GATING_STATES;
UFS_CMD_TRACE_STRINGS
UFS_CMD_TRACE_TSF_TYPES
@@ -81,27 +80,6 @@ UFS_CMD_TRACE_TSF_TYPES
#define show_ufs_cmd_trace_tsf(tsf) \
__print_symbolic(tsf, UFS_CMD_TRACE_TSF_TYPES)
-TRACE_EVENT(ufshcd_clk_gating,
-
- TP_PROTO(struct ufs_hba *hba, int state),
-
- TP_ARGS(hba, state),
-
- TP_STRUCT__entry(
- __field(struct ufs_hba *, hba)
- __field(int, state)
- ),
-
- TP_fast_assign(
- __entry->hba = hba;
- __entry->state = state;
- ),
-
- TP_printk("%s: gating state changed to %s",
- dev_name(__entry->hba->dev),
- __print_symbolic(__entry->state, UFSCHD_CLK_GATING_STATES))
-);
-
TRACE_EVENT(ufshcd_clk_scaling,
TP_PROTO(struct ufs_hba *hba, const char *state, const char *clk,
@@ -180,11 +158,6 @@ DEFINE_EVENT(ufshcd_profiling_template, ufshcd_profile_hibern8,
int err),
TP_ARGS(hba, profile_info, time_us, err));
-DEFINE_EVENT(ufshcd_profiling_template, ufshcd_profile_clk_gating,
- TP_PROTO(struct ufs_hba *hba, const char *profile_info, s64 time_us,
- int err),
- TP_ARGS(hba, profile_info, time_us, err));
-
DEFINE_EVENT(ufshcd_profiling_template, ufshcd_profile_clk_scaling,
TP_PROTO(struct ufs_hba *hba, const char *profile_info, s64 time_us,
int err),
diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c
index b3d75152abd9..1189a9fd39ff 100644
--- a/drivers/ufs/core/ufshcd.c
+++ b/drivers/ufs/core/ufshcd.c
@@ -689,7 +689,6 @@ static void ufshcd_print_host_state(struct ufs_hba *hba)
hba->pm_op_in_progress, hba->is_sys_suspended);
dev_err(hba->dev, "Auto BKOPS=%d, Host self-block=%d\n",
hba->auto_bkops_enabled, hba->host->host_self_blocked);
- dev_err(hba->dev, "Clk gate=%d\n", hba->clk_gating.state);
dev_err(hba->dev,
"last_hibern8_exit_tstamp at %lld us, hibern8_exit_cnt=%d\n",
div_u64(hba->ufs_stats.last_hibern8_exit_tstamp, 1000),
@@ -1895,40 +1894,6 @@ static void ufshcd_exit_clk_scaling(struct ufs_hba *hba)
hba->clk_scaling.is_initialized = false;
}
-static void ufshcd_ungate_work(struct work_struct *work)
-{
- int ret;
- struct ufs_hba *hba = container_of(work, struct ufs_hba,
- clk_gating.ungate_work);
-
- cancel_delayed_work_sync(&hba->clk_gating.gate_work);
-
- scoped_guard(spinlock_irqsave, &hba->clk_gating.lock) {
- if (hba->clk_gating.state == CLKS_ON)
- return;
- }
-
- ufshcd_hba_vreg_set_hpm(hba);
- ufshcd_setup_clocks(hba, true);
-
- ufshcd_enable_irq(hba);
-
- /* Exit from hibern8 */
- if (ufshcd_can_hibern8_during_gating(hba)) {
- /* Prevent gating in this path */
- hba->clk_gating.is_suspended = true;
- if (ufshcd_is_link_hibern8(hba)) {
- ret = ufshcd_uic_hibern8_exit(hba);
- if (ret)
- dev_err(hba->dev, "%s: hibern8 exit failed %d\n",
- __func__, ret);
- else
- ufshcd_set_link_active(hba);
- }
- hba->clk_gating.is_suspended = false;
- }
-}
-
/**
* ufshcd_hold - Enable clocks that were gated earlier due to ufshcd_release.
* Also, exit from hibern8 mode and set the link as active.
@@ -1943,74 +1908,6 @@ void ufshcd_hold(struct ufs_hba *hba)
}
EXPORT_SYMBOL_GPL(ufshcd_hold);
-static void ufshcd_gate_work(struct work_struct *work)
-{
- struct ufs_hba *hba = container_of(work, struct ufs_hba,
- clk_gating.gate_work.work);
- int ret;
-
- scoped_guard(spinlock_irqsave, &hba->clk_gating.lock) {
- /*
- * In case you are here to cancel this work the gating state
- * would be marked as REQ_CLKS_ON. In this case save time by
- * skipping the gating work and exit after changing the clock
- * state to CLKS_ON.
- */
- if (hba->clk_gating.is_suspended ||
- hba->clk_gating.state != REQ_CLKS_OFF) {
- hba->clk_gating.state = CLKS_ON;
- trace_ufshcd_clk_gating(hba,
- hba->clk_gating.state);
- return;
- }
-
- if (hba->clk_gating.active_reqs)
- return;
- }
-
- scoped_guard(spinlock_irqsave, hba->host->host_lock) {
- if (ufshcd_is_ufs_dev_busy(hba) ||
- hba->ufshcd_state != UFSHCD_STATE_OPERATIONAL)
- return;
- }
-
- /* put the link into hibern8 mode before turning off clocks */
- if (ufshcd_can_hibern8_during_gating(hba)) {
- ret = ufshcd_uic_hibern8_enter(hba);
- if (ret) {
- hba->clk_gating.state = CLKS_ON;
- dev_err(hba->dev, "%s: hibern8 enter failed %d\n",
- __func__, ret);
- trace_ufshcd_clk_gating(hba,
- hba->clk_gating.state);
- return;
- }
- ufshcd_set_link_hibern8(hba);
- }
-
- ufshcd_disable_irq(hba);
-
- ufshcd_setup_clocks(hba, false);
-
- /* 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
- * as REQ_CLKS_ON which would anyway imply that clocks are off
- * and a request to turn them on is pending. By doing this way,
- * we keep the state machine in tact and this would ultimately
- * prevent from doing cancel work multiple times when there are
- * new requests arriving before the current cancel work is done.
- */
- guard(spinlock_irqsave)(&hba->clk_gating.lock);
- if (hba->clk_gating.state == REQ_CLKS_OFF) {
- hba->clk_gating.state = CLKS_OFF;
- trace_ufshcd_clk_gating(hba,
- hba->clk_gating.state);
- }
-}
-
void ufshcd_release(struct ufs_hba *hba)
{
/* blk_pm_runtime_init() sets q->dev */
@@ -2127,19 +2024,8 @@ static void ufshcd_init_clk_gating(struct ufs_hba *hba)
if (!ufshcd_is_clkgating_allowed(hba))
return;
- hba->clk_gating.state = CLKS_ON;
-
- hba->clk_gating.delay_ms = 150;
- INIT_DELAYED_WORK(&hba->clk_gating.gate_work, ufshcd_gate_work);
- INIT_WORK(&hba->clk_gating.ungate_work, ufshcd_ungate_work);
-
- hba->clk_gating.clk_gating_workq = alloc_ordered_workqueue(
- "ufs_clk_gating_%d", WQ_MEM_RECLAIM | WQ_HIGHPRI,
- hba->host->host_no);
-
ufshcd_init_clk_gating_sysfs(hba);
- hba->clk_gating.is_enabled = true;
hba->clk_gating.is_initialized = true;
}
@@ -2154,8 +2040,6 @@ static void ufshcd_exit_clk_gating(struct ufs_hba *hba)
ufshcd_hold(hba);
hba->clk_gating.is_initialized = false;
ufshcd_release(hba);
-
- destroy_workqueue(hba->clk_gating.clk_gating_workq);
}
static void ufshcd_clk_scaling_start_busy(struct ufs_hba *hba)
@@ -8407,8 +8291,7 @@ static void ufshcd_rtc_work(struct work_struct *work)
/* Update RTC only when there are no requests in progress and UFSHCI is operational */
if (!ufshcd_is_ufs_dev_busy(hba) &&
- hba->ufshcd_state == UFSHCD_STATE_OPERATIONAL &&
- !hba->clk_gating.active_reqs)
+ hba->ufshcd_state == UFSHCD_STATE_OPERATIONAL)
ufshcd_update_rtc(hba);
if (ufshcd_is_ufs_dev_active(hba) && hba->dev_info.rtc_update_period)
@@ -9420,7 +9303,6 @@ static int ufshcd_setup_clocks(struct ufs_hba *hba, bool on)
int ret = 0;
struct ufs_clk_info *clki;
struct list_head *head = &hba->clk_list_head;
- ktime_t start = ktime_get();
bool clk_state_changed = false;
if (list_empty(head))
@@ -9469,17 +9351,8 @@ static int ufshcd_setup_clocks(struct ufs_hba *hba, bool on)
if (!IS_ERR_OR_NULL(clki->clk) && clki->enabled)
clk_disable_unprepare(clki->clk);
}
- } else if (!ret && on && hba->clk_gating.is_initialized) {
- scoped_guard(spinlock_irqsave, &hba->clk_gating.lock)
- hba->clk_gating.state = CLKS_ON;
- trace_ufshcd_clk_gating(hba,
- hba->clk_gating.state);
}
- if (clk_state_changed)
- trace_ufshcd_profile_clk_gating(hba,
- (on ? "on" : "off"),
- ktime_to_us(ktime_sub(ktime_get(), start)), ret);
return ret;
}
@@ -9913,9 +9786,6 @@ static int __ufshcd_wl_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)
* If we can't transition into any of the low power modes
* just gate the clocks.
*/
- ufshcd_hold(hba);
- hba->clk_gating.is_suspended = true;
-
if (ufshcd_is_clkscaling_supported(hba))
ufshcd_clk_scaling_suspend(hba, true);
@@ -10063,11 +9933,9 @@ static int __ufshcd_wl_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)
msecs_to_jiffies(RPM_DEV_FLUSH_RECHECK_WORK_DELAY_MS));
}
- if (ret) {
+ if (ret)
ufshcd_update_evt_hist(hba, UFS_EVT_WL_SUSP_ERR, (u32)ret);
- hba->clk_gating.is_suspended = false;
- ufshcd_release(hba);
- }
+
hba->pm_op_in_progress = false;
return ret;
}
@@ -10158,8 +10026,7 @@ static int __ufshcd_wl_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)
out:
if (ret)
ufshcd_update_evt_hist(hba, UFS_EVT_WL_RES_ERR, (u32)ret);
- hba->clk_gating.is_suspended = false;
- ufshcd_release(hba);
+
hba->pm_op_in_progress = false;
return ret;
}
@@ -10288,11 +10155,6 @@ static int ufshcd_suspend(struct ufs_hba *hba)
ufshcd_enable_irq(hba);
return ret;
}
- if (ufshcd_is_clkgating_allowed(hba)) {
- hba->clk_gating.state = CLKS_OFF;
- trace_ufshcd_clk_gating(hba,
- hba->clk_gating.state);
- }
ufshcd_vreg_set_lpm(hba);
/* Put the host controller in low power mode if possible */
@@ -10751,12 +10613,6 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
hba->irq = irq;
hba->vps = &ufs_hba_vps;
- /*
- * Initialize clk_gating.lock early since it is being used in
- * ufshcd_setup_clocks()
- */
- spin_lock_init(&hba->clk_gating.lock);
-
/* Initialize mutex for PM QoS request synchronization */
mutex_init(&hba->pm_qos_mutex);
diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h
index dac07a5cd998..69e86185e652 100644
--- a/include/ufs/ufshcd.h
+++ b/include/ufs/ufshcd.h
@@ -382,49 +382,16 @@ struct ufs_hba_variant_ops {
u32 (*freq_to_gear_speed)(struct ufs_hba *hba, unsigned long freq);
};
-/* clock gating state */
-enum clk_gating_state {
- CLKS_OFF,
- CLKS_ON,
- REQ_CLKS_OFF,
- REQ_CLKS_ON,
-};
-
/**
* struct ufs_clk_gating - UFS clock gating related info
- * @gate_work: worker to turn off clocks after some delay as specified in
- * delay_ms
- * @ungate_work: worker to turn on clocks that will be used in case of
- * interrupt context
- * @clk_gating_workq: workqueue for clock gating work.
- * @lock: serialize access to some struct ufs_clk_gating members. An outer lock
- * relative to the host lock
- * @state: the current clocks state
- * @delay_ms: gating delay in ms
- * @is_suspended: clk gating is suspended when set to 1 which can be used
- * during suspend/resume
* @delay_attr: sysfs attribute to control delay_attr
* @enable_attr: sysfs attribute to enable/disable clock gating
- * @is_enabled: Indicates the current status of clock gating
* @is_initialized: Indicates whether clock gating is initialized or not
- * @active_reqs: number of requests that are pending and should be waited for
- * completion before gating clocks.
*/
struct ufs_clk_gating {
- struct delayed_work gate_work;
- struct work_struct ungate_work;
- struct workqueue_struct *clk_gating_workq;
-
- spinlock_t lock;
-
- enum clk_gating_state state;
- unsigned long delay_ms;
- bool is_suspended;
struct device_attribute delay_attr;
struct device_attribute enable_attr;
- bool is_enabled;
bool is_initialized;
- int active_reqs;
};
/**
^ permalink raw reply related [flat|nested] 16+ messages in thread* Re: [PATCH 5/7] ufs: core: Remove unused code and data structures
2026-01-16 18:26 ` [PATCH 5/7] ufs: core: Remove unused code and data structures Bart Van Assche
@ 2026-01-17 2:16 ` kernel test robot
0 siblings, 0 replies; 16+ messages in thread
From: kernel test robot @ 2026-01-17 2:16 UTC (permalink / raw)
To: Bart Van Assche, Martin K . Petersen
Cc: oe-kbuild-all, linux-scsi, Bart Van Assche, James E.J. Bottomley,
Peter Wang, Avri Altman, Bean Huo, Adrian Hunter, Bao D. Nguyen
Hi Bart,
kernel test robot noticed the following build warnings:
[auto build test WARNING on jejb-scsi/for-next]
[also build test WARNING on mkp-scsi/for-next linus/master v6.19-rc5 next-20260116]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Bart-Van-Assche/ufs-core-Change-the-type-of-an-ufshcd_clkgate_delay_set-argument/20260117-022907
base: https://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi.git for-next
patch link: https://lore.kernel.org/r/20260116182628.3255116-6-bvanassche%40acm.org
patch subject: [PATCH 5/7] ufs: core: Remove unused code and data structures
config: i386-randconfig-141-20260117 (https://download.01.org/0day-ci/archive/20260117/202601170952.UMdlSqAD-lkp@intel.com/config)
compiler: gcc-14 (Debian 14.2.0-19) 14.2.0
smatch version: v0.5.0-8985-g2614ff1a
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260117/202601170952.UMdlSqAD-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202601170952.UMdlSqAD-lkp@intel.com/
All warnings (new ones prefixed by >>):
drivers/ufs/core/ufshcd.c: In function 'ufshcd_setup_clocks':
>> drivers/ufs/core/ufshcd.c:9304:14: warning: variable 'clk_state_changed' set but not used [-Wunused-but-set-variable]
9304 | bool clk_state_changed = false;
| ^~~~~~~~~~~~~~~~~
vim +/clk_state_changed +9304 drivers/ufs/core/ufshcd.c
6a771a656041f4 drivers/scsi/ufs/ufshcd.c Raviv Shvili 2014-09-25 9298
81309c247a4dcd drivers/scsi/ufs/ufshcd.c Can Guo 2020-11-25 9299 static int ufshcd_setup_clocks(struct ufs_hba *hba, bool on)
c6e79dacd86fd7 drivers/scsi/ufs/ufshcd.c Sujit Reddy Thumma 2014-09-25 9300 {
c6e79dacd86fd7 drivers/scsi/ufs/ufshcd.c Sujit Reddy Thumma 2014-09-25 9301 int ret = 0;
c6e79dacd86fd7 drivers/scsi/ufs/ufshcd.c Sujit Reddy Thumma 2014-09-25 9302 struct ufs_clk_info *clki;
c6e79dacd86fd7 drivers/scsi/ufs/ufshcd.c Sujit Reddy Thumma 2014-09-25 9303 struct list_head *head = &hba->clk_list_head;
911a0771b6fa7b drivers/scsi/ufs/ufshcd.c Subhash Jadavani 2016-12-22 @9304 bool clk_state_changed = false;
c6e79dacd86fd7 drivers/scsi/ufs/ufshcd.c Sujit Reddy Thumma 2014-09-25 9305
566ec9ad315b46 drivers/scsi/ufs/ufshcd.c Szymon Mielczarek 2017-06-05 9306 if (list_empty(head))
c6e79dacd86fd7 drivers/scsi/ufs/ufshcd.c Sujit Reddy Thumma 2014-09-25 9307 goto out;
c6e79dacd86fd7 drivers/scsi/ufs/ufshcd.c Sujit Reddy Thumma 2014-09-25 9308
1e879e8fa9f62e drivers/scsi/ufs/ufshcd.c Subhash Jadavani 2016-10-06 9309 ret = ufshcd_vops_setup_clocks(hba, on, PRE_CHANGE);
1e879e8fa9f62e drivers/scsi/ufs/ufshcd.c Subhash Jadavani 2016-10-06 9310 if (ret)
1e879e8fa9f62e drivers/scsi/ufs/ufshcd.c Subhash Jadavani 2016-10-06 9311 return ret;
1e879e8fa9f62e drivers/scsi/ufs/ufshcd.c Subhash Jadavani 2016-10-06 9312
c6e79dacd86fd7 drivers/scsi/ufs/ufshcd.c Sujit Reddy Thumma 2014-09-25 9313 list_for_each_entry(clki, head, list) {
c6e79dacd86fd7 drivers/scsi/ufs/ufshcd.c Sujit Reddy Thumma 2014-09-25 9314 if (!IS_ERR_OR_NULL(clki->clk)) {
81309c247a4dcd drivers/scsi/ufs/ufshcd.c Can Guo 2020-11-25 9315 /*
81309c247a4dcd drivers/scsi/ufs/ufshcd.c Can Guo 2020-11-25 9316 * Don't disable clocks which are needed
81309c247a4dcd drivers/scsi/ufs/ufshcd.c Can Guo 2020-11-25 9317 * to keep the link active.
81309c247a4dcd drivers/scsi/ufs/ufshcd.c Can Guo 2020-11-25 9318 */
81309c247a4dcd drivers/scsi/ufs/ufshcd.c Can Guo 2020-11-25 9319 if (ufshcd_is_link_active(hba) &&
81309c247a4dcd drivers/scsi/ufs/ufshcd.c Can Guo 2020-11-25 9320 clki->keep_link_active)
57d104c153d3d6 drivers/scsi/ufs/ufshcd.c Subhash Jadavani 2014-09-25 9321 continue;
57d104c153d3d6 drivers/scsi/ufs/ufshcd.c Subhash Jadavani 2014-09-25 9322
911a0771b6fa7b drivers/scsi/ufs/ufshcd.c Subhash Jadavani 2016-12-22 9323 clk_state_changed = on ^ clki->enabled;
c6e79dacd86fd7 drivers/scsi/ufs/ufshcd.c Sujit Reddy Thumma 2014-09-25 9324 if (on && !clki->enabled) {
c6e79dacd86fd7 drivers/scsi/ufs/ufshcd.c Sujit Reddy Thumma 2014-09-25 9325 ret = clk_prepare_enable(clki->clk);
c6e79dacd86fd7 drivers/scsi/ufs/ufshcd.c Sujit Reddy Thumma 2014-09-25 9326 if (ret) {
c6e79dacd86fd7 drivers/scsi/ufs/ufshcd.c Sujit Reddy Thumma 2014-09-25 9327 dev_err(hba->dev, "%s: %s prepare enable failed, %d\n",
c6e79dacd86fd7 drivers/scsi/ufs/ufshcd.c Sujit Reddy Thumma 2014-09-25 9328 __func__, clki->name, ret);
c6e79dacd86fd7 drivers/scsi/ufs/ufshcd.c Sujit Reddy Thumma 2014-09-25 9329 goto out;
c6e79dacd86fd7 drivers/scsi/ufs/ufshcd.c Sujit Reddy Thumma 2014-09-25 9330 }
c6e79dacd86fd7 drivers/scsi/ufs/ufshcd.c Sujit Reddy Thumma 2014-09-25 9331 } else if (!on && clki->enabled) {
c6e79dacd86fd7 drivers/scsi/ufs/ufshcd.c Sujit Reddy Thumma 2014-09-25 9332 clk_disable_unprepare(clki->clk);
c6e79dacd86fd7 drivers/scsi/ufs/ufshcd.c Sujit Reddy Thumma 2014-09-25 9333 }
c6e79dacd86fd7 drivers/scsi/ufs/ufshcd.c Sujit Reddy Thumma 2014-09-25 9334 clki->enabled = on;
c6e79dacd86fd7 drivers/scsi/ufs/ufshcd.c Sujit Reddy Thumma 2014-09-25 9335 dev_dbg(hba->dev, "%s: clk: %s %sabled\n", __func__,
c6e79dacd86fd7 drivers/scsi/ufs/ufshcd.c Sujit Reddy Thumma 2014-09-25 9336 clki->name, on ? "en" : "dis");
c6e79dacd86fd7 drivers/scsi/ufs/ufshcd.c Sujit Reddy Thumma 2014-09-25 9337 }
c6e79dacd86fd7 drivers/scsi/ufs/ufshcd.c Sujit Reddy Thumma 2014-09-25 9338 }
1ab27c9cf8b63d drivers/scsi/ufs/ufshcd.c Sahitya Tummala 2014-09-25 9339
1e879e8fa9f62e drivers/scsi/ufs/ufshcd.c Subhash Jadavani 2016-10-06 9340 ret = ufshcd_vops_setup_clocks(hba, on, POST_CHANGE);
1e879e8fa9f62e drivers/scsi/ufs/ufshcd.c Subhash Jadavani 2016-10-06 9341 if (ret)
1e879e8fa9f62e drivers/scsi/ufs/ufshcd.c Subhash Jadavani 2016-10-06 9342 return ret;
1e879e8fa9f62e drivers/scsi/ufs/ufshcd.c Subhash Jadavani 2016-10-06 9343
2777e73fc154e2 drivers/ufs/core/ufshcd.c Maramaina Naresh 2023-12-19 9344 if (!ufshcd_is_clkscaling_supported(hba))
2777e73fc154e2 drivers/ufs/core/ufshcd.c Maramaina Naresh 2023-12-19 9345 ufshcd_pm_qos_update(hba, on);
c6e79dacd86fd7 drivers/scsi/ufs/ufshcd.c Sujit Reddy Thumma 2014-09-25 9346 out:
c6e79dacd86fd7 drivers/scsi/ufs/ufshcd.c Sujit Reddy Thumma 2014-09-25 9347 if (ret) {
c6e79dacd86fd7 drivers/scsi/ufs/ufshcd.c Sujit Reddy Thumma 2014-09-25 9348 list_for_each_entry(clki, head, list) {
c6e79dacd86fd7 drivers/scsi/ufs/ufshcd.c Sujit Reddy Thumma 2014-09-25 9349 if (!IS_ERR_OR_NULL(clki->clk) && clki->enabled)
c6e79dacd86fd7 drivers/scsi/ufs/ufshcd.c Sujit Reddy Thumma 2014-09-25 9350 clk_disable_unprepare(clki->clk);
c6e79dacd86fd7 drivers/scsi/ufs/ufshcd.c Sujit Reddy Thumma 2014-09-25 9351 }
c6e79dacd86fd7 drivers/scsi/ufs/ufshcd.c Sujit Reddy Thumma 2014-09-25 9352 }
7ff5ab47363334 drivers/scsi/ufs/ufshcd.c Subhash Jadavani 2016-12-22 9353
c6e79dacd86fd7 drivers/scsi/ufs/ufshcd.c Sujit Reddy Thumma 2014-09-25 9354 return ret;
c6e79dacd86fd7 drivers/scsi/ufs/ufshcd.c Sujit Reddy Thumma 2014-09-25 9355 }
c6e79dacd86fd7 drivers/scsi/ufs/ufshcd.c Sujit Reddy Thumma 2014-09-25 9356
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH 6/7] ufs: core: Remove superfluous ufshcd_{hold,release}() calls
2026-01-16 18:26 [PATCH 0/7] ufs: Remove the clock gating code Bart Van Assche
` (4 preceding siblings ...)
2026-01-16 18:26 ` [PATCH 5/7] ufs: core: Remove unused code and data structures Bart Van Assche
@ 2026-01-16 18:26 ` Bart Van Assche
2026-01-16 18:26 ` [PATCH 7/7] ufs: core: Remove ufshcd_{hold,release}() calls from the I/O path Bart Van Assche
2026-01-22 17:30 ` [PATCH 0/7] ufs: Remove the clock gating code Manivannan Sadhasivam
7 siblings, 0 replies; 16+ messages in thread
From: Bart Van Assche @ 2026-01-16 18:26 UTC (permalink / raw)
To: Martin K . Petersen
Cc: linux-scsi, Bart Van Assche, James E.J. Bottomley, Peter Wang,
Huan Tang, Avri Altman, Zhongqiu Han, Bao D. Nguyen, Daniel Lee,
Liu Song, Bean Huo, Adrian Hunter
ufshcd_hold() and ufshcd_release() have been modified such that these
call runtime power management functions on the WLUN. Hence,
ufshcd_hold() calls that follow a ufshcd_rpm_get_sync() call and also
ufshcd_release() calls that precede ufshcd_rpm_put_sync() can be left
out.
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
---
drivers/ufs/core/ufs-sysfs.c | 2 --
drivers/ufs/core/ufshcd.c | 4 ----
2 files changed, 6 deletions(-)
diff --git a/drivers/ufs/core/ufs-sysfs.c b/drivers/ufs/core/ufs-sysfs.c
index b33f8656edb5..2cc7f5063286 100644
--- a/drivers/ufs/core/ufs-sysfs.c
+++ b/drivers/ufs/core/ufs-sysfs.c
@@ -256,9 +256,7 @@ static int ufshcd_read_hci_reg(struct ufs_hba *hba, u32 *val, unsigned int reg)
}
ufshcd_rpm_get_sync(hba);
- ufshcd_hold(hba);
*val = ufshcd_readl(hba, reg);
- ufshcd_release(hba);
ufshcd_rpm_put_sync(hba);
up(&hba->host_sem);
diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c
index 1189a9fd39ff..8c388275308f 100644
--- a/drivers/ufs/core/ufshcd.c
+++ b/drivers/ufs/core/ufshcd.c
@@ -1809,7 +1809,6 @@ static ssize_t ufshcd_clkscale_enable_store(struct device *dev,
goto out;
ufshcd_rpm_get_sync(hba);
- ufshcd_hold(hba);
hba->clk_scaling.is_enabled = value;
@@ -1834,7 +1833,6 @@ static ssize_t ufshcd_clkscale_enable_store(struct device *dev,
hba->clk_scaling.target_freq = freq;
out_rel:
- ufshcd_release(hba);
ufshcd_rpm_put_sync(hba);
out:
up(&hba->host_sem);
@@ -4368,9 +4366,7 @@ void ufshcd_auto_hibern8_update(struct ufs_hba *hba, u32 ahit)
WRITE_ONCE(hba->ahit, ahit);
if (!pm_runtime_suspended(&hba->ufs_device_wlun->sdev_gendev)) {
ufshcd_rpm_get_sync(hba);
- ufshcd_hold(hba);
ufshcd_configure_auto_hibern8(hba);
- ufshcd_release(hba);
ufshcd_rpm_put_sync(hba);
}
}
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH 7/7] ufs: core: Remove ufshcd_{hold,release}() calls from the I/O path
2026-01-16 18:26 [PATCH 0/7] ufs: Remove the clock gating code Bart Van Assche
` (5 preceding siblings ...)
2026-01-16 18:26 ` [PATCH 6/7] ufs: core: Remove superfluous ufshcd_{hold,release}() calls Bart Van Assche
@ 2026-01-16 18:26 ` Bart Van Assche
2026-01-22 17:30 ` [PATCH 0/7] ufs: Remove the clock gating code Manivannan Sadhasivam
7 siblings, 0 replies; 16+ messages in thread
From: Bart Van Assche @ 2026-01-16 18:26 UTC (permalink / raw)
To: Martin K . Petersen
Cc: linux-scsi, Bart Van Assche, James E.J. Bottomley, Peter Wang,
Avri Altman, Bean Huo, Adrian Hunter, Bao D. Nguyen
Patch "Switch from clock gating to RPM" makes it unnecessary to call
ufshcd_{hold,release}() from the I/O path. Hence, remove these calls.
Remove the code that sets host->queuecommand_may_block since this patch
removes all code that may block from the I/O path.
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
---
drivers/ufs/core/ufshcd.c | 8 +-------
1 file changed, 1 insertion(+), 7 deletions(-)
diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c
index 8c388275308f..3cefbd69ab46 100644
--- a/drivers/ufs/core/ufshcd.c
+++ b/drivers/ufs/core/ufshcd.c
@@ -2892,16 +2892,12 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
hba->req_abort_count = 0;
- ufshcd_hold(hba);
-
ufshcd_setup_scsi_cmd(hba, cmd,
ufshcd_scsi_to_upiu_lun(cmd->device->lun), tag);
err = ufshcd_map_sg(hba, cmd);
- if (err) {
- ufshcd_release(hba);
+ if (err)
goto out;
- }
if (hba->mcq_enabled)
hwq = ufshcd_mcq_req_to_hwq(hba, scsi_cmd_to_rq(cmd));
@@ -5403,7 +5399,6 @@ void ufshcd_release_scsi_cmd(struct ufs_hba *hba, struct scsi_cmnd *cmd)
{
scsi_dma_unmap(cmd);
ufshcd_crypto_clear_prdt(hba, cmd);
- ufshcd_release(hba);
ufshcd_clk_scaling_update_busy(hba);
}
@@ -10676,7 +10671,6 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
host->max_channel = UFSHCD_MAX_CHANNEL;
host->unique_id = host->host_no;
host->max_cmd_len = UFS_CDB_SIZE;
- host->queuecommand_may_block = !!(hba->caps & UFSHCD_CAP_CLK_GATING);
/* Use default RPM delay if host not set */
if (host->rpm_autosuspend_delay == 0)
^ permalink raw reply related [flat|nested] 16+ messages in thread* Re: [PATCH 0/7] ufs: Remove the clock gating code
2026-01-16 18:26 [PATCH 0/7] ufs: Remove the clock gating code Bart Van Assche
` (6 preceding siblings ...)
2026-01-16 18:26 ` [PATCH 7/7] ufs: core: Remove ufshcd_{hold,release}() calls from the I/O path Bart Van Assche
@ 2026-01-22 17:30 ` Manivannan Sadhasivam
2026-01-23 7:26 ` Peter Wang (王信友)
7 siblings, 1 reply; 16+ messages in thread
From: Manivannan Sadhasivam @ 2026-01-22 17:30 UTC (permalink / raw)
To: Bart Van Assche
Cc: Martin K . Petersen, linux-scsi, Nitin Rawat, peter.wang,
alim.akhtar
+ Nitin, Peter, Alim
On Fri, Jan 16, 2026 at 10:26:02AM -0800, Bart Van Assche wrote:
> Hi Martin,
>
> There is some duplicate code in the UFS driver: both the runtime power
> management (RPM) code and the clock gating code switch between the same
> low-power and fully-powered state. Since the RPM code is more efficient,
> this patch series remove the clock gating code. This change has been
> realized without modifying the driver behavior and without breaking the UFS
> driver sysfs interface.
>
> Please consider this patch series for the next merge window.
>
Hi Bart,
Thanks for the work! I did try to get rid of the clock gating feature a couple
of years ago as I also thought that it duplicates the behavior of the runtime PM
framework.
But when I discussed this change with Qcom UFS folks, I was told that getting
rid of clock gating will have a negative impact on the runtime power consumption
on Qcom platforms as most of the power hungry resources are gated by the clock
and there will be added latency with going through the runtime PM framework.
Nitin is working on measuring the power impact of this series on Qcom
platforms to verify whether the above concern is really valid or not. So I'd
request to hold off this series until he gets back with the analysis, since this
series is very critical for us.
It'd be good if other vendors like Mediatek and Samsung also carry out the power
impact analysis on their platforms.
- Mani
--
மணிவண்ணன் சதாசிவம்
^ permalink raw reply [flat|nested] 16+ messages in thread* Re: [PATCH 0/7] ufs: Remove the clock gating code
2026-01-22 17:30 ` [PATCH 0/7] ufs: Remove the clock gating code Manivannan Sadhasivam
@ 2026-01-23 7:26 ` Peter Wang (王信友)
2026-01-23 23:27 ` Bart Van Assche
0 siblings, 1 reply; 16+ messages in thread
From: Peter Wang (王信友) @ 2026-01-23 7:26 UTC (permalink / raw)
To: mani@kernel.org, bvanassche@acm.org
Cc: linux-scsi@vger.kernel.org, nitin.rawat@oss.qualcomm.com,
alim.akhtar@samsung.com, martin.petersen@oracle.com
On Thu, 2026-01-22 at 23:00 +0530, Manivannan Sadhasivam wrote:
>
>
> Hi Bart,
>
> Thanks for the work! I did try to get rid of the clock gating feature
> a couple
> of years ago as I also thought that it duplicates the behavior of the
> runtime PM
> framework.
>
Hi Mani,
hba->rpm_lvl = ufs_get_desired_pm_lvl_for_dev_link_state(
UFS_SLEEP_PWR_MODE,
UIC_LINK_HIBERN8_STATE
);
The default RPM level is different from clock gating,
so it should not duplicate the behavior.
RPM also sets the device to sleep mode and powers off unnecessary
voltages,
whereas clock gating only controls the clock on/off state and
hibernation maybe.
> But when I discussed this change with Qcom UFS folks, I was told that
> getting
> rid of clock gating will have a negative impact on the runtime power
> consumption
> on Qcom platforms as most of the power hungry resources are gated by
> the clock
> and there will be added latency with going through the runtime PM
> framework.
>
> Nitin is working on measuring the power impact of this series on Qcom
> platforms to verify whether the above concern is really valid or not.
> So I'd
> request to hold off this series until he gets back with the analysis,
> since this
> series is very critical for us.
>
> It'd be good if other vendors like Mediatek and Samsung also carry
> out the power
> impact analysis on their platforms.
>
> - Mani
>
Many years ago, Mediatek tested the clock gating delay time and found
that
if the delay was too long, it would affect power consumption. In the
end,
we set the delay at 10 ms. Removing it entirely would definitely impact
power.
There’s also another situation regarding whether auto-hibern8 is
enabled.
If auto-hibern8 is not enabled, manual hibern8 will be triggered along
with clock gating. If the clock gating removed, the impact should be
even greater.
Thanks
Peter
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 0/7] ufs: Remove the clock gating code
2026-01-23 7:26 ` Peter Wang (王信友)
@ 2026-01-23 23:27 ` Bart Van Assche
2026-01-26 3:44 ` Peter Wang (王信友)
0 siblings, 1 reply; 16+ messages in thread
From: Bart Van Assche @ 2026-01-23 23:27 UTC (permalink / raw)
To: Peter Wang (王信友), mani@kernel.org
Cc: linux-scsi@vger.kernel.org, nitin.rawat@oss.qualcomm.com,
alim.akhtar@samsung.com, martin.petersen@oracle.com
On 1/22/26 11:26 PM, Peter Wang (王信友) wrote:
> hba->rpm_lvl = ufs_get_desired_pm_lvl_for_dev_link_state(
> UFS_SLEEP_PWR_MODE,
> UIC_LINK_HIBERN8_STATE
>
> The default RPM level is different from clock gating,
> so it should not duplicate the behavior.
>
> RPM also sets the device to sleep mode and powers off unnecessary
> voltages,
> whereas clock gating only controls the clock on/off state and
> hibernation maybe.
My conclusion from the above is that RPM has the advantage over clock
gating, namely that it switches to a lower power state.
> There’s also another situation regarding whether auto-hibern8 is
> enabled.
> If auto-hibern8 is not enabled, manual hibern8 will be triggered along
> with clock gating. If the clock gating removed, the impact should be
> even greater.
Are there any UFS host controllers used in mobile devices that do not
support auto-hibernation? If so, how about adding clock gating support
in the runtime suspend and resume code? For my own reference: this
involves calling ufshcd_setup_clocks().
Thanks,
Bart.
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 0/7] ufs: Remove the clock gating code
2026-01-23 23:27 ` Bart Van Assche
@ 2026-01-26 3:44 ` Peter Wang (王信友)
2026-01-26 22:27 ` Bart Van Assche
0 siblings, 1 reply; 16+ messages in thread
From: Peter Wang (王信友) @ 2026-01-26 3:44 UTC (permalink / raw)
To: mani@kernel.org, bvanassche@acm.org
Cc: linux-scsi@vger.kernel.org, nitin.rawat@oss.qualcomm.com,
alim.akhtar@samsung.com, martin.petersen@oracle.com
On Fri, 2026-01-23 at 15:27 -0800, Bart Van Assche wrote:
> On 1/22/26 11:26 PM, Peter Wang (王信友) wrote:
> > hba->rpm_lvl = ufs_get_desired_pm_lvl_for_dev_link_state(
> > UFS_SLEEP_PWR_MODE,
> >
> > UIC_LINK_HIBERN8_STATE
> >
> > The default RPM level is different from clock gating,
> > so it should not duplicate the behavior.
> >
> > RPM also sets the device to sleep mode and powers off unnecessary
> > voltages,
> > whereas clock gating only controls the clock on/off state and
> > hibernation maybe.
>
> My conclusion from the above is that RPM has the advantage over clock
> gating, namely that it switches to a lower power state.
Hi Bart,
This is true when it comes to power saving, but not when it comes to
performance.
UFS resume takes more time than simply turning the clock on.
>
> > There’s also another situation regarding whether auto-hibern8 is
> > enabled.
> > If auto-hibern8 is not enabled, manual hibern8 will be triggered
> > along
> > with clock gating. If the clock gating removed, the impact should
> > be
> > even greater.
> Are there any UFS host controllers used in mobile devices that do not
> support auto-hibernation? If so, how about adding clock gating
Some older MediaTek platforms do not support auto-hibern8.
> support
> in the runtime suspend and resume code? For my own reference: this
> involves calling ufshcd_setup_clocks().
>
> Thanks,
>
> Bart.
Runtime suspend and resume already support manual hibern8 and clock
on/off.
I am not sure what you mean by "adding clock gating support in the
runtime suspend and resume code."
Thanks.
Peter
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 0/7] ufs: Remove the clock gating code
2026-01-26 3:44 ` Peter Wang (王信友)
@ 2026-01-26 22:27 ` Bart Van Assche
0 siblings, 0 replies; 16+ messages in thread
From: Bart Van Assche @ 2026-01-26 22:27 UTC (permalink / raw)
To: Peter Wang (王信友), mani@kernel.org
Cc: linux-scsi@vger.kernel.org, nitin.rawat@oss.qualcomm.com,
alim.akhtar@samsung.com, martin.petersen@oracle.com
On 1/25/26 7:44 PM, Peter Wang (王信友) wrote:
> This is true when it comes to power saving, but not when it comes to
> performance. UFS resume takes more time than simply turning the
> clock on.
Hi Peter,
It seems to me that there is insufficient consensus to proceed with the
current form of this patch series. I will look into moving the clock
gating code into the runtime suspend and resume callbacks without
affecting the behavior of the UFS driver.
Thanks,
Bart.
^ permalink raw reply [flat|nested] 16+ messages in thread