scsi: ufs: use async operation for hibern8 operation

When enabling/disabling hibern8, we will call flush_work
to wait for the task finished. Using async operation
to avoid long waiting time.

Bug: 138085490
Test: Boot, cat /sys/kernel/debug/ufshcd0/show_hba and
check hibern8_exit_cnt
Signed-off-by: Martin Liu <liumartin@google.com>
Signed-off-by: Alexander Winkowski <dereference23@outlook.com>
Change-Id: I427cd8e40cbc6674a145142babbd92a1062dc511
fourteen
Martin Liu 6 years ago committed by Jenna
parent 5d7a44ac31
commit c875dae34a
  1. 39
      drivers/scsi/ufs/ufshcd.c
  2. 3
      drivers/scsi/ufs/ufshcd.h

@ -3350,19 +3350,15 @@ static ssize_t ufshcd_hibern8_on_idle_enable_show(struct device *dev,
hba->hibern8_on_idle.is_enabled);
}
static ssize_t ufshcd_hibern8_on_idle_enable_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
static void ufshcd_hibern8_on_idle_switch_work(struct work_struct *work)
{
struct ufs_hba *hba = dev_get_drvdata(dev);
struct ufs_hba *hba;
unsigned long flags;
u32 value;
if (kstrtou32(buf, 0, &value))
return -EINVAL;
value = !!value;
if (value == hba->hibern8_on_idle.is_enabled)
goto out;
hba = container_of(work, struct ufs_hba, hibern8_on_idle_enable_work);
value = !hba->hibern8_on_idle.is_enabled;
/* Update auto hibern8 timer value if supported */
if (ufshcd_is_auto_hibern8_supported(hba)) {
@ -3386,6 +3382,28 @@ static ssize_t ufshcd_hibern8_on_idle_enable_store(struct device *dev,
hba->hibern8_on_idle.is_enabled = value;
out:
return;
}
static ssize_t ufshcd_hibern8_on_idle_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;
mutex_lock(&hba->hibern8_on_idle.enable_mutex);
/*
* make sure that former operation has been done before we exectue
* next action. This could gareatee the order and synconization.
*/
flush_work(&hba->hibern8_on_idle_enable_work);
if (hba->hibern8_on_idle.is_enabled != !!value)
schedule_work(&hba->hibern8_on_idle_enable_work);
mutex_unlock(&hba->hibern8_on_idle.enable_mutex);
return count;
}
@ -12954,12 +12972,15 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
INIT_WORK(&hba->card_detect_work, ufshcd_card_detect_handler);
INIT_WORK(&hba->rls_work, ufshcd_rls_handler);
INIT_WORK(&hba->fatal_mode_work, ufshcd_fatal_mode_handler);
INIT_WORK(&hba->hibern8_on_idle_enable_work,
ufshcd_hibern8_on_idle_switch_work);
/* Initialize UIC command mutex */
mutex_init(&hba->uic_cmd_mutex);
/* Initialize mutex for device management commands */
mutex_init(&hba->dev_cmd.lock);
mutex_init(&hba->hibern8_on_idle.enable_mutex);
#if IS_ENABLED(CONFIG_BLK_TURBO_WRITE)
/* Initialize TW ctrl mutex */

@ -520,6 +520,7 @@ enum ufshcd_hibern8_on_idle_state {
* @delay_attr: sysfs attribute to control delay_attr
* @enable_attr: sysfs attribute to enable/disable hibern8 on idle
* @is_enabled: Indicates the current status of hibern8
* @enable_mutex: protect sys node race from multithread access
*/
struct ufs_hibern8_on_idle {
struct delayed_work enter_work;
@ -531,6 +532,7 @@ struct ufs_hibern8_on_idle {
struct device_attribute delay_attr;
struct device_attribute enable_attr;
bool is_enabled;
struct mutex enable_mutex;
};
/**
@ -1079,6 +1081,7 @@ struct ufs_hba {
struct work_struct eh_work;
struct work_struct eeh_work;
struct work_struct rls_work;
struct work_struct hibern8_on_idle_enable_work;
/* HBA Errors */
u32 errors;

Loading…
Cancel
Save