Linux Device Drivers

Linux Device Drivers


Linux
Modules
Character drivers
IO & Memory
Linux Kernel
Process Management
Process Address space

Linux Scheduler
Memory Management
Interrupts
Signals
System Calls
Kernel Synchronization
Linux Inter Process Communications




Serial Ports
Parallel Ports
Introduction to Hardware
Linux Timers
DMA in Linux
Linux Threads
Linux Thread Synchronization

Linux Multi Threading
Debugging in Linux
GDB GNU Debugger
KDB Kernel Debugger
KGDB Kernel GNU Debugger
Example Ethernet Driver




Timer

Timer

 

Timers

 

The user application requires use of timers for various functions. In order to deal with timer, let us look into the following points:

 

     Understanding kernel time

     Knowing the current time

     Delaying operation for a specified amount of time

     Scheduling asynchronous functions to happen after a specified time lapse

 

 

Two main kinds of Timing measurements

 

Keeping the current time and date, so that they can be returned to user programs: time(), ftime(), and gettimeofday().

 

Maintaining timers to notify the kernel that a certain interval of time is elapsed

 

Hardware clocks

 

Three clocks: The real-time clock, the time stamp counter and Programmable Interval Timer.

 

Real time clock

 

     Real time clock (RTC)-CMOS RAM and RTC in same Chip, Motorola 146818

     Periodic interrupt on IRQ8

     Ports 0x70 and 0x71

 

Time Stamp Counter

 

     Pentium includes a 64bit Time Stamp Counter (TSC), can be read by rdtsc instruction.

     Register is a counter that is incremented at each clock.

     If the clock rate is 400 MHz, TSC is incremented at every 2.5 nsec

 

Programmable Interval Timer

 

Time measuring device, based on PIT 8254

 

Interrupts on IRQ0 at every 10 msec

 

HZ 100

CLOCK_TICK_RATE 1193180

LATCH ratio of CLOCK_TICK_RATE and HZ

 

Initialization:

outb_p(0x34, 0x43);

outb_p(LATCH & 0xff, 0x40);

outb(LATCH >> 8, 0x40);

 

 

Time Intervals in the kernel

 

The timer interrupt is a mechanism the kernel uses to keep track of time intervals.

 

Timer interrupts are generated by timer chip at regular intervals, counted by timer interrupt in global variable jiffies.

 

The time interval is set by kernel according to value of HZ, defined in <linux/param.h>. Current Linux versions define HZ to be 100, i.e. one tick is 10 msec

 

Current Time

 

To get the current time, use the function do_gettimeofday

#include <linux/time.h>

void do_gettimeofday(struct timeval*tv);

 

Delaying Execution

 

Long Delays

 

unsigned long j = jiffies + delay * HZ;

while (jiffies < j)

/* nothing */;

 

Short Delay

 

The kernel functions udelay and mdelay

 

#include <linux/delay.h>

void udelay (unsigned long usecs);

void mdelay (unsigned long msecs);

 

Timer Interrupt Handler

 

     Major activities in handler:

     Updates the time elapsed since system startup

     Updates time and date

     Determines process scheduling

     Updates resource usage statistics

     Checks expiry of software timer

 

The first activity is done in timer, other activities are done in TIMER_BH bottom half.

 

The Role of Timers

A timer is software facility that allows functions to be invoked at some future moment.

A time-out denotes a moment at which the time interval associated with a timer has elapsed.

Timers are used both by the kernel and processes. Most device drivers make use of timers to detect anomalous conditions: floppy disk driver, use timers to switch off the device motor after the floppy has not been accessed for a while.

Timers are also used to force execution of specific functions at some future time.

 

System Timers

 

int init_timer(structtimer_list*timer);

The two functions to add/delete timers:

void add_timer(structtimer_list*timer);

int del_timer(structtimer_list*timer);

 

 

 

Static timers

 

There are 32 different timers. The static timers are stored in the timer-table array, which includes 32 entries.

 

Each entry consists of the following timer_struct structure:

struct timer_struct{

unsigned long expires;

void (*fn)(void);

};

 

 

The expires field specifies when the timer expires, expresses in terms of number of ticks (jiffies)

The fn field contains the address of the function to be executed when the timer expires.

 

Dynamic Timers

 

Dynamic timers may be dynamically created and destroyed.

No limit is placed on numbers of currently active dynamic timers.

A dynamic timer is stored in the following timer_list structure:

struct timer_list{

struct timer_list*next;

struct timer_list*prev;

unsigned long expires;

unsigned long data;

void (*function) (unsigned long);

};

 

System calls related to timing measurement

System calls allow user mode processes to read and modify the time and date and to create timers.

 

time() Returns number of elapsed seconds since midnight at the start of January 1, 1970.

ftime() Returns, in a data structure of type timeb, elapsed seconds and time zone.

gettimeofday() returns elapsed time and time zone in two data structures.

 

Current Time

Linux provides the gettimeofday system call, which returns the number of seconds since 00:00:00 GMT, January 1, 1970. It also returns time zone information.

 

#include <sys/time.h>

int gettimeofday(structtimeval*tvalptr, structtimezone*tzoneptr);

struct timeval{

long tv_sec;/* seconds since 00:00:00 GMT,

Jan. 1, 1970 */

long tv_usec;/* and microseconds */

};

 

It returns zero if all is OK, with the structure pointed to by the tvalptr filled in.

settimeofday() system call sets the time of day.

 

Delaying Execution

We also use the sleep function to pause for a specified number of seconds.

unsigned int sleep(unsigned int sec);

 

The sleep function usually sets a SIGALRM signal, which it catches.

 

Scheduling asynchronous functions to happen after a specified time lapse -alarm() system call

 

The alarm() system call is used for setting software timeouts. A process can set an alarm clock by calling the alarm system call

unsigned int alarm(unsigned int sec);

 

The sec argument specifies the number of seconds to elapse before the kernel is to send the process a SIGALRM signal. The argument specifies the real time, not the CPU time. If the argument is zero, any previous alarm clock for the process is cancelled. The value returned by the function is the time remaining, if any, from the previous call to the function.

The process has to set a signal handler to process the SIGALRM signal

signal (SIGALRM, handler);

 

 

setitimer() system call

 

Linux allows user mode processes to activate special timers called interval timers. The timers cause signals to be sent periodically to the process. It is also possible to activate an interval timer so that it sends just one signal.

 

The frequency at which the signals must be emitted, or a null value if just one signal is to be generated.

The time remaining until the next signal is to be generated.

ITMER_REAL: Actual elapsed time

ITIMER_VIRTUAL: Time spent is user process

ITIMER_PROF: Time spent both in user and kernel mode.

 

The following functions allow better time monitoring of a process than does alarm().

 

#include <sys/time.h>

int getitimer(int which, struct itimerval*value);

int setitimer(int which, const struct itimerval*value,

struct itimerval *ovalue);

 

The variable which specifies one of the special timer

(ITIMER_REAL, ITIMER_VIRTUAL, ITIMER_PROF).

 

The times are indicated in the following structure:

struct itimerval{

struct timevalit_interval;/* interval */

struct timevalit_value;/* starting value */

};