Index: linux-2.6.9/drivers/char/mmtimer.c =================================================================== --- linux-2.6.9.orig/drivers/char/mmtimer.c 2004-11-02 14:47:36.000000000 -0800 +++ linux-2.6.9/drivers/char/mmtimer.c 2004-11-02 15:04:15.000000000 -0800 @@ -13,6 +13,9 @@ * * 11/01/01 - jbarnes - initial revision * 9/10/04 - Christoph Lameter - remove interrupt support for kernel inclusion + * 10/1/04 - Christoph Lameter - provide posix clock CLOCK_SGI_CYCLE + * 10/13/04 - Christoph Lameter, Dimitri Sivanich - provide timer interrupt support + * via the posix timer interface */ #include @@ -26,23 +29,39 @@ #include #include #include +#include #include #include -#include +#include #include +#include + +/* This is ugly and needs to be fixed */ +#include "../../arch/ia64/sn/include/shubio.h" MODULE_AUTHOR("Jesse Barnes "); -MODULE_DESCRIPTION("Multimedia timer support"); +MODULE_DESCRIPTION("SGI Altix RTC Timer"); MODULE_LICENSE("GPL"); /* name of the device, usually in /dev */ #define MMTIMER_NAME "mmtimer" -#define MMTIMER_DESC "IA-PC Multimedia Timer" -#define MMTIMER_VERSION "1.0" +#define MMTIMER_DESC "SGI Altix RTC Timer" +#define MMTIMER_VERSION "2.0" #define RTC_BITS 55 /* 55 bits for this implementation */ +/* Mininum RTC cycles for interrupt intervals */ +#define MIN_RTC_INTERVAL 50 +/* Max time needed to enable interrupts and set up the comparator */ +#define GUARD_CYCLES 500 + +extern unsigned long sn_rtc_cycles_per_second; + +#define RTC_COUNTER_ADDR ((long *)LOCAL_MMR_ADDR(SH_RTC)) + +#define rtc_time() (*RTC_COUNTER_ADDR) + 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); @@ -58,6 +77,179 @@ .ioctl = mmtimer_ioctl, }; +/* + * Comparators and their associated info. Shub has + * three comparison registers. + */ + +/* + * We only have comparison registers RTC1-4 currently available per + * node. RTC0 is used by SAL. + */ +#define NUM_COMPARATORS 3 +/* + * Check for an interrupt and clear the pending bit if + * one is waiting. +*/ +static int inline mmtimer_int_pending(int comparator) { + int pending = 0; + + switch (comparator) { + case 0: + if (HUB_L((unsigned long *)LOCAL_MMR_ADDR(SH_EVENT_OCCURRED)) & + SH_EVENT_OCCURRED_RTC1_INT_MASK) { + HUB_S((u64 *)LOCAL_MMR_ADDR(SH_EVENT_OCCURRED_ALIAS), + SH_EVENT_OCCURRED_RTC1_INT_MASK); + pending = 1; + } + break; + case 1: + if (HUB_L((unsigned long *)LOCAL_MMR_ADDR(SH_EVENT_OCCURRED)) & + SH_EVENT_OCCURRED_RTC2_INT_MASK) { + HUB_S((u64 *)LOCAL_MMR_ADDR(SH_EVENT_OCCURRED_ALIAS), + SH_EVENT_OCCURRED_RTC2_INT_MASK); + pending = 1; + } + break; + case 2: + if (HUB_L((unsigned long *)LOCAL_MMR_ADDR(SH_EVENT_OCCURRED)) & + SH_EVENT_OCCURRED_RTC3_INT_MASK) { + HUB_S((u64 *)LOCAL_MMR_ADDR(SH_EVENT_OCCURRED_ALIAS), + SH_EVENT_OCCURRED_RTC3_INT_MASK); + pending = 1; + } + break; + default: + return -EFAULT; + } + return pending; +} + +static void inline mmtimer_setup_int_0(void) { + u64 val; + + /* Disable interrupt */ + HUB_S((u64 *)LOCAL_MMR_ADDR(SH_RTC1_INT_ENABLE), 0UL); + + HUB_S((u64 *)LOCAL_MMR_ADDR(SH_EVENT_OCCURRED_ALIAS), + SH_EVENT_OCCURRED_RTC1_INT_MASK); + + val = ((u64)SGI_MMTIMER_VECTOR << SH_RTC1_INT_CONFIG_IDX_SHFT) | + ((u64)cpu_physical_id(smp_processor_id()) << + SH_RTC1_INT_CONFIG_PID_SHFT); + + /* Set configuration */ + HUB_S((u64 *)LOCAL_MMR_ADDR(SH_RTC1_INT_CONFIG), val); + + /* Initialize comparator value to highest value */ + HUB_S((u64 *)LOCAL_MMR_ADDR(SH_INT_CMPB), -1L); + + /* Enable RTC interrupts */ + HUB_S((u64 *)LOCAL_MMR_ADDR(SH_RTC1_INT_ENABLE), 1UL); + +} + +static void inline mmtimer_setup_int_1(void) { + u64 val; + + HUB_S((u64 *)LOCAL_MMR_ADDR(SH_RTC2_INT_ENABLE), 0UL); + + HUB_S((u64 *)LOCAL_MMR_ADDR(SH_EVENT_OCCURRED_ALIAS), + SH_EVENT_OCCURRED_RTC2_INT_MASK); + + val = ((u64)SGI_MMTIMER_VECTOR << SH_RTC2_INT_CONFIG_IDX_SHFT) | + ((u64)cpu_physical_id(smp_processor_id()) << + SH_RTC2_INT_CONFIG_PID_SHFT); + + HUB_S((u64 *)LOCAL_MMR_ADDR(SH_RTC2_INT_CONFIG), val); + + HUB_S((u64 *)LOCAL_MMR_ADDR(SH_INT_CMPC), -1L); + + HUB_S((u64 *)LOCAL_MMR_ADDR(SH_RTC2_INT_ENABLE), 1UL); +} + +static void inline mmtimer_setup_int_2(void) { + u64 val; + + HUB_S((u64 *)LOCAL_MMR_ADDR(SH_RTC3_INT_ENABLE), 0UL); + + HUB_S((u64 *)LOCAL_MMR_ADDR(SH_EVENT_OCCURRED_ALIAS), + SH_EVENT_OCCURRED_RTC3_INT_MASK); + + val = ((u64)SGI_MMTIMER_VECTOR << SH_RTC3_INT_CONFIG_IDX_SHFT) | + ((u64)cpu_physical_id(smp_processor_id()) << + SH_RTC3_INT_CONFIG_PID_SHFT); + + HUB_S((u64 *)LOCAL_MMR_ADDR(SH_RTC3_INT_CONFIG), val); + + HUB_S((u64 *)LOCAL_MMR_ADDR(SH_INT_CMPD), -1L); + + HUB_S((u64 *)LOCAL_MMR_ADDR(SH_RTC3_INT_ENABLE), 1UL); +} + +/* + * This function must be called with interrupts disabled and preemption off + * in order to insure that the setup succeeds in a deterministic time frame + * given by GUARD_CYCLES. The function checks that the expiration time + * given is not too early and will return an error and not set up + * an interrupt if the expiration is too early. + */ +static int inline mmtimer_setup(int comparator, unsigned long expires) { + + if (unlikely(rtc_time() + GUARD_CYCLES > expires)) + return 1; + + switch (comparator) { + case 0: + mmtimer_setup_int_0(); + HUB_S((u64 *)LOCAL_MMR_ADDR(SH_INT_CMPB), expires); + break; + case 1: + mmtimer_setup_int_1(); + HUB_S((u64 *)LOCAL_MMR_ADDR(SH_INT_CMPC), expires); + break; + case 2: + mmtimer_setup_int_2(); + HUB_S((u64 *)LOCAL_MMR_ADDR(SH_INT_CMPD), expires); + break; + } + + return 0; +} + +static int inline mmtimer_disable_int(long nasid, int comparator) { + switch (comparator) { + case 0: + nasid == -1 ? HUB_S((u64 *)LOCAL_MMR_ADDR(SH_RTC1_INT_ENABLE), + 0UL) : REMOTE_HUB_S(nasid, SH_RTC1_INT_ENABLE, 0UL); + break; + case 1: + nasid == -1 ? HUB_S((u64 *)LOCAL_MMR_ADDR(SH_RTC2_INT_ENABLE), + 0UL) : REMOTE_HUB_S(nasid, SH_RTC2_INT_ENABLE, 0UL); + break; + case 2: + nasid == -1 ? HUB_S((u64 *)LOCAL_MMR_ADDR(SH_RTC3_INT_ENABLE), + 0UL) : REMOTE_HUB_S(nasid, SH_RTC3_INT_ENABLE, 0UL); + break; + default: + return -EFAULT; + } + return 0; +} + +#define TIMER_OFF 0xbadcabLL + +/* There is one of these for each comparator */ +typedef struct mmtimer { + spinlock_t lock ____cacheline_aligned; + struct k_itimer *timer; +} mmtimer_t; + +/* + * Total number of comparators is comparators/node * MAX nodes/running kernel + */ +static mmtimer_t timers[NUM_COMPARATORS*MAX_COMPACT_NODES]; + /** * mmtimer_ioctl - ioctl interface for /dev/mmtimer * @inode: inode of the device @@ -183,10 +375,19 @@ static struct timespec sgi_clock_offset; static int sgi_clock_period; +/***** + * Posix Timer Interface + * The posix timer interface provides full support for the posix clock + * interface and allows the scheduling of up to three timers. + */ + +static struct timespec sgi_clock_offset; +static int sgi_clock_period; + static int sgi_clock_get(struct timespec *tp) { u64 nsec; - nsec = readq(RTC_COUNTER_ADDR) * sgi_clock_period + nsec = rtc_time() * sgi_clock_period + sgi_clock_offset.tv_nsec; tp->tv_sec = div_long_long_rem(nsec, NSEC_PER_SEC, &tp->tv_nsec) + sgi_clock_offset.tv_sec; @@ -194,12 +395,12 @@ }; static int sgi_clock_set(struct timespec *tp) { - + u64 nsec; u64 rem; - nsec = readq(RTC_COUNTER_ADDR) * sgi_clock_period; - + nsec = rtc_time() * sgi_clock_period; + sgi_clock_offset.tv_sec = tp->tv_sec - div_long_long_rem(nsec, NSEC_PER_SEC, &rem); if (rem <= tp->tv_nsec) @@ -211,12 +412,233 @@ return 0; } +/** + * 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. + * + * This interrupt is run in an interrupt context + * by the SHUB. It is therefore safe to locally access SHub + * registers. + */ +static irqreturn_t +mmtimer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + int i; + mmtimer_t *base = timers + cpuid_to_cnodeid(smp_processor_id()) * NUM_COMPARATORS; + int result = IRQ_NONE; + + /* + * Do this once for each comparison register + */ + for (i = 0; i < NUM_COMPARATORS; i++) { + unsigned long flags; + + if (mmtimer_int_pending(i) > 0) { + struct k_itimer *t; + int m = 0; + + mmtimer_disable_int(-1, i); + spin_lock(&base[i].lock); + t = base[i].timer; + base[i].timer = NULL; + if (t) { + m = t->it_timer.magic; + t->it_timer.magic = TIMER_OFF; + } + spin_unlock(&base[i].lock); + + if (t == NULL || m == TIMER_OFF) + /* No timer left here, bail out */ + goto out; + + spin_lock_irqsave(&t->it_lock, flags); + + if (posix_timer_event(t, 0) == 0) { + + if(t->it_incr) { + + /* Periodic timer */ + spin_lock(&base[i].lock); + if (base[i].timer == NULL) { + t->it_timer.expires += t->it_incr; + t->it_timer.magic = i; + base[i].timer = t; + + while (mmtimer_setup(i, t->it_timer.expires)) { + t->it_timer.expires += t->it_incr; + t->it_overrun++; + } + } + spin_unlock(&base[i].lock); + } + + } else { + + printk(KERN_WARNING "mmtimer unable to deliver signal"); + t->it_overrun++; + } + + spin_unlock_irqrestore(&t->it_lock, flags); +out: + result = IRQ_HANDLED; + } + } + return result; +} + +static int sgi_timer_create(struct k_itimer *timer) { + /* Insure that a newly created timer is off */ + timer->it_timer.magic = TIMER_OFF; + return 0; +} + +/* This does not really delete a timer. It just insures + * that the timer is not active + * + * Assumption: it_lock is already held with irq's disabled + */ +static int sgi_timer_del(struct k_itimer *timr) { + int i = timr->it_timer.magic; + cnodeid_t nodeid = timr->it_timer.data; + mmtimer_t *t = timers + nodeid * NUM_COMPARATORS +i; + unsigned long irqflags; + + if (i != TIMER_OFF) { + spin_lock_irqsave(&t->lock, irqflags); + mmtimer_disable_int(cnodeid_to_nasid(nodeid),i); + t->timer = NULL; + timr->it_timer.magic = TIMER_OFF; + spin_unlock_irqrestore(&t->lock, irqflags); + } + return 0; +} + +#define timespec_to_ns(x) ((x).tv_nsec + (x).tv_sec * NSEC_PER_SEC) +#define ns_to_timespec(ts, nsec) (ts).tv_sec = div_long_long_rem(nsec, NSEC_PER_SEC, &(ts).tv_nsec) + +/* Assumption: it_lock is already held with irq's disabled */ +static void sgi_timer_get(struct k_itimer *timr, struct itimerspec *cur_setting) { + + if (timr->it_timer.magic == TIMER_OFF) { + cur_setting->it_interval.tv_nsec = 0; + cur_setting->it_interval.tv_sec = 0; + cur_setting->it_value.tv_nsec = 0; + cur_setting->it_value.tv_sec =0; + return; + } + + ns_to_timespec(cur_setting->it_interval, timr->it_incr * sgi_clock_period); + ns_to_timespec(cur_setting->it_value, (timr->it_timer.expires - rtc_time())* sgi_clock_period); + return; +} + + +static int sgi_timer_set(struct k_itimer *timr, int flags, + struct itimerspec * new_setting, + struct itimerspec * old_setting) { + + int i; + unsigned long when, period, irqflags; + int err = 0; + cnodeid_t nodeid; + mmtimer_t *base; + + if (old_setting) + sgi_timer_get(timr, old_setting); + + sgi_timer_del(timr); + when = timespec_to_ns(new_setting->it_value); + period = timespec_to_ns(new_setting->it_interval); + + if (when == 0) + /* Clear timer */ + return 0; + + if (flags & TIMER_ABSTIME) { + struct timespec n; + + getnstimeofday(&n); + when -= timespec_to_ns(n); + } + + /* + * Convert to sgi clock period. Need to keep rtc_time() as near as possible + * to getnstimeofday() in order to be as faithful as possible to the time + * specified. + */ + when = when / sgi_clock_period + rtc_time(); + period = period / sgi_clock_period; + + if (period && period < MIN_RTC_INTERVAL) + return -EINVAL; + + /* + * We are allocating a local SHub comparator. If we would be moved to another + * cpu then another SHub may be local to us. Prohibit that by switching off + * preemption. + */ + preempt_disable(); + + nodeid = cpuid_to_cnodeid(smp_processor_id()); + base = timers + nodeid * NUM_COMPARATORS; +retry: + for(i = 0; i< NUM_COMPARATORS; i++) { + if (!base[i].timer) { + break; + } + } + + if (i == NUM_COMPARATORS) { + preempt_enable(); + return -EBUSY; + } + + spin_lock_irqsave(&base[i].lock, irqflags); + + if (base[i].timer) { + spin_unlock_irqrestore(&base[i].lock, irqflags); + goto retry; + } + base[i].timer = timr; + + timr->it_timer.magic = i; + timr->it_timer.data = nodeid; + timr->it_incr = period; + + while (mmtimer_setup(i, when)) { + if (period) { + when += period; + timr->it_overrun++; + } else { + posix_timer_event(timr, 0); + goto out; + } + } + timr->it_timer.expires = when; + +out: + spin_unlock_irqrestore(&base[i].lock, irqflags); + + preempt_enable(); + + return err; +} + static struct k_clock sgi_clock = { .res = 0, .clock_set = sgi_clock_set, .clock_get = sgi_clock_get, - .timer_create = do_posix_clock_notimer_create, - .nsleep = do_posix_clock_nonanosleep + .timer_create = sgi_timer_create, + .nsleep = do_posix_clock_nonanosleep, + .timer_set = sgi_timer_set, + .timer_del = sgi_timer_del, + .timer_get = sgi_timer_get }; /** @@ -226,6 +648,8 @@ */ static int __init mmtimer_init(void) { + unsigned i; + if (!ia64_platform_is("sn2")) return -1; @@ -241,6 +665,17 @@ mmtimer_femtoperiod = ((unsigned long)1E15 + sn_rtc_cycles_per_second / 2) / sn_rtc_cycles_per_second; + for (i=0; i< NUM_COMPARATORS*MAX_COMPACT_NODES; i++) { + spin_lock_init(&timers[i].lock); + timers[i].timer = NULL; + } + + if (request_irq(SGI_MMTIMER_VECTOR, mmtimer_interrupt, SA_PERCPU_IRQ, MMTIMER_NAME, NULL)) { + printk(KERN_WARNING "%s: unable to allocate interrupt.", + MMTIMER_NAME); + return -1; + } + strcpy(mmtimer_miscdev.devfs_name, MMTIMER_NAME); if (misc_register(&mmtimer_miscdev)) { printk(KERN_ERR "%s: failed to register device\n", Index: linux-2.6.9/include/asm/sn/intr.h =================================================================== --- linux-2.6.9.orig/include/asm/sn/intr.h 2004-11-02 14:47:37.000000000 -0800 +++ linux-2.6.9/include/asm/sn/intr.h 2004-11-02 14:49:54.000000000 -0800 @@ -18,6 +18,7 @@ #define SGI_XBOW_ERROR (0x32) #define SGI_PCIBR_ERROR (0x33) #define SGI_ACPI_SCI_INT (0x34) +#define SGI_MMTIMER_VECTOR (0x35) #define SGI_TIO_ERROR (0x36) #define SGI_XPC_NOTIFY (0xe7) Index: linux-2.6.9/include/asm-ia64/sn/shub_mmr.h =================================================================== --- linux-2.6.9.orig/include/asm-ia64/sn/shub_mmr.h 2004-10-29 09:15:58.000000000 -0700 +++ linux-2.6.9/include/asm-ia64/sn/shub_mmr.h 2004-11-02 14:49:54.000000000 -0800 @@ -196,4 +196,209 @@ #define SH_PTC_1_START_SHFT 63 #define SH_PTC_1_START_MASK 0x8000000000000000 +/* + * Register definitions + */ + +/* ==================================================================== */ +/* Register "SH_RTC1_INT_CONFIG" */ +/* SHub RTC 1 Interrupt Config Registers */ +/* ==================================================================== */ + +#define SH_RTC1_INT_CONFIG 0x0000000110001480 +#define SH_RTC1_INT_CONFIG_MASK 0x0ff3ffffffefffff +#define SH_RTC1_INT_CONFIG_INIT 0x0000000000000000 + +/* SH_RTC1_INT_CONFIG_TYPE */ +/* Description: Type of Interrupt: 0=INT, 2=PMI, 4=NMI, 5=INIT */ +#define SH_RTC1_INT_CONFIG_TYPE_SHFT 0 +#define SH_RTC1_INT_CONFIG_TYPE_MASK 0x0000000000000007 + +/* SH_RTC1_INT_CONFIG_AGT */ +/* Description: Agent, must be 0 for SHub */ +#define SH_RTC1_INT_CONFIG_AGT_SHFT 3 +#define SH_RTC1_INT_CONFIG_AGT_MASK 0x0000000000000008 + +/* SH_RTC1_INT_CONFIG_PID */ +/* Description: Processor ID, same setting as on targeted McKinley */ +#define SH_RTC1_INT_CONFIG_PID_SHFT 4 +#define SH_RTC1_INT_CONFIG_PID_MASK 0x00000000000ffff0 + +/* SH_RTC1_INT_CONFIG_BASE */ +/* Description: Optional interrupt vector area, 2MB aligned */ +#define SH_RTC1_INT_CONFIG_BASE_SHFT 21 +#define SH_RTC1_INT_CONFIG_BASE_MASK 0x0003ffffffe00000 + +/* SH_RTC1_INT_CONFIG_IDX */ +/* Description: Targeted McKinley interrupt vector */ +#define SH_RTC1_INT_CONFIG_IDX_SHFT 52 +#define SH_RTC1_INT_CONFIG_IDX_MASK 0x0ff0000000000000 + +/* ==================================================================== */ +/* Register "SH_RTC1_INT_ENABLE" */ +/* SHub RTC 1 Interrupt Enable Registers */ +/* ==================================================================== */ + +#define SH_RTC1_INT_ENABLE 0x0000000110001500 +#define SH_RTC1_INT_ENABLE_MASK 0x0000000000000001 +#define SH_RTC1_INT_ENABLE_INIT 0x0000000000000000 + +/* SH_RTC1_INT_ENABLE_RTC1_ENABLE */ +/* Description: Enable RTC 1 Interrupt */ +#define SH_RTC1_INT_ENABLE_RTC1_ENABLE_SHFT 0 +#define SH_RTC1_INT_ENABLE_RTC1_ENABLE_MASK 0x0000000000000001 + +/* ==================================================================== */ +/* Register "SH_RTC2_INT_CONFIG" */ +/* SHub RTC 2 Interrupt Config Registers */ +/* ==================================================================== */ + +#define SH_RTC2_INT_CONFIG 0x0000000110001580 +#define SH_RTC2_INT_CONFIG_MASK 0x0ff3ffffffefffff +#define SH_RTC2_INT_CONFIG_INIT 0x0000000000000000 + +/* SH_RTC2_INT_CONFIG_TYPE */ +/* Description: Type of Interrupt: 0=INT, 2=PMI, 4=NMI, 5=INIT */ +#define SH_RTC2_INT_CONFIG_TYPE_SHFT 0 +#define SH_RTC2_INT_CONFIG_TYPE_MASK 0x0000000000000007 + +/* SH_RTC2_INT_CONFIG_AGT */ +/* Description: Agent, must be 0 for SHub */ +#define SH_RTC2_INT_CONFIG_AGT_SHFT 3 +#define SH_RTC2_INT_CONFIG_AGT_MASK 0x0000000000000008 + +/* SH_RTC2_INT_CONFIG_PID */ +/* Description: Processor ID, same setting as on targeted McKinley */ +#define SH_RTC2_INT_CONFIG_PID_SHFT 4 +#define SH_RTC2_INT_CONFIG_PID_MASK 0x00000000000ffff0 + +/* SH_RTC2_INT_CONFIG_BASE */ +/* Description: Optional interrupt vector area, 2MB aligned */ +#define SH_RTC2_INT_CONFIG_BASE_SHFT 21 +#define SH_RTC2_INT_CONFIG_BASE_MASK 0x0003ffffffe00000 + +/* SH_RTC2_INT_CONFIG_IDX */ +/* Description: Targeted McKinley interrupt vector */ +#define SH_RTC2_INT_CONFIG_IDX_SHFT 52 +#define SH_RTC2_INT_CONFIG_IDX_MASK 0x0ff0000000000000 + +/* ==================================================================== */ +/* Register "SH_RTC2_INT_ENABLE" */ +/* SHub RTC 2 Interrupt Enable Registers */ +/* ==================================================================== */ + +#define SH_RTC2_INT_ENABLE 0x0000000110001600 +#define SH_RTC2_INT_ENABLE_MASK 0x0000000000000001 +#define SH_RTC2_INT_ENABLE_INIT 0x0000000000000000 + +/* SH_RTC2_INT_ENABLE_RTC2_ENABLE */ +/* Description: Enable RTC 2 Interrupt */ +#define SH_RTC2_INT_ENABLE_RTC2_ENABLE_SHFT 0 +#define SH_RTC2_INT_ENABLE_RTC2_ENABLE_MASK 0x0000000000000001 + +/* ==================================================================== */ +/* Register "SH_RTC3_INT_CONFIG" */ +/* SHub RTC 3 Interrupt Config Registers */ +/* ==================================================================== */ + +#define SH_RTC3_INT_CONFIG 0x0000000110001680 +#define SH_RTC3_INT_CONFIG_MASK 0x0ff3ffffffefffff +#define SH_RTC3_INT_CONFIG_INIT 0x0000000000000000 + +/* SH_RTC3_INT_CONFIG_TYPE */ +/* Description: Type of Interrupt: 0=INT, 2=PMI, 4=NMI, 5=INIT */ +#define SH_RTC3_INT_CONFIG_TYPE_SHFT 0 +#define SH_RTC3_INT_CONFIG_TYPE_MASK 0x0000000000000007 + +/* SH_RTC3_INT_CONFIG_AGT */ +/* Description: Agent, must be 0 for SHub */ +#define SH_RTC3_INT_CONFIG_AGT_SHFT 3 +#define SH_RTC3_INT_CONFIG_AGT_MASK 0x0000000000000008 + +/* SH_RTC3_INT_CONFIG_PID */ +/* Description: Processor ID, same setting as on targeted McKinley */ +#define SH_RTC3_INT_CONFIG_PID_SHFT 4 +#define SH_RTC3_INT_CONFIG_PID_MASK 0x00000000000ffff0 + +/* SH_RTC3_INT_CONFIG_BASE */ +/* Description: Optional interrupt vector area, 2MB aligned */ +#define SH_RTC3_INT_CONFIG_BASE_SHFT 21 +#define SH_RTC3_INT_CONFIG_BASE_MASK 0x0003ffffffe00000 + +/* SH_RTC3_INT_CONFIG_IDX */ +/* Description: Targeted McKinley interrupt vector */ +#define SH_RTC3_INT_CONFIG_IDX_SHFT 52 +#define SH_RTC3_INT_CONFIG_IDX_MASK 0x0ff0000000000000 + +/* ==================================================================== */ +/* Register "SH_RTC3_INT_ENABLE" */ +/* SHub RTC 3 Interrupt Enable Registers */ +/* ==================================================================== */ + +#define SH_RTC3_INT_ENABLE 0x0000000110001700 +#define SH_RTC3_INT_ENABLE_MASK 0x0000000000000001 +#define SH_RTC3_INT_ENABLE_INIT 0x0000000000000000 + +/* SH_RTC3_INT_ENABLE_RTC3_ENABLE */ +/* Description: Enable RTC 3 Interrupt */ +#define SH_RTC3_INT_ENABLE_RTC3_ENABLE_SHFT 0 +#define SH_RTC3_INT_ENABLE_RTC3_ENABLE_MASK 0x0000000000000001 + +/* SH_EVENT_OCCURRED_RTC1_INT */ +/* Description: Pending RTC 1 Interrupt */ +#define SH_EVENT_OCCURRED_RTC1_INT_SHFT 24 +#define SH_EVENT_OCCURRED_RTC1_INT_MASK 0x0000000001000000 + +/* SH_EVENT_OCCURRED_RTC2_INT */ +/* Description: Pending RTC 2 Interrupt */ +#define SH_EVENT_OCCURRED_RTC2_INT_SHFT 25 +#define SH_EVENT_OCCURRED_RTC2_INT_MASK 0x0000000002000000 + +/* SH_EVENT_OCCURRED_RTC3_INT */ +/* Description: Pending RTC 3 Interrupt */ +#define SH_EVENT_OCCURRED_RTC3_INT_SHFT 26 +#define SH_EVENT_OCCURRED_RTC3_INT_MASK 0x0000000004000000 + +/* ==================================================================== */ +/* Register "SH_INT_CMPB" */ +/* RTC Compare Value for Processor B */ +/* ==================================================================== */ + +#define SH_INT_CMPB 0x00000001101b0080 +#define SH_INT_CMPB_MASK 0x007fffffffffffff +#define SH_INT_CMPB_INIT 0x0000000000000000 + +/* SH_INT_CMPB_REAL_TIME_CMPB */ +/* Description: Real Time Clock Compare */ +#define SH_INT_CMPB_REAL_TIME_CMPB_SHFT 0 +#define SH_INT_CMPB_REAL_TIME_CMPB_MASK 0x007fffffffffffff + +/* ==================================================================== */ +/* Register "SH_INT_CMPC" */ +/* RTC Compare Value for Processor C */ +/* ==================================================================== */ + +#define SH_INT_CMPC 0x00000001101b0100 +#define SH_INT_CMPC_MASK 0x007fffffffffffff +#define SH_INT_CMPC_INIT 0x0000000000000000 + +/* SH_INT_CMPC_REAL_TIME_CMPC */ +/* Description: Real Time Clock Compare */ +#define SH_INT_CMPC_REAL_TIME_CMPC_SHFT 0 +#define SH_INT_CMPC_REAL_TIME_CMPC_MASK 0x007fffffffffffff + +/* ==================================================================== */ +/* Register "SH_INT_CMPD" */ +/* RTC Compare Value for Processor D */ +/* ==================================================================== */ + +#define SH_INT_CMPD 0x00000001101b0180 +#define SH_INT_CMPD_MASK 0x007fffffffffffff +#define SH_INT_CMPD_INIT 0x0000000000000000 + +/* SH_INT_CMPD_REAL_TIME_CMPD */ +/* Description: Real Time Clock Compare */ +#define SH_INT_CMPD_REAL_TIME_CMPD_SHFT 0 +#define SH_INT_CMPD_REAL_TIME_CMPD_MASK 0x007fffffffffffff + #endif /* _ASM_IA64_SN_SHUB_MMR_H */