Add a MULTIDELAY option to allow the ARM kernel to have multiple DELAY

implementations. Early in the boot the kernel will use an approximate,
however after the timer has been probed it will switch to a more accurate
implementation.

Reviewed by:	manu
Sponsored by:	ABT Systems Ltd
Differential Revision:	https://reviews.freebsd.org/D5762
This commit is contained in:
Andrew Turner 2016-04-30 17:27:33 +00:00
parent 58fef175e4
commit cca48a59de
18 changed files with 158 additions and 60 deletions

View File

@ -148,7 +148,7 @@ static platform_method_t a10_methods[] = {
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 @@ static platform_method_t a20_methods[] = {
#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 @@ static platform_method_t a31_methods[] = {
#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 @@ static platform_method_t a31s_methods[] = {
#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

View File

@ -40,6 +40,7 @@ __FBSDID("$FreeBSD$");
#include <machine/bus.h>
#include <machine/cpu.h>
#include <machine/intr.h>
#include <machine/machdep.h>
#include <dev/fdt/fdt_common.h>
#include <dev/ofw/openfirm.h>
@ -100,11 +101,12 @@ static int a10_timer_timer_stop(struct eventtimer *);
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 @@ a10_timer_attach(device_t dev)
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_attach(device_t dev)
a10_timer_timecounter.tc_frequency);
}
a10_timer_initialized = 1;
return (0);
}
@ -352,23 +354,15 @@ static devclass_t a10_timer_devclass;
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();
}

View File

@ -57,6 +57,10 @@ __FBSDID("$FreeBSD$");
#include <machine/intr.h>
#include <machine/md_var.h>
#ifdef MULTIDELAY
#include <machine/machdep.h> /* For arm_set_delay */
#endif
#ifdef FDT
#include <dev/fdt/fdt_common.h>
#include <dev/ofw/openfirm.h>
@ -126,6 +130,7 @@ static struct timecounter arm_tmr_timecount = {
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 @@ arm_tmr_attach(device_t dev)
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 @@ EARLY_DRIVER_MODULE(timer, acpi, arm_tmr_acpi_driver, arm_tmr_acpi_devclass,
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 @@ DELAY(int usec)
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)

View File

@ -243,6 +243,10 @@ uint32_t memstart[LBABI_MAX_BANKS];
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 @@ arm_generic_initclocks(void)
}
__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)
{

View File

@ -53,6 +53,7 @@ __FBSDID("$FreeBSD$");
#include <machine/bus_dma.h>
#include <machine/cpu.h>
#include <machine/intr.h>
#include <machine/machdep.h>
#include <machine/md_var.h>
#include <machine/platform.h>
#include <machine/platformvar.h>
@ -75,6 +76,10 @@ SYSCTL_STRING(_hw, OID_AUTO, platform, CTLFLAG_RDTUN | CTLFLAG_NOFETCH, plat_nam
*/
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 @@ platform_probe_and_attach(void)
* 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 @@ platform_probe_and_attach(void)
* 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);
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));
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(void)
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)

View File

@ -142,7 +142,7 @@ static platform_method_t bcm2835_methods[] = {
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 @@ static platform_method_t bcm2836_methods[] = {
PLATFORMMETHOD_END,
};
FDT_PLATFORM_DEF(bcm2836, "bcm2836", 0, "brcm,bcm2709");
FDT_PLATFORM_DEF(bcm2836, "bcm2836", 0, "brcm,bcm2709", 0);
#endif

View File

@ -30,6 +30,7 @@ options SOC_ALLWINNER_A10
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

View File

@ -34,6 +34,7 @@ options SCHED_ULE # ULE scheduler
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

View File

@ -28,6 +28,7 @@ options SCHED_ULE # 4BSD scheduler
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

View File

@ -101,4 +101,4 @@ static platform_method_t imx51_methods[] = {
PLATFORMMETHOD_END,
};
FDT_PLATFORM_DEF(imx51, "i.MX51", 0, "fsl,imx51");
FDT_PLATFORM_DEF(imx51, "i.MX51", 0, "fsl,imx51", 0);

View File

@ -101,5 +101,5 @@ static platform_method_t imx53_methods[] = {
PLATFORMMETHOD_END,
};
FDT_PLATFORM_DEF(imx53, "i.MX53", 0, "fsl,imx53");
FDT_PLATFORM_DEF(imx53, "i.MX53", 0, "fsl,imx53", 0);

View File

@ -354,6 +354,6 @@ static platform_method_t imx6_methods[] = {
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);

View File

@ -49,4 +49,9 @@ void board_set_revision(uint32_t);
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_ */

View File

@ -53,6 +53,13 @@
#include <sys/kobj.h>
#include <sys/linker_set.h>
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 @@ struct platform_kobj {
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 @@ typedef struct fdt_platform_class fdt_platform_def_t;
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 @@ static platform_def_t VAR_NAME ## _platform = { \
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_ */

View File

@ -170,4 +170,4 @@ static platform_method_t tegra124_methods[] = {
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);

View File

@ -96,4 +96,4 @@ static platform_method_t virt_methods[] = {
PLATFORMMETHOD_END,
};
FDT_PLATFORM_DEF(virt, "virt", 0, "linux,dummy-virt");
FDT_PLATFORM_DEF(virt, "virt", 0, "linux,dummy-virt", 1);

View File

@ -128,7 +128,7 @@ static platform_method_t omap4_methods[] = {
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 @@ static platform_method_t am335x_methods[] = {
PLATFORMMETHOD_END,
};
FDT_PLATFORM_DEF(am335x, "am335x", 0, "ti,am335x");
FDT_PLATFORM_DEF(am335x, "am335x", 0, "ti,am335x", 0);
#endif

View File

@ -32,6 +32,7 @@ KERNBASE opt_global.h
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