Re: /dev/tsc and timekeeping

Colin Plumb (colin@nyx.net)
Sun, 14 Jun 1998 23:15:08 -0600 (MDT)


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