Commit 9db66fce authored by Martin Peres's avatar Martin Peres Committed by Ben Skeggs

drm/nouveau/pwr: fix the timers implementation with concurent processes

The problem with the current implementation is that adding a timer improperly
checked which process would time up first by not taking into account how much
time elapsed since their timer got scheduled. Rework the re-scheduling
decision t fix this.

The catch with this fix is that we are limited to scheduling timers of up to
2^31 ticks to avoid any potential overflow. Since we are unlikely to need to
wait for more than a second, this won't be a problem :)

Another possible fix would be to decrement the timeouts of all processes but
it would duplicate a lot of code and dealing with edge cases wasn't pretty
last time I checked.
Signed-off-by: default avatarMartin Peres <martin.peres@free.fr>
Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent 2a5e5fa7
...@@ -245,9 +245,12 @@ intr: ...@@ -245,9 +245,12 @@ intr:
// request the current process be sent a message after a timeout expires // request the current process be sent a message after a timeout expires
// //
// $r15 - current // $r15 - current
// $r14 - ticks // $r14 - ticks (make sure it is < 2^31 to avoid any possible overflow)
// $r0 - zero // $r0 - zero
timer: timer:
push $r9
push $r8
// interrupts off to prevent racing with timer isr // interrupts off to prevent racing with timer isr
bclr $flags ie0 bclr $flags ie0
...@@ -255,13 +258,22 @@ timer: ...@@ -255,13 +258,22 @@ timer:
ld b32 $r8 D[$r15 + #proc_time] ld b32 $r8 D[$r15 + #proc_time]
cmp b32 $r8 0 cmp b32 $r8 0
bra g #timer_done bra g #timer_done
st b32 D[$r15 + #proc_time] $r14
// halt watchdog timer temporarily and check for a pending // halt watchdog timer temporarily
// interrupt. if there's one already pending, we can just clear b32 $r8
// bail since the timer isr will queue the next soonest
// right after it's done
nv_iowr(NV_PPWR_WATCHDOG_ENABLE, $r8) nv_iowr(NV_PPWR_WATCHDOG_ENABLE, $r8)
// find out how much time elapsed since the last update
// of the watchdog and add this time to the wanted ticks
nv_iord($r8, NV_PPWR_WATCHDOG_TIME)
ld b32 $r9 D[$r0 + #time_prev]
sub b32 $r9 $r8
add b32 $r14 $r9
st b32 D[$r15 + #proc_time] $r14
// check for a pending interrupt. if there's one already
// pending, we can just bail since the timer isr will
// queue the next soonest right after it's done
nv_iord($r8, NV_PPWR_INTR) nv_iord($r8, NV_PPWR_INTR)
and $r8 NV_PPWR_INTR_WATCHDOG and $r8 NV_PPWR_INTR_WATCHDOG
bra nz #timer_enable bra nz #timer_enable
...@@ -272,10 +284,10 @@ timer: ...@@ -272,10 +284,10 @@ timer:
cmp b32 $r14 $r0 cmp b32 $r14 $r0
bra e #timer_reset bra e #timer_reset
cmp b32 $r14 $r8 cmp b32 $r14 $r8
bra l #timer_done bra g #timer_enable
timer_reset: timer_reset:
nv_iowr(NV_PPWR_WATCHDOG_TIME, $r14) nv_iowr(NV_PPWR_WATCHDOG_TIME, $r14)
st b32 D[$r0 + #time_prev] $r14 st b32 D[$r0 + #time_prev] $r14
// re-enable the watchdog timer // re-enable the watchdog timer
timer_enable: timer_enable:
...@@ -285,6 +297,9 @@ timer: ...@@ -285,6 +297,9 @@ timer:
// interrupts back on // interrupts back on
timer_done: timer_done:
bset $flags ie0 bset $flags ie0
pop $r8
pop $r9
ret ret
// send message to another process // send message to another process
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment