mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-21 11:13:30 +00:00
Fix event timer on Raspberry Pi
- Disable interrupt when updating compare value in order to make this operation atomical - Increase minimum period for event timer. Systimer on BCM2835 is compare timer, so if minimum period is too small it might be less then fraction of time between "read current value" and "set compare timer" operations. It means that when timer is armed actual counter value is more then compare value and it will take whole cycle (~32sec for 1MHz timer) to fire interrupt. Submitted by: Daisuke Aoyama <aoyama at peach.ne.jp>
This commit is contained in:
parent
5625bb0c36
commit
0c093a7055
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=244758
@ -55,6 +55,7 @@ __FBSDID("$FreeBSD$");
|
|||||||
|
|
||||||
#define DEFAULT_TIMER 3
|
#define DEFAULT_TIMER 3
|
||||||
#define DEFAULT_FREQUENCY 1000000
|
#define DEFAULT_FREQUENCY 1000000
|
||||||
|
#define MIN_PERIOD 100LLU
|
||||||
|
|
||||||
#define SYSTIMER_CS 0x00
|
#define SYSTIMER_CS 0x00
|
||||||
#define SYSTIMER_CLO 0x04
|
#define SYSTIMER_CLO 0x04
|
||||||
@ -123,17 +124,24 @@ bcm_systimer_start(struct eventtimer *et, struct bintime *first,
|
|||||||
struct systimer *st = et->et_priv;
|
struct systimer *st = et->et_priv;
|
||||||
uint32_t clo;
|
uint32_t clo;
|
||||||
uint32_t count;
|
uint32_t count;
|
||||||
|
register_t s;
|
||||||
|
|
||||||
if (first != NULL) {
|
if (first != NULL) {
|
||||||
st->enabled = 1;
|
|
||||||
|
|
||||||
count = (st->et.et_frequency * (first->frac >> 32)) >> 32;
|
count = (st->et.et_frequency * (first->frac >> 32)) >> 32;
|
||||||
if (first->sec != 0)
|
if (first->sec != 0)
|
||||||
count += st->et.et_frequency * first->sec;
|
count += st->et.et_frequency * first->sec;
|
||||||
|
|
||||||
|
s = intr_disable();
|
||||||
clo = bcm_systimer_tc_read_4(SYSTIMER_CLO);
|
clo = bcm_systimer_tc_read_4(SYSTIMER_CLO);
|
||||||
clo += count;
|
clo += count;
|
||||||
|
/*
|
||||||
|
* Clear pending interrupts
|
||||||
|
*/
|
||||||
|
bcm_systimer_tc_write_4(SYSTIMER_CS, (1 << st->index));
|
||||||
bcm_systimer_tc_write_4(SYSTIMER_C0 + st->index*4, clo);
|
bcm_systimer_tc_write_4(SYSTIMER_C0 + st->index*4, clo);
|
||||||
|
st->enabled = 1;
|
||||||
|
intr_restore(s);
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
@ -154,7 +162,13 @@ static int
|
|||||||
bcm_systimer_intr(void *arg)
|
bcm_systimer_intr(void *arg)
|
||||||
{
|
{
|
||||||
struct systimer *st = (struct systimer *)arg;
|
struct systimer *st = (struct systimer *)arg;
|
||||||
|
uint32_t cs;
|
||||||
|
|
||||||
|
cs = bcm_systimer_tc_read_4(SYSTIMER_CS);
|
||||||
|
if ((cs & (1 << st->index)) == 0)
|
||||||
|
return (FILTER_STRAY);
|
||||||
|
|
||||||
|
/* ACK interrupt */
|
||||||
bcm_systimer_tc_write_4(SYSTIMER_CS, (1 << st->index));
|
bcm_systimer_tc_write_4(SYSTIMER_CS, (1 << st->index));
|
||||||
if (st->enabled) {
|
if (st->enabled) {
|
||||||
if (st->et.et_active) {
|
if (st->et.et_active) {
|
||||||
@ -226,7 +240,7 @@ bcm_systimer_attach(device_t dev)
|
|||||||
sc->st[DEFAULT_TIMER].et.et_frequency = sc->sysclk_freq;
|
sc->st[DEFAULT_TIMER].et.et_frequency = sc->sysclk_freq;
|
||||||
sc->st[DEFAULT_TIMER].et.et_min_period.sec = 0;
|
sc->st[DEFAULT_TIMER].et.et_min_period.sec = 0;
|
||||||
sc->st[DEFAULT_TIMER].et.et_min_period.frac =
|
sc->st[DEFAULT_TIMER].et.et_min_period.frac =
|
||||||
((0x00000002LLU << 32) / sc->st[DEFAULT_TIMER].et.et_frequency) << 32;
|
((MIN_PERIOD << 32) / sc->st[DEFAULT_TIMER].et.et_frequency) << 32;
|
||||||
sc->st[DEFAULT_TIMER].et.et_max_period.sec = 0xfffffff0U / sc->st[DEFAULT_TIMER].et.et_frequency;
|
sc->st[DEFAULT_TIMER].et.et_max_period.sec = 0xfffffff0U / sc->st[DEFAULT_TIMER].et.et_frequency;
|
||||||
sc->st[DEFAULT_TIMER].et.et_max_period.frac =
|
sc->st[DEFAULT_TIMER].et.et_max_period.frac =
|
||||||
((0xfffffffeLLU << 32) / sc->st[DEFAULT_TIMER].et.et_frequency) << 32;
|
((0xfffffffeLLU << 32) / sc->st[DEFAULT_TIMER].et.et_frequency) << 32;
|
||||||
|
Loading…
Reference in New Issue
Block a user