Index: head/sys/arm/allwinner/allwinner_machdep.c =================================================================== --- head/sys/arm/allwinner/allwinner_machdep.c +++ head/sys/arm/allwinner/allwinner_machdep.c @@ -148,7 +148,7 @@ PLATFORMMETHOD_END, }; -FDT_PLATFORM_DEF(a10, "a10", 0, "allwinner,sun4i-a10"); +FDT_PLATFORM_DEF(a10, "a10", 0, "allwinner,sun4i-a10", 200); #endif #if defined(SOC_ALLWINNER_A20) @@ -163,7 +163,7 @@ #endif PLATFORMMETHOD_END, }; -FDT_PLATFORM_DEF(a20, "a20", 0, "allwinner,sun7i-a20"); +FDT_PLATFORM_DEF(a20, "a20", 0, "allwinner,sun7i-a20", 200); #endif #if defined(SOC_ALLWINNER_A31) @@ -178,7 +178,7 @@ #endif PLATFORMMETHOD_END, }; -FDT_PLATFORM_DEF(a31, "a31", 0, "allwinner,sun6i-a31"); +FDT_PLATFORM_DEF(a31, "a31", 0, "allwinner,sun6i-a31", 200); #endif #if defined(SOC_ALLWINNER_A31S) @@ -193,7 +193,7 @@ #endif PLATFORMMETHOD_END, }; -FDT_PLATFORM_DEF(a31s, "a31s", 0, "allwinner,sun6i-a31s"); +FDT_PLATFORM_DEF(a31s, "a31s", 0, "allwinner,sun6i-a31s", 200); #endif u_int Index: head/sys/arm/allwinner/timer.c =================================================================== --- head/sys/arm/allwinner/timer.c +++ head/sys/arm/allwinner/timer.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -100,11 +101,12 @@ static uint64_t timer_read_counter64(void); -static int a10_timer_initialized = 0; static int a10_timer_hardclock(void *); static int a10_timer_probe(device_t); static int a10_timer_attach(device_t); +static delay_func a10_timer_delay; + static struct timecounter a10_timer_timecounter = { .tc_name = "a10_timer timer0", .tc_get_timecount = a10_timer_get_timecount, @@ -209,8 +211,10 @@ sc->et.et_priv = sc; et_register(&sc->et); - if (device_get_unit(dev) == 0) + if (device_get_unit(dev) == 0) { + arm_set_delay(a10_timer_delay, sc); a10_timer_sc = sc; + } a10_timer_timecounter.tc_frequency = sc->timer0_freq; tc_init(&a10_timer_timecounter); @@ -224,8 +228,6 @@ a10_timer_timecounter.tc_frequency); } - a10_timer_initialized = 1; - return (0); } @@ -352,23 +354,15 @@ EARLY_DRIVER_MODULE(a10_timer, simplebus, a10_timer_driver, a10_timer_devclass, 0, 0, BUS_PASS_TIMER + BUS_PASS_ORDER_MIDDLE); -void -DELAY(int usec) +static void +a10_timer_delay(int usec, void *arg) { - uint32_t counter; + struct a10_timer_softc *sc = arg; uint64_t end, now; - if (!a10_timer_initialized) { - for (; usec > 0; usec--) - for (counter = 50; counter > 0; counter--) - cpufunc_nullop(); - return; - } - now = timer_read_counter64(); - end = now + (a10_timer_sc->timer0_freq / 1000000) * (usec + 1); + end = now + (sc->timer0_freq / 1000000) * (usec + 1); while (now < end) now = timer_read_counter64(); } - Index: head/sys/arm/arm/generic_timer.c =================================================================== --- head/sys/arm/arm/generic_timer.c +++ head/sys/arm/arm/generic_timer.c @@ -57,6 +57,10 @@ #include #include +#ifdef MULTIDELAY +#include /* For arm_set_delay */ +#endif + #ifdef FDT #include #include @@ -126,6 +130,7 @@ static uint32_t arm_tmr_fill_vdso_timehands(struct vdso_timehands *vdso_th, struct timecounter *tc); +static void arm_tmr_do_delay(int usec, void *); static int get_freq(void) @@ -419,6 +424,10 @@ sc->et.et_priv = sc; et_register(&sc->et); +#ifdef MULTIDELAY + arm_set_delay(arm_tmr_do_delay, sc); +#endif + return (0); } @@ -463,27 +472,13 @@ 0, 0, BUS_PASS_TIMER + BUS_PASS_ORDER_MIDDLE); #endif -void -DELAY(int usec) +static void +arm_tmr_do_delay(int usec, void *arg) { + struct arm_tmr_softc *sc = arg; int32_t counts, counts_per_usec; uint32_t first, last; - /* - * Check the timers are setup, if not just - * use a for loop for the meantime - */ - if (arm_tmr_sc == NULL) { - for (; usec > 0; usec--) - for (counts = 200; counts > 0; counts--) - /* - * Prevent the compiler from optimizing - * out the loop - */ - cpufunc_nullop(); - return; - } - /* Get the number of times to count */ counts_per_usec = ((arm_tmr_timecount.tc_frequency / 1000000) + 1); @@ -498,15 +493,38 @@ else counts = usec * counts_per_usec; - first = get_cntxct(arm_tmr_sc->physical); + first = get_cntxct(sc->physical); while (counts > 0) { - last = get_cntxct(arm_tmr_sc->physical); + last = get_cntxct(sc->physical); counts -= (int32_t)(last - first); first = last; } } +#ifndef MULTIDELAY +void +DELAY(int usec) +{ + int32_t counts; + + /* + * Check the timers are setup, if not just + * use a for loop for the meantime + */ + if (arm_tmr_sc == NULL) { + for (; usec > 0; usec--) + for (counts = 200; counts > 0; counts--) + /* + * Prevent the compiler from optimizing + * out the loop + */ + cpufunc_nullop(); + } else + arm_tmr_do_delay(usec, arm_tmr_sc); +} +#endif + static uint32_t arm_tmr_fill_vdso_timehands(struct vdso_timehands *vdso_th, struct timecounter *tc) Index: head/sys/arm/arm/machdep.c =================================================================== --- head/sys/arm/arm/machdep.c +++ head/sys/arm/arm/machdep.c @@ -243,6 +243,10 @@ uint32_t memsize[LBABI_MAX_BANKS]; uint32_t membanks; #endif +#ifdef MULTIDELAY +static delay_func *delay_impl; +static void *delay_arg; +#endif static uint32_t board_revision; /* hex representation of uint64_t */ @@ -550,6 +554,24 @@ } __weak_reference(arm_generic_initclocks, cpu_initclocks); +#ifdef MULTIDELAY +void +arm_set_delay(delay_func *impl, void *arg) +{ + + KASSERT(impl != NULL, ("No DELAY implementation")); + delay_impl = impl; + delay_arg = arg; +} + +void +DELAY(int usec) +{ + + delay_impl(usec, delay_arg); +} +#endif + int fill_regs(struct thread *td, struct reg *regs) { Index: head/sys/arm/arm/platform.c =================================================================== --- head/sys/arm/arm/platform.c +++ head/sys/arm/arm/platform.c @@ -53,6 +53,7 @@ #include #include #include +#include #include #include #include @@ -75,6 +76,10 @@ */ SET_DECLARE(platform_set, platform_def_t); +#ifdef MULTIDELAY +static delay_func platform_delay; +#endif + void platform_probe_and_attach(void) { @@ -100,8 +105,9 @@ * Take care of compiling the selected class, and * then statically initialise the MMU object */ - kobj_class_compile_static(platp, &plat_kernel_kops); - kobj_init_static((kobj_t)plat_obj, platp); + kobj_class_compile_static((kobj_class_t)platp, + &plat_kernel_kops); + kobj_init_static((kobj_t)plat_obj, (kobj_class_t)platp); plat_obj->cls = platp; @@ -141,10 +147,16 @@ * correct one, and then attach. */ - kobj_class_compile_static(plat_def_impl, &plat_kernel_kops); - kobj_init_static((kobj_t)plat_obj, plat_def_impl); - - strlcpy(plat_name,plat_def_impl->name,sizeof(plat_name)); + kobj_class_compile_static((kobj_class_t)plat_def_impl, + &plat_kernel_kops); + kobj_init_static((kobj_t)plat_obj, (kobj_class_t)plat_def_impl); + + strlcpy(plat_name, plat_def_impl->name, sizeof(plat_name)); + +#ifdef MULTIDELAY + /* Set a default delay function */ + arm_set_delay(platform_delay, NULL); +#endif PLATFORM_ATTACH(plat_obj); } @@ -177,6 +189,22 @@ PLATFORM_LATE_INIT(plat_obj); } +#ifdef MULTIDELAY +static void +platform_delay(int usec, void *arg __unused) +{ + int counts; + + for (; usec > 0; usec--) + for (counts = plat_obj->cls->delay_count; counts > 0; counts--) + /* + * Prevent the compiler from optimizing + * out the loop + */ + cpufunc_nullop(); +} +#endif + #if defined(SMP) && defined(PLATFORM_SMP) void platform_mp_setmaxid(void) Index: head/sys/arm/broadcom/bcm2835/bcm2835_machdep.c =================================================================== --- head/sys/arm/broadcom/bcm2835/bcm2835_machdep.c +++ head/sys/arm/broadcom/bcm2835/bcm2835_machdep.c @@ -142,7 +142,7 @@ PLATFORMMETHOD_END, }; -FDT_PLATFORM_DEF(bcm2835, "bcm2835", 0, "raspberrypi,model-b"); +FDT_PLATFORM_DEF(bcm2835, "bcm2835", 0, "raspberrypi,model-b", 0); #endif #ifdef SOC_BCM2836 @@ -153,5 +153,5 @@ PLATFORMMETHOD_END, }; -FDT_PLATFORM_DEF(bcm2836, "bcm2836", 0, "brcm,bcm2709"); +FDT_PLATFORM_DEF(bcm2836, "bcm2836", 0, "brcm,bcm2709", 0); #endif Index: head/sys/arm/conf/A10 =================================================================== --- head/sys/arm/conf/A10 +++ head/sys/arm/conf/A10 @@ -30,6 +30,7 @@ options HZ=100 options SCHED_4BSD # 4BSD scheduler options PLATFORM +options MULTIDELAY # Debugging for use in -current makeoptions DEBUG=-g # Build kernel with gdb(1) debug symbols Index: head/sys/arm/conf/ALLWINNER =================================================================== --- head/sys/arm/conf/ALLWINNER +++ head/sys/arm/conf/ALLWINNER @@ -34,6 +34,7 @@ options SMP # Enable multiple cores options PLATFORM options PLATFORM_SMP +options MULTIDELAY # Debugging for use in -current makeoptions DEBUG=-g # Build kernel with gdb(1) debug symbols Index: head/sys/arm/conf/VIRT =================================================================== --- head/sys/arm/conf/VIRT +++ head/sys/arm/conf/VIRT @@ -28,6 +28,7 @@ options PLATFORM options PLATFORM_SMP options SMP # Enable multiple cores +options MULTIDELAY # Debugging for use in -current makeoptions DEBUG=-g # Build kernel with gdb(1) debug symbols Index: head/sys/arm/freescale/imx/imx51_machdep.c =================================================================== --- head/sys/arm/freescale/imx/imx51_machdep.c +++ head/sys/arm/freescale/imx/imx51_machdep.c @@ -101,4 +101,4 @@ PLATFORMMETHOD_END, }; -FDT_PLATFORM_DEF(imx51, "i.MX51", 0, "fsl,imx51"); +FDT_PLATFORM_DEF(imx51, "i.MX51", 0, "fsl,imx51", 0); Index: head/sys/arm/freescale/imx/imx53_machdep.c =================================================================== --- head/sys/arm/freescale/imx/imx53_machdep.c +++ head/sys/arm/freescale/imx/imx53_machdep.c @@ -101,5 +101,5 @@ PLATFORMMETHOD_END, }; -FDT_PLATFORM_DEF(imx53, "i.MX53", 0, "fsl,imx53"); +FDT_PLATFORM_DEF(imx53, "i.MX53", 0, "fsl,imx53", 0); Index: head/sys/arm/freescale/imx/imx6_machdep.c =================================================================== --- head/sys/arm/freescale/imx/imx6_machdep.c +++ head/sys/arm/freescale/imx/imx6_machdep.c @@ -354,6 +354,6 @@ PLATFORMMETHOD_END, }; -FDT_PLATFORM_DEF2(imx6, imx6s, "i.MX6 Solo", 0, "fsl,imx6s"); -FDT_PLATFORM_DEF2(imx6, imx6d, "i.MX6 Dual", 0, "fsl,imx6d"); -FDT_PLATFORM_DEF2(imx6, imx6q, "i.MX6 Quad", 0, "fsl,imx6q"); +FDT_PLATFORM_DEF2(imx6, imx6s, "i.MX6 Solo", 0, "fsl,imx6s", 0); +FDT_PLATFORM_DEF2(imx6, imx6d, "i.MX6 Dual", 0, "fsl,imx6d", 0); +FDT_PLATFORM_DEF2(imx6, imx6q, "i.MX6 Quad", 0, "fsl,imx6q", 0); Index: head/sys/arm/include/machdep.h =================================================================== --- head/sys/arm/include/machdep.h +++ head/sys/arm/include/machdep.h @@ -49,4 +49,9 @@ int arm_predict_branch(void *, u_int, register_t, register_t *, u_int (*)(void*, int), u_int (*)(void*, vm_offset_t, u_int*)); +#ifdef MULTIDELAY +typedef void delay_func(int, void *); +void arm_set_delay(delay_func *, void *); +#endif + #endif /* !_MACHINE_MACHDEP_H_ */ Index: head/sys/arm/include/platformvar.h =================================================================== --- head/sys/arm/include/platformvar.h +++ head/sys/arm/include/platformvar.h @@ -53,6 +53,13 @@ #include #include +struct platform_class { + KOBJ_CLASS_FIELDS; + + /* How many times to loop to delay approximately 1us */ + int delay_count; +}; + struct platform_kobj { /* * A platform instance is a kernel object @@ -60,11 +67,15 @@ KOBJ_FIELDS; /* Platform class, for access to class specific data */ - struct kobj_class *cls; + struct platform_class *cls; +}; + +struct platform_data { + int delay_count; }; typedef struct platform_kobj *platform_t; -typedef struct kobj_class platform_def_t; +typedef struct platform_class platform_def_t; #define platform_method_t kobj_method_t #define PLATFORMMETHOD KOBJMETHOD @@ -83,7 +94,20 @@ extern platform_method_t fdt_platform_methods[]; -#define FDT_PLATFORM_DEF2(NAME, VAR_NAME, NAME_STR, size, compatible) \ +#ifdef MULTIDELAY +#define FDT_PLATFORM_CTASSERT(delay) CTASSERT(delay > 0) +#else +#define FDT_PLATFORM_CTASSERT(delay) CTASSERT(delay == 0) +#endif + +#define PLATFORM_DATA(NAME, delay) \ +static struct platform_data NAME ## _platc = { \ + .delay_count = delay; \ +}; + +#define FDT_PLATFORM_DEF2(NAME, VAR_NAME, NAME_STR, size, compatible, \ + delay) \ +FDT_PLATFORM_CTASSERT(delay); \ static fdt_platform_def_t VAR_NAME ## _fdt_platform = { \ .name = NAME_STR, \ .methods = fdt_platform_methods, \ @@ -96,12 +120,15 @@ NAME ## _methods, \ size, \ VAR_NAME ## _baseclasses, \ + delay, \ }; \ DATA_SET(platform_set, VAR_NAME ## _platform) -#define FDT_PLATFORM_DEF(NAME, NAME_STR, size, compatible) \ - FDT_PLATFORM_DEF2(NAME, NAME, NAME_STR, size, compatible) +#define FDT_PLATFORM_DEF(NAME, NAME_STR, size, compatible, delay) \ + FDT_PLATFORM_DEF2(NAME, NAME, NAME_STR, size, compatible, delay) #endif +bool arm_tmr_timed_wait(platform_t, int); + #endif /* _MACHINE_PLATFORMVAR_H_ */ Index: head/sys/arm/nvidia/tegra124/tegra124_machdep.c =================================================================== --- head/sys/arm/nvidia/tegra124/tegra124_machdep.c +++ head/sys/arm/nvidia/tegra124/tegra124_machdep.c @@ -170,4 +170,4 @@ PLATFORMMETHOD_END, }; -FDT_PLATFORM_DEF(tegra124, "Nvidia Jetson-TK1", 0, "nvidia,jetson-tk1"); +FDT_PLATFORM_DEF(tegra124, "Nvidia Jetson-TK1", 0, "nvidia,jetson-tk1", 0); Index: head/sys/arm/qemu/virt_machdep.c =================================================================== --- head/sys/arm/qemu/virt_machdep.c +++ head/sys/arm/qemu/virt_machdep.c @@ -96,4 +96,4 @@ PLATFORMMETHOD_END, }; -FDT_PLATFORM_DEF(virt, "virt", 0, "linux,dummy-virt"); +FDT_PLATFORM_DEF(virt, "virt", 0, "linux,dummy-virt", 1); Index: head/sys/arm/ti/ti_machdep.c =================================================================== --- head/sys/arm/ti/ti_machdep.c +++ head/sys/arm/ti/ti_machdep.c @@ -128,7 +128,7 @@ PLATFORMMETHOD_END, }; -FDT_PLATFORM_DEF(omap4, "omap4", 0, "ti,omap4430"); +FDT_PLATFORM_DEF(omap4, "omap4", 0, "ti,omap4430", 0); #endif #if defined(SOC_TI_AM335X) @@ -139,5 +139,5 @@ PLATFORMMETHOD_END, }; -FDT_PLATFORM_DEF(am335x, "am335x", 0, "ti,am335x"); +FDT_PLATFORM_DEF(am335x, "am335x", 0, "ti,am335x", 0); #endif Index: head/sys/conf/options.arm =================================================================== --- head/sys/conf/options.arm +++ head/sys/conf/options.arm @@ -32,6 +32,7 @@ KERNVIRTADDR opt_global.h LINUX_BOOT_ABI opt_global.h LOADERRAMADDR opt_global.h +MULTIDELAY opt_global.h PHYSADDR opt_global.h PLATFORM opt_global.h PLATFORM_SMP opt_global.h