Pull timer updates from Thomas Gleixner: "Updates for the time(r) subsystem: Core: - Make the clocksource watchdog more robust by better validation checks of the measurement. Drivers: - New drivers for MStar and SSD20xd SOCs - The usual cleanups and improvements all over the place" * tag 'timers-core-2022-01-13' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: dt-bindings: timer: Add Mstar MSC313e timer devicetree bindings documentation clocksource/drivers/msc313e: Add support for ssd20xd-based platforms clocksource/drivers: Add MStar MSC313e timer support clocksource/drivers/pistachio: Fix -Wunused-but-set-variable warning clocksource/drivers/timer-imx-sysctr: Set cpumask to cpu_possible_mask clocksource/drivers/imx-sysctr: Mark two variable with __ro_after_init clocksource/drivers/renesas,ostm: Make RENESAS_OSTM symbol visible clocksource/drivers/renesas-ostm: Add RZ/G2L OSTM support dt-bindings: timer: renesas: ostm: Document Renesas RZ/G2L OSTM clocksource/drivers/exynos_mct: Fix silly typo resulting in checkpatch warning clocksource: Reduce the default clocksource_watchdog() retries to 2 clocksource: Avoid accidental unstable marking of clocksources dt-bindings: timer: tpm-timer: Add imx8ulp compatible string reset: Add of_reset_control_get_optional_exclusive() clocksource/drivers/exynos_mct: Refactor resources allocation dt-bindings: timer: remove rockchip,rk3066-timer compatible string from rockchip,rk-timer.yaml dt-bindings: timer: cadence_ttc: Add power-domains
Unified · Split
| @@ -612,8 +612,8 @@ · 611 unmodified lines | ||
| 612 | 612 | clocksource.max_cswd_read_retries= [KNL] |
| 613 | 613 | Number of clocksource_watchdog() retries due to |
| 614 | 614 | external delays before the clock will be marked |
| 615 | − unstable. Defaults to three retries, that is, | |
| 616 | − four attempts to read the clock under test. | |
| 615 | + unstable. Defaults to two retries, that is, | |
| 616 | + three attempts to read the clock under test. | |
| 617 | 617 | |
| 618 | 618 | clocksource.verify_n_cpus= [KNL] |
| 619 | 619 | Limit the number of CPUs checked for clocksources |
| @@ -25,6 +25,9 @@ properties: · 24 unmodified lines | ||
| 25 | 25 | clocks: |
| 26 | 26 | maxItems: 1 |
| 27 | 27 | |
| 28 | + power-domains: | |
| 29 | + maxItems: 1 | |
| 30 | + | |
| 28 | 31 | timer-width: |
| 29 | 32 | $ref: "/schemas/types.yaml#/definitions/uint32" |
| 30 | 33 | description: | |
| @@ -0,0 +1,46 @@ | ||
| 1 | +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | |
| 2 | +%YAML 1.2 | |
| 3 | +--- | |
| 4 | +$id: http://devicetree.org/schemas/timer/mstar,msc313e-timer.yaml# | |
| 5 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 6 | + | |
| 7 | +title: Mstar MSC313e Timer Device Tree Bindings | |
| 8 | + | |
| 9 | +maintainers: | |
| 10 | + - Daniel Palmer <daniel@0x0f.com> | |
| 11 | + - Romain Perier <romain.perier@gmail.com> | |
| 12 | + | |
| 13 | +properties: | |
| 14 | + compatible: | |
| 15 | + enum: | |
| 16 | + - mstar,msc313e-timer | |
| 17 | + - sstar,ssd20xd-timer | |
| 18 | + | |
| 19 | + reg: | |
| 20 | + maxItems: 1 | |
| 21 | + | |
| 22 | + interrupts: | |
| 23 | + maxItems: 1 | |
| 24 | + | |
| 25 | + clocks: | |
| 26 | + maxItems: 1 | |
| 27 | + | |
| 28 | +required: | |
| 29 | + - compatible | |
| 30 | + - reg | |
| 31 | + - interrupts | |
| 32 | + - clocks | |
| 33 | + | |
| 34 | +additionalProperties: false | |
| 35 | + | |
| 36 | +examples: | |
| 37 | + - | | |
| 38 | + #include <dt-bindings/interrupt-controller/arm-gic.h> | |
| 39 | + | |
| 40 | + timer@6040 { | |
| 41 | + compatible = "mstar,msc313e-timer"; | |
| 42 | + reg = <0x6040 0x40>; | |
| 43 | + clocks = <&xtal_div2>; | |
| 44 | + interrupts-extended = <&intc_fiq GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>; | |
| 45 | + }; | |
| 46 | +... | |
| @@ -19,7 +19,11 @@ description: | · 18 unmodified lines | ||
| 19 | 19 | |
| 20 | 20 | properties: |
| 21 | 21 | compatible: |
| 22 | − const: fsl,imx7ulp-tpm | |
| 22 | + oneOf: | |
| 23 | + - const: fsl,imx7ulp-tpm | |
| 24 | + - items: | |
| 25 | + - const: fsl,imx8ulp-tpm | |
| 26 | + - const: fsl,imx7ulp-tpm | |
| 23 | 27 | |
| 24 | 28 | reg: |
| 25 | 29 | maxItems: 1 |
| @@ -21,9 +21,10 @@ properties: · 20 unmodified lines | ||
| 21 | 21 | compatible: |
| 22 | 22 | items: |
| 23 | 23 | - enum: |
| 24 | − - renesas,r7s72100-ostm # RZ/A1H | |
| 25 | − - renesas,r7s9210-ostm # RZ/A2M | |
| 26 | − - const: renesas,ostm # Generic | |
| 24 | + - renesas,r7s72100-ostm # RZ/A1H | |
| 25 | + - renesas,r7s9210-ostm # RZ/A2M | |
| 26 | + - renesas,r9a07g044-ostm # RZ/G2{L,LC} | |
| 27 | + - const: renesas,ostm # Generic | |
| 27 | 28 | |
| 28 | 29 | reg: |
| 29 | 30 | maxItems: 1 |
| @@ -37,6 +38,9 @@ properties: · 7 unmodified lines | ||
| 37 | 38 | power-domains: |
| 38 | 39 | maxItems: 1 |
| 39 | 40 | |
| 41 | + resets: | |
| 42 | + maxItems: 1 | |
| 43 | + | |
| 40 | 44 | required: |
| 41 | 45 | - compatible |
| 42 | 46 | - reg |
| @@ -44,6 +48,16 @@ required: · 1 unmodified line | ||
| 44 | 48 | - clocks |
| 45 | 49 | - power-domains |
| 46 | 50 | |
| 51 | +if: | |
| 52 | + properties: | |
| 53 | + compatible: | |
| 54 | + contains: | |
| 55 | + enum: | |
| 56 | + - renesas,r9a07g044-ostm | |
| 57 | +then: | |
| 58 | + required: | |
| 59 | + - resets | |
| 60 | + | |
| 47 | 61 | additionalProperties: false |
| 48 | 62 | |
| 49 | 63 | examples: |
| @@ -18,7 +18,6 @@ properties: · 17 unmodified lines | ||
| 18 | 18 | - enum: |
| 19 | 19 | - rockchip,rv1108-timer |
| 20 | 20 | - rockchip,rk3036-timer |
| 21 | − - rockchip,rk3066-timer | |
| 22 | 21 | - rockchip,rk3188-timer |
| 23 | 22 | - rockchip,rk3228-timer |
| 24 | 23 | - rockchip,rk3229-timer |
| @@ -2304,6 +2304,7 @@ F: Documentation/devicetree/bindings/gpio/mstar,msc313-gpio.yaml · 2303 unmodified lines | ||
| 2304 | 2304 | F: arch/arm/boot/dts/mstar-* |
| 2305 | 2305 | F: arch/arm/mach-mstar/ |
| 2306 | 2306 | F: drivers/clk/mstar/ |
| 2307 | +F: drivers/clocksource/timer-msc313e.c | |
| 2307 | 2308 | F: drivers/gpio/gpio-msc313.c |
| 2308 | 2309 | F: drivers/rtc/rtc-msc313.c |
| 2309 | 2310 | F: drivers/watchdog/msc313e_wdt.c |
| @@ -510,7 +510,8 @@ config SH_TIMER_MTU2 · 509 unmodified lines | ||
| 510 | 510 | This hardware comes with 16-bit timer registers. |
| 511 | 511 | |
| 512 | 512 | config RENESAS_OSTM |
| 513 | − bool "Renesas OSTM timer driver" if COMPILE_TEST | |
| 513 | + bool "Renesas OSTM timer driver" | |
| 514 | + depends on ARCH_RENESAS || COMPILE_TEST | |
| 514 | 515 | select CLKSRC_MMIO |
| 515 | 516 | select TIMER_OF |
| 516 | 517 | help |
| @@ -671,6 +672,15 @@ config MILBEAUT_TIMER · 154 unmodified lines | ||
| 671 | 672 | help |
| 672 | 673 | Enables the support for Milbeaut timer driver. |
| 673 | 674 | |
| 675 | +config MSC313E_TIMER | |
| 676 | + bool "MSC313E timer driver" if COMPILE_TEST | |
| 677 | + select TIMER_OF | |
| 678 | + select CLKSRC_MMIO | |
| 679 | + help | |
| 680 | + Enables support for the MStar MSC313E timer driver. | |
| 681 | + This provides access to multiple interrupt generating | |
| 682 | + programmable 32-bit free running incrementing counters. | |
| 683 | + | |
| 674 | 684 | config INGENIC_TIMER |
| 675 | 685 | bool "Clocksource/timer using the TCU in Ingenic JZ SoCs" |
| 676 | 686 | default MACH_INGENIC |
| @@ -88,3 +88,4 @@ obj-$(CONFIG_CSKY_MP_TIMER) += timer-mp-csky.o · 87 unmodified lines | ||
| 88 | 88 | obj-$(CONFIG_GX6605S_TIMER) += timer-gx6605s.o |
| 89 | 89 | obj-$(CONFIG_HYPERV_TIMER) += hyperv_timer.o |
| 90 | 90 | obj-$(CONFIG_MICROCHIP_PIT64B) += timer-microchip-pit64b.o |
| 91 | +obj-$(CONFIG_MSC313E_TIMER) += timer-msc313e.o | |
| @@ -467,7 +467,7 @@ static int exynos4_mct_starting_cpu(unsigned int cpu) · 466 unmodified lines | ||
| 467 | 467 | evt->tick_resume = set_state_shutdown; |
| 468 | 468 | evt->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT | |
| 469 | 469 | CLOCK_EVT_FEAT_PERCPU; |
| 470 | − evt->rating = MCT_CLKEVENTS_RATING, | |
| 470 | + evt->rating = MCT_CLKEVENTS_RATING; | |
| 471 | 471 | |
| 472 | 472 | exynos4_mct_write(TICK_BASE_CNT, mevt->base + MCT_L_TCNTB_OFFSET); |
| 473 | 473 | |
| @@ -504,11 +504,14 @@ static int exynos4_mct_dying_cpu(unsigned int cpu) · 30 unmodified lines | ||
| 504 | 504 | return 0; |
| 505 | 505 | } |
| 506 | 506 | |
| 507 | −static int __init exynos4_timer_resources(struct device_node *np, void __iomem *base) | |
| 507 | +static int __init exynos4_timer_resources(struct device_node *np) | |
| 508 | 508 | { |
| 509 | − int err, cpu; | |
| 510 | 509 | struct clk *mct_clk, *tick_clk; |
| 511 | 510 | |
| 511 | + reg_base = of_iomap(np, 0); | |
| 512 | + if (!reg_base) | |
| 513 | + panic("%s: unable to ioremap mct address space\n", __func__); | |
| 514 | + | |
| 512 | 515 | tick_clk = of_clk_get_by_name(np, "fin_pll"); |
| 513 | 516 | if (IS_ERR(tick_clk)) |
| 514 | 517 | panic("%s: unable to determine tick clock rate\n", __func__); |
| @@ -519,9 +522,27 @@ static int __init exynos4_timer_resources(struct device_node *np, void __iomem * · 4 unmodified lines | ||
| 519 | 522 | panic("%s: unable to retrieve mct clock instance\n", __func__); |
| 520 | 523 | clk_prepare_enable(mct_clk); |
| 521 | 524 | |
| 522 | − reg_base = base; | |
| 523 | − if (!reg_base) | |
| 524 | − panic("%s: unable to ioremap mct address space\n", __func__); | |
| 525 | + return 0; | |
| 526 | +} | |
| 527 | + | |
| 528 | +static int __init exynos4_timer_interrupts(struct device_node *np, | |
| 529 | + unsigned int int_type) | |
| 530 | +{ | |
| 531 | + int nr_irqs, i, err, cpu; | |
| 532 | + | |
| 533 | + mct_int_type = int_type; | |
| 534 | + | |
| 535 | + /* This driver uses only one global timer interrupt */ | |
| 536 | + mct_irqs[MCT_G0_IRQ] = irq_of_parse_and_map(np, MCT_G0_IRQ); | |
| 537 | + | |
| 538 | + /* | |
| 539 | + * Find out the number of local irqs specified. The local | |
| 540 | + * timer irqs are specified after the four global timer | |
| 541 | + * irqs are specified. | |
| 542 | + */ | |
| 543 | + nr_irqs = of_irq_count(np); | |
| 544 | + for (i = MCT_L0_IRQ; i < nr_irqs; i++) | |
| 545 | + mct_irqs[i] = irq_of_parse_and_map(np, i); | |
| 525 | 546 | |
| 526 | 547 | if (mct_int_type == MCT_INT_PPI) { |
| 527 | 548 | |
| @@ -581,24 +602,13 @@ out_irq: · 53 unmodified lines | ||
| 581 | 602 | |
| 582 | 603 | static int __init mct_init_dt(struct device_node *np, unsigned int int_type) |
| 583 | 604 | { |
| 584 | − u32 nr_irqs, i; | |
| 585 | 605 | int ret; |
| 586 | 606 | |
| 587 | − mct_int_type = int_type; | |
| 588 | − | |
| 589 | − /* This driver uses only one global timer interrupt */ | |
| 590 | − mct_irqs[MCT_G0_IRQ] = irq_of_parse_and_map(np, MCT_G0_IRQ); | |
| 591 | − | |
| 592 | − /* | |
| 593 | − * Find out the number of local irqs specified. The local | |
| 594 | − * timer irqs are specified after the four global timer | |
| 595 | − * irqs are specified. | |
| 596 | − */ | |
| 597 | − nr_irqs = of_irq_count(np); | |
| 598 | − for (i = MCT_L0_IRQ; i < nr_irqs; i++) | |
| 599 | − mct_irqs[i] = irq_of_parse_and_map(np, i); | |
| 607 | + ret = exynos4_timer_resources(np); | |
| 608 | + if (ret) | |
| 609 | + return ret; | |
| 600 | 610 | |
| 601 | − ret = exynos4_timer_resources(np, of_iomap(np, 0)); | |
| 611 | + ret = exynos4_timer_interrupts(np, int_type); | |
| 602 | 612 | if (ret) |
| 603 | 613 | return ret; |
| 604 | 614 | |
| @@ -9,6 +9,8 @@ · 8 unmodified lines | ||
| 9 | 9 | #include <linux/clk.h> |
| 10 | 10 | #include <linux/clockchips.h> |
| 11 | 11 | #include <linux/interrupt.h> |
| 12 | +#include <linux/platform_device.h> | |
| 13 | +#include <linux/reset.h> | |
| 12 | 14 | #include <linux/sched_clock.h> |
| 13 | 15 | #include <linux/slab.h> |
| 14 | 16 | |
| @@ -159,6 +161,7 @@ static int __init ostm_init_clkevt(struct timer_of *to) · 144 unmodified lines | ||
| 159 | 161 | |
| 160 | 162 | static int __init ostm_init(struct device_node *np) |
| 161 | 163 | { |
| 164 | + struct reset_control *rstc; | |
| 162 | 165 | struct timer_of *to; |
| 163 | 166 | int ret; |
| 164 | 167 | |
| @@ -166,6 +169,14 @@ static int __init ostm_init(struct device_node *np) · 1 unmodified line | ||
| 166 | 169 | if (!to) |
| 167 | 170 | return -ENOMEM; |
| 168 | 171 | |
| 172 | + rstc = of_reset_control_get_optional_exclusive(np, NULL); | |
| 173 | + if (IS_ERR(rstc)) { | |
| 174 | + ret = PTR_ERR(rstc); | |
| 175 | + goto err_free; | |
| 176 | + } | |
| 177 | + | |
| 178 | + reset_control_deassert(rstc); | |
| 179 | + | |
| 169 | 180 | to->flags = TIMER_OF_BASE | TIMER_OF_CLOCK; |
| 170 | 181 | if (system_clock) { |
| 171 | 182 | /* |
| @@ -178,7 +189,7 @@ static int __init ostm_init(struct device_node *np) · 6 unmodified lines | ||
| 178 | 189 | |
| 179 | 190 | ret = timer_of_init(np, to); |
| 180 | 191 | if (ret) |
| 181 | − goto err_free; | |
| 192 | + goto err_reset; | |
| 182 | 193 | |
| 183 | 194 | /* |
| 184 | 195 | * First probed device will be used as system clocksource. Any |
| @@ -203,9 +214,35 @@ static int __init ostm_init(struct device_node *np) · 18 unmodified lines | ||
| 203 | 214 | |
| 204 | 215 | err_cleanup: |
| 205 | 216 | timer_of_cleanup(to); |
| 217 | +err_reset: | |
| 218 | + reset_control_assert(rstc); | |
| 219 | + reset_control_put(rstc); | |
| 206 | 220 | err_free: |
| 207 | 221 | kfree(to); |
| 208 | 222 | return ret; |
| 209 | 223 | } |
| 210 | 224 | |
| 211 | 225 | TIMER_OF_DECLARE(ostm, "renesas,ostm", ostm_init); |
| 226 | + | |
| 227 | +#ifdef CONFIG_ARCH_R9A07G044 | |
| 228 | +static int __init ostm_probe(struct platform_device *pdev) | |
| 229 | +{ | |
| 230 | + struct device *dev = &pdev->dev; | |
| 231 | + | |
| 232 | + return ostm_init(dev->of_node); | |
| 233 | +} | |
| 234 | + | |
| 235 | +static const struct of_device_id ostm_of_table[] = { | |
| 236 | + { .compatible = "renesas,ostm", }, | |
| 237 | + { /* sentinel */ } | |
| 238 | +}; | |
| 239 | + | |
| 240 | +static struct platform_driver ostm_device_driver = { | |
| 241 | + .driver = { | |
| 242 | + .name = "renesas_ostm", | |
| 243 | + .of_match_table = of_match_ptr(ostm_of_table), | |
| 244 | + .suppress_bind_attrs = true, | |
| 245 | + }, | |
| 246 | +}; | |
| 247 | +builtin_platform_driver_probe(ostm_device_driver, ostm_probe); | |
| 248 | +#endif | |
| @@ -20,8 +20,8 @@ · 19 unmodified lines | ||
| 20 | 20 | |
| 21 | 21 | #define SYS_CTR_CLK_DIV 0x3 |
| 22 | 22 | |
| 23 | −static void __iomem *sys_ctr_base; | |
| 24 | −static u32 cmpcr; | |
| 23 | +static void __iomem *sys_ctr_base __ro_after_init; | |
| 24 | +static u32 cmpcr __ro_after_init; | |
| 25 | 25 | |
| 26 | 26 | static void sysctr_timer_enable(bool enable) |
| 27 | 27 | { |
| @@ -119,7 +119,7 @@ static struct timer_of to_sysctr = { · 91 unmodified lines | ||
| 119 | 119 | |
| 120 | 120 | static void __init sysctr_clockevent_init(void) |
| 121 | 121 | { |
| 122 | − to_sysctr.clkevt.cpumask = cpumask_of(0); | |
| 122 | + to_sysctr.clkevt.cpumask = cpu_possible_mask; | |
| 123 | 123 | |
| 124 | 124 | clockevents_config_and_register(&to_sysctr.clkevt, |
| 125 | 125 | timer_of_rate(&to_sysctr), |
| @@ -0,0 +1,253 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0 | |
| 2 | +/* | |
| 3 | + * MStar timer driver | |
| 4 | + * | |
| 5 | + * Copyright (C) 2021 Daniel Palmer | |
| 6 | + * Copyright (C) 2021 Romain Perier | |
| 7 | + * | |
| 8 | + */ | |
| 9 | + | |
| 10 | +#include <linux/clk.h> | |
| 11 | +#include <linux/clockchips.h> | |
| 12 | +#include <linux/interrupt.h> | |
| 13 | +#include <linux/irq.h> | |
| 14 | +#include <linux/irqreturn.h> | |
| 15 | +#include <linux/sched_clock.h> | |
| 16 | +#include <linux/of.h> | |
| 17 | +#include <linux/of_address.h> | |
| 18 | +#include <linux/of_irq.h> | |
| 19 | + | |
| 20 | +#ifdef CONFIG_ARM | |
| 21 | +#include <linux/delay.h> | |
| 22 | +#endif | |
| 23 | + | |
| 24 | +#include "timer-of.h" | |
| 25 | + | |
| 26 | +#define TIMER_NAME "msc313e_timer" | |
| 27 | + | |
| 28 | +#define MSC313E_REG_CTRL 0x00 | |
| 29 | +#define MSC313E_REG_CTRL_TIMER_EN BIT(0) | |
| 30 | +#define MSC313E_REG_CTRL_TIMER_TRIG BIT(1) | |
| 31 | +#define MSC313E_REG_CTRL_TIMER_INT_EN BIT(8) | |
| 32 | +#define MSC313E_REG_TIMER_MAX_LOW 0x08 | |
| 33 | +#define MSC313E_REG_TIMER_MAX_HIGH 0x0c | |
| 34 | +#define MSC313E_REG_COUNTER_LOW 0x10 | |
| 35 | +#define MSC313E_REG_COUNTER_HIGH 0x14 | |
| 36 | +#define MSC313E_REG_TIMER_DIVIDE 0x18 | |
| 37 | + | |
| 38 | +#define MSC313E_CLK_DIVIDER 9 | |
| 39 | +#define TIMER_SYNC_TICKS 3 | |
| 40 | + | |
| 41 | +#ifdef CONFIG_ARM | |
| 42 | +struct msc313e_delay { | |
| 43 | + void __iomem *base; | |
| 44 | + struct delay_timer delay; | |
| 45 | +}; | |
| 46 | +static struct msc313e_delay msc313e_delay; | |
| 47 | +#endif | |
| 48 | + | |
| 49 | +static void __iomem *msc313e_clksrc; | |
| 50 | + | |
| 51 | +static void msc313e_timer_stop(void __iomem *base) | |
| 52 | +{ | |
| 53 | + writew(0, base + MSC313E_REG_CTRL); | |
| 54 | +} | |
| 55 | + | |
| 56 | +static void msc313e_timer_start(void __iomem *base, bool periodic) | |
| 57 | +{ | |
| 58 | + u16 reg; | |
| 59 | + | |
| 60 | + reg = readw(base + MSC313E_REG_CTRL); | |
| 61 | + if (periodic) | |
| 62 | + reg |= MSC313E_REG_CTRL_TIMER_EN; | |
| 63 | + else | |
| 64 | + reg |= MSC313E_REG_CTRL_TIMER_TRIG; | |
| 65 | + writew(reg | MSC313E_REG_CTRL_TIMER_INT_EN, base + MSC313E_REG_CTRL); | |
| 66 | +} | |
| 67 | + | |
| 68 | +static void msc313e_timer_setup(void __iomem *base, unsigned long delay) | |
| 69 | +{ | |
| 70 | + unsigned long flags; | |
| 71 | + | |
| 72 | + local_irq_save(flags); | |
| 73 | + writew(delay >> 16, base + MSC313E_REG_TIMER_MAX_HIGH); | |
| 74 | + writew(delay & 0xffff, base + MSC313E_REG_TIMER_MAX_LOW); | |
| 75 | + local_irq_restore(flags); | |
| 76 | +} | |
| 77 | + | |
| 78 | +static unsigned long msc313e_timer_current_value(void __iomem *base) | |
| 79 | +{ | |
| 80 | + unsigned long flags; | |
| 81 | + u16 l, h; | |
| 82 | + | |
| 83 | + local_irq_save(flags); | |
| 84 | + l = readw(base + MSC313E_REG_COUNTER_LOW); | |
| 85 | + h = readw(base + MSC313E_REG_COUNTER_HIGH); | |
| 86 | + local_irq_restore(flags); | |
| 87 | + | |
| 88 | + return (((u32)h) << 16 | l); | |
| 89 | +} | |
| 90 | + | |
| 91 | +static int msc313e_timer_clkevt_shutdown(struct clock_event_device *evt) | |
| 92 | +{ | |
| 93 | + struct timer_of *timer = to_timer_of(evt); | |
| 94 | + | |
| 95 | + msc313e_timer_stop(timer_of_base(timer)); | |
| 96 | + | |
| 97 | + return 0; | |
| 98 | +} | |
| 99 | + | |
| 100 | +static int msc313e_timer_clkevt_set_oneshot(struct clock_event_device *evt) | |
| 101 | +{ | |
| 102 | + struct timer_of *timer = to_timer_of(evt); | |
| 103 | + | |
| 104 | + msc313e_timer_stop(timer_of_base(timer)); | |
| 105 | + msc313e_timer_start(timer_of_base(timer), false); | |
| 106 | + | |
| 107 | + return 0; | |
| 108 | +} | |
| 109 | + | |
| 110 | +static int msc313e_timer_clkevt_set_periodic(struct clock_event_device *evt) | |
| 111 | +{ | |
| 112 | + struct timer_of *timer = to_timer_of(evt); | |
| 113 | + | |
| 114 | + msc313e_timer_stop(timer_of_base(timer)); | |
| 115 | + msc313e_timer_setup(timer_of_base(timer), timer_of_period(timer)); | |
| 116 | + msc313e_timer_start(timer_of_base(timer), true); | |
| 117 | + | |
| 118 | + return 0; | |
| 119 | +} | |
| 120 | + | |
| 121 | +static int msc313e_timer_clkevt_next_event(unsigned long evt, struct clock_event_device *clkevt) | |
| 122 | +{ | |
| 123 | + struct timer_of *timer = to_timer_of(clkevt); | |
| 124 | + | |
| 125 | + msc313e_timer_stop(timer_of_base(timer)); | |
| 126 | + msc313e_timer_setup(timer_of_base(timer), evt); | |
| 127 | + msc313e_timer_start(timer_of_base(timer), false); | |
| 128 | + | |
| 129 | + return 0; | |
| 130 | +} | |
| 131 | + | |
| 132 | +static irqreturn_t msc313e_timer_clkevt_irq(int irq, void *dev_id) | |
| 133 | +{ | |
| 134 | + struct clock_event_device *evt = dev_id; | |
| 135 | + | |
| 136 | + evt->event_handler(evt); | |
| 137 | + | |
| 138 | + return IRQ_HANDLED; | |
| 139 | +} | |
| 140 | + | |
| 141 | +static u64 msc313e_timer_clksrc_read(struct clocksource *cs) | |
| 142 | +{ | |
| 143 | + return msc313e_timer_current_value(msc313e_clksrc) & cs->mask; | |
| 144 | +} | |
| 145 | + | |
| 146 | +#ifdef CONFIG_ARM | |
| 147 | +static unsigned long msc313e_read_delay_timer_read(void) | |
| 148 | +{ | |
| 149 | + return msc313e_timer_current_value(msc313e_delay.base); | |
| 150 | +} | |
| 151 | +#endif | |
| 152 | + | |
| 153 | +static u64 msc313e_timer_sched_clock_read(void) | |
| 154 | +{ | |
| 155 | + return msc313e_timer_current_value(msc313e_clksrc); | |
| 156 | +} | |
| 157 | + | |
| 158 | +static struct clock_event_device msc313e_clkevt = { | |
| 159 | + .name = TIMER_NAME, | |
| 160 | + .rating = 300, | |
| 161 | + .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, | |
| 162 | + .set_state_shutdown = msc313e_timer_clkevt_shutdown, | |
| 163 | + .set_state_periodic = msc313e_timer_clkevt_set_periodic, | |
| 164 | + .set_state_oneshot = msc313e_timer_clkevt_set_oneshot, | |
| 165 | + .tick_resume = msc313e_timer_clkevt_shutdown, | |
| 166 | + .set_next_event = msc313e_timer_clkevt_next_event, | |
| 167 | +}; | |
| 168 | + | |
| 169 | +static int __init msc313e_clkevt_init(struct device_node *np) | |
| 170 | +{ | |
| 171 | + int ret; | |
| 172 | + struct timer_of *to; | |
| 173 | + | |
| 174 | + to = kzalloc(sizeof(*to), GFP_KERNEL); | |
| 175 | + if (!to) | |
| 176 | + return -ENOMEM; | |
| 177 | + | |
| 178 | + to->flags = TIMER_OF_IRQ | TIMER_OF_CLOCK | TIMER_OF_BASE; | |
| 179 | + to->of_irq.handler = msc313e_timer_clkevt_irq; | |
| 180 | + ret = timer_of_init(np, to); | |
| 181 | + if (ret) | |
| 182 | + return ret; | |
| 183 | + | |
| 184 | + if (of_device_is_compatible(np, "sstar,ssd20xd-timer")) { | |
| 185 | + to->of_clk.rate = clk_get_rate(to->of_clk.clk) / MSC313E_CLK_DIVIDER; | |
| 186 | + to->of_clk.period = DIV_ROUND_UP(to->of_clk.rate, HZ); | |
| 187 | + writew(MSC313E_CLK_DIVIDER - 1, timer_of_base(to) + MSC313E_REG_TIMER_DIVIDE); | |
| 188 | + } | |
| 189 | + | |
| 190 | + msc313e_clkevt.cpumask = cpu_possible_mask; | |
| 191 | + msc313e_clkevt.irq = to->of_irq.irq; | |
| 192 | + to->clkevt = msc313e_clkevt; | |
| 193 | + | |
| 194 | + clockevents_config_and_register(&to->clkevt, timer_of_rate(to), | |
| 195 | + TIMER_SYNC_TICKS, 0xffffffff); | |
| 196 | + return 0; | |
| 197 | +} | |
| 198 | + | |
| 199 | +static int __init msc313e_clksrc_init(struct device_node *np) | |
| 200 | +{ | |
| 201 | + struct timer_of to = { 0 }; | |
| 202 | + int ret; | |
| 203 | + u16 reg; | |
| 204 | + | |
| 205 | + to.flags = TIMER_OF_BASE | TIMER_OF_CLOCK; | |
| 206 | + ret = timer_of_init(np, &to); | |
| 207 | + if (ret) | |
| 208 | + return ret; | |
| 209 | + | |
| 210 | + msc313e_clksrc = timer_of_base(&to); | |
| 211 | + reg = readw(msc313e_clksrc + MSC313E_REG_CTRL); | |
| 212 | + reg |= MSC313E_REG_CTRL_TIMER_EN; | |
| 213 | + writew(reg, msc313e_clksrc + MSC313E_REG_CTRL); | |
| 214 | + | |
| 215 | +#ifdef CONFIG_ARM | |
| 216 | + msc313e_delay.base = timer_of_base(&to); | |
| 217 | + msc313e_delay.delay.read_current_timer = msc313e_read_delay_timer_read; | |
| 218 | + msc313e_delay.delay.freq = timer_of_rate(&to); | |
| 219 | + | |
| 220 | + register_current_timer_delay(&msc313e_delay.delay); | |
| 221 | +#endif | |
| 222 | + | |
| 223 | + sched_clock_register(msc313e_timer_sched_clock_read, 32, timer_of_rate(&to)); | |
| 224 | + return clocksource_mmio_init(timer_of_base(&to), TIMER_NAME, timer_of_rate(&to), 300, 32, | |
| 225 | + msc313e_timer_clksrc_read); | |
| 226 | +} | |
| 227 | + | |
| 228 | +static int __init msc313e_timer_init(struct device_node *np) | |
| 229 | +{ | |
| 230 | + int ret = 0; | |
| 231 | + static int num_called; | |
| 232 | + | |
| 233 | + switch (num_called) { | |
| 234 | + case 0: | |
| 235 | + ret = msc313e_clksrc_init(np); | |
| 236 | + if (ret) | |
| 237 | + return ret; | |
| 238 | + break; | |
| 239 | + | |
| 240 | + default: | |
| 241 | + ret = msc313e_clkevt_init(np); | |
| 242 | + if (ret) | |
| 243 | + return ret; | |
| 244 | + break; | |
| 245 | + } | |
| 246 | + | |
| 247 | + num_called++; | |
| 248 | + | |
| 249 | + return 0; | |
| 250 | +} | |
| 251 | + | |
| 252 | +TIMER_OF_DECLARE(msc313, "mstar,msc313e-timer", msc313e_timer_init); | |
| 253 | +TIMER_OF_DECLARE(ssd20xd, "sstar,ssd20xd-timer", msc313e_timer_init); | |
| @@ -71,7 +71,8 @@ static u64 notrace · 70 unmodified lines | ||
| 71 | 71 | pistachio_clocksource_read_cycles(struct clocksource *cs) |
| 72 | 72 | { |
| 73 | 73 | struct pistachio_clocksource *pcs = to_pistachio_clocksource(cs); |
| 74 | − u32 counter, overflow; | |
| 74 | + __maybe_unused u32 overflow; | |
| 75 | + u32 counter; | |
| 75 | 76 | unsigned long flags; |
| 76 | 77 | |
| 77 | 78 | /* |
| @@ -454,6 +454,26 @@ static inline struct reset_control *of_reset_control_get_exclusive( · 453 unmodified lines | ||
| 454 | 454 | return __of_reset_control_get(node, id, 0, false, false, true); |
| 455 | 455 | } |
| 456 | 456 | |
| 457 | +/** | |
| 458 | + * of_reset_control_get_optional_exclusive - Lookup and obtain an optional exclusive | |
| 459 | + * reference to a reset controller. | |
| 460 | + * @node: device to be reset by the controller | |
| 461 | + * @id: reset line name | |
| 462 | + * | |
| 463 | + * Optional variant of of_reset_control_get_exclusive(). If the requested reset | |
| 464 | + * is not specified in the device tree, this function returns NULL instead of | |
| 465 | + * an error. | |
| 466 | + * | |
| 467 | + * Returns a struct reset_control or IS_ERR() condition containing errno. | |
| 468 | + * | |
| 469 | + * Use of id names is optional. | |
| 470 | + */ | |
| 471 | +static inline struct reset_control *of_reset_control_get_optional_exclusive( | |
| 472 | + struct device_node *node, const char *id) | |
| 473 | +{ | |
| 474 | + return __of_reset_control_get(node, id, 0, false, true, true); | |
| 475 | +} | |
| 476 | + | |
| 457 | 477 | /** |
| 458 | 478 | * of_reset_control_get_shared - Lookup and obtain a shared reference |
| 459 | 479 | * to a reset controller. |
| @@ -107,7 +107,7 @@ static u64 suspend_start; · 106 unmodified lines | ||
| 107 | 107 | * This delay could be due to SMIs, NMIs, or to VCPU preemptions. Used as |
| 108 | 108 | * a lower bound for cs->uncertainty_margin values when registering clocks. |
| 109 | 109 | */ |
| 110 | −#define WATCHDOG_MAX_SKEW (50 * NSEC_PER_USEC) | |
| 110 | +#define WATCHDOG_MAX_SKEW (100 * NSEC_PER_USEC) | |
| 111 | 111 | |
| 112 | 112 | #ifdef CONFIG_CLOCKSOURCE_WATCHDOG |
| 113 | 113 | static void clocksource_watchdog_work(struct work_struct *work); |
| @@ -199,23 +199,30 @@ void clocksource_mark_unstable(struct clocksource *cs) · 85 unmodified lines | ||
| 199 | 199 | spin_unlock_irqrestore(&watchdog_lock, flags); |
| 200 | 200 | } |
| 201 | 201 | |
| 202 | −ulong max_cswd_read_retries = 3; | |
| 202 | +ulong max_cswd_read_retries = 2; | |
| 203 | 203 | module_param(max_cswd_read_retries, ulong, 0644); |
| 204 | 204 | EXPORT_SYMBOL_GPL(max_cswd_read_retries); |
| 205 | 205 | static int verify_n_cpus = 8; |
| 206 | 206 | module_param(verify_n_cpus, int, 0644); |
| 207 | 207 | |
| 208 | −static bool cs_watchdog_read(struct clocksource *cs, u64 *csnow, u64 *wdnow) | |
| 208 | +enum wd_read_status { | |
| 209 | + WD_READ_SUCCESS, | |
| 210 | + WD_READ_UNSTABLE, | |
| 211 | + WD_READ_SKIP | |
| 212 | +}; | |
| 213 | + | |
| 214 | +static enum wd_read_status cs_watchdog_read(struct clocksource *cs, u64 *csnow, u64 *wdnow) | |
| 209 | 215 | { |
| 210 | 216 | unsigned int nretries; |
| 211 | − u64 wd_end, wd_delta; | |
| 212 | − int64_t wd_delay; | |
| 217 | + u64 wd_end, wd_end2, wd_delta; | |
| 218 | + int64_t wd_delay, wd_seq_delay; | |
| 213 | 219 | |
| 214 | 220 | for (nretries = 0; nretries <= max_cswd_read_retries; nretries++) { |
| 215 | 221 | local_irq_disable(); |
| 216 | 222 | *wdnow = watchdog->read(watchdog); |
| 217 | 223 | *csnow = cs->read(cs); |
| 218 | 224 | wd_end = watchdog->read(watchdog); |
| 225 | + wd_end2 = watchdog->read(watchdog); | |
| 219 | 226 | local_irq_enable(); |
| 220 | 227 | |
| 221 | 228 | wd_delta = clocksource_delta(wd_end, *wdnow, watchdog->mask); |
| @@ -226,13 +233,34 @@ static bool cs_watchdog_read(struct clocksource *cs, u64 *csnow, u64 *wdnow) · 4 unmodified lines | ||
| 226 | 233 | pr_warn("timekeeping watchdog on CPU%d: %s retried %d times before success\n", |
| 227 | 234 | smp_processor_id(), watchdog->name, nretries); |
| 228 | 235 | } |
| 229 | − return true; | |
| 236 | + return WD_READ_SUCCESS; | |
| 230 | 237 | } |
| 238 | + | |
| 239 | + /* | |
| 240 | + * Now compute delay in consecutive watchdog read to see if | |
| 241 | + * there is too much external interferences that cause | |
| 242 | + * significant delay in reading both clocksource and watchdog. | |
| 243 | + * | |
| 244 | + * If consecutive WD read-back delay > WATCHDOG_MAX_SKEW/2, | |
| 245 | + * report system busy, reinit the watchdog and skip the current | |
| 246 | + * watchdog test. | |
| 247 | + */ | |
| 248 | + wd_delta = clocksource_delta(wd_end2, wd_end, watchdog->mask); | |
| 249 | + wd_seq_delay = clocksource_cyc2ns(wd_delta, watchdog->mult, watchdog->shift); | |
| 250 | + if (wd_seq_delay > WATCHDOG_MAX_SKEW/2) | |
| 251 | + goto skip_test; | |
| 231 | 252 | } |
| 232 | 253 | |
| 233 | 254 | pr_warn("timekeeping watchdog on CPU%d: %s read-back delay of %lldns, attempt %d, marking unstable\n", |
| 234 | 255 | smp_processor_id(), watchdog->name, wd_delay, nretries); |
| 235 | − return false; | |
| 256 | + return WD_READ_UNSTABLE; | |
| 257 | + | |
| 258 | +skip_test: | |
| 259 | + pr_info("timekeeping watchdog on CPU%d: %s wd-wd read-back delay of %lldns\n", | |
| 260 | + smp_processor_id(), watchdog->name, wd_seq_delay); | |
| 261 | + pr_info("wd-%s-wd read-back delay of %lldns, clock-skew test skipped!\n", | |
| 262 | + cs->name, wd_delay); | |
| 263 | + return WD_READ_SKIP; | |
| 236 | 264 | } |
| 237 | 265 | |
| 238 | 266 | static u64 csnow_mid; |
| @@ -356,6 +384,7 @@ static void clocksource_watchdog(struct timer_list *unused) · 117 unmodified lines | ||
| 356 | 384 | int next_cpu, reset_pending; |
| 357 | 385 | int64_t wd_nsec, cs_nsec; |
| 358 | 386 | struct clocksource *cs; |
| 387 | + enum wd_read_status read_ret; | |
| 359 | 388 | u32 md; |
| 360 | 389 | |
| 361 | 390 | spin_lock(&watchdog_lock); |
| @@ -373,9 +402,12 @@ static void clocksource_watchdog(struct timer_list *unused) · 11 unmodified lines | ||
| 373 | 402 | continue; |
| 374 | 403 | } |
| 375 | 404 | |
| 376 | − if (!cs_watchdog_read(cs, &csnow, &wdnow)) { | |
| 377 | − /* Clock readout unreliable, so give it up. */ | |
| 378 | − __clocksource_unstable(cs); | |
| 405 | + read_ret = cs_watchdog_read(cs, &csnow, &wdnow); | |
| 406 | + | |
| 407 | + if (read_ret != WD_READ_SUCCESS) { | |
| 408 | + if (read_ret == WD_READ_UNSTABLE) | |
| 409 | + /* Clock readout unreliable, so give it up. */ | |
| 410 | + __clocksource_unstable(cs); | |
| 379 | 411 | continue; |
| 380 | 412 | } |
| 381 | 413 | |