diff options
Diffstat (limited to 'arch/mips/sibyte/bcm1480')
| -rw-r--r-- | arch/mips/sibyte/bcm1480/Makefile | 2 | ||||
| -rw-r--r-- | arch/mips/sibyte/bcm1480/irq.c | 310 | ||||
| -rw-r--r-- | arch/mips/sibyte/bcm1480/setup.c | 93 | ||||
| -rw-r--r-- | arch/mips/sibyte/bcm1480/smp.c | 107 | ||||
| -rw-r--r-- | arch/mips/sibyte/bcm1480/time.c | 123 |
5 files changed, 219 insertions, 416 deletions
diff --git a/arch/mips/sibyte/bcm1480/Makefile b/arch/mips/sibyte/bcm1480/Makefile index 7b36ff3873b..cdc4c56c3e2 100644 --- a/arch/mips/sibyte/bcm1480/Makefile +++ b/arch/mips/sibyte/bcm1480/Makefile @@ -1,5 +1,3 @@ obj-y := setup.o irq.o time.o obj-$(CONFIG_SMP) += smp.o - -EXTRA_AFLAGS := $(CFLAGS) diff --git a/arch/mips/sibyte/bcm1480/irq.c b/arch/mips/sibyte/bcm1480/irq.c index a0222fa4416..373fbbc8425 100644 --- a/arch/mips/sibyte/bcm1480/irq.c +++ b/arch/mips/sibyte/bcm1480/irq.c @@ -19,15 +19,14 @@ #include <linux/init.h> #include <linux/linkage.h> #include <linux/interrupt.h> +#include <linux/smp.h> #include <linux/spinlock.h> #include <linux/mm.h> -#include <linux/slab.h> #include <linux/kernel_stat.h> #include <asm/errno.h> +#include <asm/irq_regs.h> #include <asm/signal.h> -#include <asm/system.h> -#include <asm/ptrace.h> #include <asm/io.h> #include <asm/sibyte/bcm1480_regs.h> @@ -44,69 +43,21 @@ * for interrupt lines */ - -#define shutdown_bcm1480_irq disable_bcm1480_irq -static void end_bcm1480_irq(unsigned int irq); -static void enable_bcm1480_irq(unsigned int irq); -static void disable_bcm1480_irq(unsigned int irq); -static unsigned int startup_bcm1480_irq(unsigned int irq); -static void ack_bcm1480_irq(unsigned int irq); -#ifdef CONFIG_SMP -static void bcm1480_set_affinity(unsigned int irq, cpumask_t mask); -#endif - #ifdef CONFIG_PCI extern unsigned long ht_eoi_space; #endif -#ifdef CONFIG_KGDB -#include <asm/gdb-stub.h> -extern void breakpoint(void); -static int kgdb_irq; -#ifdef CONFIG_GDB_CONSOLE -extern void register_gdb_console(void); -#endif - -/* kgdb is on when configured. Pass "nokgdb" kernel arg to turn it off */ -static int kgdb_flag = 1; -static int __init nokgdb(char *str) -{ - kgdb_flag = 0; - return 1; -} -__setup("nokgdb", nokgdb); - -/* Default to UART1 */ -int kgdb_port = 1; -#ifdef CONFIG_SIBYTE_SB1250_DUART -extern char sb1250_duart_present[]; -#endif -#endif - -static struct irq_chip bcm1480_irq_type = { - .typename = "BCM1480-IMR", - .startup = startup_bcm1480_irq, - .shutdown = shutdown_bcm1480_irq, - .enable = enable_bcm1480_irq, - .disable = disable_bcm1480_irq, - .ack = ack_bcm1480_irq, - .end = end_bcm1480_irq, -#ifdef CONFIG_SMP - .set_affinity = bcm1480_set_affinity -#endif -}; - /* Store the CPU id (not the logical number) */ int bcm1480_irq_owner[BCM1480_NR_IRQS]; -DEFINE_SPINLOCK(bcm1480_imr_lock); +static DEFINE_RAW_SPINLOCK(bcm1480_imr_lock); void bcm1480_mask_irq(int cpu, int irq) { - unsigned long flags; - u64 cur_ints,hl_spacing; + unsigned long flags, hl_spacing; + u64 cur_ints; - spin_lock_irqsave(&bcm1480_imr_lock, flags); + raw_spin_lock_irqsave(&bcm1480_imr_lock, flags); hl_spacing = 0; if ((irq >= BCM1480_NR_IRQS_HALF) && (irq <= BCM1480_NR_IRQS)) { hl_spacing = BCM1480_IMR_HL_SPACING; @@ -115,15 +66,15 @@ void bcm1480_mask_irq(int cpu, int irq) cur_ints = ____raw_readq(IOADDR(A_BCM1480_IMR_MAPPER(cpu) + R_BCM1480_IMR_INTERRUPT_MASK_H + hl_spacing)); cur_ints |= (((u64) 1) << irq); ____raw_writeq(cur_ints, IOADDR(A_BCM1480_IMR_MAPPER(cpu) + R_BCM1480_IMR_INTERRUPT_MASK_H + hl_spacing)); - spin_unlock_irqrestore(&bcm1480_imr_lock, flags); + raw_spin_unlock_irqrestore(&bcm1480_imr_lock, flags); } void bcm1480_unmask_irq(int cpu, int irq) { - unsigned long flags; - u64 cur_ints,hl_spacing; + unsigned long flags, hl_spacing; + u64 cur_ints; - spin_lock_irqsave(&bcm1480_imr_lock, flags); + raw_spin_lock_irqsave(&bcm1480_imr_lock, flags); hl_spacing = 0; if ((irq >= BCM1480_NR_IRQS_HALF) && (irq <= BCM1480_NR_IRQS)) { hl_spacing = BCM1480_IMR_HL_SPACING; @@ -132,30 +83,25 @@ void bcm1480_unmask_irq(int cpu, int irq) cur_ints = ____raw_readq(IOADDR(A_BCM1480_IMR_MAPPER(cpu) + R_BCM1480_IMR_INTERRUPT_MASK_H + hl_spacing)); cur_ints &= ~(((u64) 1) << irq); ____raw_writeq(cur_ints, IOADDR(A_BCM1480_IMR_MAPPER(cpu) + R_BCM1480_IMR_INTERRUPT_MASK_H + hl_spacing)); - spin_unlock_irqrestore(&bcm1480_imr_lock, flags); + raw_spin_unlock_irqrestore(&bcm1480_imr_lock, flags); } #ifdef CONFIG_SMP -static void bcm1480_set_affinity(unsigned int irq, cpumask_t mask) +static int bcm1480_set_affinity(struct irq_data *d, const struct cpumask *mask, + bool force) { + unsigned int irq_dirty, irq = d->irq; int i = 0, old_cpu, cpu, int_on, k; u64 cur_ints; - struct irq_desc *desc = irq_desc + irq; unsigned long flags; - unsigned int irq_dirty; - i = first_cpu(mask); - if (next_cpu(i, mask) <= NR_CPUS) { - printk("attempted to set irq affinity for irq %d to multiple CPUs\n", irq); - return; - } + i = cpumask_first_and(mask, cpu_online_mask); /* Convert logical CPU to physical CPU */ cpu = cpu_logical_map(i); /* Protect against other affinity changers and IMR manipulation */ - spin_lock_irqsave(&desc->lock, flags); - spin_lock(&bcm1480_imr_lock); + raw_spin_lock_irqsave(&bcm1480_imr_lock, flags); /* Swizzle each CPU's IMR (but leave the IP selection alone) */ old_cpu = bcm1480_irq_owner[irq]; @@ -180,37 +126,34 @@ static void bcm1480_set_affinity(unsigned int irq, cpumask_t mask) ____raw_writeq(cur_ints, IOADDR(A_BCM1480_IMR_MAPPER(cpu) + R_BCM1480_IMR_INTERRUPT_MASK_H + (k*BCM1480_IMR_HL_SPACING))); } } - spin_unlock(&bcm1480_imr_lock); - spin_unlock_irqrestore(&desc->lock, flags); + raw_spin_unlock_irqrestore(&bcm1480_imr_lock, flags); + + return 0; } #endif /*****************************************************************************/ -static unsigned int startup_bcm1480_irq(unsigned int irq) +static void disable_bcm1480_irq(struct irq_data *d) { - bcm1480_unmask_irq(bcm1480_irq_owner[irq], irq); + unsigned int irq = d->irq; - return 0; /* never anything pending */ -} - - -static void disable_bcm1480_irq(unsigned int irq) -{ bcm1480_mask_irq(bcm1480_irq_owner[irq], irq); } -static void enable_bcm1480_irq(unsigned int irq) +static void enable_bcm1480_irq(struct irq_data *d) { + unsigned int irq = d->irq; + bcm1480_unmask_irq(bcm1480_irq_owner[irq], irq); } -static void ack_bcm1480_irq(unsigned int irq) +static void ack_bcm1480_irq(struct irq_data *d) { + unsigned int irq_dirty, irq = d->irq; u64 pending; - unsigned int irq_dirty; int k; /* @@ -257,69 +200,27 @@ static void ack_bcm1480_irq(unsigned int irq) bcm1480_mask_irq(bcm1480_irq_owner[irq], irq); } - -static void end_bcm1480_irq(unsigned int irq) -{ - if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) { - bcm1480_unmask_irq(bcm1480_irq_owner[irq], irq); - } -} - +static struct irq_chip bcm1480_irq_type = { + .name = "BCM1480-IMR", + .irq_mask_ack = ack_bcm1480_irq, + .irq_mask = disable_bcm1480_irq, + .irq_unmask = enable_bcm1480_irq, +#ifdef CONFIG_SMP + .irq_set_affinity = bcm1480_set_affinity +#endif +}; void __init init_bcm1480_irqs(void) { int i; - for (i = 0; i < NR_IRQS; i++) { - irq_desc[i].status = IRQ_DISABLED; - irq_desc[i].action = 0; - irq_desc[i].depth = 1; - if (i < BCM1480_NR_IRQS) { - irq_desc[i].chip = &bcm1480_irq_type; - bcm1480_irq_owner[i] = 0; - } else { - irq_desc[i].chip = &no_irq_chip; - } + for (i = 0; i < BCM1480_NR_IRQS; i++) { + irq_set_chip_and_handler(i, &bcm1480_irq_type, + handle_level_irq); + bcm1480_irq_owner[i] = 0; } } - -static irqreturn_t bcm1480_dummy_handler(int irq, void *dev_id, - struct pt_regs *regs) -{ - return IRQ_NONE; -} - -static struct irqaction bcm1480_dummy_action = { - .handler = bcm1480_dummy_handler, - .flags = 0, - .mask = CPU_MASK_NONE, - .name = "bcm1480-private", - .next = NULL, - .dev_id = 0 -}; - -int bcm1480_steal_irq(int irq) -{ - struct irq_desc *desc = irq_desc + irq; - unsigned long flags; - int retval = 0; - - if (irq >= BCM1480_NR_IRQS) - return -EINVAL; - - spin_lock_irqsave(&desc->lock,flags); - /* Don't allow sharing at all for these */ - if (desc->action != NULL) - retval = -EBUSY; - else { - desc->action = &bcm1480_dummy_action; - desc->depth = 0; - } - spin_unlock_irqrestore(&desc->lock,flags); - return 0; -} - /* * init_IRQ is called early in the boot sequence from init/main.c. It * is responsible for setting up the interrupt mapper and installing the @@ -337,7 +238,7 @@ int bcm1480_steal_irq(int irq) * On the second cpu, everything is set to IP5, which is * ignored, EXCEPT the mailbox interrupt. That one is * set to IP[2] so it is handled. This is needed so we - * can do cross-cpu function calls, as requred by SMP + * can do cross-cpu function calls, as required by SMP */ #define IMR_IP2_VAL K_BCM1480_INT_MAP_I0 @@ -348,7 +249,6 @@ int bcm1480_steal_irq(int irq) void __init arch_init_irq(void) { - unsigned int i, cpu; u64 tmp; unsigned int imask = STATUSF_IP4 | STATUSF_IP3 | STATUSF_IP2 | @@ -383,10 +283,10 @@ void __init arch_init_irq(void) for (cpu = 0; cpu < 4; cpu++) { __raw_writeq(IMR_IP3_VAL, IOADDR(A_BCM1480_IMR_REGISTER(cpu, R_BCM1480_IMR_INTERRUPT_MAP_BASE_H) + (K_BCM1480_INT_MBOX_0_0 << 3))); - } + } - /* Clear the mailboxes. The firmware may leave them dirty */ + /* Clear the mailboxes. The firmware may leave them dirty */ for (cpu = 0; cpu < 4; cpu++) { __raw_writeq(0xffffffffffffffffULL, IOADDR(A_BCM1480_IMR_REGISTER(cpu, R_BCM1480_IMR_MAILBOX_0_CLR_CPU))); @@ -405,125 +305,57 @@ void __init arch_init_irq(void) __raw_writeq(tmp, IOADDR(A_BCM1480_IMR_REGISTER(cpu, R_BCM1480_IMR_INTERRUPT_MASK_L))); } - bcm1480_steal_irq(K_BCM1480_INT_MBOX_0_0); - /* * Note that the timer interrupts are also mapped, but this is - * done in bcm1480_time_init(). Also, the profiling driver + * done in bcm1480_time_init(). Also, the profiling driver * does its own management of IP7. */ -#ifdef CONFIG_KGDB - imask |= STATUSF_IP6; -#endif /* Enable necessary IPs, disable the rest */ change_c0_status(ST0_IM, imask); - -#ifdef CONFIG_KGDB - if (kgdb_flag) { - kgdb_irq = K_BCM1480_INT_UART_0 + kgdb_port; - -#ifdef CONFIG_SIBYTE_SB1250_DUART - sb1250_duart_present[kgdb_port] = 0; -#endif - /* Setup uart 1 settings, mapper */ - /* QQQ FIXME */ - __raw_writeq(M_DUART_IMR_BRK, IO_SPACE_BASE + A_DUART_IMRREG(kgdb_port)); - - bcm1480_steal_irq(kgdb_irq); - __raw_writeq(IMR_IP6_VAL, - IO_SPACE_BASE + A_BCM1480_IMR_REGISTER(0, R_BCM1480_IMR_INTERRUPT_MAP_BASE_H) + - (kgdb_irq<<3)); - bcm1480_unmask_irq(0, kgdb_irq); - -#ifdef CONFIG_GDB_CONSOLE - register_gdb_console(); -#endif - prom_printf("Waiting for GDB on UART port %d\n", kgdb_port); - set_debug_traps(); - breakpoint(); - } -#endif } -#ifdef CONFIG_KGDB - -#include <linux/delay.h> +extern void bcm1480_mailbox_interrupt(void); -#define duart_out(reg, val) csr_out32(val, IOADDR(A_DUART_CHANREG(kgdb_port,reg))) -#define duart_in(reg) csr_in32(IOADDR(A_DUART_CHANREG(kgdb_port,reg))) - -void bcm1480_kgdb_interrupt(struct pt_regs *regs) +static inline void dispatch_ip2(void) { + unsigned long long mask_h, mask_l; + unsigned int cpu = smp_processor_id(); + unsigned long base; + /* - * Clear break-change status (allow some time for the remote - * host to stop the break, since we would see another - * interrupt on the end-of-break too) + * Default...we've hit an IP[2] interrupt, which means we've got to + * check the 1480 interrupt registers to figure out what to do. Need + * to detect which CPU we're on, now that smp_affinity is supported. */ - kstat.irqs[smp_processor_id()][kgdb_irq]++; - mdelay(500); - duart_out(R_DUART_CMD, V_DUART_MISC_CMD_RESET_BREAK_INT | - M_DUART_RX_EN | M_DUART_TX_EN); - set_async_breakpoint(®s->cp0_epc); + base = A_BCM1480_IMR_MAPPER(cpu); + mask_h = __raw_readq( + IOADDR(base + R_BCM1480_IMR_INTERRUPT_STATUS_BASE_H)); + mask_l = __raw_readq( + IOADDR(base + R_BCM1480_IMR_INTERRUPT_STATUS_BASE_L)); + + if (mask_h) { + if (mask_h ^ 1) + do_IRQ(fls64(mask_h) - 1); + else if (mask_l) + do_IRQ(63 + fls64(mask_l)); + } } -#endif /* CONFIG_KGDB */ - -extern void bcm1480_timer_interrupt(struct pt_regs *regs); -extern void bcm1480_mailbox_interrupt(struct pt_regs *regs); -extern void bcm1480_kgdb_interrupt(struct pt_regs *regs); - -asmlinkage void plat_irq_dispatch(struct pt_regs *regs) +asmlinkage void plat_irq_dispatch(void) { + unsigned int cpu = smp_processor_id(); unsigned int pending; -#ifdef CONFIG_SIBYTE_BCM1480_PROF - /* Set compare to count to silence count/compare timer interrupts */ - write_c0_compare(read_c0_count()); -#endif - - pending = read_c0_cause(); - -#ifdef CONFIG_SIBYTE_BCM1480_PROF - if (pending & CAUSEF_IP7) /* Cpu performance counter interrupt */ - sbprof_cpu_intr(exception_epc(regs)); - else -#endif + pending = read_c0_cause() & read_c0_status(); if (pending & CAUSEF_IP4) - bcm1480_timer_interrupt(regs); - + do_IRQ(K_BCM1480_INT_TIMER_0 + cpu); #ifdef CONFIG_SMP else if (pending & CAUSEF_IP3) - bcm1480_mailbox_interrupt(regs); + bcm1480_mailbox_interrupt(); #endif -#ifdef CONFIG_KGDB - else if (pending & CAUSEF_IP6) - bcm1480_kgdb_interrupt(regs); /* KGDB (uart 1) */ -#endif - - else if (pending & CAUSEF_IP2) { - unsigned long long mask_h, mask_l; - unsigned long base; - - /* - * Default...we've hit an IP[2] interrupt, which means we've - * got to check the 1480 interrupt registers to figure out what - * to do. Need to detect which CPU we're on, now that - * smp_affinity is supported. - */ - base = A_BCM1480_IMR_MAPPER(smp_processor_id()); - mask_h = __raw_readq( - IOADDR(base + R_BCM1480_IMR_INTERRUPT_STATUS_BASE_H)); - mask_l = __raw_readq( - IOADDR(base + R_BCM1480_IMR_INTERRUPT_STATUS_BASE_L)); - - if (mask_h) { - if (mask_h ^ 1) - do_IRQ(fls64(mask_h) - 1, regs); - else - do_IRQ(63 + fls64(mask_l), regs); - } - } + else if (pending & CAUSEF_IP2) + dispatch_ip2(); } diff --git a/arch/mips/sibyte/bcm1480/setup.c b/arch/mips/sibyte/bcm1480/setup.c index 8236d0c4854..8e2e04f7787 100644 --- a/arch/mips/sibyte/bcm1480/setup.c +++ b/arch/mips/sibyte/bcm1480/setup.c @@ -15,11 +15,14 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include <linux/init.h> #include <linux/kernel.h> +#include <linux/module.h> #include <linux/reboot.h> #include <linux/string.h> #include <asm/bootinfo.h> +#include <asm/cpu.h> #include <asm/mipsregs.h> #include <asm/io.h> #include <asm/sibyte/sb1250.h> @@ -31,24 +34,59 @@ unsigned int sb1_pass; unsigned int soc_pass; unsigned int soc_type; +EXPORT_SYMBOL(soc_type); unsigned int periph_rev; unsigned int zbbus_mhz; +EXPORT_SYMBOL(zbbus_mhz); static unsigned int part_type; static char *soc_str; static char *pass_str; -static inline int setup_bcm1x80_bcm1x55(void); +static int __init setup_bcm1x80_bcm1x55(void) +{ + int ret = 0; + + switch (soc_pass) { + case K_SYS_REVISION_BCM1480_S0: + periph_rev = 1; + pass_str = "S0 (pass1)"; + break; + case K_SYS_REVISION_BCM1480_A1: + periph_rev = 1; + pass_str = "A1 (pass1)"; + break; + case K_SYS_REVISION_BCM1480_A2: + periph_rev = 1; + pass_str = "A2 (pass1)"; + break; + case K_SYS_REVISION_BCM1480_A3: + periph_rev = 1; + pass_str = "A3 (pass1)"; + break; + case K_SYS_REVISION_BCM1480_B0: + periph_rev = 1; + pass_str = "B0 (pass2)"; + break; + default: + printk("Unknown %s rev %x\n", soc_str, soc_pass); + periph_rev = 1; + pass_str = "Unknown Revision"; + break; + } + + return ret; +} /* Setup code likely to be common to all SiByte platforms */ -static inline int sys_rev_decode(void) +static int __init sys_rev_decode(void) { int ret = 0; switch (soc_type) { - case K_SYS_SOC_TYPE_BCM1x80: + case K_SYS_SOC_TYPE_BCM1x80: if (part_type == K_SYS_PART_BCM1480) soc_str = "BCM1480"; else if (part_type == K_SYS_PART_BCM1280) @@ -58,7 +96,7 @@ static inline int sys_rev_decode(void) ret = setup_bcm1x80_bcm1x55(); break; - case K_SYS_SOC_TYPE_BCM1x55: + case K_SYS_SOC_TYPE_BCM1x55: if (part_type == K_SYS_PART_BCM1455) soc_str = "BCM1455"; else if (part_type == K_SYS_PART_BCM1255) @@ -68,68 +106,35 @@ static inline int sys_rev_decode(void) ret = setup_bcm1x80_bcm1x55(); break; - default: - prom_printf("Unknown part type %x\n", part_type); + default: + printk("Unknown part type %x\n", part_type); ret = 1; break; } - return ret; -} -static inline int setup_bcm1x80_bcm1x55(void) -{ - int ret = 0; - - switch (soc_pass) { - case K_SYS_REVISION_BCM1480_S0: - periph_rev = 1; - pass_str = "S0 (pass1)"; - break; - case K_SYS_REVISION_BCM1480_A1: - periph_rev = 1; - pass_str = "A1 (pass1)"; - break; - case K_SYS_REVISION_BCM1480_A2: - periph_rev = 1; - pass_str = "A2 (pass1)"; - break; - case K_SYS_REVISION_BCM1480_A3: - periph_rev = 1; - pass_str = "A3 (pass1)"; - break; - case K_SYS_REVISION_BCM1480_B0: - periph_rev = 1; - pass_str = "B0 (pass2)"; - break; - default: - prom_printf("Unknown %s rev %x\n", soc_str, soc_pass); - periph_rev = 1; - pass_str = "Unknown Revision"; - break; - } return ret; } -void bcm1480_setup(void) +void __init bcm1480_setup(void) { uint64_t sys_rev; int plldiv; - sb1_pass = read_c0_prid() & 0xff; + sb1_pass = read_c0_prid() & PRID_REV_MASK; sys_rev = __raw_readq(IOADDR(A_SCD_SYSTEM_REVISION)); soc_type = SYS_SOC_TYPE(sys_rev); part_type = G_SYS_PART(sys_rev); soc_pass = G_SYS_REVISION(sys_rev); if (sys_rev_decode()) { - prom_printf("Restart after failure to identify SiByte chip\n"); + printk("Restart after failure to identify SiByte chip\n"); machine_restart(NULL); } plldiv = G_BCM1480_SYS_PLL_DIV(__raw_readq(IOADDR(A_SCD_SYSTEM_CFG))); zbbus_mhz = ((plldiv >> 1) * 50) + ((plldiv & 1) * 25); - prom_printf("Broadcom SiByte %s %s @ %d MHz (SB-1A rev %d)\n", + printk("Broadcom SiByte %s %s @ %d MHz (SB-1A rev %d)\n", soc_str, pass_str, zbbus_mhz * 2, sb1_pass); - prom_printf("Board type: %s\n", get_system_type()); + printk("Board type: %s\n", get_system_type()); } diff --git a/arch/mips/sibyte/bcm1480/smp.c b/arch/mips/sibyte/bcm1480/smp.c index 584a4b33faa..af7d44edd9a 100644 --- a/arch/mips/sibyte/bcm1480/smp.c +++ b/arch/mips/sibyte/bcm1480/smp.c @@ -20,9 +20,11 @@ #include <linux/delay.h> #include <linux/smp.h> #include <linux/kernel_stat.h> +#include <linux/sched.h> #include <asm/mmu_context.h> #include <asm/io.h> +#include <asm/fw/cfe/cfe_api.h> #include <asm/sibyte/sb1250.h> #include <asm/sibyte/bcm1480_regs.h> #include <asm/sibyte/bcm1480_int.h> @@ -67,13 +69,6 @@ void bcm1480_smp_init(void) change_c0_status(ST0_IM, imask); } -void bcm1480_smp_finish(void) -{ - extern void bcm1480_time_init(void); - bcm1480_time_init(); - local_irq_enable(); -} - /* * These are routines for dealing with the sb1250 smp capabilities * independent of board/firmware @@ -83,27 +78,111 @@ void bcm1480_smp_finish(void) * Simple enough; everything is set up, so just poke the appropriate mailbox * register, and we should be set */ -void core_send_ipi(int cpu, unsigned int action) +static void bcm1480_send_ipi_single(int cpu, unsigned int action) { __raw_writeq((((u64)action)<< 48), mailbox_0_set_regs[cpu]); } -void bcm1480_mailbox_interrupt(struct pt_regs *regs) +static void bcm1480_send_ipi_mask(const struct cpumask *mask, + unsigned int action) +{ + unsigned int i; + + for_each_cpu(i, mask) + bcm1480_send_ipi_single(i, action); +} + +/* + * Code to run on secondary just after probing the CPU + */ +static void bcm1480_init_secondary(void) +{ + extern void bcm1480_smp_init(void); + + bcm1480_smp_init(); +} + +/* + * Do any tidying up before marking online and running the idle + * loop + */ +static void bcm1480_smp_finish(void) +{ + extern void sb1480_clockevent_init(void); + + sb1480_clockevent_init(); + local_irq_enable(); +} + +/* + * Setup the PC, SP, and GP of a secondary processor and start it + * running! + */ +static void bcm1480_boot_secondary(int cpu, struct task_struct *idle) +{ + int retval; + + retval = cfe_cpu_start(cpu_logical_map(cpu), &smp_bootstrap, + __KSTK_TOS(idle), + (unsigned long)task_thread_info(idle), 0); + if (retval != 0) + printk("cfe_start_cpu(%i) returned %i\n" , cpu, retval); +} + +/* + * Use CFE to find out how many CPUs are available, setting up + * cpu_possible_mask and the logical/physical mappings. + * XXXKW will the boot CPU ever not be physical 0? + * + * Common setup before any secondaries are started + */ +static void __init bcm1480_smp_setup(void) +{ + int i, num; + + init_cpu_possible(cpumask_of(0)); + __cpu_number_map[0] = 0; + __cpu_logical_map[0] = 0; + + for (i = 1, num = 0; i < NR_CPUS; i++) { + if (cfe_cpu_stop(i) == 0) { + set_cpu_possible(i, true); + __cpu_number_map[i] = ++num; + __cpu_logical_map[num] = i; + } + } + printk(KERN_INFO "Detected %i available secondary CPU(s)\n", num); +} + +static void __init bcm1480_prepare_cpus(unsigned int max_cpus) +{ +} + +struct plat_smp_ops bcm1480_smp_ops = { + .send_ipi_single = bcm1480_send_ipi_single, + .send_ipi_mask = bcm1480_send_ipi_mask, + .init_secondary = bcm1480_init_secondary, + .smp_finish = bcm1480_smp_finish, + .boot_secondary = bcm1480_boot_secondary, + .smp_setup = bcm1480_smp_setup, + .prepare_cpus = bcm1480_prepare_cpus, +}; + +void bcm1480_mailbox_interrupt(void) { int cpu = smp_processor_id(); + int irq = K_BCM1480_INT_MBOX_0_0; unsigned int action; - kstat_this_cpu.irqs[K_BCM1480_INT_MBOX_0_0]++; + kstat_incr_irq_this_cpu(irq); /* Load the mailbox register to figure out what we're supposed to do */ action = (__raw_readq(mailbox_0_regs[cpu]) >> 48) & 0xffff; /* Clear the mailbox to clear the interrupt */ __raw_writeq(((u64)action)<<48, mailbox_0_clear_regs[cpu]); - /* - * Nothing to do for SMP_RESCHEDULE_YOURSELF; returning from the - * interrupt will do the reschedule for us - */ + if (action & SMP_RESCHEDULE_YOURSELF) + scheduler_ipi(); if (action & SMP_CALL_FUNCTION) smp_call_function_interrupt(); diff --git a/arch/mips/sibyte/bcm1480/time.c b/arch/mips/sibyte/bcm1480/time.c index 7e088f6c4a8..1680a68952a 100644 --- a/arch/mips/sibyte/bcm1480/time.c +++ b/arch/mips/sibyte/bcm1480/time.c @@ -15,124 +15,13 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include <linux/init.h> -/* - * These are routines to set up and handle interrupts from the - * bcm1480 general purpose timer 0. We're using the timer as a - * system clock, so we set it up to run at 100 Hz. On every - * interrupt, we update our idea of what the time of day is, - * then call do_timer() in the architecture-independent kernel - * code to do general bookkeeping (e.g. update jiffies, run - * bottom halves, etc.) - */ -#include <linux/interrupt.h> -#include <linux/sched.h> -#include <linux/spinlock.h> -#include <linux/kernel_stat.h> - -#include <asm/irq.h> -#include <asm/ptrace.h> -#include <asm/addrspace.h> -#include <asm/time.h> -#include <asm/io.h> - -#include <asm/sibyte/bcm1480_regs.h> -#include <asm/sibyte/sb1250_regs.h> -#include <asm/sibyte/bcm1480_int.h> -#include <asm/sibyte/bcm1480_scd.h> - -#include <asm/sibyte/sb1250.h> - - -#define IMR_IP2_VAL K_BCM1480_INT_MAP_I0 -#define IMR_IP3_VAL K_BCM1480_INT_MAP_I1 -#define IMR_IP4_VAL K_BCM1480_INT_MAP_I2 +extern void sb1480_clockevent_init(void); +extern void sb1480_clocksource_init(void); -extern int bcm1480_steal_irq(int irq); - -void bcm1480_time_init(void) +void __init plat_time_init(void) { - int cpu = smp_processor_id(); - int irq = K_BCM1480_INT_TIMER_0+cpu; - - /* Only have 4 general purpose timers */ - if (cpu > 3) { - BUG(); - } - - if (!cpu) { - /* Use our own gettimeoffset() routine */ - do_gettimeoffset = bcm1480_gettimeoffset; - } - - bcm1480_mask_irq(cpu, irq); - - /* Map the timer interrupt to ip[4] of this cpu */ - __raw_writeq(IMR_IP4_VAL, IOADDR(A_BCM1480_IMR_REGISTER(cpu, R_BCM1480_IMR_INTERRUPT_MAP_BASE_H) - + (irq<<3))); - - /* the general purpose timer ticks at 1 Mhz independent of the rest of the system */ - /* Disable the timer and set up the count */ - __raw_writeq(0, IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG))); - __raw_writeq( -#ifndef CONFIG_SIMULATION - 1000000/HZ -#else - 50000/HZ -#endif - , IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_INIT))); - - /* Set the timer running */ - __raw_writeq(M_SCD_TIMER_ENABLE|M_SCD_TIMER_MODE_CONTINUOUS, - IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG))); - - bcm1480_unmask_irq(cpu, irq); - bcm1480_steal_irq(irq); - /* - * This interrupt is "special" in that it doesn't use the request_irq - * way to hook the irq line. The timer interrupt is initialized early - * enough to make this a major pain, and it's also firing enough to - * warrant a bit of special case code. bcm1480_timer_interrupt is - * called directly from irq_handler.S when IP[4] is set during an - * interrupt - */ -} - -#include <asm/sibyte/sb1250.h> - -void bcm1480_timer_interrupt(struct pt_regs *regs) -{ - int cpu = smp_processor_id(); - int irq = K_BCM1480_INT_TIMER_0+cpu; - - /* Reset the timer */ - __raw_writeq(M_SCD_TIMER_ENABLE|M_SCD_TIMER_MODE_CONTINUOUS, - IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG))); - - if (cpu == 0) { - /* - * CPU 0 handles the global timer interrupt job - */ - ll_timer_interrupt(irq, regs); - } - else { - /* - * other CPUs should just do profiling and process accounting - */ - ll_local_timer_interrupt(irq, regs); - } -} - -/* - * We use our own do_gettimeoffset() instead of the generic one, - * because the generic one does not work for SMP case. - * In addition, since we use general timer 0 for system time, - * we can get accurate intra-jiffy offset without calibration. - */ -unsigned long bcm1480_gettimeoffset(void) -{ - unsigned long count = - __raw_readq(IOADDR(A_SCD_TIMER_REGISTER(0, R_SCD_TIMER_CNT))); - - return 1000000/HZ - count; + sb1480_clocksource_init(); + sb1480_clockevent_init(); } |
