All of lore.kernel.org
 help / color / mirror / Atom feed
From: Daniel Lezcano <daniel.lezcano@linaro.org>
To: Tony Lindgren <tony@atomide.com>, Thomas Gleixner <tglx@linutronix.de>
Cc: Keerthy <j-keerthy@ti.com>,
	linux-kernel@vger.kernel.org, linux-omap@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org,
	Tero Kristo <kristo@kernel.org>
Subject: Re: [PATCH 2/2] clocksource/drivers/timer-ti-dm: Handle dra7 timer wrap errata i940
Date: Mon, 22 Mar 2021 11:15:06 +0100	[thread overview]
Message-ID: <1edba5bd-5408-c545-85ea-689b4171cb5b@linaro.org> (raw)
In-Reply-To: <20210304073737.15810-3-tony@atomide.com>

On 04/03/2021 08:37, Tony Lindgren wrote:
> There is a timer wrap issue on dra7 for the ARM architected timer.
> In a typical clock configuration the timer fails to wrap after 388 days.
> 
> To work around the issue, we need to use timer-ti-dm percpu timers instead.
> 
> Let's configure dmtimer3 and 4 as percpu timers by default, and warn about
> the issue if the dtb is not configured properly.
> 
> Let's do this as a single patch so it can be backported to v5.8 and later
> kernels easily. 

Cc: <stable@vger.kernel.org> # v5.8+

??

> Note that this patch depends on earlier timer-ti-dm
> systimer posted mode fixes, and a preparatory clockevent patch
> "clocksource/drivers/timer-ti-dm: Prepare to handle dra7 timer wrap issue".
> 
> For more information, please see the errata for "AM572x Sitara Processors
> Silicon Revisions 1.1, 2.0":
> 
> https://www.ti.com/lit/er/sprz429m/sprz429m.pdf
> 
> The concept is based on earlier reference patches done by Tero Kristo and
> Keerthy.
> 
> Cc: Keerthy <j-keerthy@ti.com>
> Cc: Tero Kristo <kristo@kernel.org>
> Signed-off-by: Tony Lindgren <tony@atomide.com>
> ---
>  arch/arm/boot/dts/dra7-l4.dtsi             |  4 +-
>  arch/arm/boot/dts/dra7.dtsi                | 20 ++++++
>  drivers/clocksource/timer-ti-dm-systimer.c | 76 ++++++++++++++++++++++
>  include/linux/cpuhotplug.h                 |  1 +
>  4 files changed, 99 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/arm/boot/dts/dra7-l4.dtsi b/arch/arm/boot/dts/dra7-l4.dtsi
> --- a/arch/arm/boot/dts/dra7-l4.dtsi
> +++ b/arch/arm/boot/dts/dra7-l4.dtsi
> @@ -1168,7 +1168,7 @@ timer2: timer@0 {
>  			};
>  		};
>  
> -		target-module@34000 {			/* 0x48034000, ap 7 46.0 */
> +		timer3_target: target-module@34000 {	/* 0x48034000, ap 7 46.0 */
>  			compatible = "ti,sysc-omap4-timer", "ti,sysc";
>  			reg = <0x34000 0x4>,
>  			      <0x34010 0x4>;
> @@ -1195,7 +1195,7 @@ timer3: timer@0 {
>  			};
>  		};
>  
> -		target-module@36000 {			/* 0x48036000, ap 9 4e.0 */
> +		timer4_target: target-module@36000 {	/* 0x48036000, ap 9 4e.0 */
>  			compatible = "ti,sysc-omap4-timer", "ti,sysc";
>  			reg = <0x36000 0x4>,
>  			      <0x36010 0x4>;
> diff --git a/arch/arm/boot/dts/dra7.dtsi b/arch/arm/boot/dts/dra7.dtsi
> --- a/arch/arm/boot/dts/dra7.dtsi
> +++ b/arch/arm/boot/dts/dra7.dtsi
> @@ -46,6 +46,7 @@ aliases {
>  
>  	timer {
>  		compatible = "arm,armv7-timer";
> +		status = "disabled";	/* See ARM architected timer wrap erratum i940 */
>  		interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
>  			     <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
>  			     <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
> @@ -1241,3 +1242,22 @@ timer@0 {
>  		assigned-clock-parents = <&sys_32k_ck>;
>  	};
>  };
> +
> +/* Local timers, see ARM architected timer wrap erratum i940 */
> +&timer3_target {
> +	ti,no-reset-on-init;
> +	ti,no-idle;
> +	timer@0 {
> +		assigned-clocks = <&l4per_clkctrl DRA7_L4PER_TIMER3_CLKCTRL 24>;
> +		assigned-clock-parents = <&timer_sys_clk_div>;
> +	};
> +};
> +
> +&timer4_target {
> +	ti,no-reset-on-init;
> +	ti,no-idle;
> +	timer@0 {
> +		assigned-clocks = <&l4per_clkctrl DRA7_L4PER_TIMER4_CLKCTRL 24>;
> +		assigned-clock-parents = <&timer_sys_clk_div>;
> +	};
> +};
> diff --git a/drivers/clocksource/timer-ti-dm-systimer.c b/drivers/clocksource/timer-ti-dm-systimer.c
> --- a/drivers/clocksource/timer-ti-dm-systimer.c
> +++ b/drivers/clocksource/timer-ti-dm-systimer.c
> @@ -2,6 +2,7 @@
>  #include <linux/clk.h>
>  #include <linux/clocksource.h>
>  #include <linux/clockchips.h>
> +#include <linux/cpuhotplug.h>
>  #include <linux/interrupt.h>
>  #include <linux/io.h>
>  #include <linux/iopoll.h>
> @@ -634,6 +635,78 @@ static int __init dmtimer_clockevent_init(struct device_node *np)
>  	return error;
>  }
>  
> +/* Dmtimer as percpu timer. See dra7 ARM architected timer wrap erratum i940 */
> +static DEFINE_PER_CPU(struct dmtimer_clockevent, dmtimer_percpu_timer);
> +
> +static int __init dmtimer_percpu_timer_init(struct device_node *np, int cpu)
> +{
> +	struct dmtimer_clockevent *clkevt;
> +	int error;
> +
> +	if (!cpu_possible(cpu))
> +		return -EINVAL;
> +
> +	if (!of_property_read_bool(np->parent, "ti,no-reset-on-init") ||
> +	    !of_property_read_bool(np->parent, "ti,no-idle"))
> +		pr_warn("Incomplete dtb for percpu dmtimer %pOF\n", np->parent);
> +
> +	clkevt = per_cpu_ptr(&dmtimer_percpu_timer, cpu);
> +
> +	error = dmtimer_clkevt_init_common(clkevt, np, CLOCK_EVT_FEAT_ONESHOT,
> +					   cpumask_of(cpu), "percpu-dmtimer",
> +					   500);
> +	if (error)
> +		return error;
> +
> +	return 0;
> +}
> +
> +/* See TRM for timer internal resynch latency */
> +static int omap_dmtimer_starting_cpu(unsigned int cpu)
> +{
> +	struct dmtimer_clockevent *clkevt = per_cpu_ptr(&dmtimer_percpu_timer, cpu);
> +	struct clock_event_device *dev = &clkevt->dev;
> +	struct dmtimer_systimer *t = &clkevt->t;
> +
> +	clockevents_config_and_register(dev, t->rate, 3, ULONG_MAX);
> +	irq_force_affinity(dev->irq, cpumask_of(cpu));
> +
> +	return 0;
> +}
> +
> +static int __init dmtimer_percpu_timer_startup(void)
> +{
> +	struct dmtimer_clockevent *clkevt = per_cpu_ptr(&dmtimer_percpu_timer, 0);
> +	struct dmtimer_systimer *t = &clkevt->t;
> +
> +	if (t->sysc) {
> +		cpuhp_setup_state(CPUHP_AP_TI_GP_TIMER_STARTING,
> +				  "clockevents/omap/gptimer:starting",
> +				  omap_dmtimer_starting_cpu, NULL);
> +	}
> +
> +	return 0;
> +}
> +subsys_initcall(dmtimer_percpu_timer_startup);
> +
> +static int __init dmtimer_percpu_quirk_init(struct device_node *np, u32 pa)
> +{
> +	struct device_node *arm_timer;
> +
> +	arm_timer = of_find_compatible_node(NULL, NULL, "arm,armv7-timer");
> +	if (of_device_is_available(arm_timer)) {
> +		pr_warn_once("ARM architected timer wrap issue i940 detected\n");
> +		return 0;
> +	}
> +
> +	if (pa == 0x48034000)		/* dra7 dmtimer3 */
> +		return dmtimer_percpu_timer_init(np, 0);
> +	else if (pa == 0x48036000)	/* dra7 dmtimer4 */
> +		return dmtimer_percpu_timer_init(np, 1);
> +
> +	return 0;
> +}
> +
>  /* Clocksource */
>  static struct dmtimer_clocksource *
>  to_dmtimer_clocksource(struct clocksource *cs)
> @@ -767,6 +840,9 @@ static int __init dmtimer_systimer_init(struct device_node *np)
>  	if (clockevent == pa)
>  		return dmtimer_clockevent_init(np);
>  
> +	if (of_machine_is_compatible("ti,dra7"))
> +		return dmtimer_percpu_quirk_init(np, pa);
> +
>  	return 0;
>  }
>  
> diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h
> --- a/include/linux/cpuhotplug.h
> +++ b/include/linux/cpuhotplug.h
> @@ -135,6 +135,7 @@ enum cpuhp_state {
>  	CPUHP_AP_RISCV_TIMER_STARTING,
>  	CPUHP_AP_CLINT_TIMER_STARTING,
>  	CPUHP_AP_CSKY_TIMER_STARTING,
> +	CPUHP_AP_TI_GP_TIMER_STARTING,
>  	CPUHP_AP_HYPERV_TIMER_STARTING,
>  	CPUHP_AP_KVM_STARTING,
>  	CPUHP_AP_KVM_ARM_VGIC_INIT_STARTING,
> 


-- 
<http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog

WARNING: multiple messages have this Message-ID (diff)
From: Daniel Lezcano <daniel.lezcano@linaro.org>
To: Tony Lindgren <tony@atomide.com>, Thomas Gleixner <tglx@linutronix.de>
Cc: Keerthy <j-keerthy@ti.com>,
	linux-kernel@vger.kernel.org, linux-omap@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org,
	Tero Kristo <kristo@kernel.org>
Subject: Re: [PATCH 2/2] clocksource/drivers/timer-ti-dm: Handle dra7 timer wrap errata i940
Date: Mon, 22 Mar 2021 11:15:06 +0100	[thread overview]
Message-ID: <1edba5bd-5408-c545-85ea-689b4171cb5b@linaro.org> (raw)
In-Reply-To: <20210304073737.15810-3-tony@atomide.com>

On 04/03/2021 08:37, Tony Lindgren wrote:
> There is a timer wrap issue on dra7 for the ARM architected timer.
> In a typical clock configuration the timer fails to wrap after 388 days.
> 
> To work around the issue, we need to use timer-ti-dm percpu timers instead.
> 
> Let's configure dmtimer3 and 4 as percpu timers by default, and warn about
> the issue if the dtb is not configured properly.
> 
> Let's do this as a single patch so it can be backported to v5.8 and later
> kernels easily. 

Cc: <stable@vger.kernel.org> # v5.8+

??

> Note that this patch depends on earlier timer-ti-dm
> systimer posted mode fixes, and a preparatory clockevent patch
> "clocksource/drivers/timer-ti-dm: Prepare to handle dra7 timer wrap issue".
> 
> For more information, please see the errata for "AM572x Sitara Processors
> Silicon Revisions 1.1, 2.0":
> 
> https://www.ti.com/lit/er/sprz429m/sprz429m.pdf
> 
> The concept is based on earlier reference patches done by Tero Kristo and
> Keerthy.
> 
> Cc: Keerthy <j-keerthy@ti.com>
> Cc: Tero Kristo <kristo@kernel.org>
> Signed-off-by: Tony Lindgren <tony@atomide.com>
> ---
>  arch/arm/boot/dts/dra7-l4.dtsi             |  4 +-
>  arch/arm/boot/dts/dra7.dtsi                | 20 ++++++
>  drivers/clocksource/timer-ti-dm-systimer.c | 76 ++++++++++++++++++++++
>  include/linux/cpuhotplug.h                 |  1 +
>  4 files changed, 99 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/arm/boot/dts/dra7-l4.dtsi b/arch/arm/boot/dts/dra7-l4.dtsi
> --- a/arch/arm/boot/dts/dra7-l4.dtsi
> +++ b/arch/arm/boot/dts/dra7-l4.dtsi
> @@ -1168,7 +1168,7 @@ timer2: timer@0 {
>  			};
>  		};
>  
> -		target-module@34000 {			/* 0x48034000, ap 7 46.0 */
> +		timer3_target: target-module@34000 {	/* 0x48034000, ap 7 46.0 */
>  			compatible = "ti,sysc-omap4-timer", "ti,sysc";
>  			reg = <0x34000 0x4>,
>  			      <0x34010 0x4>;
> @@ -1195,7 +1195,7 @@ timer3: timer@0 {
>  			};
>  		};
>  
> -		target-module@36000 {			/* 0x48036000, ap 9 4e.0 */
> +		timer4_target: target-module@36000 {	/* 0x48036000, ap 9 4e.0 */
>  			compatible = "ti,sysc-omap4-timer", "ti,sysc";
>  			reg = <0x36000 0x4>,
>  			      <0x36010 0x4>;
> diff --git a/arch/arm/boot/dts/dra7.dtsi b/arch/arm/boot/dts/dra7.dtsi
> --- a/arch/arm/boot/dts/dra7.dtsi
> +++ b/arch/arm/boot/dts/dra7.dtsi
> @@ -46,6 +46,7 @@ aliases {
>  
>  	timer {
>  		compatible = "arm,armv7-timer";
> +		status = "disabled";	/* See ARM architected timer wrap erratum i940 */
>  		interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
>  			     <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
>  			     <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
> @@ -1241,3 +1242,22 @@ timer@0 {
>  		assigned-clock-parents = <&sys_32k_ck>;
>  	};
>  };
> +
> +/* Local timers, see ARM architected timer wrap erratum i940 */
> +&timer3_target {
> +	ti,no-reset-on-init;
> +	ti,no-idle;
> +	timer@0 {
> +		assigned-clocks = <&l4per_clkctrl DRA7_L4PER_TIMER3_CLKCTRL 24>;
> +		assigned-clock-parents = <&timer_sys_clk_div>;
> +	};
> +};
> +
> +&timer4_target {
> +	ti,no-reset-on-init;
> +	ti,no-idle;
> +	timer@0 {
> +		assigned-clocks = <&l4per_clkctrl DRA7_L4PER_TIMER4_CLKCTRL 24>;
> +		assigned-clock-parents = <&timer_sys_clk_div>;
> +	};
> +};
> diff --git a/drivers/clocksource/timer-ti-dm-systimer.c b/drivers/clocksource/timer-ti-dm-systimer.c
> --- a/drivers/clocksource/timer-ti-dm-systimer.c
> +++ b/drivers/clocksource/timer-ti-dm-systimer.c
> @@ -2,6 +2,7 @@
>  #include <linux/clk.h>
>  #include <linux/clocksource.h>
>  #include <linux/clockchips.h>
> +#include <linux/cpuhotplug.h>
>  #include <linux/interrupt.h>
>  #include <linux/io.h>
>  #include <linux/iopoll.h>
> @@ -634,6 +635,78 @@ static int __init dmtimer_clockevent_init(struct device_node *np)
>  	return error;
>  }
>  
> +/* Dmtimer as percpu timer. See dra7 ARM architected timer wrap erratum i940 */
> +static DEFINE_PER_CPU(struct dmtimer_clockevent, dmtimer_percpu_timer);
> +
> +static int __init dmtimer_percpu_timer_init(struct device_node *np, int cpu)
> +{
> +	struct dmtimer_clockevent *clkevt;
> +	int error;
> +
> +	if (!cpu_possible(cpu))
> +		return -EINVAL;
> +
> +	if (!of_property_read_bool(np->parent, "ti,no-reset-on-init") ||
> +	    !of_property_read_bool(np->parent, "ti,no-idle"))
> +		pr_warn("Incomplete dtb for percpu dmtimer %pOF\n", np->parent);
> +
> +	clkevt = per_cpu_ptr(&dmtimer_percpu_timer, cpu);
> +
> +	error = dmtimer_clkevt_init_common(clkevt, np, CLOCK_EVT_FEAT_ONESHOT,
> +					   cpumask_of(cpu), "percpu-dmtimer",
> +					   500);
> +	if (error)
> +		return error;
> +
> +	return 0;
> +}
> +
> +/* See TRM for timer internal resynch latency */
> +static int omap_dmtimer_starting_cpu(unsigned int cpu)
> +{
> +	struct dmtimer_clockevent *clkevt = per_cpu_ptr(&dmtimer_percpu_timer, cpu);
> +	struct clock_event_device *dev = &clkevt->dev;
> +	struct dmtimer_systimer *t = &clkevt->t;
> +
> +	clockevents_config_and_register(dev, t->rate, 3, ULONG_MAX);
> +	irq_force_affinity(dev->irq, cpumask_of(cpu));
> +
> +	return 0;
> +}
> +
> +static int __init dmtimer_percpu_timer_startup(void)
> +{
> +	struct dmtimer_clockevent *clkevt = per_cpu_ptr(&dmtimer_percpu_timer, 0);
> +	struct dmtimer_systimer *t = &clkevt->t;
> +
> +	if (t->sysc) {
> +		cpuhp_setup_state(CPUHP_AP_TI_GP_TIMER_STARTING,
> +				  "clockevents/omap/gptimer:starting",
> +				  omap_dmtimer_starting_cpu, NULL);
> +	}
> +
> +	return 0;
> +}
> +subsys_initcall(dmtimer_percpu_timer_startup);
> +
> +static int __init dmtimer_percpu_quirk_init(struct device_node *np, u32 pa)
> +{
> +	struct device_node *arm_timer;
> +
> +	arm_timer = of_find_compatible_node(NULL, NULL, "arm,armv7-timer");
> +	if (of_device_is_available(arm_timer)) {
> +		pr_warn_once("ARM architected timer wrap issue i940 detected\n");
> +		return 0;
> +	}
> +
> +	if (pa == 0x48034000)		/* dra7 dmtimer3 */
> +		return dmtimer_percpu_timer_init(np, 0);
> +	else if (pa == 0x48036000)	/* dra7 dmtimer4 */
> +		return dmtimer_percpu_timer_init(np, 1);
> +
> +	return 0;
> +}
> +
>  /* Clocksource */
>  static struct dmtimer_clocksource *
>  to_dmtimer_clocksource(struct clocksource *cs)
> @@ -767,6 +840,9 @@ static int __init dmtimer_systimer_init(struct device_node *np)
>  	if (clockevent == pa)
>  		return dmtimer_clockevent_init(np);
>  
> +	if (of_machine_is_compatible("ti,dra7"))
> +		return dmtimer_percpu_quirk_init(np, pa);
> +
>  	return 0;
>  }
>  
> diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h
> --- a/include/linux/cpuhotplug.h
> +++ b/include/linux/cpuhotplug.h
> @@ -135,6 +135,7 @@ enum cpuhp_state {
>  	CPUHP_AP_RISCV_TIMER_STARTING,
>  	CPUHP_AP_CLINT_TIMER_STARTING,
>  	CPUHP_AP_CSKY_TIMER_STARTING,
> +	CPUHP_AP_TI_GP_TIMER_STARTING,
>  	CPUHP_AP_HYPERV_TIMER_STARTING,
>  	CPUHP_AP_KVM_STARTING,
>  	CPUHP_AP_KVM_ARM_VGIC_INIT_STARTING,
> 


-- 
<http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

  reply	other threads:[~2021-03-22 10:16 UTC|newest]

Thread overview: 26+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-03-04  7:37 [PATCH 0/2] Fixes for for dra7 timer wrap errata i940 Tony Lindgren
2021-03-04  7:37 ` Tony Lindgren
2021-03-04  7:37 ` [PATCH 1/2] clocksource/drivers/timer-ti-dm: Prepare to handle dra7 timer wrap issue Tony Lindgren
2021-03-04  7:37   ` Tony Lindgren
2021-03-22 15:55   ` Daniel Lezcano
2021-03-22 15:55     ` Daniel Lezcano
2021-03-22 16:33     ` Tony Lindgren
2021-03-22 16:33       ` Tony Lindgren
2021-03-22 18:23       ` Daniel Lezcano
2021-03-22 18:23         ` Daniel Lezcano
2021-03-23  6:31         ` Tony Lindgren
2021-03-23  6:31           ` Tony Lindgren
2021-03-04  7:37 ` [PATCH 2/2] clocksource/drivers/timer-ti-dm: Handle dra7 timer wrap errata i940 Tony Lindgren
2021-03-04  7:37   ` Tony Lindgren
2021-03-22 10:15   ` Daniel Lezcano [this message]
2021-03-22 10:15     ` Daniel Lezcano
2021-03-22 10:17     ` Tony Lindgren
2021-03-22 10:17       ` Tony Lindgren
2021-03-23  7:43 [PATCHv2 0/2] Fixes for for " Tony Lindgren
2021-03-23  7:43 ` [PATCH 2/2] clocksource/drivers/timer-ti-dm: Handle " Tony Lindgren
2021-03-23  7:43   ` Tony Lindgren
2022-01-29 21:05   ` Drew Fustini
2022-01-29 21:05     ` Drew Fustini
2022-01-31 10:16     ` Tony Lindgren
2022-01-31 10:16       ` Tony Lindgren
2022-02-02 20:54       ` Drew Fustini
2022-02-02 20:54         ` Drew Fustini

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1edba5bd-5408-c545-85ea-689b4171cb5b@linaro.org \
    --to=daniel.lezcano@linaro.org \
    --cc=j-keerthy@ti.com \
    --cc=kristo@kernel.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-omap@vger.kernel.org \
    --cc=tglx@linutronix.de \
    --cc=tony@atomide.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.