Skip to content

Commit 6bf999e

Browse files
beanhuomartinkpetersen
authored andcommitted
scsi: ufs: core: Add UFS RTC support
Add Real Time Clock (RTC) support for UFS device. This enhancement is crucial for the internal maintenance operations of the UFS device. The patch enables the device to handle both absolute and relative time information. Furthermore, it includes periodic task to update the RTC in accordance with the UFS Spec, ensuring the accuracy of RTC information for the device's internal processes. RTC and qTimestamp serve distinct purposes. The RTC provides a coarse level of granularity with, at best, approximate single-second resolution. This makes the RTC well-suited for the device to determine the approximate age of programmed blocks after being updated by the host. On the other hand, qTimestamp offers nanosecond granularity and is specifically designed for synchronizing Device Error Log entries with corresponding host-side logs. Given that the RTC has been a standard feature since UFS Spec 2.0, and qTimestamp was introduced in UFS Spec 4.0, the majority of UFS devices currently on the market rely on RTC. Therefore, it is advisable to continue supporting RTC in the Linux kernel. This ensures compatibility with the prevailing UFS device implementations and facilitates seamless integration with existing hardware. By maintaining support for RTC, we ensure broad compatibility and avoid potential issues arising from deviations in device specifications across different UFS versions. Signed-off-by: Bean Huo <beanhuo@micron.com> Signed-off-by: Mike Bi <mikebi@micron.com> Signed-off-by: Luca Porzio <lporzio@micron.com> Link: https://lore.kernel.org/r/20231212220825.85255-3-beanhuo@iokpp.de Acked-by: Avri Altman <avri.altman@wdc.com> Reviewed-by: Thomas Weißschuh <linux@weissschuh.net> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
1 parent 9fa2688 commit 6bf999e

File tree

3 files changed

+98
-2
lines changed

3 files changed

+98
-2
lines changed

drivers/ufs/core/ufshcd.c

+81-2
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,9 @@
9999
/* Polling time to wait for fDeviceInit */
100100
#define FDEVICEINIT_COMPL_TIMEOUT 1500 /* millisecs */
101101

102+
/* Default RTC update every 10 seconds */
103+
#define UFS_RTC_UPDATE_INTERVAL_MS (10 * MSEC_PER_SEC)
104+
102105
/* UFSHC 4.0 compliant HC support this mode. */
103106
static bool use_mcq_mode = true;
104107

@@ -683,6 +686,8 @@ static void ufshcd_device_reset(struct ufs_hba *hba)
683686
hba->dev_info.wb_enabled = false;
684687
hba->dev_info.wb_buf_flush_enabled = false;
685688
}
689+
if (hba->dev_info.rtc_type == UFS_RTC_RELATIVE)
690+
hba->dev_info.rtc_time_baseline = 0;
686691
}
687692
if (err != -EOPNOTSUPP)
688693
ufshcd_update_evt_hist(hba, UFS_EVT_DEV_RESET, err);
@@ -8188,6 +8193,72 @@ static void ufs_fixup_device_setup(struct ufs_hba *hba)
81888193
ufshcd_vops_fixup_dev_quirks(hba);
81898194
}
81908195

8196+
static void ufshcd_update_rtc(struct ufs_hba *hba)
8197+
{
8198+
struct timespec64 ts64;
8199+
int err;
8200+
u32 val;
8201+
8202+
ktime_get_real_ts64(&ts64);
8203+
8204+
if (ts64.tv_sec < hba->dev_info.rtc_time_baseline) {
8205+
dev_warn_once(hba->dev, "%s: Current time precedes previous setting!\n", __func__);
8206+
return;
8207+
}
8208+
8209+
/*
8210+
* The Absolute RTC mode has a 136-year limit, spanning from 2010 to 2146. If a time beyond
8211+
* 2146 is required, it is recommended to choose the relative RTC mode.
8212+
*/
8213+
val = ts64.tv_sec - hba->dev_info.rtc_time_baseline;
8214+
8215+
ufshcd_rpm_get_sync(hba);
8216+
err = ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_WRITE_ATTR, QUERY_ATTR_IDN_SECONDS_PASSED,
8217+
0, 0, &val);
8218+
ufshcd_rpm_put_sync(hba);
8219+
8220+
if (err)
8221+
dev_err(hba->dev, "%s: Failed to update rtc %d\n", __func__, err);
8222+
else if (hba->dev_info.rtc_type == UFS_RTC_RELATIVE)
8223+
hba->dev_info.rtc_time_baseline = ts64.tv_sec;
8224+
}
8225+
8226+
static void ufshcd_rtc_work(struct work_struct *work)
8227+
{
8228+
struct ufs_hba *hba;
8229+
8230+
hba = container_of(to_delayed_work(work), struct ufs_hba, ufs_rtc_update_work);
8231+
8232+
/* Update RTC only when there are no requests in progress and UFSHCI is operational */
8233+
if (!ufshcd_is_ufs_dev_busy(hba) && hba->ufshcd_state == UFSHCD_STATE_OPERATIONAL)
8234+
ufshcd_update_rtc(hba);
8235+
8236+
if (ufshcd_is_ufs_dev_active(hba))
8237+
schedule_delayed_work(&hba->ufs_rtc_update_work,
8238+
msecs_to_jiffies(UFS_RTC_UPDATE_INTERVAL_MS));
8239+
}
8240+
8241+
static void ufs_init_rtc(struct ufs_hba *hba, u8 *desc_buf)
8242+
{
8243+
u16 periodic_rtc_update = get_unaligned_be16(&desc_buf[DEVICE_DESC_PARAM_FRQ_RTC]);
8244+
struct ufs_dev_info *dev_info = &hba->dev_info;
8245+
8246+
if (periodic_rtc_update & UFS_RTC_TIME_BASELINE) {
8247+
dev_info->rtc_type = UFS_RTC_ABSOLUTE;
8248+
8249+
/*
8250+
* The concept of measuring time in Linux as the number of seconds elapsed since
8251+
* 00:00:00 UTC on January 1, 1970, and UFS ABS RTC is elapsed from January 1st
8252+
* 2010 00:00, here we need to adjust ABS baseline.
8253+
*/
8254+
dev_info->rtc_time_baseline = mktime64(2010, 1, 1, 0, 0, 0) -
8255+
mktime64(1970, 1, 1, 0, 0, 0);
8256+
} else {
8257+
dev_info->rtc_type = UFS_RTC_RELATIVE;
8258+
dev_info->rtc_time_baseline = 0;
8259+
}
8260+
}
8261+
81918262
static int ufs_get_device_desc(struct ufs_hba *hba)
81928263
{
81938264
int err;
@@ -8240,6 +8311,8 @@ static int ufs_get_device_desc(struct ufs_hba *hba)
82408311

82418312
ufshcd_temp_notif_probe(hba, desc_buf);
82428313

8314+
ufs_init_rtc(hba, desc_buf);
8315+
82438316
if (hba->ext_iid_sup)
82448317
ufshcd_ext_iid_probe(hba, desc_buf);
82458318

@@ -8793,6 +8866,8 @@ static int ufshcd_device_init(struct ufs_hba *hba, bool init_dev_params)
87938866
ufshcd_force_reset_auto_bkops(hba);
87948867

87958868
ufshcd_set_timestamp_attr(hba);
8869+
schedule_delayed_work(&hba->ufs_rtc_update_work,
8870+
msecs_to_jiffies(UFS_RTC_UPDATE_INTERVAL_MS));
87968871

87978872
/* Gear up to HS gear if supported */
87988873
if (hba->max_pwr_info.is_valid) {
@@ -9749,6 +9824,8 @@ static int __ufshcd_wl_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)
97499824
ret = ufshcd_vops_suspend(hba, pm_op, POST_CHANGE);
97509825
if (ret)
97519826
goto set_link_active;
9827+
9828+
cancel_delayed_work_sync(&hba->ufs_rtc_update_work);
97529829
goto out;
97539830

97549831
set_link_active:
@@ -9843,6 +9920,8 @@ static int __ufshcd_wl_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)
98439920
if (ret)
98449921
goto set_old_link_state;
98459922
ufshcd_set_timestamp_attr(hba);
9923+
schedule_delayed_work(&hba->ufs_rtc_update_work,
9924+
msecs_to_jiffies(UFS_RTC_UPDATE_INTERVAL_MS));
98469925
}
98479926

98489927
if (ufshcd_keep_autobkops_enabled_except_suspend(hba))
@@ -10539,8 +10618,8 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
1053910618
UFS_SLEEP_PWR_MODE,
1054010619
UIC_LINK_HIBERN8_STATE);
1054110620

10542-
INIT_DELAYED_WORK(&hba->rpm_dev_flush_recheck_work,
10543-
ufshcd_rpm_dev_flush_recheck_work);
10621+
INIT_DELAYED_WORK(&hba->rpm_dev_flush_recheck_work, ufshcd_rpm_dev_flush_recheck_work);
10622+
INIT_DELAYED_WORK(&hba->ufs_rtc_update_work, ufshcd_rtc_work);
1054410623

1054510624
/* Set the default auto-hiberate idle timer value to 150 ms */
1054610625
if (ufshcd_is_auto_hibern8_supported(hba) && !hba->ahit) {

include/ufs/ufs.h

+13
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <linux/bitops.h>
1515
#include <linux/types.h>
1616
#include <uapi/scsi/scsi_bsg_ufs.h>
17+
#include <linux/time64.h>
1718

1819
/*
1920
* Using static_assert() is not allowed in UAPI header files. Hence the check
@@ -551,6 +552,14 @@ struct ufs_vreg_info {
551552
struct ufs_vreg *vdd_hba;
552553
};
553554

555+
/* UFS device descriptor wPeriodicRTCUpdate bit9 defines RTC time baseline */
556+
#define UFS_RTC_TIME_BASELINE BIT(9)
557+
558+
enum ufs_rtc_time {
559+
UFS_RTC_RELATIVE,
560+
UFS_RTC_ABSOLUTE
561+
};
562+
554563
struct ufs_dev_info {
555564
bool f_power_on_wp_en;
556565
/* Keeps information if any of the LU is power on write protected */
@@ -578,6 +587,10 @@ struct ufs_dev_info {
578587

579588
/* UFS EXT_IID Enable */
580589
bool b_ext_iid_en;
590+
591+
/* UFS RTC */
592+
enum ufs_rtc_time rtc_type;
593+
time64_t rtc_time_baseline;
581594
};
582595

583596
/*

include/ufs/ufshcd.h

+4
Original file line numberDiff line numberDiff line change
@@ -911,6 +911,8 @@ enum ufshcd_mcq_opr {
911911
* @mcq_base: Multi circular queue registers base address
912912
* @uhq: array of supported hardware queues
913913
* @dev_cmd_queue: Queue for issuing device management commands
914+
* @mcq_opr: MCQ operation and runtime registers
915+
* @ufs_rtc_update_work: A work for UFS RTC periodic update
914916
*/
915917
struct ufs_hba {
916918
void __iomem *mmio_base;
@@ -1071,6 +1073,8 @@ struct ufs_hba {
10711073
struct ufs_hw_queue *uhq;
10721074
struct ufs_hw_queue *dev_cmd_queue;
10731075
struct ufshcd_mcq_opr_info_t mcq_opr[OPR_MAX];
1076+
1077+
struct delayed_work ufs_rtc_update_work;
10741078
};
10751079

10761080
/**

0 commit comments

Comments
 (0)