HPET Timer implementation for multiple IRQ's
Problem Statement:
We want to use 8 hpet timers/comparators for generating interrupts in parallel for different applications on RHEL 7.1(3.10.0-229 kernel) on Intel core-i7 processor with RT Patch Kernel build 3.10.75.
When we tried to open /dev/hpet in different user applications , maximum two applications are only allowing to open /dev/hpet device.
We checked dmesg log: we found below log.
hpet0: at MMIO 0xfed00000, IRQs 2, 8, 0, 0, 0, 0, 0, 0
hpet0: 8 comparators, 64-bit 14.318180 MHz counter
In the Hpet specification document software-developers-hpet-spec-1-0a.pdf (attached), they have mentioned as below in section 3.2.2
3.2.2 HPET Block Interrupt Routing
Except for the case where HPET are being used to replace 8254/RTC functionality, all HPET interrupts are disabled.
The OS is responsible for establishing interrupt routing/delivery metrics prior to utilizing any given comparator within a Timer Block.
As per the intel document "564464_HPET.pdf" (attached) currently our system is configured as per section 6.2.4.1 Mapping Option #1 (Legacy Replacement Option)
Due to this in Dmesg IRQs are assigned as 2,8, 0,0,0,0,0,0 in I/O APIC Mode and i have checked "LEG_RT_CNF" in linux/hpet.h directory it i set as value (0x02UL) This means LEG_RT_CNF is set. In Hpet.c present in the path "arch/x86/kernel/hpet.c"
The following function code present as below:
static void hpet_reserve_platform_timers(unsigned int id)
{
struct hpet __iomem *hpet = hpet_virt_address;
struct hpet_timer __iomem *timer = &hpet->hpet_timers[2];
unsigned int nrtimers, i;
struct hpet_data hd;
nrtimers = ((id & HPET_ID_NUMBER) >> HPET_ID_NUMBER_SHIFT) + 1;
memset(&hd, 0, sizeof(hd));
hd.hd_phys_address = hpet_address;
hd.hd_address = hpet;
hd.hd_nirqs = nrtimers;
hpet_reserve_timer(&hd, 0);
ifdef CONFIG_HPET_EMULATE_RTC
hpet_reserve_timer(&hd, 1);
endif
/*
* NOTE that hd_irq[] reflects IOAPIC input pins (LEGACY_8254
* is wrong for i8259!) not the output IRQ. Many BIOS writers
* don't bother configuring *any* comparator interrupts.
*/
hd.hd_irq[0] = HPET_LEGACY_8254;
hd.hd_irq[1] = HPET_LEGACY_RTC;
for (i = 2; i < nrtimers; timer++, i++) {
hd.hd_irq[i] = (readl(&timer->hpet_config) &
Tn_INT_ROUTE_CNF_MASK) >> Tn_INT_ROUTE_CNF_SHIFT;
}
hpet_reserve_msi_timers(&hd);
hpet_alloc(&hd);
}
In the above code the yellow highlighted ones are assigned for first 2 timers (IRQ 2,8) HPET_LEGACY_8254 macro defined in hpet.h as 2 and HPET_LEGACY_RTC macro defined in hpet.h as 8.
As per the document section 6.2.4.2 Mapping Option #2 (Standard Option):
I have updated LEG_RT_CNF values in hpet.h to 0x00UL. and i have assigned 3 IRQ's in hpet.c driver code as below.
static void hpet_reserve_platform_timers(unsigned int id)
{
struct hpet __iomem *hpet = hpet_virt_address;
struct hpet_timer __iomem *timer = &hpet->hpet_timers[2];
unsigned int nrtimers, i;
struct hpet_data hd;
nrtimers = ((id & HPET_ID_NUMBER) >> HPET_ID_NUMBER_SHIFT) + 1;
memset(&hd, 0, sizeof(hd));
hd.hd_phys_address = hpet_address;
hd.hd_address = hpet;
hd.hd_nirqs = nrtimers;
hpet_reserve_timer(&hd, 0);
ifdef CONFIG_HPET_EMULATE_RTC
hpet_reserve_timer(&hd, 1);
endif
/*
* NOTE that hd_irq[] reflects IOAPIC input pins (LEGACY_8254
* is wrong for i8259!) not the output IRQ. Many BIOS writers
* don't bother configuring *any* comparator interrupts.
*/
hd.hd_irq[0] = 20; //Added manually
hd.hd_irq[1] = 21; //Added manually
hd.hd_irq[2] = 22; //Added manually
for (i = 3; i < nrtimers; timer++, i++) {
hd.hd_irq[i] = (readl(&timer->hpet_config) &
Tn_INT_ROUTE_CNF_MASK) >> Tn_INT_ROUTE_CNF_SHIFT;
}
hpet_reserve_msi_timers(&hd);
hpet_alloc(&hd);
}
I have assigned IRQ0,1,2 to 20,21,22 aftre updation of this code i have build the kernel using commands "make, make modules, make modules_install, make install". After successful build i have rebooted. After rebooting dmesg log contains following output
" IRQ 20,21,22,0,0,0,0,0".
Please clarify the following questions: Kernal version 3.10.75 RT Patch
-
How to use the Mapping Option #3 (Processor Message Option) to use remaining interrupts? To use this option, Tn_PROCMSG_EN_CNF,Tn_PROCMSG_INT_ADDR & Tn_PROCMSG_INT_VAL fileds are not present in Hpet Header files and c files.
-
How to check whether all 8 timer interrupts enabled or Not??
-
If interrupts are enabled, it will show in cat /proc/interrupts file or not?
-
Can you please provide the procedure for configuring the 8 timer interrups as per the section 6.2.4.2 Mapping Option #3 (Processor Message Option) and sample code for user space applications?
-
At current we are able to open /dev/hpet in maximum of two(2) user space applications for generating interrupts, But when we opened more than two(2) user space applications ".failed to open /dev/hpet" error and "HPET_IE_ON failed" errors are coming. So please provide the procedure to open /dev/hpet device to generate interrupts for 8 user space applications.
-
Can you please tell us the meaning of "HPET_IE_ON failed" error. I have attached the user space application code,dmesg log, /proc/interrupts logs for your reference.
Source code of hpet.c can be found in this weblink :
https://elixir.bootlin.com/linux/v3.10.75/source/arch/x86/kernel/hpet.c
Please provide the support and do the needful.
Thanks & Regards