1*1da177e4SLinus Torvalds /* 2*1da177e4SLinus Torvalds * Copyright (C) 2001, 2002, 2003 Broadcom Corporation 3*1da177e4SLinus Torvalds * 4*1da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or 5*1da177e4SLinus Torvalds * modify it under the terms of the GNU General Public License 6*1da177e4SLinus Torvalds * as published by the Free Software Foundation; either version 2 7*1da177e4SLinus Torvalds * of the License, or (at your option) any later version. 8*1da177e4SLinus Torvalds * 9*1da177e4SLinus Torvalds * This program is distributed in the hope that it will be useful, 10*1da177e4SLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of 11*1da177e4SLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12*1da177e4SLinus Torvalds * GNU General Public License for more details. 13*1da177e4SLinus Torvalds * 14*1da177e4SLinus Torvalds * You should have received a copy of the GNU General Public License 15*1da177e4SLinus Torvalds * along with this program; if not, write to the Free Software 16*1da177e4SLinus Torvalds * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17*1da177e4SLinus Torvalds */ 18*1da177e4SLinus Torvalds 19*1da177e4SLinus Torvalds #include <linux/init.h> 20*1da177e4SLinus Torvalds #include <linux/delay.h> 21*1da177e4SLinus Torvalds #include <linux/interrupt.h> 22*1da177e4SLinus Torvalds #include <linux/smp.h> 23*1da177e4SLinus Torvalds #include <linux/kernel_stat.h> 24*1da177e4SLinus Torvalds 25*1da177e4SLinus Torvalds #include <asm/mmu_context.h> 26*1da177e4SLinus Torvalds #include <asm/io.h> 27*1da177e4SLinus Torvalds #include <asm/sibyte/sb1250.h> 28*1da177e4SLinus Torvalds #include <asm/sibyte/sb1250_regs.h> 29*1da177e4SLinus Torvalds #include <asm/sibyte/sb1250_int.h> 30*1da177e4SLinus Torvalds 31*1da177e4SLinus Torvalds static void *mailbox_set_regs[] = { 32*1da177e4SLinus Torvalds (void *)IOADDR(A_IMR_CPU0_BASE + R_IMR_MAILBOX_SET_CPU), 33*1da177e4SLinus Torvalds (void *)IOADDR(A_IMR_CPU1_BASE + R_IMR_MAILBOX_SET_CPU) 34*1da177e4SLinus Torvalds }; 35*1da177e4SLinus Torvalds 36*1da177e4SLinus Torvalds static void *mailbox_clear_regs[] = { 37*1da177e4SLinus Torvalds (void *)IOADDR(A_IMR_CPU0_BASE + R_IMR_MAILBOX_CLR_CPU), 38*1da177e4SLinus Torvalds (void *)IOADDR(A_IMR_CPU1_BASE + R_IMR_MAILBOX_CLR_CPU) 39*1da177e4SLinus Torvalds }; 40*1da177e4SLinus Torvalds 41*1da177e4SLinus Torvalds static void *mailbox_regs[] = { 42*1da177e4SLinus Torvalds (void *)IOADDR(A_IMR_CPU0_BASE + R_IMR_MAILBOX_CPU), 43*1da177e4SLinus Torvalds (void *)IOADDR(A_IMR_CPU1_BASE + R_IMR_MAILBOX_CPU) 44*1da177e4SLinus Torvalds }; 45*1da177e4SLinus Torvalds 46*1da177e4SLinus Torvalds /* 47*1da177e4SLinus Torvalds * SMP init and finish on secondary CPUs 48*1da177e4SLinus Torvalds */ 49*1da177e4SLinus Torvalds void sb1250_smp_init(void) 50*1da177e4SLinus Torvalds { 51*1da177e4SLinus Torvalds unsigned int imask = STATUSF_IP4 | STATUSF_IP3 | STATUSF_IP2 | 52*1da177e4SLinus Torvalds STATUSF_IP1 | STATUSF_IP0; 53*1da177e4SLinus Torvalds 54*1da177e4SLinus Torvalds /* Set interrupt mask, but don't enable */ 55*1da177e4SLinus Torvalds change_c0_status(ST0_IM, imask); 56*1da177e4SLinus Torvalds } 57*1da177e4SLinus Torvalds 58*1da177e4SLinus Torvalds void sb1250_smp_finish(void) 59*1da177e4SLinus Torvalds { 60*1da177e4SLinus Torvalds extern void sb1250_time_init(void); 61*1da177e4SLinus Torvalds sb1250_time_init(); 62*1da177e4SLinus Torvalds local_irq_enable(); 63*1da177e4SLinus Torvalds } 64*1da177e4SLinus Torvalds 65*1da177e4SLinus Torvalds /* 66*1da177e4SLinus Torvalds * These are routines for dealing with the sb1250 smp capabilities 67*1da177e4SLinus Torvalds * independent of board/firmware 68*1da177e4SLinus Torvalds */ 69*1da177e4SLinus Torvalds 70*1da177e4SLinus Torvalds /* 71*1da177e4SLinus Torvalds * Simple enough; everything is set up, so just poke the appropriate mailbox 72*1da177e4SLinus Torvalds * register, and we should be set 73*1da177e4SLinus Torvalds */ 74*1da177e4SLinus Torvalds void core_send_ipi(int cpu, unsigned int action) 75*1da177e4SLinus Torvalds { 76*1da177e4SLinus Torvalds bus_writeq((((u64)action) << 48), mailbox_set_regs[cpu]); 77*1da177e4SLinus Torvalds } 78*1da177e4SLinus Torvalds 79*1da177e4SLinus Torvalds void sb1250_mailbox_interrupt(struct pt_regs *regs) 80*1da177e4SLinus Torvalds { 81*1da177e4SLinus Torvalds int cpu = smp_processor_id(); 82*1da177e4SLinus Torvalds unsigned int action; 83*1da177e4SLinus Torvalds 84*1da177e4SLinus Torvalds kstat_this_cpu.irqs[K_INT_MBOX_0]++; 85*1da177e4SLinus Torvalds /* Load the mailbox register to figure out what we're supposed to do */ 86*1da177e4SLinus Torvalds action = (__bus_readq(mailbox_regs[cpu]) >> 48) & 0xffff; 87*1da177e4SLinus Torvalds 88*1da177e4SLinus Torvalds /* Clear the mailbox to clear the interrupt */ 89*1da177e4SLinus Torvalds __bus_writeq(((u64)action) << 48, mailbox_clear_regs[cpu]); 90*1da177e4SLinus Torvalds 91*1da177e4SLinus Torvalds /* 92*1da177e4SLinus Torvalds * Nothing to do for SMP_RESCHEDULE_YOURSELF; returning from the 93*1da177e4SLinus Torvalds * interrupt will do the reschedule for us 94*1da177e4SLinus Torvalds */ 95*1da177e4SLinus Torvalds 96*1da177e4SLinus Torvalds if (action & SMP_CALL_FUNCTION) 97*1da177e4SLinus Torvalds smp_call_function_interrupt(); 98*1da177e4SLinus Torvalds } 99