From nobody Mon Sep 07 20:32:29 2026 X-Original-To: dev-commits-src-main@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4hdzJs5jtTz6s0fg for ; Mon, 07 Sep 2026 20:32:29 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "YR2" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4hdzJs1K9Sz3Psg for ; Mon, 07 Sep 2026 20:32:29 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1788813149; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=5D7SxCbT+PFZIdS2QkZxkWh6h8ttNFXzfdp647NBiAU=; b=fsug1epnePizRTL+pMK2egrPj3FdRoSBS4b8tYRxlxEj4Gj8xiaFAGVw15b3B+rdEahJGa CptK+HQJn8N1TWvECCm/7/U0yU4KlUkRQXWYSFYU0YkR9+XmbjRb8oTnuVtEaA8dycRMYE zMNVkhWnFyMmZQy8rjeqpqEAEIFf+7WtMZGlev9ePVLpt8Ag/r6UCQNKquu7zwQy2Dd9zZ FRr1N6hckCEZg3nRMb2Dv95RT6zOzy13iE0r06U4heNek/+gXKpjRdNJksU71MjIdQ/Tzw KPxoRh7wTrZk9SGLJ7+I/+AMzlW+fl7VhwFUSXP0xb9xNGPV/n3gNZrP58yxpA== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1788813149; a=rsa-sha256; cv=none; b=dZ641ZM30Lv+Zba8vq7ReHwvSdM+y8JEte9pWSrsY2tJVQYsKh1dScfVPda6ywLKC7pCC4 Xy7ecF4i+Qqpi7hYiCb6BRPTMrqZaVNJDVHpCT6/X/TJWWRfNPuvwciY5/KoY14i/p/HQs 6E3hoMdfhEM2Tv1wNyoJjAipfDs3AapV88HwfkNpwt8zvXuFRXzbdt3gy1046+tHRJRvS3 g9gGcK2fkjB7YHNLPgKAT+LuVODZDQu3a9nzyoy3WzLDxdDKXSNKq4OAVw7xUmTRLX7l7b rLJYHn4pbJttdpfp+xOLY0HIU9VgiETtZhGZXUwSvBteRXmBNS4peNF1GqPI9g== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1788813149; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=5D7SxCbT+PFZIdS2QkZxkWh6h8ttNFXzfdp647NBiAU=; b=NVRxzumkqi7uOb8JaUb/kFsiEBe1AilHLblttGgQOREZqZ6gfNAQIOIrnwPwbyWHSCQUUb BKs8+zONDZ4oPXhbog2YyZsjyEW6HE+IlsPmi56vs9dlGgrfOU7i1mmkYo2Or3tMExT4mK framb5nYCRwiSdoJEqCBECzEZbUsDjwZRD5GNt3Rb2QWOG6xGZYP7rbKG/Pm+8LjS45XXK oDt8nivhEE+qnHT9kXmqMr2GsXZZx8rG5YwmG0p1opJW3LQ4aApKwEksSsCdjM/7U83Pqg gnLygArK956xFEbG1rWqy/54Sup5dlwqai8RTc18zyEslsANGtHeF9yiqU3j1w== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4hdzJs0K4Rzb3v for ; Mon, 07 Sep 2026 20:32:29 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 43f1f by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Mon, 07 Sep 2026 20:32:29 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Jean-=?utf-8?Q?S=C3=A9bast?==?utf-8?Q?ien P=C3=A9?=dron Subject: git: 5fad251f0563 - main - linuxkpi: Add `timer64_to_tm()` List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-main@freebsd.org Sender: owner-dev-commits-src-main@FreeBSD.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: dumbbell X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 5fad251f05634e3220d36d51f624d77b41bc01c1 Auto-Submitted: auto-generated Date: Mon, 07 Sep 2026 20:32:29 +0000 Message-Id: <6a9f1f5d.43f1f.43fc1014@gitrepo.freebsd.org> The branch main has been updated by dumbbell: URL: https://cgit.FreeBSD.org/src/commit/?id=5fad251f05634e3220d36d51f624d77b41bc01c1 commit 5fad251f05634e3220d36d51f624d77b41bc01c1 Author: Jean-Sébastien Pédron AuthorDate: 2026-08-15 18:31:15 +0000 Commit: Jean-Sébastien Pédron CommitDate: 2026-09-07 20:31:39 +0000 linuxkpi: Add `timer64_to_tm()` The function converts a number of seconds since Epoch to a `struct tm`. The implementation was copied from `contrib/tzcode/localtime.c`. The amdgpu DRM driver started to use it in Linux 6.15. Reviewed by: bz Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D58758 --- sys/compat/linuxkpi/common/include/linux/time.h | 19 +++ sys/compat/linuxkpi/common/src/linux_timesub.c | 183 ++++++++++++++++++++++++ sys/conf/files | 2 + sys/modules/linuxkpi/Makefile | 1 + 4 files changed, 205 insertions(+) diff --git a/sys/compat/linuxkpi/common/include/linux/time.h b/sys/compat/linuxkpi/common/include/linux/time.h index ca77a20516ff..0bc47e4135c5 100644 --- a/sys/compat/linuxkpi/common/include/linux/time.h +++ b/sys/compat/linuxkpi/common/include/linux/time.h @@ -44,6 +44,21 @@ typedef int64_t time64_t; +/* Copied from `include/time.h` (userland). */ +struct tm { + int tm_sec; /* seconds after the minute [0-60] */ + int tm_min; /* minutes after the hour [0-59] */ + int tm_hour; /* hours since midnight [0-23] */ + int tm_mday; /* day of the month [1-31] */ + int tm_mon; /* months since January [0-11] */ + int tm_year; /* years since 1900 */ + int tm_wday; /* days since Sunday [0-6] */ + int tm_yday; /* days since January 1 [0-365] */ + int tm_isdst; /* Daylight Savings Time flag */ + long tm_gmtoff; /* offset from UTC in seconds */ + char *tm_zone; /* timezone abbreviation */ +}; + static inline struct timeval ns_to_timeval(const int64_t nsec) { @@ -138,4 +153,8 @@ get_seconds(void) return time_uptime; } +void linuxkpi_time64_to_tm(time64_t totalsecs, int offset, struct tm *result); +#define time64_to_tm(totalsecs, offset, result) \ + linuxkpi_time64_to_tm(totalsecs, offset, result) + #endif /* _LINUXKPI_LINUX_TIME_H_ */ diff --git a/sys/compat/linuxkpi/common/src/linux_timesub.c b/sys/compat/linuxkpi/common/src/linux_timesub.c new file mode 100644 index 000000000000..bc3fc0f1a702 --- /dev/null +++ b/sys/compat/linuxkpi/common/src/linux_timesub.c @@ -0,0 +1,183 @@ +/* + * This file is in the public domain, so clarified as of + * 1996-06-05 by Arthur David Olson. + */ + +/* + * The whole implementation of `timesub()` and its dependencies are copied from + * `contrib/tzcode/localtime.c` as of FreeBSD commit + * 28f617de7d9b9c708eacb3c2c13e5287e1b7354d. + */ + +#include + +enum { + SECSPERMIN = 60, + MINSPERHOUR = 60, + SECSPERHOUR = SECSPERMIN * MINSPERHOUR, + HOURSPERDAY = 24, + DAYSPERWEEK = 7, + DAYSPERNYEAR = 365, + DAYSPERLYEAR = DAYSPERNYEAR + 1, + MONSPERYEAR = 12, + YEARSPERREPEAT = 400 /* years before a Gregorian repeat */ +}; + +enum { + TM_SUNDAY, + TM_MONDAY, + TM_TUESDAY, + TM_WEDNESDAY, + TM_THURSDAY, + TM_FRIDAY, + TM_SATURDAY +}; + +enum { + TM_JANUARY, + TM_FEBRUARY, + TM_MARCH, + TM_APRIL, + TM_MAY, + TM_JUNE, + TM_JULY, + TM_AUGUST, + TM_SEPTEMBER, + TM_OCTOBER, + TM_NOVEMBER, + TM_DECEMBER +}; + +enum { + TM_YEAR_BASE = 1900, + TM_WDAY_BASE = TM_MONDAY, + EPOCH_YEAR = 1970, + EPOCH_WDAY = TM_THURSDAY +}; + +#define SECSPERDAY (SECSPERHOUR * HOURSPERDAY) +#define DAYSPERREPEAT (400 * 365 + 100 - 4 + 1) + +#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0)) + +#define TYPE_SIGNED(type) (((type) -1) < 0) + +static const int mon_lengths[2][MONSPERYEAR] = { + { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, + { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } +}; + +static const int year_lengths[2] = { + DAYSPERNYEAR, DAYSPERLYEAR +}; + +static time_t +leaps_thru_end_of_nonneg(time_t y) +{ + return y / 4 - y / 100 + y / 400; +} + +static time_t +leaps_thru_end_of(time_t y) +{ + return (y < 0 + ? -1 - leaps_thru_end_of_nonneg(-1 - y) + : leaps_thru_end_of_nonneg(y)); +} + +static struct tm * +timesub(const time64_t *timep, int offset, struct tm *tmp) +{ + time_t tdays; + const int * ip; + int corr; + int idays, rem, dayoff, dayrem; + time_t y; + + /* If less than SECSPERMIN, the number of seconds since the + most recent positive leap second; otherwise, do not add 1 + to localtime tm_sec because of leap seconds. */ + time_t secs_since_posleap = SECSPERMIN; + + corr = 0; + + /* Calculate the year, avoiding integer overflow even if + time_t is unsigned. */ + tdays = *timep / SECSPERDAY; + rem = *timep % SECSPERDAY; + rem += offset % SECSPERDAY - corr % SECSPERDAY + 3 * SECSPERDAY; + dayoff = offset / SECSPERDAY - corr / SECSPERDAY + rem / SECSPERDAY - 3; + rem %= SECSPERDAY; + /* y = (EPOCH_YEAR + + floor((tdays + dayoff) / DAYSPERREPEAT) * YEARSPERREPEAT), + sans overflow. But calculate against 1570 (EPOCH_YEAR - + YEARSPERREPEAT) instead of against 1970 so that things work + for localtime values before 1970 when time_t is unsigned. */ + dayrem = tdays % DAYSPERREPEAT; + dayrem += dayoff % DAYSPERREPEAT; + y = (EPOCH_YEAR - YEARSPERREPEAT + + ((1 + dayoff / DAYSPERREPEAT + dayrem / DAYSPERREPEAT + - ((dayrem % DAYSPERREPEAT) < 0) + + tdays / DAYSPERREPEAT) + * YEARSPERREPEAT)); + /* idays = (tdays + dayoff) mod DAYSPERREPEAT, sans overflow. */ + idays = tdays % DAYSPERREPEAT; + idays += dayoff % DAYSPERREPEAT + 2 * DAYSPERREPEAT; + idays %= DAYSPERREPEAT; + /* Increase Y and decrease IDAYS until IDAYS is in range for Y. */ + while (year_lengths[isleap(y)] <= idays) { + int tdelta = idays / DAYSPERLYEAR; + int_fast32_t ydelta = tdelta + !tdelta; + time_t newy = y + ydelta; + register int leapdays; + leapdays = leaps_thru_end_of(newy - 1) - + leaps_thru_end_of(y - 1); + idays -= ydelta * DAYSPERNYEAR; + idays -= leapdays; + y = newy; + } + + if (!TYPE_SIGNED(time_t) && y < TM_YEAR_BASE) { + int signed_y = y; + tmp->tm_year = signed_y - TM_YEAR_BASE; + } else if ((!TYPE_SIGNED(time_t) || INT_MIN + TM_YEAR_BASE <= y) + && y - TM_YEAR_BASE <= INT_MAX) + tmp->tm_year = y - TM_YEAR_BASE; + else { + return NULL; + } + tmp->tm_yday = idays; + /* + ** The "extra" mods below avoid overflow problems. + */ + tmp->tm_wday = (TM_WDAY_BASE + + ((tmp->tm_year % DAYSPERWEEK) + * (DAYSPERNYEAR % DAYSPERWEEK)) + + leaps_thru_end_of(y - 1) + - leaps_thru_end_of(TM_YEAR_BASE - 1) + + idays); + tmp->tm_wday %= DAYSPERWEEK; + if (tmp->tm_wday < 0) + tmp->tm_wday += DAYSPERWEEK; + tmp->tm_hour = rem / SECSPERHOUR; + rem %= SECSPERHOUR; + tmp->tm_min = rem / SECSPERMIN; + tmp->tm_sec = rem % SECSPERMIN; + + /* Use "... ??:??:60" at the end of the localtime minute containing + the second just before the positive leap second. */ + tmp->tm_sec += secs_since_posleap <= tmp->tm_sec; + + ip = mon_lengths[isleap(y)]; + for (tmp->tm_mon = 0; idays >= ip[tmp->tm_mon]; ++(tmp->tm_mon)) + idays -= ip[tmp->tm_mon]; + tmp->tm_mday = idays + 1; + tmp->tm_isdst = 0; + return tmp; +} + +void +linuxkpi_time64_to_tm(time64_t totalsecs, int offset, struct tm *result) +{ + timesub(&totalsecs, offset, result); +} diff --git a/sys/conf/files b/sys/conf/files index e6f996812a8f..8dd5a6a6873b 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -4772,6 +4772,8 @@ compat/linuxkpi/common/src/linux_skbuff.c optional compat_linuxkpi \ compile-with "${LINUXKPI_C}" compat/linuxkpi/common/src/linux_slab.c optional compat_linuxkpi \ compile-with "${LINUXKPI_C}" +compat/linuxkpi/common/src/linux_timesub.c optional compat_linuxkpi \ + compile-with "${LINUXKPI_C}" compat/linuxkpi/common/src/linux_usb.c optional compat_linuxkpi usb \ compile-with "${LINUXKPI_C}" compat/linuxkpi/common/src/linux_work.c optional compat_linuxkpi \ diff --git a/sys/modules/linuxkpi/Makefile b/sys/modules/linuxkpi/Makefile index da8d003e1d22..35dc19f93185 100644 --- a/sys/modules/linuxkpi/Makefile +++ b/sys/modules/linuxkpi/Makefile @@ -35,6 +35,7 @@ SRCS= linux_compat.c \ linux_skbuff.c \ linux_slab.c \ linux_tasklet.c \ + linux_timesub.c \ linux_usb.c \ linux_work.c \ linux_xarray.c