Thursday, January 10, 2008

More on HPET..

Welcome back!

If you are all waiting for what the reply from kernelnewbies was , there was no reply infact! This post is about the HPET research i carried out with the specs in hand and looking at the source code.

The line hpet0: at MMIO 0xfed00000, IRQs 2, 8, 0, make me realize that something was fishy, so I decided to look into the area where the IRQs were actually assigned, and I found it in arch/x86/kernel/hpet.c.

In that piece of code, a register field names TN_INT_ROUTE_CNF was being read from the per timer Configuration and Capabilities register. I quickly turned pages in the specs to see what it does, and It read that

" Default is 00h Software writes to this field to select which interrupt in the I/O (x) will be used for this timer’s interrupt. If the value is not supported by this prarticular timer, then the value read back will not match what is written. The software must only write valid values."

So, I got the reason why the value of 0 IRQ was being given to timer 2. Well, if it's zero be default, who changes it was the question. Ideally the BIOS assigns IRQs to various PCI devices. So, could it be a BIOS bug ? No, because many posts on LKML with dmesg, showed the same line which I got.

I decided to try one more thing. Why not mmap /dev/hpet and look at the registers ? I did so, and got a dump of its 1K register space and began examining it. I turn to the 'Timer N Configuration and Capabilities register' in the spec, and began looking at the first field,

" Tn_INT_ROUTE_CAP - Timer n Interrupt Routing Capability: (where n is the timer number: 00 to 31) This 32-bit read-only field indicates to which interrupts in the I/O (x) APIC this timer’s interrupt can be routed. This is used in conjunction with the Tn_INT_ROUTE_CNF field. Each bit in this field corresponds to a particular interrupt. For example, if this timer’s interrupt can be mapped to interrupts 16, 18, 20, 22, or 24, then bits 16, 18, 20, 22, and 24 in this field will be set to 1. All other bits will be 0. "

Wow!! was my reaction. So using this bitmap field, I could assign interrupts to timers! I wrote a dirty and quick patch, and ran the userspace program and to my astonishment, it worked like a charm!

This is about making the userspace API work. The kernelspace API is a bit different, in that it does not use ioctls, but has a struct hpet_task object and stuff. Its simple to use. So my next job is to make the kernelspace API to work..

Will post again on that.. stay tuned folks!


David R said...

Can you post your "dirty and quick" patch for the example app, please?

I'm also trying to get HPET support for my laptop.
I enabled some support by editing "arch/x86/kernel/quirks.c" and adding one of my pci-ids (1106:3337) to that file. Now I get HPET with hpet=force in the boot options.
But now I'm stuck with your same problem.

Kernel log:

pci 0000:00:11.0: Force enabled HPET at 0xfed00000
hpet clockevent registered
hpet0: at MMIO 0xfed00000, IRQs 2, 8, 0
hpet0: 3 32-bit timers, 14318180 Hz
rtc0: alarms up to one year, y3k, hpet irqs

I will follow your blog from time to time to see if you come with more info. ;)

5TmVsTx2vONCvOoZmTD7qNN7GLcD said...

Could you please provide source code of your solution?


Finnbarr P. Murphy said...

The diffs can be found at

Note: The changes are in the kernel space - not in the hpet demo program.