On Wed, 8 Sep 2004, Andrew Morton wrote:
> Many eyes make light work. Please resubmit the patch, this time cc'ing
> linux-kernel, thanks.
Ok. Here it comes.
SGI has been using this driver under Linux since 2001 but it was
never included in the upstream kernel. SuSE did include the patch for mmtimer
in SLES 9. The driver has been widely used for applications on the Altix platform.
The timer hardware was designed around the multimedia timer specification by Intel
but to my knowledge only SGI has implemented that standard. The driver was written
by Jesse Barnes.
Changelog:
* Add driver for Altix SHub system clock
Signed-off-by: Christoph Lameter <[email protected]>
Index: linux-2.6.9-rc1/arch/ia64/sn/kernel/setup.c
===================================================================
--- linux-2.6.9-rc1.orig/arch/ia64/sn/kernel/setup.c 2004-08-24 00:02:24.000000000 -0700
+++ linux-2.6.9-rc1/arch/ia64/sn/kernel/setup.c 2004-09-08 20:40:39.000000000 -0700
@@ -64,6 +64,8 @@
unsigned long sn_rtc_cycles_per_second;
+EXPORT_SYMBOL(sn_rtc_cycles_per_second);
+
partid_t sn_partid = -1;
char sn_system_serial_number_string[128];
u64 sn_partition_serial_number;
Index: linux-2.6.9-rc1/drivers/char/Kconfig
===================================================================
--- linux-2.6.9-rc1.orig/drivers/char/Kconfig 2004-09-08 20:40:28.000000000 -0700
+++ linux-2.6.9-rc1/drivers/char/Kconfig 2004-09-08 20:44:31.000000000 -0700
@@ -981,5 +981,13 @@
out to lunch past a certain margin. It can reboot the system
or merely print a warning.
+config MMTIMER
+ tristate "MMTIMER Memory mapped RTC for SGI Altix"
+ depends on IA64_GENERIC || IA64_SGI_SN2
+ default y
+ help
+ The mmtimer device allows direct userspace access to the
+ Altix system timer.
+
endmenu
Index: linux-2.6.9-rc1/drivers/char/Makefile
===================================================================
--- linux-2.6.9-rc1.orig/drivers/char/Makefile 2004-09-08 20:40:28.000000000 -0700
+++ linux-2.6.9-rc1/drivers/char/Makefile 2004-09-08 20:40:39.000000000 -0700
@@ -45,6 +45,7 @@
obj-$(CONFIG_HVC_CONSOLE) += hvc_console.o hvsi.o
obj-$(CONFIG_RAW_DRIVER) += raw.o
obj-$(CONFIG_SGI_SNSC) += snsc.o
+obj-$(CONFIG_MMTIMER) += mmtimer.o
obj-$(CONFIG_VIOCONS) += viocons.o
obj-$(CONFIG_VIOTAPE) += viotape.o
obj-$(CONFIG_HVCS) += hvcs.o
Index: linux-2.6.9-rc1/drivers/char/mmtimer.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.9-rc1/drivers/char/mmtimer.c 2004-09-08 22:01:46.000000000 -0700
@@ -0,0 +1,317 @@
+/*
+ * Intel Multimedia Timer device implementation for SGI SN platforms.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (c) 2001-2003 Silicon Graphics, Inc. All rights reserved.
+ *
+ * This driver implements a subset of the interface required by the
+ * IA-PC Multimedia Timers Draft Specification (rev. 0.97) from Intel.
+ *
+ * 11/01/01 - jbarnes - initial revision
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/ioctl.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/devfs_fs_kernel.h>
+#include <linux/mmtimer.h>
+#include <linux/miscdevice.h>
+#include <asm/uaccess.h>
+#include <asm/sn/addrs.h>
+#include <asm/sn/clksupport.h>
+#include <asm/sn/mmtimer_private.h>
+
+#undef MMTIMER_INTERRUPT_SUPPORT
+
+MODULE_AUTHOR("Jesse Barnes <[email protected]>");
+MODULE_DESCRIPTION("Multimedia timer support");
+MODULE_LICENSE("GPL");
+
+static int mmtimer_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+static int mmtimer_mmap(struct file *file, struct vm_area_struct *vma);
+
+/*
+ * Period in femtoseconds (10^-15 s)
+ */
+static unsigned long mmtimer_femtoperiod = 0;
+
+static struct file_operations mmtimer_fops = {
+ .owner = THIS_MODULE,
+ .mmap = mmtimer_mmap,
+ .ioctl = mmtimer_ioctl,
+};
+
+/*
+ * Comparators and their associated info. Bedrock has
+ * two comparison registers.
+ */
+#ifdef MMTIMER_INTERRUPT_SUPPORT
+static mmtimer_t timers[] = { { SPIN_LOCK_UNLOCKED, 0, 0,
+ (unsigned long *)RTC_COMPARE_A_ADDR, 0 },
+ { SPIN_LOCK_UNLOCKED, 0, 0,
+ (unsigned long *)RTC_COMPARE_B_ADDR, 0 } };
+#endif
+
+/**
+ * mmtimer_ioctl - ioctl interface for /dev/mmtimer
+ * @inode: inode of the device
+ * @file: file structure for the device
+ * @cmd: command to execute
+ * @arg: optional argument to command
+ *
+ * Executes the command specified by @cmd. Returns 0 for success, <0 for failure.
+ * Valid commands are
+ *
+ * %MMTIMER_GETOFFSET - Should return the offset (relative to the start
+ * of the page where the registers are mapped) for the counter in question.
+ *
+ * %MMTIMER_GETRES - Returns the resolution of the clock in femto (10^-15)
+ * seconds
+ *
+ * %MMTIMER_GETFREQ - Copies the frequency of the clock in Hz to the address
+ * specified by @arg
+ *
+ * %MMTIMER_GETBITS - Returns the number of bits in the clock's counter
+ *
+ * %MMTIMER_GETNUM - Returns the umber of comparators available
+ *
+ * %MMTIMER_MMAPAVAIL - Returns 1 if the registers can be mmap'd into userspace
+ *
+ * %MMTIMER_SETPERIODIC - Sets the comparator in question to the value specified.
+ * The interrupt handler will add the value specified to the comparator after a
+ * match. In this case, @arg is the address of a struct mmtimer_alarm.
+ *
+ * %MMTIMER_SETONESHOT - Like the above, but the comparator is not updated
+ * after the match. @arg is also the same as above.
+ *
+ * %MMTIMER_GETCOUNTER - Gets the current value in the counter and places it
+ * in the address specified by @arg.
+ */
+static int
+mmtimer_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+ int ret = 0;
+#ifdef MMTIMER_INTERRUPT_SUPPORT
+ mmtimer_alarm_t alm;
+ unsigned long flags;
+#endif
+
+ switch (cmd) {
+ case MMTIMER_GETOFFSET: /* offset of the counter */
+ /*
+ * SN RTC registers are on their own 64k page
+ */
+ if(PAGE_SIZE <= (1 << 16))
+ ret = (((long)RTC_COUNTER_ADDR) & (PAGE_SIZE-1)) / 8;
+ else
+ ret = -ENOSYS;
+ break;
+
+ case MMTIMER_GETRES: /* resolution of the clock in 10^-15 s */
+ if(copy_to_user((unsigned long *)arg, &mmtimer_femtoperiod, sizeof(unsigned long)))
+ return -EFAULT;
+ break;
+
+ case MMTIMER_GETFREQ: /* frequency in Hz */
+ if(copy_to_user((unsigned long *)arg, &sn_rtc_cycles_per_second, sizeof(unsigned long)))
+ return -EFAULT;
+ ret = 0;
+ break;
+
+ case MMTIMER_GETBITS: /* number of bits in the clock */
+ ret = RTC_BITS;
+ break;
+
+ case MMTIMER_GETNUM: /* number of comparators available */
+ ret = 1;
+ break;
+
+ case MMTIMER_MMAPAVAIL: /* can we mmap the clock into userspace? */
+ ret = (PAGE_SIZE <= (1 << 16)) ? 1 : 0;
+ break;
+
+ case MMTIMER_SETPERIODIC: /* set a periodically signalling timer */
+#ifdef MMTIMER_INTERRUPT_SUPPORT
+ if(copy_from_user(&alm, (mmtimer_alarm_t *)arg, sizeof(mmtimer_alarm_t)))
+ return -EFAULT;
+ if(alm.id < 0 || alm.id > NUM_COMPARATORS) {
+ if(timers[alm.id].process) {
+ ret = -EBUSY;
+ }
+ else {
+ spin_lock_irqsave(&timers[alm.id].timer_lock, flags);
+ timers[alm.id].periodic = 1;
+ *(timers[alm.id].compare) = alm.value;
+ timers[alm.id].process = current;
+ timers[alm.id].signo = alm.signo;
+ MMTIMER_ENABLE_INT(alm.id);
+ spin_unlock_irqrestore(&timers[alm.id].timer_lock, flags);
+ }
+ }
+ else
+#endif /* MMTIMER_INTERRUPT_SUPPORT */
+ ret = -ENOSYS;
+ break;
+
+ case MMTIMER_SETONESHOT: /* set a one shot alarm */
+#ifdef MMTIMER_INTERRUPT_SUPPORT
+ if(copy_from_user(&alm, (mmtimer_alarm_t *)arg, sizeof(mmtimer_alarm_t)))
+ return -EFAULT;
+ if(alm.id != 0 || alm.id != 1) {
+ if(timers[alm.id].process) {
+ ret = -EBUSY;
+ }
+ else {
+ spin_lock_irqsave(&timers[alm.id].timer_lock, flags);
+ timers[alm.id].periodic = 0;
+ *(timers[alm.id].compare) = alm.value;
+ timers[alm.id].process = current;
+ timers[alm.id].signo = alm.signo;
+ MMTIMER_ENABLE_INT(alm.id);
+ spin_unlock_irqrestore(&timers[alm.id].timer_lock, flags);
+ }
+ }
+ else
+#endif /* MMTIMER_INTERRUPT_SUPPORT */
+ ret = -ENOSYS;
+ break;
+
+ case MMTIMER_GETCOUNTER:
+ if(copy_to_user((unsigned long *)arg, RTC_COUNTER_ADDR, sizeof(unsigned long)))
+ return -EFAULT;
+ break;
+ default:
+ ret = -ENOSYS;
+ break;
+ }
+
+ return ret;
+}
+
+/**
+ * mmtimer_mmap - maps the clock's registers into userspace
+ * @file: file structure for the device
+ * @vma: VMA to map the registers into
+ *
+ * Calls remap_page_range() to map the clock's registers into
+ * the calling process' address space.
+ */
+static int
+mmtimer_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ unsigned long mmtimer_addr;
+
+ if (vma->vm_end - vma->vm_start != PAGE_SIZE)
+ return -EINVAL;
+
+ if (vma->vm_flags & VM_WRITE)
+ return -EPERM;
+
+ if (PAGE_SIZE > (1 << 16))
+ return -ENOSYS;
+
+ vma->vm_flags |= (VM_IO | VM_SHM | VM_LOCKED );
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+ mmtimer_addr = __pa(RTC_COUNTER_ADDR);
+ mmtimer_addr &= ~(PAGE_SIZE - 1);
+ mmtimer_addr &= 0xfffffffffffffffUL;
+
+ if (remap_page_range(vma, vma->vm_start, mmtimer_addr, PAGE_SIZE, vma->vm_page_prot)) {
+ printk(KERN_ERR "remap_page_range failed in mmtimer.c\n");
+ return -EAGAIN;
+ }
+
+ return 0;
+}
+
+#ifdef MMTIMER_INTERRUPT_SUPPORT
+/**
+ * mmtimer_interrupt - timer interrupt handler
+ * @irq: irq received
+ * @dev_id: device the irq came from
+ * @regs: register state upon receipt of the interrupt
+ *
+ * Called when one of the comarators matches the counter, this
+ * routine will send signals to processes that have requested
+ * them.
+ */
+static void
+mmtimer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ unsigned long flags;
+ int i;
+
+ /*
+ * Do this once for each comparison register
+ */
+ for(i = 0; i < NUM_COMPARATORS; i++) {
+ if(MMTIMER_INT_PENDING(i)) {
+ spin_lock_irqsave(&timers[i].timer_lock, flags);
+ force_sig(timers[i].signo, timers[i].process);
+ if(timers[i].periodic)
+ *(timers[i].compare) += timers[i].periodic;
+ else {
+ timers[i].process = 0;
+ MMTIMER_DISABLE_INT(i);
+ }
+ spin_unlock_irqrestore(&timers[i].timer_lock, flags);
+ }
+ }
+}
+#endif /* MMTIMER_INTERRUPT_SUPPORT */
+
+static struct miscdevice mmtimer_miscdev = {
+ SGI_MMTIMER,
+ MMTIMER_NAME,
+ &mmtimer_fops
+};
+
+/**
+ * mmtimer_init - device initialization routine
+ *
+ * Does initial setup for the mmtimer device.
+ */
+static int __init
+mmtimer_init(void)
+{
+#ifdef MMTIMER_INTERRUPT_SUPPORT
+ int irq;
+#endif
+
+ /*
+ * Sanity check the cycles/sec variable
+ */
+ if (sn_rtc_cycles_per_second < 100000) {
+ printk(KERN_ERR "%s: unable to determine clock frequency\n", MMTIMER_NAME);
+ return -1;
+ }
+#ifdef MMTIMER_INTERRUPT_SUPPORT
+ irq = 4; /* or whatever the RTC interrupt is */
+ if(request_irq(irq, mmtimer_interrupt, SA_INTERRUPT, MMTIMER_NAME, NULL))
+ return -1;
+#endif /* MMTIMER_INTERRUPT_SUPPORT */
+
+ mmtimer_femtoperiod = ((unsigned long)1E15 + sn_rtc_cycles_per_second / 2) /
+ sn_rtc_cycles_per_second;
+
+ strcpy(mmtimer_miscdev.devfs_name, MMTIMER_NAME);
+ if (misc_register(&mmtimer_miscdev)) {
+ printk(KERN_ERR "%s: failed to register device\n", MMTIMER_NAME);
+ return -1;
+ }
+
+ printk(KERN_INFO "%s: v%s, %ld MHz\n", MMTIMER_DESC, MMTIMER_VERSION, sn_rtc_cycles_per_second/(unsigned long)1E6);
+
+ return 0;
+}
+
+module_init(mmtimer_init);
+
Index: linux-2.6.9-rc1/include/asm-ia64/sn/mmtimer_private.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.9-rc1/include/asm-ia64/sn/mmtimer_private.h 2004-09-08 20:40:39.000000000 -0700
@@ -0,0 +1,42 @@
+/*
+ * Intel Multimedia Timer device interface
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (c) 2001-2003 Silicon Graphics, Inc. All rights reserved.
+ *
+ * Helper file for the SN implementation of mmtimers
+ *
+ * 11/01/01 - jbarnes - initial revision
+ */
+
+#ifndef _SN_MMTIMER_PRIVATE_H
+
+#define RTC_BITS 55 /* 55 bits for this implementation */
+#define NUM_COMPARATORS 2 /* two comparison registers in SN1 */
+
+/*
+ * Check for an interrupt and clear the pending bit if
+ * one is waiting.
+ */
+#define MMTIMER_INT_PENDING(x) (x ? *(RTC_INT_PENDING_B_ADDR) : *(RTC_INT_PENDING_A_ADDR))
+
+/*
+ * Set interrupts on RTC 'x' to 'v' (true or false)
+ */
+#define MMTIMER_SET_INT(x,v) (x ? (*(RTC_INT_ENABLED_B_ADDR) = (unsigned long)(v)) : (*(RTC_INT_ENABLED_A_ADDR) = (unsigned long)(v)))
+
+#define MMTIMER_ENABLE_INT(x) MMTIMER_SET_INT(x, 1)
+#define MMTIMER_DISABLE_INT(x) MMTIMER_SET_INT(x, 0)
+
+typedef struct mmtimer {
+ spinlock_t timer_lock;
+ unsigned long periodic;
+ int signo;
+ volatile unsigned long *compare;
+ struct task_struct *process;
+} mmtimer_t;
+
+#endif /* _SN_LINUX_MMTIMER_PRIVATE_H */
Index: linux-2.6.9-rc1/include/linux/miscdevice.h
===================================================================
--- linux-2.6.9-rc1.orig/include/linux/miscdevice.h 2004-08-24 00:02:58.000000000 -0700
+++ linux-2.6.9-rc1/include/linux/miscdevice.h 2004-09-08 20:40:39.000000000 -0700
@@ -19,6 +19,7 @@
#define SUN_OPENPROM_MINOR 139
#define DMAPI_MINOR 140 /* DMAPI */
#define NVRAM_MINOR 144
+#define SGI_MMTIMER 153
#define STORE_QUEUE_MINOR 155
#define I2O_MINOR 166
#define MICROCODE_MINOR 184
Index: linux-2.6.9-rc1/include/linux/mmtimer.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.9-rc1/include/linux/mmtimer.h 2004-09-08 20:40:39.000000000 -0700
@@ -0,0 +1,170 @@
+/*
+ * Intel Multimedia Timer device interface
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (c) 2001-2003 Silicon Graphics, Inc. All rights reserved.
+ *
+ * This file should define an interface compatible with the IA-PC Multimedia
+ * Timers Draft Specification (rev. 0.97) from Intel. Note that some
+ * hardware may not be able to safely export its registers to userspace,
+ * so the ioctl interface should support all necessary functionality.
+ *
+ * 11/01/01 - jbarnes - initial revision
+ */
+
+#ifndef _LINUX_MMTIMER_H
+#define _LINUX_MMTIMER_H
+
+/* name of the device, usually in /dev */
+#define MMTIMER_NAME "mmtimer"
+#define MMTIMER_FULLNAME "/dev/mmtimer"
+#define MMTIMER_DESC "IA-PC Multimedia Timer"
+#define MMTIMER_VERSION "1.0"
+
+/*
+ * Used by the user to setup an alarm
+ */
+typedef struct mmtimer_alarm {
+ int id;
+ unsigned long value;
+ int signo;
+} mmtimer_alarm_t;
+
+/*
+ * Breakdown of the ioctl's available. An 'optional' next to the command
+ * indicates that supporting this command is optional, while 'required'
+ * commands must be implemented if conformance is desired.
+ *
+ * MMTIMER_GETOFFSET - optional
+ * Should return the offset (relative to the start of the page where the
+ * registers are mapped) for the counter in question.
+ *
+ * MMTIMER_GETRES - required
+ * The resolution of the clock in femto (10^-15) seconds
+ *
+ * MMTIMER_GETFREQ - required
+ * Frequency of the clock in Hz
+ *
+ * MMTIMER_GETBITS - required
+ * Number of bits in the clock's counter
+ *
+ * MMTIMER_GETNUM - required
+ * Number of comparators available
+ *
+ * MMTIMER_MMAPAVAIL - required
+ * Returns nonzero if the registers can be mmap'd into userspace, 0 otherwise
+ *
+ * MMTIMER_SETPERIODIC - required
+ * Sets the comparator in question to the value specified.
+ * The interrupt handler will add the value specified to the
+ * comparator after a match.
+ *
+ * MMTIMER_SETONESHOT - required
+ * Like the above, but the comparator is not updated after the match.
+ *
+ * MMTIMER_GETCOUNTER - required
+ * Gets the current value in the counter
+ */
+#define MMTIMER_IOCTL_BASE 'm'
+
+#define MMTIMER_GETOFFSET _IO(MMTIMER_IOCTL_BASE, 0)
+#define MMTIMER_GETRES _IOR(MMTIMER_IOCTL_BASE, 1, unsigned long)
+#define MMTIMER_GETFREQ _IOR(MMTIMER_IOCTL_BASE, 2, unsigned long)
+#define MMTIMER_GETBITS _IO(MMTIMER_IOCTL_BASE, 4)
+#define MMTIMER_GETNUM _IO(MMTIMER_IOCTL_BASE, 5)
+#define MMTIMER_MMAPAVAIL _IO(MMTIMER_IOCTL_BASE, 6)
+#define MMTIMER_SETPERIODIC _IOW(MMTIMER_IOCTL_BASE, 7, mmtimer_alarm_t)
+#define MMTIMER_SETONESHOT _IOW(MMTIMER_IOCTL_BASE, 8, mmtimer_alarm_t)
+#define MMTIMER_GETCOUNTER _IOR(MMTIMER_IOCTL_BASE, 9, unsigned long)
+
+/*
+ * An mmtimer verification program. WARNINGs are ok, but ERRORs indicate
+ * that the device doesn't fully support the interface defined here.
+ */
+#ifdef _MMTIMER_TEST_PROGRAM
+
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <sys/ioctl.h>
+
+#include "mmtimer.h"
+
+int main(int argc, char *argv[])
+{
+ int result, fd;
+ unsigned long val = 0;
+ unsigned long i;
+
+ if((fd = open("/dev/"MMTIMER_NAME, O_RDONLY)) == -1) {
+ printf("failed to open /dev/%s", MMTIMER_NAME);
+ return 1;
+ }
+
+ /*
+ * How many comparators are there?
+ */
+ if((result = ioctl(fd, MMTIMER_GETNUM, 0)) != -ENOSYS)
+ printf("comparators available: %d\n", result);
+ else
+ printf("ERROR: no comparators available\n");
+
+ /*
+ * Can we mmap in the counter?
+ */
+ if((result = ioctl(fd, MMTIMER_MMAPAVAIL, 0)) == 1) {
+ printf("mmap available\n");
+ /* ... so try getting the offset for each clock */
+ if((result = ioctl(fd, MMTIMER_GETOFFSET, 0)) != -ENOSYS)
+ printf("offset: %d\n", result);
+ else
+ printf("WARNING: offset unavailable for clock\n");
+ }
+ else
+ printf("WARNING: mmap unavailable\n");
+
+ /*
+ * Get the resolution in femtoseconds
+ */
+ if((result = ioctl(fd, MMTIMER_GETRES, &val)) != -ENOSYS)
+ printf("resolution: %ld femtoseconds\n", val);
+ else
+ printf("ERROR: failed to get resolution\n");
+
+ /*
+ * Get the frequency in Hz
+ */
+ if((result = ioctl(fd, MMTIMER_GETFREQ, &val)) != -ENOSYS)
+ if(val < 10000000) /* less than 10 MHz? */
+ printf("ERROR: frequency only %ld MHz, should be >= 10 MHz\n", val/1000000);
+ else
+ printf("frequency: %ld MHz\n", val/1000000);
+ else
+ printf("ERROR: failed to get frequency\n");
+
+ /*
+ * How many bits in the counter?
+ */
+ if((result = ioctl(fd, MMTIMER_GETBITS, 0)) != -ENOSYS)
+ printf("bits in counter: %d\n", result);
+ else
+ printf("ERROR: can't get number of bits in counter\n");
+
+ if((result = ioctl(fd, MMTIMER_GETCOUNTER, &val)) != -ENOSYS)
+ printf("counter value: %ld\n", val);
+ else
+ printf("ERROR: can't get counter value\n");
+
+ return 0;
+}
+
+#endif /* _MMTIMER_TEST_PROGRM */
+
+#endif /* _LINUX_MMTIMER_H */
[resending to lkml just for fun]
On Wednesday, September 8, 2004 8:59 pm, Christoph Lameter wrote:
> SGI has been using this driver under Linux since 2001 in the software
> that they distributed (ProPacks) but it wasnever included in the upstream
> kernel. SuSE did include the patch for mmtimerin SLES 9. The driver has
> been widely used for applications on the Altix platform.
>
> The timer hardware was designed around the multimedia timer specification
> by Intel but to my knowledge only SGI has implemented that standard. The
> driver was written by Jesse Barnes.
>
> Changelog:
> * Add driver for Altix SHub system clock
> --- linux-2.6.9-rc1.orig/drivers/char/Makefile 2004-09-08
> 20:40:28.000000000 -0700 +++
> linux-2.6.9-rc1/drivers/char/Makefile 2004-09-08 20:40:39.000000000 -0700
> @@ -45,6 +45,7 @@
> obj-$(CONFIG_HVC_CONSOLE) += hvc_console.o hvsi.o
> obj-$(CONFIG_RAW_DRIVER) += raw.o
> obj-$(CONFIG_SGI_SNSC) += snsc.o
> +obj-$(CONFIG_MMTIMER) += mmtimer.o
> obj-$(CONFIG_VIOCONS) += viocons.o
> obj-$(CONFIG_VIOTAPE) += viotape.o
> obj-$(CONFIG_HVCS) += hvcs.o
Maybe it's just my mailer, but is the indentation in this file all messed up?
> +#ifdef MMTIMER_INTERRUPT_SUPPORT
> +static mmtimer_t timers[] = { { SPIN_LOCK_UNLOCKED, 0, 0,
> + (unsigned long *)RTC_COMPARE_A_ADDR, 0 },
> + { SPIN_LOCK_UNLOCKED, 0, 0,
> + (unsigned long *)RTC_COMPARE_B_ADDR, 0 } };
> +#endif
We may as well kill anything under MMTIMER_INTERRUPT_SUPPORT. IIRC, people
use SHub timer interrupts, but not via this driver. If you want to fix it,
that's ok too, but you can kill the #ifdef in that case also.
Thanks,
Jesse
On Wed, 8 Sep 2004, Jesse Barnes wrote:
> We may as well kill anything under MMTIMER_INTERRUPT_SUPPORT. IIRC, people
> use SHub timer interrupts, but not via this driver. If you want to fix it,
> that's ok too, but you can kill the #ifdef in that case also.
Here is the driver with the interrupt support "killed". Hope this is
enough to get it into the kernel, Andrew? I did not get any other
feedback:
---------------------------MMTIMER-Driver-----------------------------------------
SGI has been using this driver under Linux since 2001 but it was
never included in the upstream kernel. SuSE did include the patch for mmtimer
in SLES 9. The driver has been widely used for applications on the Altix
platform.
The timer hardware was designed around the multimedia timer specification by
Intel but to my knowledge only SGI has implemented that standard. The driver
was written by Jesse Barnes.
The second revision has interrupt support removed and was somewhat simplified
by removing one include file.
Changelog:
* Add driver for Altix SHub system clock (MMTIMER)
Signed-off-by: Christoph Lameter <[email protected]>
Index: linux-2.6.9-rc1/arch/ia64/sn/kernel/setup.c
===================================================================
--- linux-2.6.9-rc1.orig/arch/ia64/sn/kernel/setup.c 2004-08-24 00:02:24.000000000 -0700
+++ linux-2.6.9-rc1/arch/ia64/sn/kernel/setup.c 2004-09-10 08:49:37.000000000 -0700
@@ -64,6 +64,8 @@
unsigned long sn_rtc_cycles_per_second;
+EXPORT_SYMBOL(sn_rtc_cycles_per_second);
+
partid_t sn_partid = -1;
char sn_system_serial_number_string[128];
u64 sn_partition_serial_number;
Index: linux-2.6.9-rc1/drivers/char/Kconfig
===================================================================
--- linux-2.6.9-rc1.orig/drivers/char/Kconfig 2004-09-10 08:49:29.000000000 -0700
+++ linux-2.6.9-rc1/drivers/char/Kconfig 2004-09-10 08:49:37.000000000 -0700
@@ -981,5 +981,13 @@
out to lunch past a certain margin. It can reboot the system
or merely print a warning.
+config MMTIMER
+ tristate "MMTIMER Memory mapped RTC for SGI Altix"
+ depends on IA64_GENERIC || IA64_SGI_SN2
+ default y
+ help
+ The mmtimer device allows direct userspace access to the
+ Altix system timer.
+
endmenu
Index: linux-2.6.9-rc1/drivers/char/Makefile
===================================================================
--- linux-2.6.9-rc1.orig/drivers/char/Makefile 2004-09-10 08:49:29.000000000 -0700
+++ linux-2.6.9-rc1/drivers/char/Makefile 2004-09-10 10:07:04.000000000 -0700
@@ -45,6 +45,7 @@
obj-$(CONFIG_HVC_CONSOLE) += hvc_console.o hvsi.o
obj-$(CONFIG_RAW_DRIVER) += raw.o
obj-$(CONFIG_SGI_SNSC) += snsc.o
+obj-$(CONFIG_MMTIMER) += mmtimer.o
obj-$(CONFIG_VIOCONS) += viocons.o
obj-$(CONFIG_VIOTAPE) += viotape.o
obj-$(CONFIG_HVCS) += hvcs.o
Index: linux-2.6.9-rc1/drivers/char/mmtimer.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.9-rc1/drivers/char/mmtimer.c 2004-09-10 08:49:37.000000000 -0700
@@ -0,0 +1,198 @@
+/*
+ * Intel Multimedia Timer device implementation for SGI SN platforms.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (c) 2001-2003 Silicon Graphics, Inc. All rights reserved.
+ *
+ * This driver implements a subset of the interface required by the
+ * IA-PC Multimedia Timers Draft Specification (rev. 0.97) from Intel.
+ *
+ * 11/01/01 - jbarnes - initial revision
+ * 9/10/04 - Christoph Lameter - remove interrupt support for kernel inclusion
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/ioctl.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/devfs_fs_kernel.h>
+#include <linux/mmtimer.h>
+#include <linux/miscdevice.h>
+#include <asm/uaccess.h>
+#include <asm/sn/addrs.h>
+#include <asm/sn/clksupport.h>
+
+MODULE_AUTHOR("Jesse Barnes <[email protected]>");
+MODULE_DESCRIPTION("Multimedia timer support");
+MODULE_LICENSE("GPL");
+
+#define RTC_BITS 55 /* 55 bits for this implementation */
+
+static int mmtimer_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+static int mmtimer_mmap(struct file *file, struct vm_area_struct *vma);
+
+/*
+ * Period in femtoseconds (10^-15 s)
+ */
+static unsigned long mmtimer_femtoperiod = 0;
+
+static struct file_operations mmtimer_fops = {
+ .owner = THIS_MODULE,
+ .mmap = mmtimer_mmap,
+ .ioctl = mmtimer_ioctl,
+};
+
+/**
+ * mmtimer_ioctl - ioctl interface for /dev/mmtimer
+ * @inode: inode of the device
+ * @file: file structure for the device
+ * @cmd: command to execute
+ * @arg: optional argument to command
+ *
+ * Executes the command specified by @cmd. Returns 0 for success, <0 for failure.
+ * Valid commands are
+ *
+ * %MMTIMER_GETOFFSET - Should return the offset (relative to the start
+ * of the page where the registers are mapped) for the counter in question.
+ *
+ * %MMTIMER_GETRES - Returns the resolution of the clock in femto (10^-15)
+ * seconds
+ *
+ * %MMTIMER_GETFREQ - Copies the frequency of the clock in Hz to the address
+ * specified by @arg
+ *
+ * %MMTIMER_GETBITS - Returns the number of bits in the clock's counter
+ *
+ * %MMTIMER_MMAPAVAIL - Returns 1 if the registers can be mmap'd into userspace
+ *
+ * %MMTIMER_GETCOUNTER - Gets the current value in the counter and places it
+ * in the address specified by @arg.
+ */
+static int
+mmtimer_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+ int ret = 0;
+
+ switch (cmd) {
+ case MMTIMER_GETOFFSET: /* offset of the counter */
+ /*
+ * SN RTC registers are on their own 64k page
+ */
+ if(PAGE_SIZE <= (1 << 16))
+ ret = (((long)RTC_COUNTER_ADDR) & (PAGE_SIZE-1)) / 8;
+ else
+ ret = -ENOSYS;
+ break;
+
+ case MMTIMER_GETRES: /* resolution of the clock in 10^-15 s */
+ if(copy_to_user((unsigned long *)arg, &mmtimer_femtoperiod, sizeof(unsigned long)))
+ return -EFAULT;
+ break;
+
+ case MMTIMER_GETFREQ: /* frequency in Hz */
+ if(copy_to_user((unsigned long *)arg, &sn_rtc_cycles_per_second, sizeof(unsigned long)))
+ return -EFAULT;
+ ret = 0;
+ break;
+
+ case MMTIMER_GETBITS: /* number of bits in the clock */
+ ret = RTC_BITS;
+ break;
+
+ case MMTIMER_MMAPAVAIL: /* can we mmap the clock into userspace? */
+ ret = (PAGE_SIZE <= (1 << 16)) ? 1 : 0;
+ break;
+
+ case MMTIMER_GETCOUNTER:
+ if(copy_to_user((unsigned long *)arg, RTC_COUNTER_ADDR, sizeof(unsigned long)))
+ return -EFAULT;
+ break;
+ default:
+ ret = -ENOSYS;
+ break;
+ }
+
+ return ret;
+}
+
+/**
+ * mmtimer_mmap - maps the clock's registers into userspace
+ * @file: file structure for the device
+ * @vma: VMA to map the registers into
+ *
+ * Calls remap_page_range() to map the clock's registers into
+ * the calling process' address space.
+ */
+static int
+mmtimer_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ unsigned long mmtimer_addr;
+
+ if (vma->vm_end - vma->vm_start != PAGE_SIZE)
+ return -EINVAL;
+
+ if (vma->vm_flags & VM_WRITE)
+ return -EPERM;
+
+ if (PAGE_SIZE > (1 << 16))
+ return -ENOSYS;
+
+ vma->vm_flags |= (VM_IO | VM_SHM | VM_LOCKED );
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+ mmtimer_addr = __pa(RTC_COUNTER_ADDR);
+ mmtimer_addr &= ~(PAGE_SIZE - 1);
+ mmtimer_addr &= 0xfffffffffffffffUL;
+
+ if (remap_page_range(vma, vma->vm_start, mmtimer_addr, PAGE_SIZE, vma->vm_page_prot)) {
+ printk(KERN_ERR "remap_page_range failed in mmtimer.c\n");
+ return -EAGAIN;
+ }
+
+ return 0;
+}
+
+static struct miscdevice mmtimer_miscdev = {
+ SGI_MMTIMER,
+ MMTIMER_NAME,
+ &mmtimer_fops
+};
+
+/**
+ * mmtimer_init - device initialization routine
+ *
+ * Does initial setup for the mmtimer device.
+ */
+static int __init
+mmtimer_init(void)
+{
+ /*
+ * Sanity check the cycles/sec variable
+ */
+ if (sn_rtc_cycles_per_second < 100000) {
+ printk(KERN_ERR "%s: unable to determine clock frequency\n", MMTIMER_NAME);
+ return -1;
+ }
+
+ mmtimer_femtoperiod = ((unsigned long)1E15 + sn_rtc_cycles_per_second / 2) /
+ sn_rtc_cycles_per_second;
+
+ strcpy(mmtimer_miscdev.devfs_name, MMTIMER_NAME);
+ if (misc_register(&mmtimer_miscdev)) {
+ printk(KERN_ERR "%s: failed to register device\n", MMTIMER_NAME);
+ return -1;
+ }
+
+ printk(KERN_INFO "%s: v%s, %ld MHz\n", MMTIMER_DESC, MMTIMER_VERSION, sn_rtc_cycles_per_second/(unsigned long)1E6);
+
+ return 0;
+}
+
+module_init(mmtimer_init);
+
Index: linux-2.6.9-rc1/include/linux/miscdevice.h
===================================================================
--- linux-2.6.9-rc1.orig/include/linux/miscdevice.h 2004-08-24 00:02:58.000000000 -0700
+++ linux-2.6.9-rc1/include/linux/miscdevice.h 2004-09-10 08:49:37.000000000 -0700
@@ -19,6 +19,7 @@
#define SUN_OPENPROM_MINOR 139
#define DMAPI_MINOR 140 /* DMAPI */
#define NVRAM_MINOR 144
+#define SGI_MMTIMER 153
#define STORE_QUEUE_MINOR 155
#define I2O_MINOR 166
#define MICROCODE_MINOR 184
Index: linux-2.6.9-rc1/include/linux/mmtimer.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.9-rc1/include/linux/mmtimer.h 2004-09-10 08:49:37.000000000 -0700
@@ -0,0 +1,140 @@
+/*
+ * Intel Multimedia Timer device interface
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (c) 2001-2003 Silicon Graphics, Inc. All rights reserved.
+ *
+ * This file should define an interface compatible with the IA-PC Multimedia
+ * Timers Draft Specification (rev. 0.97) from Intel. Note that some
+ * hardware may not be able to safely export its registers to userspace,
+ * so the ioctl interface should support all necessary functionality.
+ *
+ * 11/01/01 - jbarnes - initial revision
+ * 9/10/04 - Christoph Lameter - remove interrupt support
+ */
+
+#ifndef _LINUX_MMTIMER_H
+#define _LINUX_MMTIMER_H
+
+/* name of the device, usually in /dev */
+#define MMTIMER_NAME "mmtimer"
+#define MMTIMER_FULLNAME "/dev/mmtimer"
+#define MMTIMER_DESC "IA-PC Multimedia Timer"
+#define MMTIMER_VERSION "1.0"
+
+/*
+ * Breakdown of the ioctl's available. An 'optional' next to the command
+ * indicates that supporting this command is optional, while 'required'
+ * commands must be implemented if conformance is desired.
+ *
+ * MMTIMER_GETOFFSET - optional
+ * Should return the offset (relative to the start of the page where the
+ * registers are mapped) for the counter in question.
+ *
+ * MMTIMER_GETRES - required
+ * The resolution of the clock in femto (10^-15) seconds
+ *
+ * MMTIMER_GETFREQ - required
+ * Frequency of the clock in Hz
+ *
+ * MMTIMER_GETBITS - required
+ * Number of bits in the clock's counter
+ *
+ * MMTIMER_MMAPAVAIL - required
+ * Returns nonzero if the registers can be mmap'd into userspace, 0 otherwise
+ *
+ * MMTIMER_GETCOUNTER - required
+ * Gets the current value in the counter
+ */
+#define MMTIMER_IOCTL_BASE 'm'
+
+#define MMTIMER_GETOFFSET _IO(MMTIMER_IOCTL_BASE, 0)
+#define MMTIMER_GETRES _IOR(MMTIMER_IOCTL_BASE, 1, unsigned long)
+#define MMTIMER_GETFREQ _IOR(MMTIMER_IOCTL_BASE, 2, unsigned long)
+#define MMTIMER_GETBITS _IO(MMTIMER_IOCTL_BASE, 4)
+#define MMTIMER_MMAPAVAIL _IO(MMTIMER_IOCTL_BASE, 6)
+#define MMTIMER_GETCOUNTER _IOR(MMTIMER_IOCTL_BASE, 9, unsigned long)
+
+/*
+ * An mmtimer verification program. WARNINGs are ok, but ERRORs indicate
+ * that the device doesn't fully support the interface defined here.
+ */
+#ifdef _MMTIMER_TEST_PROGRAM
+
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <sys/ioctl.h>
+
+#include "mmtimer.h"
+
+int main(int argc, char *argv[])
+{
+ int result, fd;
+ unsigned long val = 0;
+ unsigned long i;
+
+ if((fd = open("/dev/"MMTIMER_NAME, O_RDONLY)) == -1) {
+ printf("failed to open /dev/%s", MMTIMER_NAME);
+ return 1;
+ }
+
+ /*
+ * Can we mmap in the counter?
+ */
+ if((result = ioctl(fd, MMTIMER_MMAPAVAIL, 0)) == 1) {
+ printf("mmap available\n");
+ /* ... so try getting the offset for each clock */
+ if((result = ioctl(fd, MMTIMER_GETOFFSET, 0)) != -ENOSYS)
+ printf("offset: %d\n", result);
+ else
+ printf("WARNING: offset unavailable for clock\n");
+ }
+ else
+ printf("WARNING: mmap unavailable\n");
+
+ /*
+ * Get the resolution in femtoseconds
+ */
+ if((result = ioctl(fd, MMTIMER_GETRES, &val)) != -ENOSYS)
+ printf("resolution: %ld femtoseconds\n", val);
+ else
+ printf("ERROR: failed to get resolution\n");
+
+ /*
+ * Get the frequency in Hz
+ */
+ if((result = ioctl(fd, MMTIMER_GETFREQ, &val)) != -ENOSYS)
+ if(val < 10000000) /* less than 10 MHz? */
+ printf("ERROR: frequency only %ld MHz, should be >= 10 MHz\n", val/1000000);
+ else
+ printf("frequency: %ld MHz\n", val/1000000);
+ else
+ printf("ERROR: failed to get frequency\n");
+
+ /*
+ * How many bits in the counter?
+ */
+ if((result = ioctl(fd, MMTIMER_GETBITS, 0)) != -ENOSYS)
+ printf("bits in counter: %d\n", result);
+ else
+ printf("ERROR: can't get number of bits in counter\n");
+
+ if((result = ioctl(fd, MMTIMER_GETCOUNTER, &val)) != -ENOSYS)
+ printf("counter value: %ld\n", val);
+ else
+ printf("ERROR: can't get counter value\n");
+
+ return 0;
+}
+
+#endif /* _MMTIMER_TEST_PROGRM */
+
+#endif /* _LINUX_MMTIMER_H */
On Fri, Sep 10, 2004 at 12:54:30PM -0700, Christoph Lameter wrote:
> On Wed, 8 Sep 2004, Jesse Barnes wrote:
> > We may as well kill anything under MMTIMER_INTERRUPT_SUPPORT. IIRC, people
> > use SHub timer interrupts, but not via this driver. If you want to fix it,
> > that's ok too, but you can kill the #ifdef in that case also.
>
> Here is the driver with the interrupt support "killed". Hope this is
> enough to get it into the kernel, Andrew? I did not get any other
> feedback:
please at least kill all the userland gunk from mmtmer.h
On Sat, 11 Sep 2004, Christoph Hellwig wrote:
> On Fri, Sep 10, 2004 at 12:54:30PM -0700, Christoph Lameter wrote:
> > On Wed, 8 Sep 2004, Jesse Barnes wrote:
> > > We may as well kill anything under MMTIMER_INTERRUPT_SUPPORT. IIRC, people
> > > use SHub timer interrupts, but not via this driver. If you want to fix it,
> > > that's ok too, but you can kill the #ifdef in that case also.
> >
> > Here is the driver with the interrupt support "killed". Hope this is
> > enough to get it into the kernel, Andrew? I did not get any other
> > feedback:
>
> please at least kill all the userland gunk from mmtmer.h
>
Its just a test program.... and mmtimer.h is already quite tiny.
Christoph Lameter wrote:
> The timer hardware was designed around the multimedia timer specification by Intel
> but to my knowledge only SGI has implemented that standard. The driver was written
> by Jesse Barnes.
As far as I can see, drivers/char/hpet.c talks to the same hardware.
HP sx1000 machines (and probably others) also implement the HPET.
I think you should look at adding your functionality to hpet.c
rather than adding a new driver.
On Thursday, September 16, 2004 9:03 am, Bjorn Helgaas wrote:
> Christoph Lameter wrote:
> > The timer hardware was designed around the multimedia timer specification
> > by Intel but to my knowledge only SGI has implemented that standard. The
> > driver was written by Jesse Barnes.
>
> As far as I can see, drivers/char/hpet.c talks to the same hardware.
> HP sx1000 machines (and probably others) also implement the HPET.
No, it's different hardware.
> I think you should look at adding your functionality to hpet.c
> rather than adding a new driver.
I think Christoph already looked at that. And HPET doesn't provide mmap
functionality, does it? I.e. allow a userspace program to dereference the
counter register directly?
Jesse
On Thu, 2004-09-16 at 18:09, Jesse Barnes wrote:
> I think Christoph already looked at that. And HPET doesn't provide mmap
> functionality, does it? I.e. allow a userspace program to dereference the
> counter register directly?
drivers/char/Kconfig:
config HPET_MMAP
bool "Allow mmap of HPET"
default y
depends on HPET
help
If you say Y here, user applications will be able to mmap
the HPET registers.
In some hardware implementations, the page containing HPET
registers may also contain other things that shouldn't be
exposed to the user. If this applies to your hardware,
say N here.
--
Marcello Barnaba - SoftMedia S.c.r.l. :: Mobile: +39 (340) 3698342
Via Mauro Amoruso, 11 - 70124 Bari :: Phone: +39 (080) 5046314
pub 1024D/F04476A2 :: 6807 EEA5 7F97 AC9A D8EF AE73 64CD 71A2 F044 76A2
On Thursday 16 September 2004 10:32 am, Christoph Lameter wrote:
> On Thu, 16 Sep 2004, Bjorn Helgaas wrote:
> > Christoph Lameter wrote:
> > > The timer hardware was designed around the multimedia timer specification by Intel
> > > but to my knowledge only SGI has implemented that standard. The driver was written
> > > by Jesse Barnes.
> >
> > As far as I can see, drivers/char/hpet.c talks to the same hardware.
> > HP sx1000 machines (and probably others) also implement the HPET.
>
> The Intel Multimedia Standard is a earlier and different timer spec.
I have a spec that's labelled "IA-PC Multimedia Timers", preliminary
draft of June 2000, revision 0.97, which looks like the one mentioned
in your patch.
I also have something labelled "IA-PC HPET (High Precision Event
Timers) Specification", draft of February 2002, revision 0.98,
which is what drivers/char/hpet.c supports.
I admit I haven't compared them in great detail, but they certainly
*look* like they're close enough that the same driver could support
both, and the 0.98 revision history only mentions fairly cosmetic
changes (like the name :)).
Is there something specific that drivers/char/hpet.c expects that
your hardware doesn't implement?
On Iau, 2004-09-16 at 17:09, Jesse Barnes wrote:
> I think Christoph already looked at that. And HPET doesn't provide mmap
> functionality, does it? I.e. allow a userspace program to dereference the
> counter register directly?
It can do but that assumes nothing else is mapped into the same page
that would be harmful or reveal information that should not be revealed
etc..
On Thursday, September 16, 2004 8:52 am, Alan Cox wrote:
> On Iau, 2004-09-16 at 17:09, Jesse Barnes wrote:
> > I think Christoph already looked at that. And HPET doesn't provide mmap
> > functionality, does it? I.e. allow a userspace program to dereference
> > the counter register directly?
>
> It can do but that assumes nothing else is mapped into the same page
> that would be harmful or reveal information that should not be revealed
> etc..
And what about the register layout? mmtimer makes sure that the register is
on a page by itself before it allows the mmap, and only exports the counter
register itself. Can hpet do that?
Jesse
On Thu, 16 Sep 2004, Bjorn Helgaas wrote:
> Christoph Lameter wrote:
> > The timer hardware was designed around the multimedia timer specification by Intel
> > but to my knowledge only SGI has implemented that standard. The driver was written
> > by Jesse Barnes.
>
> As far as I can see, drivers/char/hpet.c talks to the same hardware.
> HP sx1000 machines (and probably others) also implement the HPET.
The Intel Multimedia Standard is a earlier and different timer spec.
On Thu, 16 Sep 2004, Jesse Barnes wrote:
> > As far as I can see, drivers/char/hpet.c talks to the same hardware.
> > HP sx1000 machines (and probably others) also implement the HPET.
>
> No, it's different hardware.
>
> > I think you should look at adding your functionality to hpet.c
> > rather than adding a new driver.
>
> I think Christoph already looked at that. And HPET doesn't provide mmap
> functionality, does it? I.e. allow a userspace program to dereference the
> counter register directly?
HPET also allows mmaping to userspace.
Alan Cox wrote:
>On Iau, 2004-09-16 at 17:09, Jesse Barnes wrote:
>
>
>>I think Christoph already looked at that. And HPET doesn't provide mmap
>>functionality, does it? I.e. allow a userspace program to dereference the
>>counter register directly?
>>
>>
>
>It can do but that assumes nothing else is mapped into the same page
>that would be harmful or reveal information that should not be revealed
>etc..
>
>
>
HPET driver does provide mmap for user programs.
I agree with caution of other device registers in the same page.
Bjorn Helgaas wrote:
>On Thursday 16 September 2004 10:32 am, Christoph Lameter wrote:
>
>
>>On Thu, 16 Sep 2004, Bjorn Helgaas wrote:
>>
>>
>>>Christoph Lameter wrote:
>>>
>>>
>>>>The timer hardware was designed around the multimedia timer specification by Intel
>>>>but to my knowledge only SGI has implemented that standard. The driver was written
>>>>by Jesse Barnes.
>>>>
>>>>
>>>As far as I can see, drivers/char/hpet.c talks to the same hardware.
>>>HP sx1000 machines (and probably others) also implement the HPET.
>>>
>>>
>>The Intel Multimedia Standard is a earlier and different timer spec.
>>
>>
>
>I have a spec that's labelled "IA-PC Multimedia Timers", preliminary
>draft of June 2000, revision 0.97, which looks like the one mentioned
>in your patch.
>
>I also have something labelled "IA-PC HPET (High Precision Event
>Timers) Specification", draft of February 2002, revision 0.98,
>which is what drivers/char/hpet.c supports.
>
>I admit I haven't compared them in great detail, but they certainly
>*look* like they're close enough that the same driver could support
>both, and the 0.98 revision history only mentions fairly cosmetic
>changes (like the name :)).
>
>Is there something specific that drivers/char/hpet.c expects that
>your hardware doesn't implement?
>
>
>
Look at HPET revision history. Specifically 0.98 01/20/2002
* Product name changed: from Multimedia Timer to HPET (High
Precision Event Timer)
Bob
Jesse Barnes wrote:
>On Thursday, September 16, 2004 8:52 am, Alan Cox wrote:
>
>
>>On Iau, 2004-09-16 at 17:09, Jesse Barnes wrote:
>>
>>
>>>I think Christoph already looked at that. And HPET doesn't provide mmap
>>>functionality, does it? I.e. allow a userspace program to dereference
>>>the counter register directly?
>>>
>>>
>>It can do but that assumes nothing else is mapped into the same page
>>that would be harmful or reveal information that should not be revealed
>>etc..
>>
>>
>
>And what about the register layout? mmtimer makes sure that the register is
>on a page by itself before it allows the mmap, and only exports the counter
>register itself. Can hpet do that?
>
>Jesse
>
>
>
The hpet driver checks that the mapping is page aligned. It's up to the
platform to provide this alignment. It's also dependent on the platform
for what resides in the page. Also the configured page size could
impact what is within the page.
On Thu, Sep 16, 2004 at 09:09:12AM -0700, Jesse Barnes wrote:
> On Thursday, September 16, 2004 9:03 am, Bjorn Helgaas wrote:
> > Christoph Lameter wrote:
> > > The timer hardware was designed around the multimedia timer specification
> > > by Intel but to my knowledge only SGI has implemented that standard. The
> > > driver was written by Jesse Barnes.
> >
> > As far as I can see, drivers/char/hpet.c talks to the same hardware.
> > HP sx1000 machines (and probably others) also implement the HPET.
>
> No, it's different hardware.
mmtimer and hpet are the same hardware actually, just a different
specification revision, hpet being the newer one.
> > I think you should look at adding your functionality to hpet.c
> > rather than adding a new driver.
>
> I think Christoph already looked at that. And HPET doesn't provide mmap
> functionality, does it? I.e. allow a userspace program to dereference the
> counter register directly?
HPET registers are MMIO so it's in theory possible, while not really
useful if you're using it as your system timer as well.
--
Vojtech Pavlik
SuSE Labs, SuSE CR
On Thu, Sep 16, 2004 at 10:54:51AM -0600, Bjorn Helgaas wrote:
> On Thursday 16 September 2004 10:32 am, Christoph Lameter wrote:
> > On Thu, 16 Sep 2004, Bjorn Helgaas wrote:
> > > Christoph Lameter wrote:
> > > > The timer hardware was designed around the multimedia timer specification by Intel
> > > > but to my knowledge only SGI has implemented that standard. The driver was written
> > > > by Jesse Barnes.
> > >
> > > As far as I can see, drivers/char/hpet.c talks to the same hardware.
> > > HP sx1000 machines (and probably others) also implement the HPET.
> >
> > The Intel Multimedia Standard is a earlier and different timer spec.
>
> I have a spec that's labelled "IA-PC Multimedia Timers", preliminary
> draft of June 2000, revision 0.97, which looks like the one mentioned
> in your patch.
>
> I also have something labelled "IA-PC HPET (High Precision Event
> Timers) Specification", draft of February 2002, revision 0.98,
> which is what drivers/char/hpet.c supports.
>
> I admit I haven't compared them in great detail, but they certainly
> *look* like they're close enough that the same driver could support
> both, and the 0.98 revision history only mentions fairly cosmetic
> changes (like the name :)).
Indeed, I coded the x86-64 HPET support using the 0.97 spec, and then
only did a few minor fixups when I got the 0.98 spec.
> Is there something specific that drivers/char/hpet.c expects that
> your hardware doesn't implement?
> -
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
--
Vojtech Pavlik
SuSE Labs, SuSE CR
On Thursday, September 16, 2004 11:17 am, Robert Picco wrote:
> The hpet driver checks that the mapping is page aligned. It's up to the
> platform to provide this alignment. It's also dependent on the platform
> for what resides in the page. Also the configured page size could
> impact what is within the page.
Right, mmtimer has the same checks. I'll leave it up to Christoph. I haven't
looked at the hpet driver at all, so I'm not sure if it's appropriate.
Jesse
On Thursday, September 16, 2004 11:14 am, Vojtech Pavlik wrote:
> On Thu, Sep 16, 2004 at 09:09:12AM -0700, Jesse Barnes wrote:
> > On Thursday, September 16, 2004 9:03 am, Bjorn Helgaas wrote:
> > > Christoph Lameter wrote:
> > > > The timer hardware was designed around the multimedia timer
> > > > specification by Intel but to my knowledge only SGI has implemented
> > > > that standard. The driver was written by Jesse Barnes.
> > >
> > > As far as I can see, drivers/char/hpet.c talks to the same hardware.
> > > HP sx1000 machines (and probably others) also implement the HPET.
> >
> > No, it's different hardware.
>
> mmtimer and hpet are the same hardware actually, just a different
> specification revision, hpet being the newer one.
Well, the SHub RTC hardware (which mmtimer accesses) isn't really HPET or
mmtimer hardware, but I tried to make the mmtimer *API* useful for HPET style
hardware. The idea was to have several drivers supporting the mmtimer API
with different hardware underneath.
> HPET registers are MMIO so it's in theory possible, while not really
> useful if you're using it as your system timer as well.
I don't think anyone does this.
Jesse
On Thu, 16 Sep 2004, Vojtech Pavlik wrote:
> mmtimer and hpet are the same hardware actually, just a different
> specification revision, hpet being the newer one.
Its basically the same software API but different hardware. But
I would actually welcome a driver integration. If you would be willing to
let me wedge the mmtimer specifics into the hpet.c driver ;-). I would
insist though that the way mmtimer maps its timer to userspace
be also supported by the hpet driver and that you will not insist on
preserving the current memory layout of the userspace mapping for hpet.
The rest of the API could be shared to large extend.
On Thu, 16 Sep 2004, Robert Picco wrote:
> >Is there something specific that drivers/char/hpet.c expects that
> >your hardware doesn't implement?
> Look at HPET revision history. Specifically 0.98 01/20/2002
> * Product name changed: from Multimedia Timer to HPET (High
> Precision Event Timer)
The HPET timer has a specific memory layout of registers that is mappable
to user space. The mmtimer driver only allows the mapping of a single 64
bit counter to use space. We have lots of applications at SGI
that rely on mmtimer since mmtimer provides a locally accessible
clock in an NUMA environment with hundreds of CPU. A hpet device would
have to show up in the global address space and require cross node
accesses in our NUMA environment that would make access to the timer
slow. All CPU would content for access to a certain global memory address.
The HPET hardware and the sgi mmtimer are totally different architectures
that are not easily reconcilable.
The software API to handle both is similar and we would like it to be as
compatible as possible.
On Thu, Sep 16, 2004 at 11:35:52AM -0700, Jesse Barnes wrote:
> On Thursday, September 16, 2004 11:14 am, Vojtech Pavlik wrote:
> > On Thu, Sep 16, 2004 at 09:09:12AM -0700, Jesse Barnes wrote:
> > > On Thursday, September 16, 2004 9:03 am, Bjorn Helgaas wrote:
> > > > Christoph Lameter wrote:
> > > > > The timer hardware was designed around the multimedia timer
> > > > > specification by Intel but to my knowledge only SGI has implemented
> > > > > that standard. The driver was written by Jesse Barnes.
> > > >
> > > > As far as I can see, drivers/char/hpet.c talks to the same hardware.
> > > > HP sx1000 machines (and probably others) also implement the HPET.
> > >
> > > No, it's different hardware.
> >
> > mmtimer and hpet are the same hardware actually, just a different
> > specification revision, hpet being the newer one.
>
> Well, the SHub RTC hardware (which mmtimer accesses) isn't really HPET or
> mmtimer hardware, but I tried to make the mmtimer *API* useful for HPET style
> hardware. The idea was to have several drivers supporting the mmtimer API
> with different hardware underneath.
Sorry, I got confused by the driver name.
> > HPET registers are MMIO so it's in theory possible, while not really
> > useful if you're using it as your system timer as well.
>
> I don't think anyone does this.
x86-64 does if SMP is enabled and HPET is present.
--
Vojtech Pavlik
SuSE Labs, SuSE CR
Christoph Lameter wrote:
>On Thu, 16 Sep 2004, Robert Picco wrote:
>
>
>
>>>Is there something specific that drivers/char/hpet.c expects that
>>>your hardware doesn't implement?
>>>
>>>
>>Look at HPET revision history. Specifically 0.98 01/20/2002
>> * Product name changed: from Multimedia Timer to HPET (High
>>Precision Event Timer)
>>
>>
>
>The HPET timer has a specific memory layout of registers that is mappable
>to user space. The mmtimer driver only allows the mapping of a single 64
>bit counter to use space. We have lots of applications at SGI
>that rely on mmtimer since mmtimer provides a locally accessible
>clock in an NUMA environment with hundreds of CPU. A hpet device would
>have to show up in the global address space and require cross node
>accesses in our NUMA environment that would make access to the timer
>slow. All CPU would content for access to a certain global memory address.
>
>The HPET hardware and the sgi mmtimer are totally different architectures
>that are not easily reconcilable.
>
>The software API to handle both is similar and we would like it to be as
>compatible as possible.
>
>-
>To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
>the body of a message to [email protected]
>More majordomo info at http://vger.kernel.org/majordomo-info.html
>Please read the FAQ at http://www.tux.org/lkml/
>
>
>
Ah. Well this might be possible. The HP HPET hardware is on each NUMA
node. So cross node issues could be addressed. The bit counter isn't an
open point for the HPET driver. Only the HPET timers which march
against the bit counter can be opened. The current open logic in the
driver hunts to find an available timer. To coexist with mmtimer and
just enabling the mmaping of the bit counter would require changing the
driver API. The other API issues are resolvable with little effort. I
think ;-)
Bob
On Thursday 16 September 2004 12:46 pm, Christoph Lameter wrote:
> On Thu, 16 Sep 2004, Vojtech Pavlik wrote:
> > mmtimer and hpet are the same hardware actually, just a different
> > specification revision, hpet being the newer one.
>
> Its basically the same software API but different hardware.
OK, I guess I'm convinced that the SGI mmtimer and the HPET
really are different things. It looks like the counter resolution,
frequency, and size (which are all described in the HPET register
set) are either compiled into mmtimer or discovered via special-
purpose SGI hooks.
So maybe it's not really a good thing to integrate mmtimer and
hpet. Apps that mmap the HPET will be expecting a certain register
layout that mmtimer doesn't support.
I was confused because your mmtimer patch mentions the Intel
spec, and the driver identifies itself as "IA-PC Multimedia Timer".
My vote would be to leave mmtimer alone, and perhaps remove the
references to the Intel spec and change the driver ident string.
After all, it doesn't really implement very much of the HPET
functionality, and I don't think the Intel spec says anything
that relates to the SGI hardware.