Skip to content

Commit eeb15aa

Browse files
kwd-doodlingcfriedt
authored andcommitted
timer: hpet: enable 64 bit mode for better usages
Get longer maximum timeout Make HPET counter usable as timestamp Signed-off-by: Dong Wang <[email protected]>
1 parent f6f521b commit eeb15aa

File tree

1 file changed

+50
-37
lines changed

1 file changed

+50
-37
lines changed

drivers/timer/hpet.c

Lines changed: 50 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2018 Intel Corporation
2+
* Copyright (c) 2018-2021 Intel Corporation
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
@@ -95,13 +95,15 @@ DEVICE_MMIO_TOPLEVEL_STATIC(hpet_regs, DT_DRV_INST(0));
9595
#define INTR_STATUS_REG HPET_REG_ADDR(0x20)
9696

9797
/* Main Counter Register */
98-
#define MAIN_COUNTER_REG HPET_REG_ADDR(0xf0)
98+
#define MAIN_COUNTER_LOW_REG HPET_REG_ADDR(0xf0)
99+
#define MAIN_COUNTER_HIGH_REG HPET_REG_ADDR(0xf4)
99100

100101
/* Timer 0 Configuration and Capabilities register */
101102
#define TIMER0_CONF_REG HPET_REG_ADDR(0x100)
102103

103104
/* Timer 0 Comparator Register */
104-
#define TIMER0_COMPARATOR_REG HPET_REG_ADDR(0x108)
105+
#define TIMER0_COMPARATOR_LOW_REG HPET_REG_ADDR(0x108)
106+
#define TIMER0_COMPARATOR_HIGH_REG HPET_REG_ADDR(0x10c)
105107

106108
/**
107109
* @brief Setup memory mappings needed to access HPET registers.
@@ -119,9 +121,17 @@ static inline void hpet_mmio_init(void)
119121
*
120122
* @return Value of Main Counter
121123
*/
122-
static inline uint32_t hpet_counter_get(void)
124+
static inline uint64_t hpet_counter_get(void)
123125
{
124-
return sys_read32(MAIN_COUNTER_REG);
126+
uint32_t high;
127+
uint32_t low;
128+
129+
do {
130+
high = sys_read32(MAIN_COUNTER_HIGH_REG);
131+
low = sys_read32(MAIN_COUNTER_LOW_REG);
132+
} while (high != sys_read32(MAIN_COUNTER_HIGH_REG));
133+
134+
return ((uint64_t)high << 32) | low;
125135
}
126136

127137
/**
@@ -208,9 +218,14 @@ static inline void hpet_timer_conf_set(uint32_t val)
208218
*
209219
* @param val Value to be written to the register
210220
*/
211-
static inline void hpet_timer_comparator_set(uint32_t val)
221+
static inline void hpet_timer_comparator_set(uint64_t val)
212222
{
213-
sys_write32(val, TIMER0_COMPARATOR_REG);
223+
#if CONFIG_X86_64
224+
sys_write64(val, TIMER0_COMPARATOR_LOW_REG);
225+
#else
226+
sys_write32((uint32_t)val, TIMER0_COMPARATOR_LOW_REG);
227+
sys_write32((uint32_t)(val >> 32), TIMER0_COMPARATOR_HIGH_REG);
228+
#endif
214229
}
215230
#endif /* HPET_USE_CUSTOM_REG_ACCESS_FUNCS */
216231

@@ -224,30 +239,26 @@ static inline void hpet_timer_comparator_set(uint32_t val)
224239
#define HPET_CMP_MIN_DELAY (1000)
225240
#endif
226241

227-
#define MAX_TICKS 0x7FFFFFFFUL
228-
229242
static __pinned_bss struct k_spinlock lock;
230-
static __pinned_bss unsigned int last_count;
243+
static __pinned_bss uint64_t last_count;
231244

232245
#ifdef CONFIG_TIMER_READS_ITS_FREQUENCY_AT_RUNTIME
233246
static __pinned_bss unsigned int cyc_per_tick;
234-
static __pinned_bss unsigned int max_ticks;
235247
#else
236248
#define cyc_per_tick \
237249
(CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC / CONFIG_SYS_CLOCK_TICKS_PER_SEC)
238-
239-
#define max_ticks \
240-
((MAX_TICKS - cyc_per_tick) / cyc_per_tick)
241250
#endif /* CONFIG_TIMER_READS_ITS_FREQUENCY_AT_RUNTIME */
242251

252+
#define HPET_MAX_TICKS ((int32_t)0x7fffffff)
253+
243254
__isr
244255
static void hpet_isr(const void *arg)
245256
{
246257
ARG_UNUSED(arg);
247258

248259
k_spinlock_key_t key = k_spin_lock(&lock);
249260

250-
uint32_t now = hpet_counter_get();
261+
uint64_t now = hpet_counter_get();
251262

252263
#if ((DT_INST_IRQ(0, sense) & IRQ_TYPE_LEVEL) == IRQ_TYPE_LEVEL)
253264
/*
@@ -265,27 +276,27 @@ static void hpet_isr(const void *arg)
265276
* on the other CPU, despite the HPET being
266277
* theoretically a global device.
267278
*/
268-
int32_t diff = (int32_t)(now - last_count);
279+
int64_t diff = (int64_t)(now - last_count);
269280

270281
if (last_count && diff < 0) {
271282
now = last_count;
272283
}
273284
}
274-
uint32_t dticks = (now - last_count) / cyc_per_tick;
285+
uint32_t dticks = (uint32_t)((now - last_count) / cyc_per_tick);
275286

276-
last_count += dticks * cyc_per_tick;
287+
last_count += (uint64_t)dticks * cyc_per_tick;
277288

278289
if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) {
279-
uint32_t next = last_count + cyc_per_tick;
290+
uint64_t next = last_count + cyc_per_tick;
280291

281-
if ((int32_t)(next - now) < HPET_CMP_MIN_DELAY) {
282-
next += cyc_per_tick;
292+
if ((int64_t)(next - now) < HPET_CMP_MIN_DELAY) {
293+
next = now + HPET_CMP_MIN_DELAY;
283294
}
284295
hpet_timer_comparator_set(next);
285296
}
286297

287298
k_spin_unlock(&lock, key);
288-
sys_clock_announce(IS_ENABLED(CONFIG_TICKLESS_KERNEL) ? dticks : 1);
299+
sys_clock_announce(dticks);
289300
}
290301

291302
__pinned_func
@@ -326,12 +337,8 @@ int sys_clock_driver_init(const struct device *dev)
326337
hz = (uint32_t)(HPET_COUNTER_CLK_PERIOD / hpet_counter_clk_period_get());
327338
z_clock_hw_cycles_per_sec = hz;
328339
cyc_per_tick = hz / CONFIG_SYS_CLOCK_TICKS_PER_SEC;
329-
330-
max_ticks = (MAX_TICKS - cyc_per_tick) / cyc_per_tick;
331340
#endif
332341

333-
last_count = hpet_counter_get();
334-
335342
/* Note: we set the legacy routing bit, because otherwise
336343
* nothing in Zephyr disables the PIT which then fires
337344
* interrupts into the same IRQ. But that means we're then
@@ -345,11 +352,16 @@ int sys_clock_driver_init(const struct device *dev)
345352
reg = hpet_timer_conf_get();
346353
reg &= ~TIMER_CONF_PERIODIC;
347354
reg &= ~TIMER_CONF_FSB_EN;
348-
reg |= TIMER_CONF_MODE32;
355+
reg &= ~TIMER_CONF_MODE32;
349356
reg |= TIMER_CONF_INT_ENABLE;
350357
hpet_timer_conf_set(reg);
351358

352-
hpet_timer_comparator_set(last_count + cyc_per_tick);
359+
last_count = hpet_counter_get();
360+
if (cyc_per_tick >= HPET_CMP_MIN_DELAY) {
361+
hpet_timer_comparator_set(last_count + cyc_per_tick);
362+
} else {
363+
hpet_timer_comparator_set(last_count + HPET_CMP_MIN_DELAY);
364+
}
353365

354366
return 0;
355367
}
@@ -378,15 +390,15 @@ void sys_clock_set_timeout(int32_t ticks, bool idle)
378390
return;
379391
}
380392

381-
ticks = ticks == K_TICKS_FOREVER ? max_ticks : ticks;
382-
ticks = CLAMP(ticks - 1, 0, (int32_t)max_ticks);
393+
ticks = ticks == K_TICKS_FOREVER ? HPET_MAX_TICKS : ticks;
394+
ticks = CLAMP(ticks - 1, 0, HPET_MAX_TICKS);
383395

384396
k_spinlock_key_t key = k_spin_lock(&lock);
385-
uint32_t now = hpet_counter_get(), cyc, adj;
386-
uint32_t max_cyc = max_ticks * cyc_per_tick;
397+
uint64_t now = hpet_counter_get(), cyc, adj;
398+
uint64_t max_cyc = (uint64_t)HPET_MAX_TICKS * cyc_per_tick;
387399

388400
/* Round up to next tick boundary. */
389-
cyc = ticks * cyc_per_tick;
401+
cyc = (uint64_t)ticks * cyc_per_tick;
390402
adj = (now - last_count) + (cyc_per_tick - 1);
391403
if (cyc <= max_cyc - adj) {
392404
cyc += adj;
@@ -396,8 +408,8 @@ void sys_clock_set_timeout(int32_t ticks, bool idle)
396408
cyc = (cyc / cyc_per_tick) * cyc_per_tick;
397409
cyc += last_count;
398410

399-
if ((cyc - now) < HPET_CMP_MIN_DELAY) {
400-
cyc += cyc_per_tick;
411+
if ((int64_t)(cyc - now) < HPET_CMP_MIN_DELAY) {
412+
cyc = now + HPET_CMP_MIN_DELAY;
401413
}
402414

403415
hpet_timer_comparator_set(cyc);
@@ -413,7 +425,8 @@ uint32_t sys_clock_elapsed(void)
413425
}
414426

415427
k_spinlock_key_t key = k_spin_lock(&lock);
416-
uint32_t ret = (hpet_counter_get() - last_count) / cyc_per_tick;
428+
uint64_t now = hpet_counter_get();
429+
uint32_t ret = (uint32_t)((now - last_count) / cyc_per_tick);
417430

418431
k_spin_unlock(&lock, key);
419432
return ret;
@@ -422,7 +435,7 @@ uint32_t sys_clock_elapsed(void)
422435
__pinned_func
423436
uint32_t sys_clock_cycle_get_32(void)
424437
{
425-
return hpet_counter_get();
438+
return (uint32_t)hpet_counter_get();
426439
}
427440

428441
__pinned_func

0 commit comments

Comments
 (0)