/* If you trust current SCSI layer to handle different SCSI IRQs, enable this. I don't trust it... -jj */
/* #define DISTRIBUTE_IRQS */
-struct sun4d_timer_regs *sun4d_timers;
+struct sun4d_timer_regs {
+ u32 l10_timer_limit;
+ u32 l10_cur_countx;
+ u32 l10_limit_noclear;
+ u32 ctrl;
+ u32 l10_cur_count;
+};
+
+static struct sun4d_timer_regs __iomem *sun4d_timers;
+
#define TIMER_IRQ 10
#define MAX_STATIC_ALLOC 4
extern struct irqaction static_irqaction[MAX_STATIC_ALLOC];
extern int static_irq_count;
-#ifdef CONFIG_SMP
static unsigned char sbus_tid[32];
-#endif
static struct irqaction *irq_action[NR_IRQS];
extern spinlock_t irq_action_lock;
};
static int nsbi;
-#ifdef CONFIG_SMP
+
+/* Exported for sun4d_smp.c */
DEFINE_SPINLOCK(sun4d_imsk_lock);
-#endif
int show_sun4d_interrupts(struct seq_file *p, void *v)
{
static void sun4d_disable_irq(unsigned int irq)
{
-#ifdef CONFIG_SMP
int tid = sbus_tid[(irq >> 5) - 1];
unsigned long flags;
-#endif
- if (irq < NR_IRQS) return;
-#ifdef CONFIG_SMP
+ if (irq < NR_IRQS)
+ return;
+
spin_lock_irqsave(&sun4d_imsk_lock, flags);
cc_set_imsk_other(tid, cc_get_imsk_other(tid) | (1 << sbus_to_pil[(irq >> 2) & 7]));
spin_unlock_irqrestore(&sun4d_imsk_lock, flags);
-#else
- cc_set_imsk(cc_get_imsk() | (1 << sbus_to_pil[(irq >> 2) & 7]));
-#endif
}
static void sun4d_enable_irq(unsigned int irq)
{
-#ifdef CONFIG_SMP
int tid = sbus_tid[(irq >> 5) - 1];
unsigned long flags;
-#endif
- if (irq < NR_IRQS) return;
-#ifdef CONFIG_SMP
+ if (irq < NR_IRQS)
+ return;
+
spin_lock_irqsave(&sun4d_imsk_lock, flags);
cc_set_imsk_other(tid, cc_get_imsk_other(tid) & ~(1 << sbus_to_pil[(irq >> 2) & 7]));
spin_unlock_irqrestore(&sun4d_imsk_lock, flags);
-#else
- cc_set_imsk(cc_get_imsk() & ~(1 << sbus_to_pil[(irq >> 2) & 7]));
-#endif
}
#ifdef CONFIG_SMP
static void sun4d_clear_clock_irq(void)
{
- volatile unsigned int clear_intr;
- clear_intr = sun4d_timers->l10_timer_limit;
-}
-
-static void sun4d_clear_profile_irq(int cpu)
-{
- bw_get_prof_limit(cpu);
+ sbus_readl(&sun4d_timers->l10_timer_limit);
}
static void sun4d_load_profile_irq(int cpu, unsigned int limit)
bw_set_prof_limit(cpu, limit);
}
-static void __init sun4d_init_timers(irq_handler_t counter_fn)
+static void __init sun4d_load_profile_irqs(void)
{
- int irq;
- int cpu;
- struct resource r;
- int mid;
+ int cpu = 0, mid;
+
+ while (!cpu_find_by_instance(cpu, NULL, &mid)) {
+ sun4d_load_profile_irq(mid >> 3, 0);
+ cpu++;
+ }
+}
- /* Map the User Timer registers. */
- memset(&r, 0, sizeof(r));
+static void __init sun4d_fixup_trap_table(void)
+{
#ifdef CONFIG_SMP
- r.start = CSR_BASE(boot_cpu_id)+BW_TIMER_LIMIT;
-#else
- r.start = CSR_BASE(0)+BW_TIMER_LIMIT;
+ unsigned long flags;
+ extern unsigned long lvl14_save[4];
+ struct tt_entry *trap_table = &sparc_ttable[SP_TRAP_IRQ1 + (14 - 1)];
+ extern unsigned int real_irq_entry[], smp4d_ticker[];
+ extern unsigned int patchme_maybe_smp_msg[];
+
+ /* Adjust so that we jump directly to smp4d_ticker */
+ lvl14_save[2] += smp4d_ticker - real_irq_entry;
+
+ /* For SMP we use the level 14 ticker, however the bootup code
+ * has copied the firmware's level 14 vector into the boot cpu's
+ * trap table, we must fix this now or we get squashed.
+ */
+ local_irq_save(flags);
+ patchme_maybe_smp_msg[0] = 0x01000000; /* NOP out the branch */
+ trap_table->inst_one = lvl14_save[0];
+ trap_table->inst_two = lvl14_save[1];
+ trap_table->inst_three = lvl14_save[2];
+ trap_table->inst_four = lvl14_save[3];
+ local_flush_cache_all();
+ local_irq_restore(flags);
#endif
- r.flags = 0xf;
- sun4d_timers = (struct sun4d_timer_regs *) of_ioremap(&r, 0,
- PAGE_SIZE, "user timer");
+}
- sun4d_timers->l10_timer_limit = (((1000000/HZ) + 1) << 10);
- master_l10_counter = &sun4d_timers->l10_cur_count;
- master_l10_limit = &sun4d_timers->l10_timer_limit;
+static void __init sun4d_init_timers(irq_handler_t counter_fn)
+{
+ struct device_node *dp;
+ struct resource res;
+ const u32 *reg;
+ int err;
- irq = request_irq(TIMER_IRQ,
- counter_fn,
- (IRQF_DISABLED | SA_STATIC_ALLOC),
- "timer", NULL);
- if (irq) {
- prom_printf("time_init: unable to attach IRQ%d\n",TIMER_IRQ);
+ dp = of_find_node_by_name(NULL, "cpu-unit");
+ if (!dp) {
+ prom_printf("sun4d_init_timers: Unable to find cpu-unit\n");
prom_halt();
}
-
- /* Enable user timer free run for CPU 0 in BW */
- /* bw_set_ctrl(0, bw_get_ctrl(0) | BW_CTRL_USER_TIMER); */
- cpu = 0;
- while (!cpu_find_by_instance(cpu, NULL, &mid)) {
- sun4d_load_profile_irq(mid >> 3, 0);
- cpu++;
+ /* Which cpu-unit we use is arbitrary, we can view the bootbus timer
+ * registers via any cpu's mapping. The first 'reg' property is the
+ * bootbus.
+ */
+ reg = of_get_property(dp, "reg", NULL);
+ if (!reg) {
+ prom_printf("sun4d_init_timers: No reg property\n");
+ prom_halt();
}
-
-#ifdef CONFIG_SMP
- {
- unsigned long flags;
- extern unsigned long lvl14_save[4];
- struct tt_entry *trap_table = &sparc_ttable[SP_TRAP_IRQ1 + (14 - 1)];
- extern unsigned int real_irq_entry[], smp4d_ticker[];
- extern unsigned int patchme_maybe_smp_msg[];
-
- /* Adjust so that we jump directly to smp4d_ticker */
- lvl14_save[2] += smp4d_ticker - real_irq_entry;
-
- /* For SMP we use the level 14 ticker, however the bootup code
- * has copied the firmware's level 14 vector into the boot cpu's
- * trap table, we must fix this now or we get squashed.
- */
- local_irq_save(flags);
- patchme_maybe_smp_msg[0] = 0x01000000; /* NOP out the branch */
- trap_table->inst_one = lvl14_save[0];
- trap_table->inst_two = lvl14_save[1];
- trap_table->inst_three = lvl14_save[2];
- trap_table->inst_four = lvl14_save[3];
- local_flush_cache_all();
- local_irq_restore(flags);
+
+ res.start = reg[1];
+ res.end = reg[2] - 1;
+ res.flags = reg[0] & 0xff;
+ sun4d_timers = of_ioremap(&res, BW_TIMER_LIMIT,
+ sizeof(struct sun4d_timer_regs), "user timer");
+ if (!sun4d_timers) {
+ prom_printf("sun4d_init_timers: Can't map timer regs\n");
+ prom_halt();
}
-#endif
+
+ sbus_writel((((1000000/HZ) + 1) << 10), &sun4d_timers->l10_timer_limit);
+
+ master_l10_counter = &sun4d_timers->l10_cur_count;
+
+ err = request_irq(TIMER_IRQ, counter_fn,
+ (IRQF_DISABLED | SA_STATIC_ALLOC),
+ "timer", NULL);
+ if (err) {
+ prom_printf("sun4d_init_timers: request_irq() failed with %d\n", err);
+ prom_halt();
+ }
+ sun4d_load_profile_irqs();
+ sun4d_fixup_trap_table();
}
void __init sun4d_init_sbi_irq(void)
{
struct device_node *dp;
+ int target_cpu = 0;
+
+#ifdef CONFIG_SMP
+ target_cpu = boot_cpu_id;
+#endif
nsbi = 0;
for_each_node_by_name(dp, "sbi")
int board = of_getintprop_default(dp, "board#", 0);
unsigned int mask;
-#ifdef CONFIG_SMP
- {
- extern unsigned char boot_cpu_id;
-
- set_sbi_tid(devid, boot_cpu_id << 3);
- sbus_tid[board] = boot_cpu_id;
- }
-#endif
+ set_sbi_tid(devid, target_cpu << 3);
+ sbus_tid[board] = target_cpu;
+
/* Get rid of pending irqs from PROM */
mask = acquire_sbi(devid, 0xffffffff);
if (mask) {
BTFIXUPSET_CALL(enable_irq, sun4d_enable_irq, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(disable_irq, sun4d_disable_irq, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(clear_clock_irq, sun4d_clear_clock_irq, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(clear_profile_irq, sun4d_clear_profile_irq, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(load_profile_irq, sun4d_load_profile_irq, BTFIXUPCALL_NORM);
sparc_init_timers = sun4d_init_timers;
#ifdef CONFIG_SMP