[an error occurred while processing this directive]

Device Driver for High-Resolution Clock



The kernel maintains in the kernel information page (KIP) a real-time clock with a 1ms resolution. For many purposes, e.g., benchmarking, a higher clock resolution is desired. The U4600 machines feature a chip which contains several high-frequency counters which can be used for a timer.

The Driver Interface

Your driver needs to export the interface specified in src/clock.h. There are the following functions:
Initialises the driver.
Registers the calling thread to receive an IPC message after a specified time interval (in microseconds, though actual wakeup resolution will depend on the timer resolution). Several registrations may be pending at any time.
Returns the current real-time clock value (microsecond accurate).
Stops operation of the driver. This will cancel any outstanding timer requests (by sending them a premature IPC indicating failure).
The IPC message sent by the timer contains in register 0 a return code (TIMER_R_OK, TIMER_R_UINT, TIMER_R_CNCL) and in register 1 the present value of the real-time clock.

The U4600

This is a simplified block diagram of the U4600 boards. The GT chip is a PCI bridge. It acts to interface the CPU with the PCI bus as well as to memory. Full details of the GT chip can be found its reference manual [1].

The R4600 has 8 IRQ exceptions consisting of 2 "software IRQs", 5 external hardware IRQs, and 1 IRQ that can be configured via external logic to either the internal timer (which it is on the U4600) or another external IRQ.

GT Chip

Your main job is to learn how to program the GT chip to generate timer interrupts and how to write an L4 driver to handle these interrupts.

The GT chip contains four 24 bit timer/counters. For our purposes, we are only interested in the GT chip as our source of timer interrupts. You will only be using one of these timers. The GT's interrupt line is connected to CPU interrupt pin 3 (see INT_GT64010A in kernel/u4600.h) and it is clocked at 50Mhz.

There is an abundance of different devices and writing device drivers is usually seen as a very difficult task. This is true in a sense. However, programming a device is really just a matter of learning about its registers, what values to read and write to those registers and when to do it.

The minimal subset of the GT chip's functionality that you must understand and use is listed below (the numbers in parentheses are the offsets of the register addresses from the chip's base address). Refer to the reference manual for full(er) descriptions [1].

Again, this is only the minimal understanding that you need. For deeper understanding, you are encouraged to learn about the other registers and can even play with those as well.

NOTE: This section is deliberately kept short (e.g., we do not dictated which timer to use or in what mode to use it in). The idea is that you work things out for yourself and make your own design and implementation decisions. There are only two conditions that must be satisfied:

  1. You must use an interrupt generated from the GT chip.
  2. You must implement the driver interface described above.

MIPS/L4 Interrupts

The MIPS/L4 kernel exports specific interrupts to a user level interrupt handler via IPC. A user level thread can register itself to be the handler for any one of the exported interrupts. After that, any interrupts of the registered number will get sent as an IPC to the interrupt handler.

Refer to the MIPS/L4 Reference Manual the MIPS/L4 User Manual for further information on the interrupt registration and delivery protocol.

NOTE: MIPS/L4 interrupt numbers are one higher than the number of the actual interrupt pin on the processor. That is, to handle processor interrupt 0, an L4 handler must register itself for L4 interrupt number 1.

Device Mappings

In MIPS/L4, device registers are memory mapped. That is, hardware registers can be accessed via normal load/store operations to special addresses. To access device registers, your handler must first request the correct device mapping from sigma0.

Refer to either the MIPS/L4 Reference Manual the MIPS/L4 User Manual for the device mapping protocol.

Note that all accesses device registers must bypass the cache. Device mappings sent by sigma0 use ``uncached'' mappings. If such a device page is mapped on to another address space, the caching attribute will be maintained (in fact, the present version of L4/MIPS does not allow changing caching attributes of mappings). This allows tasks other than initial servers to operate as device drivers. However, you will be well advised to run your driver inside the initial server's address space. Later you can migrate it to a child task, or to a separate initial server (like the serial port driver).


Device frequently use a different byte order than the CPU, so device drivers must generally deal with endianess, and your clock driver is no exception. Endianess refers to how indivdual bytes within a multi-byte word are addressed. The following two figures should illustrate how big and little endian works. In the figure the numbers refer to the relative addresses of the individual bytes.

The R4600 is big endian while all GT chip registers are little endian. Therefore, you will need to do some byte swapping when reading from and writing to the GT registers.


You may need to resolve some or all of these issues:


The file clock.h, as well as some other header files you might find useful, can be found in src/clock/.


[1] GT-64010A Reference Manual.
Last modified: 14 Aug 2002. [an error occurred while processing this directive]