From patchwork Wed Dec 19 09:29:04 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Uri Yanai X-Patchwork-Id: 10736961 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 2ACE5924 for ; Wed, 19 Dec 2018 09:29:48 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 14C082ABAF for ; Wed, 19 Dec 2018 09:29:48 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 085E02AB20; Wed, 19 Dec 2018 09:29:47 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.7 required=2.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 9B2F12AB20 for ; Wed, 19 Dec 2018 09:29:47 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728306AbeLSJ3r (ORCPT ); Wed, 19 Dec 2018 04:29:47 -0500 Received: from esa4.hgst.iphmx.com ([216.71.154.42]:30648 "EHLO esa4.hgst.iphmx.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727673AbeLSJ3r (ORCPT ); Wed, 19 Dec 2018 04:29:47 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=wdc.com; i=@wdc.com; q=dns/txt; s=dkim.wdc.com; t=1545211787; x=1576747787; h=from:to:cc:subject:date:message-id:in-reply-to: references; bh=/ZRs8WBIPjmaslPKXA/2bUrcDnn/ZfeMI79Z9lmKFIs=; b=VK3fT8ww3pT6xE5ivVRJpPD8Fc2rh84B/1FqltLuId7AYj/XEEGIqmI+ uOS7dyllbtQgPRK0ZsYgpE+FGc5cvssMsj8lZWUHGBNkFgiOxJAUXUZ0X 9Zk8vumNjiaNEJhMM9CQPTtQzgqAZ0gcW8QwiYuCqyjqpOXnUCX7PjPwz uaSs+cXKUTrlSN9nyBzGHS38vE0oAGDfx9XWbPxX+AmKKULjIGyXtqdMC 1FNZIJmBrEkF1viXu3bBTx2z44rXk/XZfguhjdb2JGsaK/WnO6Mv430zO KdzQk4oTMjv9ew+nuuxq6scW5vkNKO/KEl2pnaFmv/TgMuhvjk5Btn+I2 g==; X-IronPort-AV: E=Sophos;i="5.56,372,1539619200"; d="scan'208";a="96959321" Received: from h199-255-45-15.hgst.com (HELO uls-op-cesaep02.wdc.com) ([199.255.45.15]) by ob1.hgst.iphmx.com with ESMTP; 19 Dec 2018 17:29:42 +0800 Received: from uls-op-cesaip01.wdc.com ([10.248.3.36]) by uls-op-cesaep02.wdc.com with ESMTP; 19 Dec 2018 01:11:48 -0800 Received: from ilb000457.sdcorp.global.sandisk.com ([10.0.230.247]) by uls-op-cesaip01.wdc.com with ESMTP; 19 Dec 2018 01:29:40 -0800 From: Uri To: "James E . J . Bottomley" , "Martin K . Petersen" , linux-scsi@vger.kernel.org Cc: Alex Lemberg , Uri Yanai Subject: [PATCH 1/2] scsi: ufs: temperature notification Date: Wed, 19 Dec 2018 11:29:04 +0200 Message-Id: <1545211745-21208-2-git-send-email-uri.yanai@wdc.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1545211745-21208-1-git-send-email-uri.yanai@wdc.com> References: <1545211745-21208-1-git-send-email-uri.yanai@wdc.com> Sender: linux-scsi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Uri Yanai Support the new temperature notification attributes introduced in UFSv3.0 Added new query requests, exception event mask, and ufs features attributes. Signed-off-by: Uri Yanai --- drivers/scsi/ufs/ufs-sysfs.c | 3 +++ drivers/scsi/ufs/ufs.h | 8 ++++++++ drivers/scsi/ufs/ufshcd.c | 2 ++ 3 files changed, 13 insertions(+) diff --git a/drivers/scsi/ufs/ufs-sysfs.c b/drivers/scsi/ufs/ufs-sysfs.c index 8d9332b..eda4ddb 100644 --- a/drivers/scsi/ufs/ufs-sysfs.c +++ b/drivers/scsi/ufs/ufs-sysfs.c @@ -684,6 +684,9 @@ UFS_ATTRIBUTE(exception_event_status, _EE_STATUS); UFS_ATTRIBUTE(ffu_status, _FFU_STATUS); UFS_ATTRIBUTE(psa_state, _PSA_STATE); UFS_ATTRIBUTE(psa_data_size, _PSA_DATA_SIZE); +UFS_ATTRIBUTE(rough_temp, _ROUGH_TEMP); +UFS_ATTRIBUTE(too_high_temp, _TOO_HIGH_TEMP); +UFS_ATTRIBUTE(too_low_temp, _TOO_LOW_TEMP); static struct attribute *ufs_sysfs_attributes[] = { &dev_attr_boot_lun_enabled.attr, diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h index 8e4e526..20c5b21 100644 --- a/drivers/scsi/ufs/ufs.h +++ b/drivers/scsi/ufs/ufs.h @@ -168,6 +168,9 @@ enum attr_idn { QUERY_ATTR_IDN_FFU_STATUS = 0x14, QUERY_ATTR_IDN_PSA_STATE = 0x15, QUERY_ATTR_IDN_PSA_DATA_SIZE = 0x16, + QUERY_ATTR_IDN_ROUGH_TEMP = 0x18, + QUERY_ATTR_IDN_TOO_HIGH_TEMP = 0x19, + QUERY_ATTR_IDN_TOO_LOW_TEMP = 0x1A, }; /* Descriptor idn for Query requests */ @@ -354,6 +357,8 @@ enum power_desc_param_offset { enum { MASK_EE_STATUS = 0xFFFF, MASK_EE_URGENT_BKOPS = (1 << 2), + MASK_EE_TOO_HIGH_TEMP = (1 << 3), + MASK_EE_TOO_LOW_TEMP = (1 << 4), }; /* Background operation status */ @@ -543,6 +548,9 @@ struct ufs_dev_info { */ struct ufs_dev_desc { u16 wmanufacturerid; + u16 ufs_features; +#define UFS_FEATURE_TOO_HIGH_TEMPERATURE (1 << 4) +#define UFS_FEATURE_TOO_LOW_TEMPERATURE (1 << 5) char model[MAX_MODEL_LEN + 1]; }; diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 003d489..5004c94 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -6433,6 +6433,8 @@ static int ufs_get_device_desc(struct ufs_hba *hba, model_index = desc_buf[DEVICE_DESC_PARAM_PRDCT_NAME]; + dev_desc->ufs_features = desc_buf[DEVICE_DESC_PARAM_UFS_FEAT]; + /* Zero-pad entire buffer for string termination. */ memset(desc_buf, 0, buff_len); From patchwork Wed Dec 19 09:29:05 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Uri Yanai X-Patchwork-Id: 10736963 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id A34D213AD for ; Wed, 19 Dec 2018 09:29:49 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 920242AB20 for ; Wed, 19 Dec 2018 09:29:49 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 866542ABBC; Wed, 19 Dec 2018 09:29:49 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.7 required=2.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 705052AB20 for ; Wed, 19 Dec 2018 09:29:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728309AbeLSJ3s (ORCPT ); Wed, 19 Dec 2018 04:29:48 -0500 Received: from esa4.hgst.iphmx.com ([216.71.154.42]:30648 "EHLO esa4.hgst.iphmx.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728160AbeLSJ3r (ORCPT ); Wed, 19 Dec 2018 04:29:47 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=wdc.com; i=@wdc.com; q=dns/txt; s=dkim.wdc.com; t=1545211787; x=1576747787; h=from:to:cc:subject:date:message-id:in-reply-to: references; bh=pgJ6tkkcrolbgbpPmo+B6xtYaPdT6IAWgKmbpFvjMz8=; b=QcdsQjYzgf9im/Z2B1nh9LNUcm7xtxNgw5iUKHsdgV/Xw0J5Zbuy9JVX lW2rRbQT88QhFX+P4akWXrBFKiX+bBywojAO9CUvUj7VGxWn+7T+lkRlF 7wKfD7WpyvQ5OQB9VPp4jKh0zXI6KWcO/xbyBBTMaYT+c9NvMOANQdVH5 F63M9J+9U/F4zTlfSuRvjkeydw/KMOok6M6wbnI7CZPrFEnDv8kIbg6Zn s30ejLsPCNCgT1iA7wfkq0zWbvZWjNKSvdqGsclkNuSslaGplzRA8QTKr p9XnjWMhXo9d4CFXqSEXnnSiGkiR9QBpetBJr9WEYqTzzD9qjCX2VcmRV Q==; X-IronPort-AV: E=Sophos;i="5.56,372,1539619200"; d="scan'208";a="96959325" Received: from h199-255-45-15.hgst.com (HELO uls-op-cesaep02.wdc.com) ([199.255.45.15]) by ob1.hgst.iphmx.com with ESMTP; 19 Dec 2018 17:29:46 +0800 Received: from uls-op-cesaip01.wdc.com ([10.248.3.36]) by uls-op-cesaep02.wdc.com with ESMTP; 19 Dec 2018 01:11:53 -0800 Received: from ilb000457.sdcorp.global.sandisk.com ([10.0.230.247]) by uls-op-cesaip01.wdc.com with ESMTP; 19 Dec 2018 01:29:45 -0800 From: Uri To: "James E . J . Bottomley" , "Martin K . Petersen" , linux-scsi@vger.kernel.org Cc: Alex Lemberg , Uri Yanai Subject: [PATCH 2/2] scsi: ufs: add registration to thermal zone Date: Wed, 19 Dec 2018 11:29:05 +0200 Message-Id: <1545211745-21208-3-git-send-email-uri.yanai@wdc.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1545211745-21208-1-git-send-email-uri.yanai@wdc.com> References: <1545211745-21208-1-git-send-email-uri.yanai@wdc.com> Sender: linux-scsi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Uri Yanai Register to thermal_zone interface and implement the thermal ops. The thermal sets the temperature thresholds the Thermal Manager would be notified on crossing thresholds. The thermal interface adds a new thermal zone device sensor under /sys/class/thermal/ folder. Signed-off-by: Uri Yanai --- drivers/scsi/ufs/ufs-sysfs.c | 3 + drivers/scsi/ufs/ufshcd.c | 180 +++++++++++++++++++++++++++++++++++++++++++ drivers/scsi/ufs/ufshcd.h | 33 ++++++++ 3 files changed, 216 insertions(+) diff --git a/drivers/scsi/ufs/ufs-sysfs.c b/drivers/scsi/ufs/ufs-sysfs.c index eda4ddb..859511d 100644 --- a/drivers/scsi/ufs/ufs-sysfs.c +++ b/drivers/scsi/ufs/ufs-sysfs.c @@ -705,6 +705,9 @@ static struct attribute *ufs_sysfs_attributes[] = { &dev_attr_ffu_status.attr, &dev_attr_psa_state.attr, &dev_attr_psa_data_size.attr, + &dev_attr_rough_temp.attr, + &dev_attr_too_high_temp.attr, + &dev_attr_too_low_temp.attr, NULL, }; diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 5004c94..b843ef0 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -42,6 +42,7 @@ #include #include #include +#include #include "ufshcd.h" #include "ufs_quirks.h" #include "unipro.h" @@ -4883,6 +4884,174 @@ static int ufshcd_enable_ee(struct ufs_hba *hba, u16 mask) return err; } +#ifdef CONFIG_THERMAL + +#define attr2milicelcius(attr) (((0xFF & attr) - 80) * 1000) +#define dev_thermal_info dev_info + +static int ufshcd_thermal_get_temp(struct thermal_zone_device *device, + int *temperature) +{ + struct ufs_hba *hba = (struct ufs_hba *)device->devdata; + u32 temp; + + const int err = ufshcd_query_attr_retry(hba, + UPIU_QUERY_OPCODE_READ_ATTR, + QUERY_ATTR_IDN_ROUGH_TEMP, + 0, 0, &temp); + if (err) + return -EINVAL; + + *temperature = attr2milicelcius(temp); + return 0; +} + +static int ufshcd_thermal_get_trip_temp( + struct thermal_zone_device *device, + int trip, int *temp) +{ + struct ufs_hba *hba = (struct ufs_hba *)device->devdata; + + if (trip < 0 || trip >= UFS_THERM_MAX_TRIPS) + return -EINVAL; + + if (hba->thermal.trip[UFS_THERM_TOO_HIGH_TRIP].index == trip) + *temp = hba->thermal.trip[ + UFS_THERM_TOO_HIGH_TRIP].temp_boundary; + else if (hba->thermal.trip[UFS_THERM_TOO_LOW_TRIP].index == trip) + *temp = hba->thermal.trip[UFS_THERM_TOO_LOW_TRIP].temp_boundary; + + return 0; +} + +static int ufshcd_thermal_get_trip_type( + struct thermal_zone_device *device, + int trip, enum thermal_trip_type *type) +{ + if (trip < 0 || trip >= UFS_THERM_MAX_TRIPS) + return -EINVAL; + + *type = THERMAL_TRIP_PASSIVE; + + return 0; +} + +static void ufshcd_therm_exception_event_handler(struct ufs_hba *hba, + u32 exception_status) +{ + if (exception_status & MASK_EE_TOO_HIGH_TEMP) { + thermal_notify_framework(hba->thermal.zone, + hba->thermal.trip[UFS_THERM_TOO_HIGH_TRIP].index); + dev_thermal_info(hba->dev, + "High temperature raised\n"); + } else if (exception_status & MASK_EE_TOO_LOW_TEMP) { + thermal_notify_framework(hba->thermal.zone, + hba->thermal.trip[UFS_THERM_TOO_LOW_TRIP].index); + dev_thermal_info(hba->dev, + "Low temperature raised\n"); + } +} + +static struct thermal_zone_device_ops thermal_ops = { + .get_temp = ufshcd_thermal_get_temp, + .get_trip_temp = ufshcd_thermal_get_trip_temp, + .get_trip_type = ufshcd_thermal_get_trip_type, +}; + +static bool ufshcd_thermal_get_boundary(struct ufs_hba *hba, + int trip, int *boundary) +{ + const u32 atrib = ((trip == UFS_THERM_TOO_HIGH_TRIP) ? + QUERY_ATTR_IDN_TOO_HIGH_TEMP : + QUERY_ATTR_IDN_TOO_LOW_TEMP); + const int err = ufshcd_query_attr_retry(hba, + UPIU_QUERY_OPCODE_READ_ATTR, + atrib, 0, 0, boundary); + if (err) { + dev_err(hba->dev, + "Failed to get device too %s temperature boundary\n", + trip == UFS_THERM_TOO_HIGH_TRIP ? "high" : "low"); + return false; + } + + *boundary = attr2milicelcius(*boundary); + + return true; +} + +static int ufshcd_thermal_enable_ee(struct ufs_hba *hba, int trip) +{ + const u16 mask = ((trip == UFS_THERM_TOO_HIGH_TRIP) ? + MASK_EE_TOO_HIGH_TEMP : MASK_EE_TOO_LOW_TEMP); + const int err = ufshcd_enable_ee(hba, mask); + + if (err) { + dev_err(hba->dev, + "%s: failed to enable theraml too %s exception event %d\n", + __func__, UFS_THERM_TOO_HIGH_TRIP == trip ? + "high" : "low", err); + } + return err; +} + +static bool ufshcd_thermal_set_trip(struct ufs_hba *hba, int trip, + int *trip_count) +{ + int temp; + + if (ufshcd_thermal_get_boundary(hba, trip, &temp)) { + hba->thermal.trip[trip].index = (*trip_count)++; + hba->thermal.trip[trip].temp_boundary = temp; + return (ufshcd_thermal_enable_ee(hba, trip) == 0); + } + return false; +} + +static void ufshcd_thermal_register(struct ufs_hba *hba, int thermal_features) +{ + char name[] = "ufs_storage"; + int trip_count = 0; + + BUILD_BUG_ON(ARRAY_SIZE(name) >= THERMAL_NAME_LENGTH); + + if (thermal_features & UFS_FEATURE_TOO_HIGH_TEMPERATURE) + ufshcd_thermal_set_trip(hba, UFS_THERM_TOO_HIGH_TRIP, + &trip_count); + + if (thermal_features & UFS_FEATURE_TOO_LOW_TEMPERATURE) + ufshcd_thermal_set_trip(hba, UFS_THERM_TOO_LOW_TRIP, + &trip_count); + + if (trip_count > 0) { + hba->thermal.zone = thermal_zone_device_register("ufs_storage", + trip_count, 0, hba, &thermal_ops, NULL, 0, 0); + if (IS_ERR(hba->thermal.zone)) { + dev_err(hba->dev, "Failed to register to thermal zone (err = %ld)\n", + PTR_ERR(hba->thermal.zone)); + hba->thermal.zone = NULL; + } else + dev_thermal_info(hba->dev, "Succeeded to register to thermal zone"); + } +} + +static void ufshcd_thermal_zone_unregister(struct ufs_hba *hba) +{ + if (hba->thermal.zone) { + dev_dbg(hba->dev, "Thermal zone device unregister\n"); + thermal_zone_device_unregister(hba->thermal.zone); + hba->thermal.zone = NULL; + } +} +#else +static void ufshcd_thermal_register(struct ufs_hba *hba, int thermal_features) +{ +} + +static void ufshcd_thermal_zone_unregister(struct ufs_hba *hba) +{ +} +#endif /* CONFIG_THERMAL */ + /** * ufshcd_enable_auto_bkops - Allow device managed BKOPS * @hba: per-adapter instance @@ -5121,6 +5290,10 @@ static void ufshcd_exception_event_handler(struct work_struct *work) if (status & MASK_EE_URGENT_BKOPS) ufshcd_bkops_exception_event_handler(hba); +#ifdef CONFIG_THERMAL + if (status & (MASK_EE_TOO_HIGH_TEMP | MASK_EE_TOO_LOW_TEMP)) + ufshcd_therm_exception_event_handler(hba, status); +#endif /* CONFIG_THERMAL */ out: scsi_unblock_requests(hba->host); @@ -6858,6 +7031,9 @@ static int ufshcd_probe_hba(struct ufs_hba *hba) * context, no need to scan the host */ if (!ufshcd_eh_in_progress(hba) && !hba->pm_op_in_progress) { + const int thermal_features = (card.ufs_features & + (UFS_FEATURE_TOO_HIGH_TEMPERATURE | + UFS_FEATURE_TOO_LOW_TEMPERATURE)); bool flag; /* clear any previous UFS device information */ @@ -6891,6 +7067,9 @@ static int ufshcd_probe_hba(struct ufs_hba *hba) scsi_scan_host(hba->host); pm_runtime_put_sync(hba->dev); + + if (ufshcd_thermal_management_enabled(hba) && thermal_features) + ufshcd_thermal_register(hba, thermal_features); } if (!hba->is_init_prefetch) @@ -7444,6 +7623,7 @@ static int ufshcd_hba_init(struct ufs_hba *hba) static void ufshcd_hba_exit(struct ufs_hba *hba) { if (hba->is_powered) { + ufshcd_thermal_zone_unregister(hba); ufshcd_variant_hba_exit(hba); ufshcd_setup_vreg(hba, false); ufshcd_suspend_clkscaling(hba); diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index 69ba744..474d2d9 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -447,6 +447,29 @@ struct ufs_stats { struct ufs_uic_err_reg_hist dme_err; }; +enum { + UFS_THERM_TOO_HIGH_TRIP, + UFS_THERM_TOO_LOW_TRIP, + UFS_THERM_MAX_TRIPS, +}; + +#ifdef CONFIG_THERMAL +/** + *struct ufs_thermal - thermal zone related data + * @tzone: thermal zone device data + * @trip.temp_boundary: temperature thresholds for report + * @trip.index: the trip enumeration + * @trip: trip array, high and low if supported + */ +struct ufs_thermal { + struct thermal_zone_device *zone; + struct { + int index; + int temp_boundary; + } trip[UFS_THERM_MAX_TRIPS]; +}; +#endif /*CONFIG_THERMAL*/ + /** * struct ufs_hba - per adapter private structure * @mmio_base: UFSHCI base register address @@ -693,6 +716,8 @@ struct ufs_hba { */ #define UFSHCD_CAP_KEEP_AUTO_BKOPS_ENABLED_EXCEPT_SUSPEND (1 << 5) +#define UFSHCD_CAP_THERMAL_MANAGEMENT (1 << 6) + struct devfreq *devfreq; struct ufs_clk_scaling clk_scaling; bool is_sys_suspended; @@ -706,6 +731,10 @@ struct ufs_hba { struct device bsg_dev; struct request_queue *bsg_queue; +#ifdef CONFIG_THERMAL + /*Thermal data*/ + struct ufs_thermal thermal; +#endif /*CONFIG_THERMAL*/ }; /* Returns true if clocks can be gated. Otherwise false */ @@ -725,6 +754,10 @@ static inline bool ufshcd_can_autobkops_during_suspend(struct ufs_hba *hba) { return hba->caps & UFSHCD_CAP_AUTO_BKOPS_SUSPEND; } +static inline bool ufshcd_thermal_management_enabled(struct ufs_hba *hba) +{ + return hba->caps & UFSHCD_CAP_THERMAL_MANAGEMENT; +} static inline bool ufshcd_is_intr_aggr_allowed(struct ufs_hba *hba) {