Re: [PATCH v6 15/29] x86/hpet: Add helper function hpet_set_comparator_periodic()
On Sat, May 14, 2022 at 10:17:38AM +0200, Thomas Gleixner wrote: > On Fri, May 13 2022 at 14:19, Ricardo Neri wrote: > > On Fri, May 06, 2022 at 11:41:13PM +0200, Thomas Gleixner wrote: > >> The argument about not bloating the code > >> with an "obvious???" function which is quite small is slightly beyond my > >> comprehension level. > > > > That obvious function would look like this: > > > > void hpet_set_comparator_one_shot(int channel, u32 delta) > > { > > u32 count; > > > > count = hpet_readl(HPET_COUNTER); > > count += delta; > > hpet_writel(count, HPET_Tn_CMP(channel)); > > } > > This function only works reliably when the delta is large. See > hpet_clkevt_set_next_event(). That is a good point. One more reason to not have a hpet_set_comparator_one_shot(), IMO. Thanks and BR, Ricardo ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH v6 15/29] x86/hpet: Add helper function hpet_set_comparator_periodic()
On Fri, May 13 2022 at 14:19, Ricardo Neri wrote: > On Fri, May 06, 2022 at 11:41:13PM +0200, Thomas Gleixner wrote: >> The argument about not bloating the code >> with an "obvious???" function which is quite small is slightly beyond my >> comprehension level. > > That obvious function would look like this: > > void hpet_set_comparator_one_shot(int channel, u32 delta) > { > u32 count; > > count = hpet_readl(HPET_COUNTER); > count += delta; > hpet_writel(count, HPET_Tn_CMP(channel)); > } This function only works reliably when the delta is large. See hpet_clkevt_set_next_event(). Thanks, tglx ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH v6 15/29] x86/hpet: Add helper function hpet_set_comparator_periodic()
On Fri, May 06, 2022 at 11:51:52PM +0200, Thomas Gleixner wrote: > On Fri, May 06 2022 at 23:41, Thomas Gleixner wrote: > > On Thu, May 05 2022 at 16:59, Ricardo Neri wrote: > >> Programming an HPET channel as periodic requires setting the > >> HPET_TN_SETVAL bit in the channel configuration. Plus, the comparator > >> register must be written twice (once for the comparator value and once for > >> the periodic value). Since this programming might be needed in several > >> places (e.g., the HPET clocksource and the HPET-based hardlockup detector), > >> add a helper function for this purpose. > >> > >> A helper function hpet_set_comparator_oneshot() could also be implemented. > >> However, such function would only program the comparator register and the > >> function would be quite small. Hence, it is better to not bloat the code > >> with such an obvious function. > > > > This word salad above does not provide a single reason why the periodic > > programming function is required and better suited for the NMI watchdog > > case and then goes on and blurbs about why a function which is not > > required is not implemented. The argument about not bloating the code > > with an "obvious???" function which is quite small is slightly beyond my > > comprehension level. > > What's even more uncomprehensible is that the patch which actually sets > up that NMI watchdog cruft has: > > > + if (hc->boot_cfg & HPET_TN_PERIODIC_CAP) > > + hld_data->has_periodic = true; > > So how the heck does that work with a HPET which does not support > periodic mode? If the HPET channel does not support periodic mode (as indicated by the flag above), it will read the HPET counter into a local variable, increment that local variable, and write comparator of the HPET channel. If the HPET channel does support periodic mode, it will not kick it again. It will only kick a periodic HPET channel if needed (e.g., if the NMI watchdog was idle of watchdog_thresh changed its value). > > That watchdog muck will still happily invoke that set periodic function > in the hope that it works by chance? It will not. It will check hld_data->has_periodic and act accordingly. FWIW, I have tested this NMI watchdog with periodic and non-periodic HPET channels. Thanks and BR, Ricardo ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH v6 15/29] x86/hpet: Add helper function hpet_set_comparator_periodic()
On Fri, May 06, 2022 at 11:41:13PM +0200, Thomas Gleixner wrote: > On Thu, May 05 2022 at 16:59, Ricardo Neri wrote: > > Programming an HPET channel as periodic requires setting the > > HPET_TN_SETVAL bit in the channel configuration. Plus, the comparator > > register must be written twice (once for the comparator value and once for > > the periodic value). Since this programming might be needed in several > > places (e.g., the HPET clocksource and the HPET-based hardlockup detector), > > add a helper function for this purpose. > > > > A helper function hpet_set_comparator_oneshot() could also be implemented. > > However, such function would only program the comparator register and the > > function would be quite small. Hence, it is better to not bloat the code > > with such an obvious function. > > This word salad above does not provide a single reason why the periodic > programming function is required and better suited for the NMI watchdog > case The goal of hpet_set_comparator_periodic() is to avoid code duplication. The functions hpet_clkevt_set_state_periodic() and kick_timer() in the HPET NMI watchdog need to program a periodic HPET channel when supported. > and then goes on and blurbs about why a function which is not > required is not implemented. I can remove this. > The argument about not bloating the code > with an "obvious???" function which is quite small is slightly beyond my > comprehension level. That obvious function would look like this: void hpet_set_comparator_one_shot(int channel, u32 delta) { u32 count; count = hpet_readl(HPET_COUNTER); count += delta; hpet_writel(count, HPET_Tn_CMP(channel)); } It involves one register read, one addition and one register write. IMO, this code is sufficiently simple and small to allow duplication. Programming a periodic HPET channel is not as straightforward, IMO. It involves handling two different values (period and comparator) written in a specific sequence, one configuration bit, and one delay. It also involves three register writes and one register read. Thanks and BR, Ricardo ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH v6 15/29] x86/hpet: Add helper function hpet_set_comparator_periodic()
On Fri, May 06 2022 at 23:41, Thomas Gleixner wrote: > On Thu, May 05 2022 at 16:59, Ricardo Neri wrote: >> Programming an HPET channel as periodic requires setting the >> HPET_TN_SETVAL bit in the channel configuration. Plus, the comparator >> register must be written twice (once for the comparator value and once for >> the periodic value). Since this programming might be needed in several >> places (e.g., the HPET clocksource and the HPET-based hardlockup detector), >> add a helper function for this purpose. >> >> A helper function hpet_set_comparator_oneshot() could also be implemented. >> However, such function would only program the comparator register and the >> function would be quite small. Hence, it is better to not bloat the code >> with such an obvious function. > > This word salad above does not provide a single reason why the periodic > programming function is required and better suited for the NMI watchdog > case and then goes on and blurbs about why a function which is not > required is not implemented. The argument about not bloating the code > with an "obvious???" function which is quite small is slightly beyond my > comprehension level. What's even more uncomprehensible is that the patch which actually sets up that NMI watchdog cruft has: > + if (hc->boot_cfg & HPET_TN_PERIODIC_CAP) > + hld_data->has_periodic = true; So how the heck does that work with a HPET which does not support periodic mode? That watchdog muck will still happily invoke that set periodic function in the hope that it works by chance? Thanks, tglx ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH v6 15/29] x86/hpet: Add helper function hpet_set_comparator_periodic()
On Thu, May 05 2022 at 16:59, Ricardo Neri wrote: > Programming an HPET channel as periodic requires setting the > HPET_TN_SETVAL bit in the channel configuration. Plus, the comparator > register must be written twice (once for the comparator value and once for > the periodic value). Since this programming might be needed in several > places (e.g., the HPET clocksource and the HPET-based hardlockup detector), > add a helper function for this purpose. > > A helper function hpet_set_comparator_oneshot() could also be implemented. > However, such function would only program the comparator register and the > function would be quite small. Hence, it is better to not bloat the code > with such an obvious function. This word salad above does not provide a single reason why the periodic programming function is required and better suited for the NMI watchdog case and then goes on and blurbs about why a function which is not required is not implemented. The argument about not bloating the code with an "obvious???" function which is quite small is slightly beyond my comprehension level. Thanks, tglx ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v6 15/29] x86/hpet: Add helper function hpet_set_comparator_periodic()
Programming an HPET channel as periodic requires setting the HPET_TN_SETVAL bit in the channel configuration. Plus, the comparator register must be written twice (once for the comparator value and once for the periodic value). Since this programming might be needed in several places (e.g., the HPET clocksource and the HPET-based hardlockup detector), add a helper function for this purpose. A helper function hpet_set_comparator_oneshot() could also be implemented. However, such function would only program the comparator register and the function would be quite small. Hence, it is better to not bloat the code with such an obvious function. Cc: Andi Kleen Cc: Tony Luck Cc: Stephane Eranian Cc: "Ravi V. Shankar" Cc: iommu@lists.linux-foundation.org Cc: linuxppc-...@lists.ozlabs.org Cc: x...@kernel.org Originally-by: Suravee Suthikulpanit Reviewed-by: Tony Luck Signed-off-by: Ricardo Neri --- When programming the HPET channel in periodic mode, a udelay(1) between the two successive writes to HPET_Tn_CMP was introduced in commit e9e2cdb41241 ("[PATCH] clockevents: i386 drivers"). The commit message does not give any reason for such delay. The hardware specification does not seem to require it. The refactoring in this patch simply carries such delay. --- Changes since v5: * None Changes since v4: * Implement function only for periodic mode. This removed extra logic to to use a non-zero period value as a proxy for periodic mode programming. (Thomas) * Added a comment on the history of the udelay() when programming the channel in periodic mode. (Ashok) Changes since v3: * Added back a missing hpet_writel() for time configuration. Changes since v2: * Introduced this patch. Changes since v1: * N/A --- arch/x86/include/asm/hpet.h | 2 ++ arch/x86/kernel/hpet.c | 49 - 2 files changed, 39 insertions(+), 12 deletions(-) diff --git a/arch/x86/include/asm/hpet.h b/arch/x86/include/asm/hpet.h index be9848f0883f..486e001413c7 100644 --- a/arch/x86/include/asm/hpet.h +++ b/arch/x86/include/asm/hpet.h @@ -74,6 +74,8 @@ extern void hpet_disable(void); extern unsigned int hpet_readl(unsigned int a); extern void hpet_writel(unsigned int d, unsigned int a); extern void force_hpet_resume(void); +extern void hpet_set_comparator_periodic(int channel, unsigned int cmp, +unsigned int period); #ifdef CONFIG_HPET_EMULATE_RTC diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c index 47678e7927ff..2c6713b40921 100644 --- a/arch/x86/kernel/hpet.c +++ b/arch/x86/kernel/hpet.c @@ -294,6 +294,39 @@ static void hpet_enable_legacy_int(void) hpet_legacy_int_enabled = true; } +/** + * hpet_set_comparator_periodic() - Helper function to set periodic channel + * @channel: The HPET channel + * @cmp: The value to be written to the comparator/accumulator + * @period:Number of ticks per period + * + * Helper function for updating comparator, accumulator and period values. + * + * In periodic mode, HPET needs HPET_TN_SETVAL to be set before writing + * to the Tn_CMP to update the accumulator. Then, HPET needs a second + * write (with HPET_TN_SETVAL cleared) to Tn_CMP to set the period. + * The HPET_TN_SETVAL bit is automatically cleared after the first write. + * + * This function takes a 1 microsecond delay. However, this function is supposed + * to be called only once (or when reprogramming the timer) as it deals with a + * periodic timer channel. + * + * See the following documents: + * - Intel IA-PC HPET (High Precision Event Timers) Specification + * - AMD-8111 HyperTransport I/O Hub Data Sheet, Publication # 24674 + */ +void hpet_set_comparator_periodic(int channel, unsigned int cmp, unsigned int period) +{ + unsigned int v = hpet_readl(HPET_Tn_CFG(channel)); + + hpet_writel(v | HPET_TN_SETVAL, HPET_Tn_CFG(channel)); + + hpet_writel(cmp, HPET_Tn_CMP(channel)); + + udelay(1); + hpet_writel(period, HPET_Tn_CMP(channel)); +} + static int hpet_clkevt_set_state_periodic(struct clock_event_device *evt) { unsigned int channel = clockevent_to_channel(evt)->num; @@ -306,19 +339,11 @@ static int hpet_clkevt_set_state_periodic(struct clock_event_device *evt) now = hpet_readl(HPET_COUNTER); cmp = now + (unsigned int)delta; cfg = hpet_readl(HPET_Tn_CFG(channel)); - cfg |= HPET_TN_ENABLE | HPET_TN_PERIODIC | HPET_TN_SETVAL | - HPET_TN_32BIT; + cfg |= HPET_TN_ENABLE | HPET_TN_PERIODIC | HPET_TN_32BIT; hpet_writel(cfg, HPET_Tn_CFG(channel)); - hpet_writel(cmp, HPET_Tn_CMP(channel)); - udelay(1); - /* -* HPET on AMD 81xx needs a second write (with HPET_TN_SETVAL -* cleared) to T0_CMP to set the period. The HPET_TN_SETVAL -* bit is automatically cleared after the first write. -* (See AMD-8111 HyperTransport I/O Hub Data Sheet, -* Publication # 24674) -