diff mbox series

[2/3] scsi: ufs: Add temperature notification exception handling

Message ID 20210901123707.5014-3-avri.altman@wdc.com (mailing list archive)
State Superseded
Headers show
Series Add temperature notification support | expand

Commit Message

Avri Altman Sept. 1, 2021, 12:37 p.m. UTC
The device may notify the host of an extreme temperature by using the
exception event mechanism. The exception can be raised when the device’s
Tcase temperature is either too high or too low.

It is essentially up to the platform to decide what further actions need
to be taken. So add a designated vop for that.  Each chipset vendor can
decide if it wants to use the thermal subsystem, hw monitor, or some
Privet implementation.

Signed-off-by: Avri Altman <avri.altman@wdc.com>
---
 drivers/scsi/ufs/ufs.h    |  2 ++
 drivers/scsi/ufs/ufshcd.c | 18 ++++++++++++++++++
 drivers/scsi/ufs/ufshcd.h |  7 +++++++
 3 files changed, 27 insertions(+)

Comments

Asutosh Das (asd) Sept. 1, 2021, 3:51 p.m. UTC | #1
On 9/1/2021 5:37 AM, Avri Altman wrote:
> The device may notify the host of an extreme temperature by using the
> exception event mechanism. The exception can be raised when the device’s
> Tcase temperature is either too high or too low.
> 
> It is essentially up to the platform to decide what further actions need
> to be taken. So add a designated vop for that.  Each chipset vendor can
> decide if it wants to use the thermal subsystem, hw monitor, or some
> Privet implementation.
The sensors of thermal subsystem would essentially get the skin 
temperature and invoke the registered handlers to throttle, if possible.

I'm not sure how the vendor drivers can use thermal subsystem now if the 
ufs device doesn't inform the thermal subsystem about its increase in 
temperature.

Meaning, (FWIU):
  -> ufs device senses an increase in temperature
     -> informs thermal subsystem
       -> registered vendor driver cb() is invoked by thermal subsystem.

Please let me know if I'm missing something.

> 
> Signed-off-by: Avri Altman <avri.altman@wdc.com>
> ---
>   drivers/scsi/ufs/ufs.h    |  2 ++
>   drivers/scsi/ufs/ufshcd.c | 18 ++++++++++++++++++
>   drivers/scsi/ufs/ufshcd.h |  7 +++++++
>   3 files changed, 27 insertions(+)
> 
> diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
> index dee897ef9631..4f2a2fe0c84a 100644
> --- a/drivers/scsi/ufs/ufs.h
> +++ b/drivers/scsi/ufs/ufs.h
> @@ -374,6 +374,8 @@ enum {
>   	MASK_EE_PERFORMANCE_THROTTLING	= BIT(6),
>   };
>   
> +#define MASK_EE_URGENT_TEMP (MASK_EE_TOO_HIGH_TEMP | MASK_EE_TOO_LOW_TEMP)
> +
>   /* Background operation status */
>   enum bkops_status {
>   	BKOPS_STATUS_NO_OP               = 0x0,
> diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
> index 6ad51ae764c5..5f1fce21b655 100644
> --- a/drivers/scsi/ufs/ufshcd.c
> +++ b/drivers/scsi/ufs/ufshcd.c
> @@ -5642,6 +5642,11 @@ static void ufshcd_bkops_exception_event_handler(struct ufs_hba *hba)
>   				__func__, err);
>   }
>   
> +static void ufshcd_temp_exception_event_handler(struct ufs_hba *hba, u16 status)
> +{
> +	ufshcd_vops_temp_notify(hba, status);
> +}
> +
>   static int __ufshcd_wb_toggle(struct ufs_hba *hba, bool set, enum flag_idn idn)
>   {
>   	u8 index;
> @@ -5821,6 +5826,9 @@ static void ufshcd_exception_event_handler(struct work_struct *work)
>   	if (status & hba->ee_drv_mask & MASK_EE_URGENT_BKOPS)
>   		ufshcd_bkops_exception_event_handler(hba);
>   
> +	if (status & hba->ee_drv_mask & MASK_EE_URGENT_TEMP)
> +		ufshcd_temp_exception_event_handler(hba, status);
> +
>   	ufs_debugfs_exception_event(hba, status);
>   out:
>   	ufshcd_scsi_unblock_requests(hba);
> @@ -7473,6 +7481,7 @@ static void ufshcd_temp_notif_probe(struct ufs_hba *hba, u8 *desc_buf)
>   {
>   	struct ufs_dev_info *dev_info = &hba->dev_info;
>   	u32 ext_ufs_feature;
> +	u16 mask = 0;
>   
>   	if (!(hba->caps & UFSHCD_CAP_TEMP_NOTIF) ||
>   	    dev_info->wspecversion < 0x300)
> @@ -7483,6 +7492,15 @@ static void ufshcd_temp_notif_probe(struct ufs_hba *hba, u8 *desc_buf)
>   
>   	dev_info->low_temp_notif = ext_ufs_feature & UFS_DEV_LOW_TEMP_NOTIF;
>   	dev_info->high_temp_notif = ext_ufs_feature & UFS_DEV_HIGH_TEMP_NOTIF;
> +
> +	if (dev_info->low_temp_notif)
> +		mask |= MASK_EE_TOO_LOW_TEMP;
> +
> +	if (dev_info->high_temp_notif)
> +		mask |= MASK_EE_TOO_HIGH_TEMP;
> +
> +	if (mask)
> +		ufshcd_enable_ee(hba, mask);
>   }
>   
>   void ufshcd_fixup_dev_quirks(struct ufs_hba *hba, struct ufs_dev_fix *fixups)
> diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
> index 467affbaec80..98ac7e7c8ec3 100644
> --- a/drivers/scsi/ufs/ufshcd.h
> +++ b/drivers/scsi/ufs/ufshcd.h
> @@ -356,6 +356,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);
> +	void	(*temp_notify)(struct ufs_hba *hba, u16 status);
>   };
>   
>   /* clock gating state  */
> @@ -1355,6 +1356,12 @@ static inline void ufshcd_vops_config_scaling_param(struct ufs_hba *hba,
>   		hba->vops->config_scaling_param(hba, profile, data);
>   }
>   
> +static inline void ufshcd_vops_temp_notify(struct ufs_hba *hba, u16 status)
> +{
> +	if (hba->vops && hba->vops->temp_notify)
> +		hba->vops->temp_notify(hba, status);
> +}
> +
>   extern struct ufs_pm_lvl_states ufs_pm_lvl_states[];
>   
>   /*
>
Bart Van Assche Sept. 1, 2021, 4:39 p.m. UTC | #2
On 9/1/21 5:37 AM, Avri Altman wrote:
> It is essentially up to the platform to decide what further actions need
> to be taken. So add a designated vop for that.  Each chipset vendor can
> decide if it wants to use the thermal subsystem, hw monitor, or some
> Privet implementation.

Why to make chipset vendors define what to do in case of extreme 
temperatures? I'd prefer a single implementation in ufshcd.c instead of 
making each vendor come up with a different implementation.

> +	void	(*temp_notify)(struct ufs_hba *hba, u16 status);

Please do not add new vops without adding at least one implementation of 
that vop.

Thanks,

Bart.
Asutosh Das (asd) Sept. 1, 2021, 7:40 p.m. UTC | #3
On 9/1/2021 9:39 AM, Bart Van Assche wrote:
> On 9/1/21 5:37 AM, Avri Altman wrote:
>> It is essentially up to the platform to decide what further actions need
>> to be taken. So add a designated vop for that.  Each chipset vendor can
>> decide if it wants to use the thermal subsystem, hw monitor, or some
>> Privet implementation.
> 
> Why to make chipset vendors define what to do in case of extreme 
> temperatures? I'd prefer a single implementation in ufshcd.c instead of 
> making each vendor come up with a different implementation.
> 
I think it should be either i.e. if a vendor specific implementation is 
defined use that else use the generic implementation in ufshcd.
There may be a bunch of things that each vendor may need/want do 
depending upon use-case, I imagine.

>> +    void    (*temp_notify)(struct ufs_hba *hba, u16 status);
> 
> Please do not add new vops without adding at least one implementation of 
> that vop.
> 
> Thanks,
> 
> Bart.
Avri Altman Sept. 2, 2021, 6:46 a.m. UTC | #4
> On 9/1/2021 9:39 AM, Bart Van Assche wrote:
> > On 9/1/21 5:37 AM, Avri Altman wrote:
> >> It is essentially up to the platform to decide what further actions need
> >> to be taken. So add a designated vop for that.  Each chipset vendor can
> >> decide if it wants to use the thermal subsystem, hw monitor, or some
> >> Privet implementation.
> >
> > Why to make chipset vendors define what to do in case of extreme
> > temperatures? I'd prefer a single implementation in ufshcd.c instead of
> > making each vendor come up with a different implementation.
The storage device is merely acting as a temperature sensor.
This info, jointly with other temperature sensors of the system,
Should be used elsewhere in a much broader scope - probably by Android.
Either way, ufshcd is hardly the place for those decisions.

> >
> I think it should be either i.e. if a vendor specific implementation is
> defined use that else use the generic implementation in ufshcd.
> There may be a bunch of things that each vendor may need/want do
> depending upon use-case, I imagine.
I agree, and this is why I wanted to allow that that flexibility.
But I get Bart's point. I will register the sensor in some subsystem.
It should allow the required degrees of freedom.

Thanks,
Avri
> 
> >> +    void    (*temp_notify)(struct ufs_hba *hba, u16 status);
> >
> > Please do not add new vops without adding at least one implementation of
> > that vop.
> >
> > Thanks,
> >
> > Bart.
> 
> 
> --
> The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
> Linux Foundation Collaborative Project
diff mbox series

Patch

diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
index dee897ef9631..4f2a2fe0c84a 100644
--- a/drivers/scsi/ufs/ufs.h
+++ b/drivers/scsi/ufs/ufs.h
@@ -374,6 +374,8 @@  enum {
 	MASK_EE_PERFORMANCE_THROTTLING	= BIT(6),
 };
 
+#define MASK_EE_URGENT_TEMP (MASK_EE_TOO_HIGH_TEMP | MASK_EE_TOO_LOW_TEMP)
+
 /* Background operation status */
 enum bkops_status {
 	BKOPS_STATUS_NO_OP               = 0x0,
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 6ad51ae764c5..5f1fce21b655 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -5642,6 +5642,11 @@  static void ufshcd_bkops_exception_event_handler(struct ufs_hba *hba)
 				__func__, err);
 }
 
+static void ufshcd_temp_exception_event_handler(struct ufs_hba *hba, u16 status)
+{
+	ufshcd_vops_temp_notify(hba, status);
+}
+
 static int __ufshcd_wb_toggle(struct ufs_hba *hba, bool set, enum flag_idn idn)
 {
 	u8 index;
@@ -5821,6 +5826,9 @@  static void ufshcd_exception_event_handler(struct work_struct *work)
 	if (status & hba->ee_drv_mask & MASK_EE_URGENT_BKOPS)
 		ufshcd_bkops_exception_event_handler(hba);
 
+	if (status & hba->ee_drv_mask & MASK_EE_URGENT_TEMP)
+		ufshcd_temp_exception_event_handler(hba, status);
+
 	ufs_debugfs_exception_event(hba, status);
 out:
 	ufshcd_scsi_unblock_requests(hba);
@@ -7473,6 +7481,7 @@  static void ufshcd_temp_notif_probe(struct ufs_hba *hba, u8 *desc_buf)
 {
 	struct ufs_dev_info *dev_info = &hba->dev_info;
 	u32 ext_ufs_feature;
+	u16 mask = 0;
 
 	if (!(hba->caps & UFSHCD_CAP_TEMP_NOTIF) ||
 	    dev_info->wspecversion < 0x300)
@@ -7483,6 +7492,15 @@  static void ufshcd_temp_notif_probe(struct ufs_hba *hba, u8 *desc_buf)
 
 	dev_info->low_temp_notif = ext_ufs_feature & UFS_DEV_LOW_TEMP_NOTIF;
 	dev_info->high_temp_notif = ext_ufs_feature & UFS_DEV_HIGH_TEMP_NOTIF;
+
+	if (dev_info->low_temp_notif)
+		mask |= MASK_EE_TOO_LOW_TEMP;
+
+	if (dev_info->high_temp_notif)
+		mask |= MASK_EE_TOO_HIGH_TEMP;
+
+	if (mask)
+		ufshcd_enable_ee(hba, mask);
 }
 
 void ufshcd_fixup_dev_quirks(struct ufs_hba *hba, struct ufs_dev_fix *fixups)
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 467affbaec80..98ac7e7c8ec3 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -356,6 +356,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);
+	void	(*temp_notify)(struct ufs_hba *hba, u16 status);
 };
 
 /* clock gating state  */
@@ -1355,6 +1356,12 @@  static inline void ufshcd_vops_config_scaling_param(struct ufs_hba *hba,
 		hba->vops->config_scaling_param(hba, profile, data);
 }
 
+static inline void ufshcd_vops_temp_notify(struct ufs_hba *hba, u16 status)
+{
+	if (hba->vops && hba->vops->temp_notify)
+		hba->vops->temp_notify(hba, status);
+}
+
 extern struct ufs_pm_lvl_states ufs_pm_lvl_states[];
 
 /*