On Fri, Jun 28, 2019 at 4:36 PM Waldemar Kozaczuk <jwkozac...@gmail.com>
wrote:

> This patch enhances the hpet clock with 32-bit main
> counter to handle wrap-arounds. It does it by maintaining
> separate upper 32-bit counter and incrementing it
> when wrap around is detected.
>
> Signed-off-by: Waldemar Kozaczuk <jwkozac...@gmail.com>
> ---
>  drivers/hpet.cc | 26 +++++++++++++++++++++-----
>  1 file changed, 21 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/hpet.cc b/drivers/hpet.cc
> index ba9ed3bc..a6696405 100644
> --- a/drivers/hpet.cc
> +++ b/drivers/hpet.cc
> @@ -34,21 +34,37 @@ protected:
>
>  #define HPET_COUNTER    0x0f0
>
> -//FIXME: Enhance this class to handle wrap-around
>  class hpet_32bit_clock : public hpetclock {
>  public:
>      hpet_32bit_clock(mmioaddr_t hpet_mmio_address) :
> hpetclock(hpet_mmio_address) {
> -        debug_early_u64("WARNING: hpet with 32-bit counter will wrap
> around in seconds: ",
> -            (_period * (1UL << 32)) / 1000000000UL);
> +        _upper_32bit_counter.store(0);
>      }
>  protected:
>      virtual s64 time() override __attribute__((no_instrument_function)) {
> -        return _wall + mmio_getl(_addr + HPET_COUNTER) * _period;
> +        return _wall + fetch_counter() * _period;
>      }
>
>      virtual s64 uptime() override __attribute__((no_instrument_function))
> {
> -        return mmio_getl(_addr + HPET_COUNTER) * _period;
> +        return fetch_counter() * _period;
> +    }
> +private:
> +    s64 fetch_counter() {
> +        auto last_valid_counter = _last_read_counter.load();
>
+        auto upper_counter = _upper_32bit_counter.load();
>

Again, can use relaxed memory ordering in this load, or we're trying to
order some memory access with something else? Maybe "counter"?

+
> +        s64 counter = mmio_getl(_addr + HPET_COUNTER);
> +        if (counter < last_valid_counter) { // Wrap-around
>
+           // In case more than one thread fetches the value and encounter
> +           // the wrap-around, make sure the upper counter is only
> incremented
> +           // once
> +           _upper_32bit_counter.compare_exchange_strong(upper_counter,
> upper_counter + 1);
>

This doesn't look 100% safe to me. Look at the following time sequence on
two CPUs:

   CPU 1                             CPU2
   last_counter=2^32-1               last_counter=2^32-1
   upper_counter = 17
   counter = 137 (<last_counter)
   upper_counter = 18 (with CAS)
                                     upper_counter = 18
                                     counter=785 (<last_counter)
                                     upper_counter = 19 (with CAS)
                                     last_counter = 137
   last_counter = 18

I think that the end result of this extremely-unlikely timing is that
upper_counter was incremented twice (from 17 to 19) despite just one
wrap-around period passing.

I wonder if it wouldn't be much simpler to have the upper_counter per-cpu
instead of trying to make it global. We would need
to assume that each of the CPUs calls the clock many times per wrap-around
period to be able to catch this wrap-around, but
I think that with an 8 minute period (IIRC... am I right? can you please
verify?), this will always be the case.

By the way, I believe we also get an interrupt on every wrap-around, so can
use that to count the wrap-around instead of
trying to guess when it happens. Can you please take a look at other HPET
drivers (e.g., in Linux) to see how they handle
32-bit hpet and perhaps get ideas?


> +        }
> +
> +        _last_read_counter.store(counter);
> +        return _upper_32bit_counter.load() * (1UL << 32) + counter;
>

Nitpick: Instead of *(1<<32) you can (s64).. << 32, instead of hoping the
optimizer will replace the multiplication by a shift.

     }
> +
> +    std::atomic<s64> _upper_32bit_counter;
>  };
>
>  class hpet_64bit_clock : public hpetclock {
> --
> 2.20.1
>
> --
> You received this message because you are subscribed to the Google Groups
> "OSv Development" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to osv-dev+unsubscr...@googlegroups.com.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/osv-dev/20190628133630.7563-1-jwkozaczuk%40gmail.com
> .
> For more options, visit https://groups.google.com/d/optout.
>

-- 
You received this message because you are subscribed to the Google Groups "OSv 
Development" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to osv-dev+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/osv-dev/CANEVyjucG1bUznM0xtZWgS15WVXu_Lhzots-9BXxoOu6orxRLQ%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to