summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/rtc/apm,xgene-rtc.yaml45
-rw-r--r--Documentation/devicetree/bindings/rtc/isil,isl12057.txt74
-rw-r--r--Documentation/devicetree/bindings/rtc/nxp,pcf85063.yaml10
-rw-r--r--Documentation/devicetree/bindings/rtc/s3c-rtc.yaml40
-rw-r--r--Documentation/devicetree/bindings/rtc/trivial-rtc.yaml6
-rw-r--r--Documentation/devicetree/bindings/rtc/xgene-rtc.txt28
-rw-r--r--arch/s390/kernel/vmlinux.lds.S44
-rw-r--r--drivers/rtc/Kconfig38
-rw-r--r--drivers/rtc/Makefile1
-rw-r--r--drivers/rtc/interface.c27
-rw-r--r--drivers/rtc/rtc-amlogic-a4.c14
-rw-r--r--drivers/rtc/rtc-cpcap.c1
-rw-r--r--drivers/rtc/rtc-efi.c76
-rw-r--r--drivers/rtc/rtc-isl12022.c1
-rw-r--r--drivers/rtc/rtc-meson.c1
-rw-r--r--drivers/rtc/rtc-optee.c465
-rw-r--r--drivers/rtc/rtc-pcf2127.c19
-rw-r--r--drivers/rtc/rtc-s3c.c49
-rw-r--r--drivers/rtc/rtc-s3c.h19
-rw-r--r--drivers/rtc/rtc-sd2405al.c4
-rw-r--r--drivers/rtc/rtc-spacemit-p1.c167
-rw-r--r--drivers/rtc/rtc-tps6586x.c1
-rw-r--r--drivers/rtc/rtc-x1205.c2
-rw-r--r--drivers/rtc/rtc-zynqmp.c19
-rw-r--r--kernel/trace/trace.c12
-rw-r--r--scripts/Makefile.extrawarn8
-rw-r--r--scripts/Makefile.vmlinux7
-rw-r--r--usr/gen_init_cpio.c5
-rwxr-xr-xusr/include/headers_check.pl2
29 files changed, 799 insertions, 386 deletions
diff --git a/Documentation/devicetree/bindings/rtc/apm,xgene-rtc.yaml b/Documentation/devicetree/bindings/rtc/apm,xgene-rtc.yaml
new file mode 100644
index 000000000000..b8f46536fd5a
--- /dev/null
+++ b/Documentation/devicetree/bindings/rtc/apm,xgene-rtc.yaml
@@ -0,0 +1,45 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/rtc/apm,xgene-rtc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: APM X-Gene Real Time Clock
+
+maintainers:
+ - Khuong Dinh <khuong@os.amperecomputing.com>
+
+properties:
+ compatible:
+ const: apm,xgene-rtc
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ '#clock-cells':
+ const: 1
+
+ clocks:
+ maxItems: 1
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - '#clock-cells'
+ - clocks
+
+additionalProperties: false
+
+examples:
+ - |
+ rtc@10510000 {
+ compatible = "apm,xgene-rtc";
+ reg = <0x10510000 0x400>;
+ interrupts = <0x0 0x46 0x4>;
+ #clock-cells = <1>;
+ clocks = <&rtcclk 0>;
+ };
diff --git a/Documentation/devicetree/bindings/rtc/isil,isl12057.txt b/Documentation/devicetree/bindings/rtc/isil,isl12057.txt
deleted file mode 100644
index ff7c43555199..000000000000
--- a/Documentation/devicetree/bindings/rtc/isil,isl12057.txt
+++ /dev/null
@@ -1,74 +0,0 @@
-Intersil ISL12057 I2C RTC/Alarm chip
-
-ISL12057 is a trivial I2C device (it has simple device tree bindings,
-consisting of a compatible field, an address and possibly an interrupt
-line).
-
-Nonetheless, it also supports an option boolean property
-("wakeup-source") to handle the specific use-case found
-on at least three in-tree users of the chip (NETGEAR ReadyNAS 102, 104
-and 2120 ARM-based NAS); On those devices, the IRQ#2 pin of the chip
-(associated with the alarm supported by the driver) is not connected
-to the SoC but to a PMIC. It allows the device to be powered up when
-RTC alarm rings. In order to mark the device has a wakeup source and
-get access to the 'wakealarm' sysfs entry, this specific property can
-be set when the IRQ#2 pin of the chip is not connected to the SoC but
-can wake up the device.
-
-Required properties supported by the device:
-
- - "compatible": must be "isil,isl12057"
- - "reg": I2C bus address of the device
-
-Optional properties:
-
- - "wakeup-source": mark the chip as a wakeup source, independently of
- the availability of an IRQ line connected to the SoC.
-
-
-Example isl12057 node without IRQ#2 pin connected (no alarm support):
-
- isl12057: isl12057@68 {
- compatible = "isil,isl12057";
- reg = <0x68>;
- };
-
-
-Example isl12057 node with IRQ#2 pin connected to main SoC via MPP6 (note
-that the pinctrl-related properties below are given for completeness and
-may not be required or may be different depending on your system or
-SoC, and the main function of the MPP used as IRQ line, i.e.
-"interrupt-parent" and "interrupts" are usually sufficient):
-
- pinctrl {
- ...
-
- rtc_alarm_pin: rtc_alarm_pin {
- marvell,pins = "mpp6";
- marvell,function = "gpio";
- };
-
- ...
-
- };
-
- ...
-
- isl12057: isl12057@68 {
- compatible = "isil,isl12057";
- reg = <0x68>;
- pinctrl-0 = <&rtc_alarm_pin>;
- pinctrl-names = "default";
- interrupt-parent = <&gpio0>;
- interrupts = <6 IRQ_TYPE_EDGE_FALLING>;
- };
-
-
-Example isl12057 node without IRQ#2 pin connected to the SoC but to a
-PMIC, allowing the device to be started based on configured alarm:
-
- isl12057: isl12057@68 {
- compatible = "isil,isl12057";
- reg = <0x68>;
- wakeup-source;
- };
diff --git a/Documentation/devicetree/bindings/rtc/nxp,pcf85063.yaml b/Documentation/devicetree/bindings/rtc/nxp,pcf85063.yaml
index 1e6277e524c2..f7013cd8fc20 100644
--- a/Documentation/devicetree/bindings/rtc/nxp,pcf85063.yaml
+++ b/Documentation/devicetree/bindings/rtc/nxp,pcf85063.yaml
@@ -65,16 +65,6 @@ allOf:
- if:
properties:
compatible:
- contains:
- enum:
- - nxp,pcf85063
- then:
- properties:
- quartz-load-femtofarads:
- const: 7000
- - if:
- properties:
- compatible:
not:
contains:
enum:
diff --git a/Documentation/devicetree/bindings/rtc/s3c-rtc.yaml b/Documentation/devicetree/bindings/rtc/s3c-rtc.yaml
index bf4e11d6dffb..338874e7ed7f 100644
--- a/Documentation/devicetree/bindings/rtc/s3c-rtc.yaml
+++ b/Documentation/devicetree/bindings/rtc/s3c-rtc.yaml
@@ -13,9 +13,6 @@ properties:
compatible:
oneOf:
- enum:
- - samsung,s3c2410-rtc
- - samsung,s3c2416-rtc
- - samsung,s3c2443-rtc
- samsung,s3c6410-rtc
- items:
- enum:
@@ -29,19 +26,12 @@ properties:
maxItems: 1
clocks:
- description:
- Must contain a list of phandle and clock specifier for the rtc
- clock and in the case of a s3c6410 compatible controller, also
- a source clock.
- minItems: 1
maxItems: 2
clock-names:
- description:
- Must contain "rtc" and for a s3c6410 compatible controller
- also "rtc_src".
- minItems: 1
- maxItems: 2
+ items:
+ - const: rtc
+ - const: rtc_src
interrupts:
description:
@@ -54,30 +44,6 @@ properties:
allOf:
- $ref: rtc.yaml#
- - if:
- properties:
- compatible:
- contains:
- enum:
- - samsung,s3c6410-rtc
- - samsung,exynos3250-rtc
- then:
- properties:
- clocks:
- minItems: 2
- maxItems: 2
- clock-names:
- items:
- - const: rtc
- - const: rtc_src
- else:
- properties:
- clocks:
- minItems: 1
- maxItems: 1
- clock-names:
- items:
- - const: rtc
unevaluatedProperties: false
diff --git a/Documentation/devicetree/bindings/rtc/trivial-rtc.yaml b/Documentation/devicetree/bindings/rtc/trivial-rtc.yaml
index 5e0c7cd25cc6..b47822370d6f 100644
--- a/Documentation/devicetree/bindings/rtc/trivial-rtc.yaml
+++ b/Documentation/devicetree/bindings/rtc/trivial-rtc.yaml
@@ -38,6 +38,8 @@ properties:
- dallas,ds1672
# Extremely Accurate I²C RTC with Integrated Crystal and SRAM
- dallas,ds3232
+ # Dallas m41t00 Real-time Clock
+ - dallas,m41t00
# SD2405AL Real-Time Clock
- dfrobot,sd2405al
# EM Microelectronic EM3027 RTC
@@ -83,8 +85,8 @@ properties:
- via,vt8500-rtc
# I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
- whwave,sd3078
- # Xircom X1205 I2C RTC
- - xircom,x1205
+ # Xicor/Intersil X1205 I2C RTC
+ - xicor,x1205
reg:
maxItems: 1
diff --git a/Documentation/devicetree/bindings/rtc/xgene-rtc.txt b/Documentation/devicetree/bindings/rtc/xgene-rtc.txt
deleted file mode 100644
index fd195c358446..000000000000
--- a/Documentation/devicetree/bindings/rtc/xgene-rtc.txt
+++ /dev/null
@@ -1,28 +0,0 @@
-* APM X-Gene Real Time Clock
-
-RTC controller for the APM X-Gene Real Time Clock
-
-Required properties:
-- compatible : Should be "apm,xgene-rtc"
-- reg: physical base address of the controller and length of memory mapped
- region.
-- interrupts: IRQ line for the RTC.
-- #clock-cells: Should be 1.
-- clocks: Reference to the clock entry.
-
-Example:
-
-rtcclk: rtcclk {
- compatible = "fixed-clock";
- #clock-cells = <1>;
- clock-frequency = <100000000>;
- clock-output-names = "rtcclk";
-};
-
-rtc: rtc@10510000 {
- compatible = "apm,xgene-rtc";
- reg = <0x0 0x10510000 0x0 0x400>;
- interrupts = <0x0 0x46 0x4>;
- #clock-cells = <1>;
- clocks = <&rtcclk 0>;
-};
diff --git a/arch/s390/kernel/vmlinux.lds.S b/arch/s390/kernel/vmlinux.lds.S
index feecf1a6ddb4..d74d4c52ccd0 100644
--- a/arch/s390/kernel/vmlinux.lds.S
+++ b/arch/s390/kernel/vmlinux.lds.S
@@ -215,6 +215,28 @@ SECTIONS
ELF_DETAILS
/*
+ * Make sure that the .got.plt is either completely empty or it
+ * contains only the three reserved double words.
+ */
+ .got.plt : {
+ *(.got.plt)
+ }
+ ASSERT(SIZEOF(.got.plt) == 0 || SIZEOF(.got.plt) == 0x18, "Unexpected GOT/PLT entries detected!")
+
+ /*
+ * Sections that should stay zero sized, which is safer to
+ * explicitly check instead of blindly discarding.
+ */
+ .plt : {
+ *(.plt) *(.plt.*) *(.iplt) *(.igot .igot.plt)
+ }
+ ASSERT(SIZEOF(.plt) == 0, "Unexpected run-time procedure linkages detected!")
+ .rela.dyn : {
+ *(.rela.*) *(.rela_*)
+ }
+ ASSERT(SIZEOF(.rela.dyn) == 0, "Unexpected run-time relocations (.rela) detected!")
+
+ /*
* uncompressed image info used by the decompressor
* it should match struct vmlinux_info
*/
@@ -244,28 +266,6 @@ SECTIONS
#endif
} :NONE
- /*
- * Make sure that the .got.plt is either completely empty or it
- * contains only the three reserved double words.
- */
- .got.plt : {
- *(.got.plt)
- }
- ASSERT(SIZEOF(.got.plt) == 0 || SIZEOF(.got.plt) == 0x18, "Unexpected GOT/PLT entries detected!")
-
- /*
- * Sections that should stay zero sized, which is safer to
- * explicitly check instead of blindly discarding.
- */
- .plt : {
- *(.plt) *(.plt.*) *(.iplt) *(.igot .igot.plt)
- }
- ASSERT(SIZEOF(.plt) == 0, "Unexpected run-time procedure linkages detected!")
- .rela.dyn : {
- *(.rela.*) *(.rela_*)
- }
- ASSERT(SIZEOF(.rela.dyn) == 0, "Unexpected run-time relocations (.rela) detected!")
-
/* Sections to be discarded */
DISCARDS
/DISCARD/ : {
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 4a8dc8d0a4b7..2933c41c77c8 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -406,6 +406,16 @@ config RTC_DRV_MAX77686
This driver can also be built as a module. If so, the module
will be called rtc-max77686.
+config RTC_DRV_SPACEMIT_P1
+ tristate "SpacemiT P1 RTC"
+ depends on ARCH_SPACEMIT || COMPILE_TEST
+ select MFD_SPACEMIT_P1
+ default ARCH_SPACEMIT
+ help
+ Enable support for the RTC function in the SpacemiT P1 PMIC.
+ This driver can also be built as a module, which will be called
+ "spacemit-p1-rtc".
+
config RTC_DRV_NCT3018Y
tristate "Nuvoton NCT3018Y"
depends on OF
@@ -2044,20 +2054,6 @@ config RTC_DRV_RENESAS_RTCA3
This driver can also be built as a module, if so, the module
will be called "rtc-rtca3".
-comment "HID Sensor RTC drivers"
-
-config RTC_DRV_HID_SENSOR_TIME
- tristate "HID Sensor Time"
- depends on USB_HID
- depends on HID_SENSOR_HUB && IIO
- select HID_SENSOR_IIO_COMMON
- help
- Say yes here to build support for the HID Sensors of type Time.
- This drivers makes such sensors available as RTCs.
-
- If this driver is compiled as a module, it will be named
- rtc-hid-sensor-time.
-
config RTC_DRV_GOLDFISH
tristate "Goldfish Real Time Clock"
depends on HAS_IOMEM
@@ -2132,4 +2128,18 @@ config RTC_DRV_S32G
This RTC module can be used as a wakeup source.
Please note that it is not battery-powered.
+comment "HID Sensor RTC drivers"
+
+config RTC_DRV_HID_SENSOR_TIME
+ tristate "HID Sensor Time"
+ depends on USB_HID
+ depends on HID_SENSOR_HUB && IIO
+ select HID_SENSOR_IIO_COMMON
+ help
+ Say yes here to build support for the HID Sensors of type Time.
+ This drivers makes such sensors available as RTCs.
+
+ If this driver is compiled as a module, it will be named
+ rtc-hid-sensor-time.
+
endif # RTC_CLASS
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 610a9ee5fd33..8221bda6e6dc 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -172,6 +172,7 @@ obj-$(CONFIG_RTC_DRV_SD2405AL) += rtc-sd2405al.o
obj-$(CONFIG_RTC_DRV_SD3078) += rtc-sd3078.o
obj-$(CONFIG_RTC_DRV_SH) += rtc-sh.o
obj-$(CONFIG_RTC_DRV_SNVS) += rtc-snvs.o
+obj-$(CONFIG_RTC_DRV_SPACEMIT_P1) += rtc-spacemit-p1.o
obj-$(CONFIG_RTC_DRV_SPEAR) += rtc-spear.o
obj-$(CONFIG_RTC_DRV_STARFIRE) += rtc-starfire.o
obj-$(CONFIG_RTC_DRV_STK17TA8) += rtc-stk17ta8.o
diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c
index dc741ba29fa3..b8b298efd9a9 100644
--- a/drivers/rtc/interface.c
+++ b/drivers/rtc/interface.c
@@ -443,6 +443,29 @@ static int __rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
else
err = rtc->ops->set_alarm(rtc->dev.parent, alarm);
+ /*
+ * Check for potential race described above. If the waiting for next
+ * second, and the second just ticked since the check above, either
+ *
+ * 1) It ticked after the alarm was set, and an alarm irq should be
+ * generated.
+ *
+ * 2) It ticked before the alarm was set, and alarm irq most likely will
+ * not be generated.
+ *
+ * While we cannot easily check for which of these two scenarios we
+ * are in, we can return -ETIME to signal that the timer has already
+ * expired, which is true in both cases.
+ */
+ if ((scheduled - now) <= 1) {
+ err = __rtc_read_time(rtc, &tm);
+ if (err)
+ return err;
+ now = rtc_tm_to_time64(&tm);
+ if (scheduled <= now)
+ return -ETIME;
+ }
+
trace_rtc_set_alarm(rtc_tm_to_time64(&alarm->time), err);
return err;
}
@@ -594,6 +617,10 @@ int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled)
rtc->uie_rtctimer.node.expires = ktime_add(now, onesec);
rtc->uie_rtctimer.period = ktime_set(1, 0);
err = rtc_timer_enqueue(rtc, &rtc->uie_rtctimer);
+ if (!err && rtc->ops && rtc->ops->alarm_irq_enable)
+ err = rtc->ops->alarm_irq_enable(rtc->dev.parent, 1);
+ if (err)
+ goto out;
} else {
rtc_timer_remove(rtc, &rtc->uie_rtctimer);
}
diff --git a/drivers/rtc/rtc-amlogic-a4.c b/drivers/rtc/rtc-amlogic-a4.c
index 09d78c2cc691..1928b29c1045 100644
--- a/drivers/rtc/rtc-amlogic-a4.c
+++ b/drivers/rtc/rtc-amlogic-a4.c
@@ -72,13 +72,6 @@ struct aml_rtc_data {
const struct aml_rtc_config *config;
};
-static const struct regmap_config aml_rtc_regmap_config = {
- .reg_bits = 32,
- .val_bits = 32,
- .reg_stride = 4,
- .max_register = RTC_REAL_TIME,
-};
-
static inline u32 gray_to_binary(u32 gray)
{
u32 bcd = gray;
@@ -328,6 +321,13 @@ static int aml_rtc_probe(struct platform_device *pdev)
void __iomem *base;
int ret = 0;
+ const struct regmap_config aml_rtc_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .max_register = RTC_REAL_TIME,
+ };
+
rtc = devm_kzalloc(dev, sizeof(*rtc), GFP_KERNEL);
if (!rtc)
return -ENOMEM;
diff --git a/drivers/rtc/rtc-cpcap.c b/drivers/rtc/rtc-cpcap.c
index c170345ac076..8b6b35716f53 100644
--- a/drivers/rtc/rtc-cpcap.c
+++ b/drivers/rtc/rtc-cpcap.c
@@ -268,6 +268,7 @@ static int cpcap_rtc_probe(struct platform_device *pdev)
return err;
rtc->alarm_irq = platform_get_irq(pdev, 0);
+ rtc->alarm_enabled = true;
err = devm_request_threaded_irq(dev, rtc->alarm_irq, NULL,
cpcap_rtc_alarm_irq,
IRQF_TRIGGER_NONE | IRQF_ONESHOT,
diff --git a/drivers/rtc/rtc-efi.c b/drivers/rtc/rtc-efi.c
index fa8bf82df948..b4f44999ef0f 100644
--- a/drivers/rtc/rtc-efi.c
+++ b/drivers/rtc/rtc-efi.c
@@ -112,48 +112,6 @@ convert_from_efi_time(efi_time_t *eft, struct rtc_time *wtime)
return true;
}
-static int efi_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
-{
- efi_time_t eft;
- efi_status_t status;
-
- /*
- * As of EFI v1.10, this call always returns an unsupported status
- */
- status = efi.get_wakeup_time((efi_bool_t *)&wkalrm->enabled,
- (efi_bool_t *)&wkalrm->pending, &eft);
-
- if (status != EFI_SUCCESS)
- return -EINVAL;
-
- if (!convert_from_efi_time(&eft, &wkalrm->time))
- return -EIO;
-
- return rtc_valid_tm(&wkalrm->time);
-}
-
-static int efi_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
-{
- efi_time_t eft;
- efi_status_t status;
-
- convert_to_efi_time(&wkalrm->time, &eft);
-
- /*
- * XXX Fixme:
- * As of EFI 0.92 with the firmware I have on my
- * machine this call does not seem to work quite
- * right
- *
- * As of v1.10, this call always returns an unsupported status
- */
- status = efi.set_wakeup_time((efi_bool_t)wkalrm->enabled, &eft);
-
- dev_warn(dev, "write status is %d\n", (int)status);
-
- return status == EFI_SUCCESS ? 0 : -EINVAL;
-}
-
static int efi_read_time(struct device *dev, struct rtc_time *tm)
{
efi_status_t status;
@@ -188,17 +146,13 @@ static int efi_set_time(struct device *dev, struct rtc_time *tm)
static int efi_procfs(struct device *dev, struct seq_file *seq)
{
- efi_time_t eft, alm;
+ efi_time_t eft;
efi_time_cap_t cap;
- efi_bool_t enabled, pending;
- struct rtc_device *rtc = dev_get_drvdata(dev);
memset(&eft, 0, sizeof(eft));
- memset(&alm, 0, sizeof(alm));
memset(&cap, 0, sizeof(cap));
efi.get_time(&eft, &cap);
- efi.get_wakeup_time(&enabled, &pending, &alm);
seq_printf(seq,
"Time\t\t: %u:%u:%u.%09u\n"
@@ -214,26 +168,6 @@ static int efi_procfs(struct device *dev, struct seq_file *seq)
/* XXX fixme: convert to string? */
seq_printf(seq, "Timezone\t: %u\n", eft.timezone);
- if (test_bit(RTC_FEATURE_ALARM, rtc->features)) {
- seq_printf(seq,
- "Alarm Time\t: %u:%u:%u.%09u\n"
- "Alarm Date\t: %u-%u-%u\n"
- "Alarm Daylight\t: %u\n"
- "Enabled\t\t: %s\n"
- "Pending\t\t: %s\n",
- alm.hour, alm.minute, alm.second, alm.nanosecond,
- alm.year, alm.month, alm.day,
- alm.daylight,
- enabled == 1 ? "yes" : "no",
- pending == 1 ? "yes" : "no");
-
- if (alm.timezone == EFI_UNSPECIFIED_TIMEZONE)
- seq_puts(seq, "Timezone\t: unspecified\n");
- else
- /* XXX fixme: convert to string? */
- seq_printf(seq, "Timezone\t: %u\n", alm.timezone);
- }
-
/*
* now prints the capabilities
*/
@@ -249,8 +183,6 @@ static int efi_procfs(struct device *dev, struct seq_file *seq)
static const struct rtc_class_ops efi_rtc_ops = {
.read_time = efi_read_time,
.set_time = efi_set_time,
- .read_alarm = efi_read_alarm,
- .set_alarm = efi_set_alarm,
.proc = efi_procfs,
};
@@ -271,11 +203,7 @@ static int __init efi_rtc_probe(struct platform_device *dev)
platform_set_drvdata(dev, rtc);
rtc->ops = &efi_rtc_ops;
- clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->features);
- if (efi_rt_services_supported(EFI_RT_SUPPORTED_WAKEUP_SERVICES))
- set_bit(RTC_FEATURE_ALARM_WAKEUP_ONLY, rtc->features);
- else
- clear_bit(RTC_FEATURE_ALARM, rtc->features);
+ clear_bit(RTC_FEATURE_ALARM, rtc->features);
device_init_wakeup(&dev->dev, true);
diff --git a/drivers/rtc/rtc-isl12022.c b/drivers/rtc/rtc-isl12022.c
index 9b44839a7402..5fc52dc64213 100644
--- a/drivers/rtc/rtc-isl12022.c
+++ b/drivers/rtc/rtc-isl12022.c
@@ -413,6 +413,7 @@ static int isl12022_setup_irq(struct device *dev, int irq)
if (ret)
return ret;
+ isl12022->irq_enabled = true;
ret = devm_request_threaded_irq(dev, irq, NULL,
isl12022_rtc_interrupt,
IRQF_SHARED | IRQF_ONESHOT,
diff --git a/drivers/rtc/rtc-meson.c b/drivers/rtc/rtc-meson.c
index 47e9ebf58ffc..21eceb9e2e13 100644
--- a/drivers/rtc/rtc-meson.c
+++ b/drivers/rtc/rtc-meson.c
@@ -72,7 +72,6 @@ static const struct regmap_config meson_rtc_peripheral_regmap_config = {
.val_bits = 32,
.reg_stride = 4,
.max_register = RTC_REG4,
- .fast_io = true,
};
/* RTC front-end serialiser controls */
diff --git a/drivers/rtc/rtc-optee.c b/drivers/rtc/rtc-optee.c
index 9f8b5d4a8f6b..184c6d142801 100644
--- a/drivers/rtc/rtc-optee.c
+++ b/drivers/rtc/rtc-optee.c
@@ -5,19 +5,104 @@
#include <linux/device.h>
#include <linux/kernel.h>
+#include <linux/kthread.h>
#include <linux/module.h>
#include <linux/rtc.h>
#include <linux/tee_drv.h>
-#define RTC_INFO_VERSION 0x1
+#define RTC_INFO_VERSION 0x1
-#define TA_CMD_RTC_GET_INFO 0x0
-#define TA_CMD_RTC_GET_TIME 0x1
-#define TA_CMD_RTC_SET_TIME 0x2
-#define TA_CMD_RTC_GET_OFFSET 0x3
-#define TA_CMD_RTC_SET_OFFSET 0x4
+#define TA_RTC_FEATURE_CORRECTION BIT(0)
+#define TA_RTC_FEATURE_ALARM BIT(1)
+#define TA_RTC_FEATURE_WAKEUP_ALARM BIT(2)
-#define TA_RTC_FEATURE_CORRECTION BIT(0)
+enum rtc_optee_pta_cmd {
+ /* PTA_CMD_RTC_GET_INFO - Get RTC information
+ *
+ * [out] memref[0] RTC buffer memory reference containing a struct pta_rtc_info
+ */
+ PTA_CMD_RTC_GET_INF = 0x0,
+
+ /*
+ * PTA_CMD_RTC_GET_TIME - Get time from RTC
+ *
+ * [out] memref[0] RTC buffer memory reference containing a struct pta_rtc_time
+ */
+ PTA_CMD_RTC_GET_TIME = 0x1,
+
+ /*
+ * PTA_CMD_RTC_SET_TIME - Set time from RTC
+ *
+ * [in] memref[0] RTC buffer memory reference containing a struct pta_rtc_time to be
+ * used as RTC time
+ */
+ PTA_CMD_RTC_SET_TIME = 0x2,
+
+ /*
+ * PTA_CMD_RTC_GET_OFFSET - Get RTC offset
+ *
+ * [out] value[0].a RTC offset (signed 32bit value)
+ */
+ PTA_CMD_RTC_GET_OFFSET = 0x3,
+
+ /*
+ * PTA_CMD_RTC_SET_OFFSET - Set RTC offset
+ *
+ * [in] value[0].a RTC offset to be set (signed 32bit value)
+ */
+ PTA_CMD_RTC_SET_OFFSET = 0x4,
+
+ /*
+ * PTA_CMD_RTC_READ_ALARM - Read RTC alarm
+ *
+ * [out] memref[0] RTC buffer memory reference containing a struct pta_rtc_alarm
+ */
+ PTA_CMD_RTC_READ_ALARM = 0x5,
+
+ /*
+ * PTA_CMD_RTC_SET_ALARM - Set RTC alarm
+ *
+ * [in] memref[0] RTC buffer memory reference containing a struct pta_rtc_alarm to be
+ * used as RTC alarm
+ */
+ PTA_CMD_RTC_SET_ALARM = 0x6,
+
+ /*
+ * PTA_CMD_RTC_ENABLE_ALARM - Enable Alarm
+ *
+ * [in] value[0].a RTC IRQ flag (uint32_t), 0 to disable the alarm, 1 to enable
+ */
+ PTA_CMD_RTC_ENABLE_ALARM = 0x7,
+
+ /*
+ * PTA_CMD_RTC_WAIT_ALARM - Get alarm event
+ *
+ * [out] value[0].a RTC wait alarm return status (uint32_t):
+ * - 0: No alarm event
+ * - 1: Alarm event occurred
+ * - 2: Alarm event canceled
+ */
+ PTA_CMD_RTC_WAIT_ALARM = 0x8,
+
+ /*
+ * PTA_CMD_RTC_CANCEL_WAIT - Cancel wait for alarm event
+ */
+ PTA_CMD_RTC_CANCEL_WAIT = 0x9,
+
+ /*
+ * PTA_CMD_RTC_SET_WAKE_ALARM_STATUS - Set RTC wake alarm status flag
+ *
+ * [in] value[0].a RTC IRQ wake alarm flag (uint32_t), 0 to disable the wake up
+ * capability, 1 to enable.
+ */
+ PTA_CMD_RTC_SET_WAKE_ALARM_STATUS = 0xA,
+};
+
+enum rtc_wait_alarm_status {
+ WAIT_ALARM_RESET = 0x0,
+ WAIT_ALARM_ALARM_OCCURRED = 0x1,
+ WAIT_ALARM_CANCELED = 0x2,
+};
struct optee_rtc_time {
u32 tm_sec;
@@ -29,6 +114,12 @@ struct optee_rtc_time {
u32 tm_wday;
};
+struct optee_rtc_alarm {
+ u8 enabled;
+ u8 pending;
+ struct optee_rtc_time time;
+};
+
struct optee_rtc_info {
u64 version;
u64 features;
@@ -41,15 +132,21 @@ struct optee_rtc_info {
* @dev: OP-TEE based RTC device.
* @ctx: OP-TEE context handler.
* @session_id: RTC TA session identifier.
+ * @session2_id: RTC wait alarm session identifier.
* @shm: Memory pool shared with RTC device.
* @features: Bitfield of RTC features
+ * @alarm_task: RTC wait alamr task.
+ * @rtc: RTC device.
*/
struct optee_rtc {
struct device *dev;
struct tee_context *ctx;
u32 session_id;
+ u32 session2_id;
struct tee_shm *shm;
u64 features;
+ struct task_struct *alarm_task;
+ struct rtc_device *rtc;
};
static int optee_rtc_readtime(struct device *dev, struct rtc_time *tm)
@@ -60,7 +157,7 @@ static int optee_rtc_readtime(struct device *dev, struct rtc_time *tm)
struct tee_param param[4] = {0};
int ret;
- inv_arg.func = TA_CMD_RTC_GET_TIME;
+ inv_arg.func = PTA_CMD_RTC_GET_TIME;
inv_arg.session = priv->session_id;
inv_arg.num_params = 4;
@@ -97,19 +194,10 @@ static int optee_rtc_settime(struct device *dev, struct rtc_time *tm)
struct optee_rtc *priv = dev_get_drvdata(dev);
struct tee_ioctl_invoke_arg inv_arg = {0};
struct tee_param param[4] = {0};
- struct optee_rtc_time optee_tm;
- void *rtc_data;
+ struct optee_rtc_time *optee_tm;
int ret;
- optee_tm.tm_sec = tm->tm_sec;
- optee_tm.tm_min = tm->tm_min;
- optee_tm.tm_hour = tm->tm_hour;
- optee_tm.tm_mday = tm->tm_mday;
- optee_tm.tm_mon = tm->tm_mon;
- optee_tm.tm_year = tm->tm_year + 1900;
- optee_tm.tm_wday = tm->tm_wday;
-
- inv_arg.func = TA_CMD_RTC_SET_TIME;
+ inv_arg.func = PTA_CMD_RTC_SET_TIME;
inv_arg.session = priv->session_id;
inv_arg.num_params = 4;
@@ -117,11 +205,17 @@ static int optee_rtc_settime(struct device *dev, struct rtc_time *tm)
param[0].u.memref.shm = priv->shm;
param[0].u.memref.size = sizeof(struct optee_rtc_time);
- rtc_data = tee_shm_get_va(priv->shm, 0);
- if (IS_ERR(rtc_data))
- return PTR_ERR(rtc_data);
+ optee_tm = tee_shm_get_va(priv->shm, 0);
+ if (IS_ERR(optee_tm))
+ return PTR_ERR(optee_tm);
- memcpy(rtc_data, &optee_tm, sizeof(struct optee_rtc_time));
+ optee_tm->tm_min = tm->tm_min;
+ optee_tm->tm_sec = tm->tm_sec;
+ optee_tm->tm_hour = tm->tm_hour;
+ optee_tm->tm_mday = tm->tm_mday;
+ optee_tm->tm_mon = tm->tm_mon;
+ optee_tm->tm_year = tm->tm_year + 1900;
+ optee_tm->tm_wday = tm->tm_wday;
ret = tee_client_invoke_func(priv->ctx, &inv_arg, param);
if (ret < 0 || inv_arg.ret != 0)
@@ -140,7 +234,7 @@ static int optee_rtc_readoffset(struct device *dev, long *offset)
if (!(priv->features & TA_RTC_FEATURE_CORRECTION))
return -EOPNOTSUPP;
- inv_arg.func = TA_CMD_RTC_GET_OFFSET;
+ inv_arg.func = PTA_CMD_RTC_GET_OFFSET;
inv_arg.session = priv->session_id;
inv_arg.num_params = 4;
@@ -165,7 +259,7 @@ static int optee_rtc_setoffset(struct device *dev, long offset)
if (!(priv->features & TA_RTC_FEATURE_CORRECTION))
return -EOPNOTSUPP;
- inv_arg.func = TA_CMD_RTC_SET_OFFSET;
+ inv_arg.func = PTA_CMD_RTC_SET_OFFSET;
inv_arg.session = priv->session_id;
inv_arg.num_params = 4;
@@ -179,13 +273,228 @@ static int optee_rtc_setoffset(struct device *dev, long offset)
return 0;
}
+static int optee_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+ struct optee_rtc *priv = dev_get_drvdata(dev);
+ struct tee_ioctl_invoke_arg inv_arg = {0};
+ struct optee_rtc_alarm *optee_alarm;
+ struct tee_param param[1] = {0};
+ int ret;
+
+ if (!(priv->features & TA_RTC_FEATURE_ALARM))
+ return -EOPNOTSUPP;
+
+ inv_arg.func = PTA_CMD_RTC_READ_ALARM;
+ inv_arg.session = priv->session_id;
+ inv_arg.num_params = 1;
+
+ /* Fill invoke cmd params */
+ param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT;
+ param[0].u.memref.shm = priv->shm;
+ param[0].u.memref.size = sizeof(struct optee_rtc_alarm);
+
+ ret = tee_client_invoke_func(priv->ctx, &inv_arg, param);
+ if (ret < 0 || inv_arg.ret != 0)
+ return ret ? ret : -EPROTO;
+
+ optee_alarm = tee_shm_get_va(priv->shm, 0);
+ if (IS_ERR(optee_alarm))
+ return PTR_ERR(optee_alarm);
+
+ if (param[0].u.memref.size != sizeof(*optee_alarm))
+ return -EPROTO;
+
+ alarm->enabled = optee_alarm->enabled;
+ alarm->pending = optee_alarm->pending;
+ alarm->time.tm_sec = optee_alarm->time.tm_sec;
+ alarm->time.tm_min = optee_alarm->time.tm_min;
+ alarm->time.tm_hour = optee_alarm->time.tm_hour;
+ alarm->time.tm_mday = optee_alarm->time.tm_mday;
+ alarm->time.tm_mon = optee_alarm->time.tm_mon;
+ alarm->time.tm_year = optee_alarm->time.tm_year - 1900;
+ alarm->time.tm_wday = optee_alarm->time.tm_wday;
+ alarm->time.tm_yday = rtc_year_days(alarm->time.tm_mday,
+ alarm->time.tm_mon,
+ alarm->time.tm_year);
+
+ return 0;
+}
+
+static int optee_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+ struct optee_rtc *priv = dev_get_drvdata(dev);
+ struct tee_ioctl_invoke_arg inv_arg = {0};
+ struct optee_rtc_alarm *optee_alarm;
+ struct tee_param param[1] = {0};
+ int ret;
+
+ if (!(priv->features & TA_RTC_FEATURE_ALARM))
+ return -EOPNOTSUPP;
+
+ inv_arg.func = PTA_CMD_RTC_SET_ALARM;
+ inv_arg.session = priv->session_id;
+ inv_arg.num_params = 1;
+
+ param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT;
+ param[0].u.memref.shm = priv->shm;
+ param[0].u.memref.size = sizeof(struct optee_rtc_alarm);
+
+ optee_alarm = tee_shm_get_va(priv->shm, 0);
+ if (IS_ERR(optee_alarm))
+ return PTR_ERR(optee_alarm);
+
+ optee_alarm->enabled = alarm->enabled;
+ optee_alarm->pending = alarm->pending;
+ optee_alarm->time.tm_sec = alarm->time.tm_sec;
+ optee_alarm->time.tm_min = alarm->time.tm_min;
+ optee_alarm->time.tm_hour = alarm->time.tm_hour;
+ optee_alarm->time.tm_mday = alarm->time.tm_mday;
+ optee_alarm->time.tm_mon = alarm->time.tm_mon;
+ optee_alarm->time.tm_year = alarm->time.tm_year + 1900;
+ optee_alarm->time.tm_wday = alarm->time.tm_wday;
+
+ ret = tee_client_invoke_func(priv->ctx, &inv_arg, param);
+ if (ret < 0 || inv_arg.ret != 0)
+ return ret ? ret : -EPROTO;
+
+ return 0;
+}
+
+static int optee_rtc_enable_alarm(struct device *dev, unsigned int enabled)
+{
+ struct optee_rtc *priv = dev_get_drvdata(dev);
+ struct tee_ioctl_invoke_arg inv_arg = {0};
+ struct tee_param param[1] = {0};
+ int ret;
+
+ if (!(priv->features & TA_RTC_FEATURE_ALARM))
+ return -EOPNOTSUPP;
+
+ inv_arg.func = PTA_CMD_RTC_ENABLE_ALARM;
+ inv_arg.session = priv->session_id;
+ inv_arg.num_params = 1;
+
+ param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT;
+ param[0].u.value.a = (bool)enabled;
+
+ ret = tee_client_invoke_func(priv->ctx, &inv_arg, param);
+ if (ret < 0 || inv_arg.ret != 0)
+ return ret ? ret : -EPROTO;
+
+ return 0;
+}
+
static const struct rtc_class_ops optee_rtc_ops = {
- .read_time = optee_rtc_readtime,
- .set_time = optee_rtc_settime,
- .set_offset = optee_rtc_setoffset,
- .read_offset = optee_rtc_readoffset,
+ .read_time = optee_rtc_readtime,
+ .set_time = optee_rtc_settime,
+ .set_offset = optee_rtc_setoffset,
+ .read_offset = optee_rtc_readoffset,
+ .read_alarm = optee_rtc_read_alarm,
+ .set_alarm = optee_rtc_set_alarm,
+ .alarm_irq_enable = optee_rtc_enable_alarm,
};
+static int optee_rtc_wait_alarm(struct device *dev, int *return_status)
+{
+ struct optee_rtc *priv = dev_get_drvdata(dev);
+ struct tee_ioctl_invoke_arg inv_arg = {0};
+ struct tee_param param[1] = {0};
+ int ret;
+
+ if (!(priv->features & TA_RTC_FEATURE_ALARM))
+ return -EOPNOTSUPP;
+
+ inv_arg.func = PTA_CMD_RTC_WAIT_ALARM;
+ inv_arg.session = priv->session2_id;
+ inv_arg.num_params = 1;
+
+ param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT;
+
+ ret = tee_client_invoke_func(priv->ctx, &inv_arg, param);
+ if (ret < 0 || inv_arg.ret != 0)
+ return ret ? ret : -EPROTO;
+
+ *return_status = param[0].u.value.a;
+
+ return 0;
+}
+
+static int optee_rtc_cancel_wait_alarm(struct device *dev)
+{
+ struct optee_rtc *priv = dev_get_drvdata(dev);
+ struct tee_ioctl_invoke_arg inv_arg = {0};
+ struct tee_param param[1] = {0};
+ int ret;
+
+ if (!(priv->features & TA_RTC_FEATURE_ALARM))
+ return -EOPNOTSUPP;
+
+ inv_arg.func = PTA_CMD_RTC_CANCEL_WAIT;
+ inv_arg.session = priv->session_id;
+ inv_arg.num_params = 0;
+
+ ret = tee_client_invoke_func(priv->ctx, &inv_arg, param);
+ if (ret < 0 || inv_arg.ret != 0)
+ return ret ? ret : -EPROTO;
+
+ return 0;
+}
+
+static int optee_rtc_set_alarm_wake_status(struct device *dev, bool status)
+{
+ struct optee_rtc *priv = dev_get_drvdata(dev);
+ struct tee_ioctl_invoke_arg inv_arg = {0};
+ struct tee_param param[1] = {0};
+ int ret;
+
+ if (!(priv->features & TA_RTC_FEATURE_ALARM))
+ return -EOPNOTSUPP;
+
+ inv_arg.func = PTA_CMD_RTC_SET_WAKE_ALARM_STATUS;
+ inv_arg.session = priv->session_id;
+ inv_arg.num_params = 1;
+
+ param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT;
+ param[0].u.value.a = status;
+
+ ret = tee_client_invoke_func(priv->ctx, &inv_arg, param);
+
+ if (ret < 0 || inv_arg.ret != 0)
+ return ret ? ret : -EPROTO;
+
+ return 0;
+}
+
+static int optee_rtc_handle_alarm_event(void *data)
+{
+ struct optee_rtc *priv = (struct optee_rtc *)data;
+ int wait_alarm_return_status = 0;
+ int ret;
+
+ while (!kthread_should_stop()) {
+ ret = optee_rtc_wait_alarm(priv->dev, &wait_alarm_return_status);
+ if (ret) {
+ dev_err(priv->dev, "Failed to wait for alarm: %d\n", ret);
+ return ret;
+ }
+ switch (wait_alarm_return_status) {
+ case WAIT_ALARM_ALARM_OCCURRED:
+ dev_dbg(priv->dev, "Alarm occurred\n");
+ rtc_update_irq(priv->rtc, 1, RTC_IRQF | RTC_AF);
+ break;
+ case WAIT_ALARM_CANCELED:
+ dev_dbg(priv->dev, "Alarm canceled\n");
+ break;
+ default:
+ dev_warn(priv->dev, "Unknown return status: %d\n",
+ wait_alarm_return_status);
+ break;
+ }
+ }
+
+ return 0;
+}
+
static int optee_rtc_read_info(struct device *dev, struct rtc_device *rtc,
u64 *features)
{
@@ -196,7 +505,7 @@ static int optee_rtc_read_info(struct device *dev, struct rtc_device *rtc,
struct optee_rtc_time *tm;
int ret;
- inv_arg.func = TA_CMD_RTC_GET_INFO;
+ inv_arg.func = PTA_CMD_RTC_GET_INF;
inv_arg.session = priv->session_id;
inv_arg.num_params = 4;
@@ -241,14 +550,13 @@ static int optee_ctx_match(struct tee_ioctl_version_data *ver, const void *data)
static int optee_rtc_probe(struct device *dev)
{
struct tee_client_device *rtc_device = to_tee_client_device(dev);
- struct tee_ioctl_open_session_arg sess_arg;
+ struct tee_ioctl_open_session_arg sess2_arg = {0};
+ struct tee_ioctl_open_session_arg sess_arg = {0};
struct optee_rtc *priv;
struct rtc_device *rtc;
struct tee_shm *shm;
int ret, err;
- memset(&sess_arg, 0, sizeof(sess_arg));
-
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
@@ -257,12 +565,14 @@ static int optee_rtc_probe(struct device *dev)
if (IS_ERR(rtc))
return PTR_ERR(rtc);
+ priv->rtc = rtc;
+
/* Open context with TEE driver */
priv->ctx = tee_client_open_context(NULL, optee_ctx_match, NULL, NULL);
if (IS_ERR(priv->ctx))
return -ENODEV;
- /* Open session with rtc Trusted App */
+ /* Open first session with rtc Pseudo Trusted App */
export_uuid(sess_arg.uuid, &rtc_device->id.uuid);
sess_arg.clnt_login = TEE_IOCTL_LOGIN_REE_KERNEL;
@@ -274,6 +584,11 @@ static int optee_rtc_probe(struct device *dev)
}
priv->session_id = sess_arg.session;
+ /*
+ * Shared memory is used for passing an instance of either struct optee_rtc_info,
+ * struct optee_rtc_time or struct optee_rtc_alarm to OP-TEE service.
+ * The former is by definition large enough to cover both parameter cases.
+ */
shm = tee_shm_alloc_kernel_buf(priv->ctx, sizeof(struct optee_rtc_info));
if (IS_ERR(shm)) {
dev_err(priv->dev, "tee_shm_alloc_kernel_buf failed\n");
@@ -293,19 +608,70 @@ static int optee_rtc_probe(struct device *dev)
goto out_shm;
}
+ /* Handle feature's related setup before registering to rtc framework */
+ if (priv->features & TA_RTC_FEATURE_ALARM) {
+ priv->alarm_task = kthread_create(optee_rtc_handle_alarm_event,
+ priv, "rtc_alarm_evt");
+ if (IS_ERR(priv->alarm_task)) {
+ dev_err(dev, "Failed to create alarm thread\n");
+ err = PTR_ERR(priv->alarm_task);
+ goto out_shm;
+ }
+
+ /*
+ * In case of supported alarm feature on optee side, we create a kthread
+ * that will, in a new optee session, call a PTA interface "rtc_wait_alarm".
+ * This call return in case of alarm and in case of canceled alarm.
+ * The new optee session is therefore only needed in this case as we cannot
+ * use the same session for parallel calls to optee PTA.
+ * Hence one session is reserved to wait for alarms and the other to make
+ * standard calls to RTC PTA.
+ */
+
+ /* Open second session with rtc Trusted App */
+ export_uuid(sess2_arg.uuid, &rtc_device->id.uuid);
+ sess2_arg.clnt_login = TEE_IOCTL_LOGIN_REE_KERNEL;
+
+ ret = tee_client_open_session(priv->ctx, &sess2_arg, NULL);
+ if (ret < 0 || sess2_arg.ret != 0) {
+ dev_err(dev, "tee_client_open_session failed, err: %x\n", sess2_arg.ret);
+ err = -EINVAL;
+ goto out_thrd;
+ }
+ priv->session2_id = sess2_arg.session;
+
+ if (priv->features & TA_RTC_FEATURE_WAKEUP_ALARM)
+ device_init_wakeup(dev, true);
+ }
+
err = devm_rtc_register_device(rtc);
if (err)
- goto out_shm;
+ goto out_wk;
/*
- * We must clear this bit after registering because rtc_register_device
- * will set it if it sees that .set_offset is provided.
+ * We must clear those bits after registering because registering a rtc_device
+ * will set them if it sees that .set_offset and .set_alarm are provided.
*/
if (!(priv->features & TA_RTC_FEATURE_CORRECTION))
clear_bit(RTC_FEATURE_CORRECTION, rtc->features);
+ if (!(priv->features & TA_RTC_FEATURE_ALARM))
+ clear_bit(RTC_FEATURE_ALARM, rtc->features);
- return 0;
+ /* Start the thread after the rtc is setup */
+ if (priv->alarm_task) {
+ wake_up_process(priv->alarm_task);
+ dev_dbg(dev, "Wait alarm thread successfully started\n");
+ }
+ return 0;
+out_wk:
+ if (priv->features & TA_RTC_FEATURE_ALARM) {
+ device_init_wakeup(dev, false);
+ tee_client_close_session(priv->ctx, priv->session2_id);
+ }
+out_thrd:
+ if (priv->features & TA_RTC_FEATURE_ALARM)
+ kthread_stop(priv->alarm_task);
out_shm:
tee_shm_free(priv->shm);
out_sess:
@@ -320,12 +686,34 @@ static int optee_rtc_remove(struct device *dev)
{
struct optee_rtc *priv = dev_get_drvdata(dev);
+ if (priv->features & TA_RTC_FEATURE_ALARM) {
+ optee_rtc_cancel_wait_alarm(dev);
+ kthread_stop(priv->alarm_task);
+ device_init_wakeup(dev, false);
+ tee_client_close_session(priv->ctx, priv->session2_id);
+ }
+
+ tee_shm_free(priv->shm);
tee_client_close_session(priv->ctx, priv->session_id);
tee_client_close_context(priv->ctx);
return 0;
}
+static int optee_rtc_suspend(struct device *dev)
+{
+ int res = optee_rtc_set_alarm_wake_status(dev, device_may_wakeup(dev));
+
+ if (res) {
+ dev_err(dev, "Unable to transmit wakeup information to optee rtc\n");
+ return res;
+ }
+
+ return 0;
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(optee_rtc_pm_ops, optee_rtc_suspend, NULL);
+
static const struct tee_client_device_id optee_rtc_id_table[] = {
{UUID_INIT(0xf389f8c8, 0x845f, 0x496c,
0x8b, 0xbe, 0xd6, 0x4b, 0xd2, 0x4c, 0x92, 0xfd)},
@@ -341,6 +729,7 @@ static struct tee_client_driver optee_rtc_driver = {
.bus = &tee_bus_type,
.probe = optee_rtc_probe,
.remove = optee_rtc_remove,
+ .pm = pm_sleep_ptr(&optee_rtc_pm_ops),
},
};
diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c
index 2e1ac0c42e93..bb4fe81d3d62 100644
--- a/drivers/rtc/rtc-pcf2127.c
+++ b/drivers/rtc/rtc-pcf2127.c
@@ -42,6 +42,7 @@
#define PCF2127_BIT_CTRL2_AF BIT(4)
#define PCF2127_BIT_CTRL2_TSF2 BIT(5)
#define PCF2127_BIT_CTRL2_WDTF BIT(6)
+#define PCF2127_BIT_CTRL2_MSF BIT(7)
/* Control register 3 */
#define PCF2127_REG_CTRL3 0x02
#define PCF2127_BIT_CTRL3_BLIE BIT(0)
@@ -96,7 +97,8 @@
#define PCF2127_CTRL2_IRQ_MASK ( \
PCF2127_BIT_CTRL2_AF | \
PCF2127_BIT_CTRL2_WDTF | \
- PCF2127_BIT_CTRL2_TSF2)
+ PCF2127_BIT_CTRL2_TSF2 | \
+ PCF2127_BIT_CTRL2_MSF)
#define PCF2127_MAX_TS_SUPPORTED 4
@@ -606,6 +608,21 @@ static int pcf2127_watchdog_init(struct device *dev, struct pcf2127 *pcf2127)
set_bit(WDOG_HW_RUNNING, &pcf2127->wdd.status);
}
+ /*
+ * When using interrupt pin (INT A) as watchdog output, only allow
+ * watchdog interrupt (PCF2131_BIT_INT_WD_CD) and disable (mask) all
+ * other interrupts.
+ */
+ if (pcf2127->cfg->type == PCF2131) {
+ ret = regmap_write(pcf2127->regmap,
+ PCF2131_REG_INT_A_MASK1,
+ PCF2131_BIT_INT_BLIE |
+ PCF2131_BIT_INT_BIE |
+ PCF2131_BIT_INT_AIE |
+ PCF2131_BIT_INT_SI |
+ PCF2131_BIT_INT_MI);
+ }
+
return devm_watchdog_register_device(dev, &pcf2127->wdd);
}
diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c
index 79b2a16f15ad..291c0ccb0acd 100644
--- a/drivers/rtc/rtc-s3c.c
+++ b/drivers/rtc/rtc-s3c.c
@@ -331,7 +331,7 @@ static const struct rtc_class_ops s3c_rtcops = {
.alarm_irq_enable = s3c_rtc_setaie,
};
-static void s3c24xx_rtc_enable(struct s3c_rtc *info)
+static void s3c6410_rtc_enable(struct s3c_rtc *info)
{
unsigned int con, tmp;
@@ -361,19 +361,6 @@ static void s3c24xx_rtc_enable(struct s3c_rtc *info)
}
}
-static void s3c24xx_rtc_disable(struct s3c_rtc *info)
-{
- unsigned int con;
-
- con = readw(info->base + S3C2410_RTCCON);
- con &= ~S3C2410_RTCCON_RTCEN;
- writew(con, info->base + S3C2410_RTCCON);
-
- con = readb(info->base + S3C2410_TICNT);
- con &= ~S3C2410_TICNT_ENABLE;
- writeb(con, info->base + S3C2410_TICNT);
-}
-
static void s3c6410_rtc_disable(struct s3c_rtc *info)
{
unsigned int con;
@@ -538,53 +525,21 @@ static int s3c_rtc_resume(struct device *dev)
#endif
static SIMPLE_DEV_PM_OPS(s3c_rtc_pm_ops, s3c_rtc_suspend, s3c_rtc_resume);
-static void s3c24xx_rtc_irq(struct s3c_rtc *info, int mask)
-{
- rtc_update_irq(info->rtc, 1, RTC_AF | RTC_IRQF);
-}
-
static void s3c6410_rtc_irq(struct s3c_rtc *info, int mask)
{
rtc_update_irq(info->rtc, 1, RTC_AF | RTC_IRQF);
writeb(mask, info->base + S3C2410_INTP);
}
-static const struct s3c_rtc_data s3c2410_rtc_data = {
- .irq_handler = s3c24xx_rtc_irq,
- .enable = s3c24xx_rtc_enable,
- .disable = s3c24xx_rtc_disable,
-};
-
-static const struct s3c_rtc_data s3c2416_rtc_data = {
- .irq_handler = s3c24xx_rtc_irq,
- .enable = s3c24xx_rtc_enable,
- .disable = s3c24xx_rtc_disable,
-};
-
-static const struct s3c_rtc_data s3c2443_rtc_data = {
- .irq_handler = s3c24xx_rtc_irq,
- .enable = s3c24xx_rtc_enable,
- .disable = s3c24xx_rtc_disable,
-};
-
static const struct s3c_rtc_data s3c6410_rtc_data = {
.needs_src_clk = true,
.irq_handler = s3c6410_rtc_irq,
- .enable = s3c24xx_rtc_enable,
+ .enable = s3c6410_rtc_enable,
.disable = s3c6410_rtc_disable,
};
static const __maybe_unused struct of_device_id s3c_rtc_dt_match[] = {
{
- .compatible = "samsung,s3c2410-rtc",
- .data = &s3c2410_rtc_data,
- }, {
- .compatible = "samsung,s3c2416-rtc",
- .data = &s3c2416_rtc_data,
- }, {
- .compatible = "samsung,s3c2443-rtc",
- .data = &s3c2443_rtc_data,
- }, {
.compatible = "samsung,s3c6410-rtc",
.data = &s3c6410_rtc_data,
}, {
diff --git a/drivers/rtc/rtc-s3c.h b/drivers/rtc/rtc-s3c.h
index 3552914aa611..11d7a1255ce4 100644
--- a/drivers/rtc/rtc-s3c.h
+++ b/drivers/rtc/rtc-s3c.h
@@ -21,25 +21,6 @@
#define S3C2443_RTCCON_TICSEL (1 << 4)
#define S3C64XX_RTCCON_TICEN (1 << 8)
-#define S3C2410_TICNT S3C2410_RTCREG(0x44)
-#define S3C2410_TICNT_ENABLE (1 << 7)
-
-/* S3C2443: tick count is 15 bit wide
- * TICNT[6:0] contains upper 7 bits
- * TICNT1[7:0] contains lower 8 bits
- */
-#define S3C2443_TICNT_PART(x) ((x & 0x7f00) >> 8)
-#define S3C2443_TICNT1 S3C2410_RTCREG(0x4C)
-#define S3C2443_TICNT1_PART(x) (x & 0xff)
-
-/* S3C2416: tick count is 32 bit wide
- * TICNT[6:0] contains bits [14:8]
- * TICNT1[7:0] contains lower 8 bits
- * TICNT2[16:0] contains upper 17 bits
- */
-#define S3C2416_TICNT2 S3C2410_RTCREG(0x48)
-#define S3C2416_TICNT2_PART(x) ((x & 0xffff8000) >> 15)
-
#define S3C2410_RTCALM S3C2410_RTCREG(0x50)
#define S3C2410_RTCALM_ALMEN (1 << 6)
#define S3C2410_RTCALM_YEAREN (1 << 5)
diff --git a/drivers/rtc/rtc-sd2405al.c b/drivers/rtc/rtc-sd2405al.c
index 00c3033e8079..708ea5d964de 100644
--- a/drivers/rtc/rtc-sd2405al.c
+++ b/drivers/rtc/rtc-sd2405al.c
@@ -5,7 +5,9 @@
* Datasheet:
* https://image.dfrobot.com/image/data/TOY0021/SD2405AL%20datasheet%20(Angelo%20v0.1).pdf
*
- * Copyright (C) 2024 Tóth János <gomba007@gmail.com>
+ * I2C slave address: 0x32
+ *
+ * Copyright (C) 2024-2025 Tóth János <gomba007@gmail.com>
*/
#include <linux/bcd.h>
diff --git a/drivers/rtc/rtc-spacemit-p1.c b/drivers/rtc/rtc-spacemit-p1.c
new file mode 100644
index 000000000000..43ab62494bb4
--- /dev/null
+++ b/drivers/rtc/rtc-spacemit-p1.c
@@ -0,0 +1,167 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for the RTC found in the SpacemiT P1 PMIC
+ *
+ * Copyright (C) 2025 by RISCstar Solutions Corporation. All rights reserved.
+ */
+
+#include <linux/bits.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/rtc.h>
+
+#define MOD_NAME "spacemit-p1-rtc"
+
+/*
+ * Six consecutive 1-byte registers hold the seconds, minutes, hours,
+ * day-of-month, month, and year (respectively).
+ *
+ * The range of values in these registers is:
+ * seconds 0-59
+ * minutes 0-59
+ * hours 0-59
+ * day 0-30 (struct tm is 1-31)
+ * month 0-11
+ * year years since 2000 (struct tm is since 1900)
+ *
+ * Note that the day and month must be converted after reading and
+ * before writing.
+ */
+#define RTC_TIME 0x0d /* Offset of the seconds register */
+
+#define RTC_CTRL 0x1d
+#define RTC_EN BIT(2)
+
+/* Number of attempts to read a consistent time stamp before giving up */
+#define RTC_READ_TRIES 20 /* At least 1 */
+
+struct p1_rtc {
+ struct regmap *regmap;
+ struct rtc_device *rtc;
+};
+
+/*
+ * The P1 hardware documentation states that the register values are
+ * latched to ensure a consistent time snapshot within the registers,
+ * but these are in fact unstable due to a bug in the hardware design.
+ * So we loop until we get two identical readings.
+ */
+static int p1_rtc_read_time(struct device *dev, struct rtc_time *t)
+{
+ struct p1_rtc *p1 = dev_get_drvdata(dev);
+ struct regmap *regmap = p1->regmap;
+ u32 count = RTC_READ_TRIES;
+ u8 seconds;
+ u8 time[6];
+ int ret;
+
+ if (!regmap_test_bits(regmap, RTC_CTRL, RTC_EN))
+ return -EINVAL; /* RTC is disabled */
+
+ ret = regmap_bulk_read(regmap, RTC_TIME, time, sizeof(time));
+ if (ret)
+ return ret;
+
+ do {
+ seconds = time[0];
+ ret = regmap_bulk_read(regmap, RTC_TIME, time, sizeof(time));
+ if (ret)
+ return ret;
+ } while (time[0] != seconds && --count);
+
+ if (!count)
+ return -EIO; /* Unable to get a consistent result */
+
+ t->tm_sec = time[0] & GENMASK(5, 0);
+ t->tm_min = time[1] & GENMASK(5, 0);
+ t->tm_hour = time[2] & GENMASK(4, 0);
+ t->tm_mday = (time[3] & GENMASK(4, 0)) + 1;
+ t->tm_mon = time[4] & GENMASK(3, 0);
+ t->tm_year = (time[5] & GENMASK(5, 0)) + 100;
+
+ return 0;
+}
+
+/*
+ * The P1 hardware documentation states that values in the registers are
+ * latched so when written they represent a consistent time snapshot.
+ * Nevertheless, this is not guaranteed by the implementation, so we must
+ * disable the RTC while updating it.
+ */
+static int p1_rtc_set_time(struct device *dev, struct rtc_time *t)
+{
+ struct p1_rtc *p1 = dev_get_drvdata(dev);
+ struct regmap *regmap = p1->regmap;
+ u8 time[6];
+ int ret;
+
+ time[0] = t->tm_sec;
+ time[1] = t->tm_min;
+ time[2] = t->tm_hour;
+ time[3] = t->tm_mday - 1;
+ time[4] = t->tm_mon;
+ time[5] = t->tm_year - 100;
+
+ /* Disable the RTC to update; re-enable again when done */
+ ret = regmap_clear_bits(regmap, RTC_CTRL, RTC_EN);
+ if (ret)
+ return ret;
+
+ /* If something goes wrong, leave the RTC disabled */
+ ret = regmap_bulk_write(regmap, RTC_TIME, time, sizeof(time));
+ if (ret)
+ return ret;
+
+ return regmap_set_bits(regmap, RTC_CTRL, RTC_EN);
+}
+
+static const struct rtc_class_ops p1_rtc_class_ops = {
+ .read_time = p1_rtc_read_time,
+ .set_time = p1_rtc_set_time,
+};
+
+static int p1_rtc_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct rtc_device *rtc;
+ struct p1_rtc *p1;
+
+ p1 = devm_kzalloc(dev, sizeof(*p1), GFP_KERNEL);
+ if (!p1)
+ return -ENOMEM;
+ dev_set_drvdata(dev, p1);
+
+ p1->regmap = dev_get_regmap(dev->parent, NULL);
+ if (!p1->regmap)
+ return dev_err_probe(dev, -ENODEV, "failed to get regmap\n");
+
+ rtc = devm_rtc_allocate_device(dev);
+ if (IS_ERR(rtc))
+ return dev_err_probe(dev, PTR_ERR(rtc),
+ "error allocating device\n");
+ p1->rtc = rtc;
+
+ rtc->ops = &p1_rtc_class_ops;
+ rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
+ rtc->range_max = RTC_TIMESTAMP_END_2063;
+
+ clear_bit(RTC_FEATURE_ALARM, rtc->features);
+ clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->features);
+
+ return devm_rtc_register_device(rtc);
+}
+
+static struct platform_driver p1_rtc_driver = {
+ .probe = p1_rtc_probe,
+ .driver = {
+ .name = MOD_NAME,
+ },
+};
+
+module_platform_driver(p1_rtc_driver);
+
+MODULE_DESCRIPTION("SpacemiT P1 RTC driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" MOD_NAME);
diff --git a/drivers/rtc/rtc-tps6586x.c b/drivers/rtc/rtc-tps6586x.c
index 54c8429b16bf..76ecf7b798f0 100644
--- a/drivers/rtc/rtc-tps6586x.c
+++ b/drivers/rtc/rtc-tps6586x.c
@@ -258,6 +258,7 @@ static int tps6586x_rtc_probe(struct platform_device *pdev)
irq_set_status_flags(rtc->irq, IRQ_NOAUTOEN);
+ rtc->irq_en = true;
ret = devm_request_threaded_irq(&pdev->dev, rtc->irq, NULL,
tps6586x_rtc_irq,
IRQF_ONESHOT,
diff --git a/drivers/rtc/rtc-x1205.c b/drivers/rtc/rtc-x1205.c
index 4bcd7ca32f27..b8a0fccef14e 100644
--- a/drivers/rtc/rtc-x1205.c
+++ b/drivers/rtc/rtc-x1205.c
@@ -669,7 +669,7 @@ static const struct i2c_device_id x1205_id[] = {
MODULE_DEVICE_TABLE(i2c, x1205_id);
static const struct of_device_id x1205_dt_ids[] = {
- { .compatible = "xircom,x1205", },
+ { .compatible = "xicor,x1205", },
{},
};
MODULE_DEVICE_TABLE(of, x1205_dt_ids);
diff --git a/drivers/rtc/rtc-zynqmp.c b/drivers/rtc/rtc-zynqmp.c
index f39102b66eac..3baa2b481d9f 100644
--- a/drivers/rtc/rtc-zynqmp.c
+++ b/drivers/rtc/rtc-zynqmp.c
@@ -277,6 +277,10 @@ static irqreturn_t xlnx_rtc_interrupt(int irq, void *id)
static int xlnx_rtc_probe(struct platform_device *pdev)
{
struct xlnx_rtc_dev *xrtcdev;
+ bool is_alarm_set = false;
+ u32 pending_alrm_irq;
+ u32 current_time;
+ u32 alarm_time;
int ret;
xrtcdev = devm_kzalloc(&pdev->dev, sizeof(*xrtcdev), GFP_KERNEL);
@@ -296,6 +300,17 @@ static int xlnx_rtc_probe(struct platform_device *pdev)
if (IS_ERR(xrtcdev->reg_base))
return PTR_ERR(xrtcdev->reg_base);
+ /* Clear any pending alarm interrupts from previous kernel/boot */
+ pending_alrm_irq = readl(xrtcdev->reg_base + RTC_INT_STS) & RTC_INT_ALRM;
+ if (pending_alrm_irq)
+ writel(pending_alrm_irq, xrtcdev->reg_base + RTC_INT_STS);
+
+ /* Check if a valid alarm is already set from previous kernel/boot */
+ alarm_time = readl(xrtcdev->reg_base + RTC_ALRM);
+ current_time = readl(xrtcdev->reg_base + RTC_CUR_TM);
+ if (alarm_time > current_time && alarm_time != 0)
+ is_alarm_set = true;
+
xrtcdev->alarm_irq = platform_get_irq_byname(pdev, "alarm");
if (xrtcdev->alarm_irq < 0)
return xrtcdev->alarm_irq;
@@ -337,6 +352,10 @@ static int xlnx_rtc_probe(struct platform_device *pdev)
xlnx_init_rtc(xrtcdev);
+ /* Re-enable alarm interrupt if a valid alarm was found */
+ if (is_alarm_set)
+ writel(RTC_INT_ALRM, xrtcdev->reg_base + RTC_INT_EN);
+
device_init_wakeup(&pdev->dev, true);
return devm_rtc_register_device(xrtcdev->rtc);
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 98b6a9cb1454..d1e527cf2aae 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -7441,7 +7441,8 @@ static ssize_t write_raw_marker_to_buffer(struct trace_array *tr,
ssize_t written;
size_t size;
- size = sizeof(*entry) + cnt;
+ /* cnt includes both the entry->id and the data behind it. */
+ size = struct_size(entry, buf, cnt - sizeof(entry->id));
buffer = tr->array_buffer.buffer;
@@ -7455,7 +7456,10 @@ static ssize_t write_raw_marker_to_buffer(struct trace_array *tr,
return -EBADF;
entry = ring_buffer_event_data(event);
- memcpy(&entry->id, buf, cnt);
+ unsafe_memcpy(&entry->id, buf, cnt,
+ "id and content already reserved on ring buffer"
+ "'buf' includes the 'id' and the data."
+ "'entry' was allocated with cnt from 'id'.");
written = cnt;
__buffer_unlock_commit(buffer, event);
@@ -7497,12 +7501,12 @@ tracing_mark_raw_write(struct file *filp, const char __user *ubuf,
if (tr == &global_trace) {
guard(rcu)();
list_for_each_entry_rcu(tr, &marker_copies, marker_list) {
- written = write_raw_marker_to_buffer(tr, ubuf, cnt);
+ written = write_raw_marker_to_buffer(tr, buf, cnt);
if (written < 0)
break;
}
} else {
- written = write_raw_marker_to_buffer(tr, ubuf, cnt);
+ written = write_raw_marker_to_buffer(tr, buf, cnt);
}
return written;
diff --git a/scripts/Makefile.extrawarn b/scripts/Makefile.extrawarn
index 1434cb6208cb..6af392f9cd02 100644
--- a/scripts/Makefile.extrawarn
+++ b/scripts/Makefile.extrawarn
@@ -223,9 +223,11 @@ KBUILD_USERCFLAGS += -Werror
KBUILD_USERLDFLAGS += -Wl,--fatal-warnings
KBUILD_RUSTFLAGS += -Dwarnings
-endif
-
-# Hostprog flags are used during build bootstrapping and can not rely on CONFIG_ symbols.
+# While hostprog flags are used during build bootstrapping (thus should not
+# depend on CONFIG_ symbols), -Werror is disruptive and should be opted into.
+# Only apply -Werror to hostprogs built after the initial Kconfig stage.
KBUILD_HOSTCFLAGS += -Werror
KBUILD_HOSTLDFLAGS += -Wl,--fatal-warnings
KBUILD_HOSTRUSTFLAGS += -Dwarnings
+
+endif
diff --git a/scripts/Makefile.vmlinux b/scripts/Makefile.vmlinux
index 7c6ae9886f8f..ced4379550d7 100644
--- a/scripts/Makefile.vmlinux
+++ b/scripts/Makefile.vmlinux
@@ -82,9 +82,12 @@ endif
# ---------------------------------------------------------------------------
remove-section-y := .modinfo
-remove-section-$(CONFIG_ARCH_VMLINUX_NEEDS_RELOCS) += '.rel*'
+remove-section-$(CONFIG_ARCH_VMLINUX_NEEDS_RELOCS) += '.rel*' '!.rel*.dyn'
+# for compatibility with binutils < 2.32
+# https://sourceware.org/git/?p=binutils-gdb.git;a=commit;h=c12d9fa2afe7abcbe407a00e15719e1a1350c2a7
+remove-section-$(CONFIG_ARCH_VMLINUX_NEEDS_RELOCS) += '.rel.*'
-remove-symbols := -w --strip-symbol='__mod_device_table__*'
+remove-symbols := -w --strip-unneeded-symbol='__mod_device_table__*'
# To avoid warnings: "empty loadable segment detected at ..." from GNU objcopy,
# it is necessary to remove the PT_LOAD flag from the segment.
diff --git a/usr/gen_init_cpio.c b/usr/gen_init_cpio.c
index 75e9561ba313..b7296edc6626 100644
--- a/usr/gen_init_cpio.c
+++ b/usr/gen_init_cpio.c
@@ -112,7 +112,10 @@ static int cpio_trailer(void)
push_pad(padlen(offset, 512)) < 0)
return -1;
- return fsync(outfd);
+ if (fsync(outfd) < 0 && errno != EINVAL)
+ return -1;
+
+ return 0;
}
static int cpio_mkslink(const char *name, const char *target,
diff --git a/usr/include/headers_check.pl b/usr/include/headers_check.pl
index 21c2fb9520e6..1fbc8785f96e 100755
--- a/usr/include/headers_check.pl
+++ b/usr/include/headers_check.pl
@@ -155,6 +155,8 @@ sub check_sizetypes
if (my $included = ($line =~ /^\s*#\s*include\s+[<"](\S+)[>"]/)[0]) {
check_include_typesh($included);
}
+ # strip single-line comments, as types may be referenced within them
+ $line =~ s@/\*.*?\*/@@;
if ($line =~ m/__[us](8|16|32|64)\b/) {
printf STDERR "$filename:$lineno: " .
"found __[us]{8,16,32,64} type " .