Messages in this thread Patch in this message | | | Date | Sun, 14 Jun 1998 23:15:08 -0600 (MDT) | From | Colin Plumb <> | Subject | Re: /dev/tsc and timekeeping |
| |
Oops, forgot the patch...
--- linux/arch/i386/kernel/time.c Sun Jun 14 15:19:40 1998 +++ linux/arch/i386/kernel/time.c Sun Jun 14 16:57:59 1998 @@ -34,6 +34,15 @@ #include <linux/timex.h> #include <linux/config.h> +#define TSC /* Debugging /dev/tsc device */ + +#ifdef TSC +#include <linux/miscdevice.h> +#include <linux/poll.h> +#include <linux/major.h> +#undef CONFIG_APM +#endif + /* * for x86_do_profile() */ @@ -430,6 +439,13 @@ #endif } +#ifdef TSC + unsigned long tsc_data[1024]; /* Well over 1 second's worth */ + unsigned volatile tsc_ptr; + struct wait_queue *tsc_readers = 0; + struct wait_queue *tsc_readbig = 0; +#endif + #ifndef CONFIG_APM /* cycle counter may be unreliable */ /* * This is the same as the above, except we _also_ save the current @@ -443,7 +459,123 @@ :"=a" (last_timer_cc.low), "=d" (last_timer_cc.high)); timer_interrupt(irq, NULL, regs); +#ifdef TSC +{ + unsigned ptr = tsc_ptr & (sizeof(tsc_data)-1); + ((unsigned long *)((char *)tsc_data+ptr))[0] = last_timer_cc.low; + ((unsigned long *)((char *)tsc_data+ptr))[1] = last_timer_cc.high; + tsc_ptr += 2*sizeof(unsigned long); + if (((ptr+2*sizeof(unsigned long)) & (sizeof(tsc_data)/2-1)) == 0) + wake_up_interruptible(&tsc_readbig); + wake_up_interruptible(&tsc_readers); +} +#endif /* TSC */ +} + +#ifdef TSC + +static loff_t +tsc_lseek(struct file *file, loff_t offset, int orig) +{ + return -ESPIPE; /* Unseekable */ +} + +static int +tsc_open(struct inode *inode, struct file *file) +{ + file->f_pos = tsc_ptr; + return 0; } + +static ssize_t +tsc_read(struct file *file, char *buf, size_t count, loff_t *ppos) +{ + unsigned pos; + size_t const count0 = count; + struct wait_queue wait = { current, NULL }; + struct wait_queue **queue; + unsigned ptr; + unsigned len; + int retval = 0; /* Return value for error-free length-0 read */ + + queue = &tsc_readbig; + add_wait_queue(queue, &wait); + + while (count) { + if (count < sizeof(tsc_data)/2 && queue == &tsc_readbig) { + remove_wait_queue(queue, &wait); + queue = &tsc_readers; + add_wait_queue(queue, &wait); + } + + current->state = TASK_INTERRUPTIBLE; + /* Set state *before* checking sleep condition */ + pos = (unsigned)*ppos; + ptr = tsc_ptr; + len = ptr - pos; + if (!len) { + /* No data available */ + retval = -EAGAIN; + if (file->f_flags & O_NONBLOCK) + break; + retval = -ERESTARTSYS; + if (signal_pending(current)) + break; + schedule(); + continue; + } + retval = -EPIPE; /* Overrun, stop! */ + if (len > (unsigned)sizeof(tsc_data)-8) + break; + /* Read position in circular buffer */ + pos &= ((unsigned)sizeof(tsc_data)-1); + /* Split the rad if it wraps around */ + if (len > (unsigned)sizeof(tsc_data) - pos) + len = (unsigned)sizeof(tsc_data) - pos; + if (len > count) + len = (unsigned)count; + len -= copy_to_user(buf, (char *)tsc_data+pos, len); + retval = -EFAULT; + if (!len) /* If no bytes copied, fault */ + break; + buf += len; + *ppos += len; + count -= len; + } + current->state = TASK_RUNNING; + remove_wait_queue(queue, &wait); + return count0 - count ?: retval; +} + +/* Poll is nice and easy to do, so support it */ +static unsigned int +tsc_poll(struct file *file, poll_table *wait) +{ + poll_wait(file, &tsc_readers, wait); + if (tsc_ptr != (file->f_pos & ((unsigned)sizeof(tsc_data) - 1))) + return POLLIN | POLLRDNORM; + return 0; +} + +struct file_operations tsc_fops = { + tsc_lseek, + tsc_read, + NULL, /* write */ + NULL, /* readdir */ + tsc_poll, + NULL, /* ioctl */ + NULL, /* mmap */ + tsc_open, + NULL, /* release */ + NULL /* fsync */ +}; + +struct miscdevice tsc_misc = { + MISC_DYNAMIC_MINOR, + "tsc", + &tsc_fops +}; +#endif /* TSC */ #endif /* Converts Gregorian date to seconds since 1970-01-01 00:00:00. @@ -558,4 +690,13 @@ } #endif setup_x86_irq(0, &irq0); + +#ifdef TSC + if (misc_register(&tsc_misc)) { + printk("TSC: misc_register failed\n"); + } else { + printk("TSC: Registered as %d:%d\n", + MISC_MAJOR, tsc_misc.minor); + } +#endif /* TSC */ } - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu
| |