2010-05-28 23:09:12 -04:00
/*
* Copyright 2010 Tilera Corporation . All Rights Reserved .
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation , version 2.
*
* This program is distributed in the hope that it will be useful , but
* WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE , GOOD TITLE or
* NON INFRINGEMENT . See the GNU General Public License for
* more details .
*/
# include <linux/percpu.h>
# include <linux/smp.h>
# include <linux/hardirq.h>
# include <linux/ptrace.h>
# include <asm/hv_driver.h>
# include <asm/irq_regs.h>
2010-06-25 17:04:17 -04:00
# include <asm/traps.h>
2010-05-28 23:09:12 -04:00
# include <hv/hypervisor.h>
# include <arch/interrupts.h>
/* All messages are stored here */
static DEFINE_PER_CPU ( HV_MsgState , msg_state ) ;
2013-06-18 17:28:07 -04:00
void init_messaging ( void )
2010-05-28 23:09:12 -04:00
{
/* Allocate storage for messages in kernel space */
HV_MsgState * state = & __get_cpu_var ( msg_state ) ;
int rc = hv_register_message_state ( state ) ;
if ( rc ! = HV_OK )
panic ( " hv_register_message_state: error %d " , rc ) ;
/* Make sure downcall interrupts will be enabled. */
2010-11-01 15:24:29 -04:00
arch_local_irq_unmask ( INT_INTCTRL_K ) ;
2010-05-28 23:09:12 -04:00
}
void hv_message_intr ( struct pt_regs * regs , int intnum )
{
/*
* We enter with interrupts disabled and leave them disabled ,
* to match expectations of called functions ( e . g .
* do_ccupdate_local ( ) in mm / slab . c ) . This is also consistent
* with normal call entry for device interrupts .
*/
int message [ HV_MAX_MESSAGE_SIZE / sizeof ( int ) ] ;
HV_RcvMsgInfo rmi ;
int nmsgs = 0 ;
/* Track time spent here in an interrupt context */
struct pt_regs * old_regs = set_irq_regs ( regs ) ;
irq_enter ( ) ;
# ifdef CONFIG_DEBUG_STACKOVERFLOW
/* Debugging check for stack overflow: less than 1/8th stack free? */
{
long sp = stack_pointer - ( long ) current_thread_info ( ) ;
if ( unlikely ( sp < ( sizeof ( struct thread_info ) + STACK_WARN ) ) ) {
2010-06-25 17:04:17 -04:00
pr_emerg ( " hv_message_intr: "
2010-05-28 23:09:12 -04:00
" stack overflow: %ld \n " ,
sp - sizeof ( struct thread_info ) ) ;
dump_stack ( ) ;
}
}
# endif
while ( 1 ) {
2014-03-06 15:31:59 -05:00
HV_MsgState * state = this_cpu_ptr ( & msg_state ) ;
rmi = hv_receive_message ( * state , ( HV_VirtAddr ) message ,
2010-05-28 23:09:12 -04:00
sizeof ( message ) ) ;
if ( rmi . msglen = = 0 )
break ;
if ( rmi . msglen < 0 )
panic ( " hv_receive_message failed: %d " , rmi . msglen ) ;
+ + nmsgs ;
if ( rmi . source = = HV_MSG_TILE ) {
int tag ;
/* we just send tags for now */
BUG_ON ( rmi . msglen ! = sizeof ( int ) ) ;
tag = message [ 0 ] ;
# ifdef CONFIG_SMP
evaluate_message ( message [ 0 ] ) ;
# else
panic ( " Received IPI message %d in UP mode " , tag ) ;
# endif
} else if ( rmi . source = = HV_MSG_INTR ) {
HV_IntrMsg * him = ( HV_IntrMsg * ) message ;
struct hv_driver_cb * cb =
( struct hv_driver_cb * ) him - > intarg ;
cb - > callback ( cb , him - > intdata ) ;
__get_cpu_var ( irq_stat ) . irq_hv_msg_count + + ;
}
}
/*
* We shouldn ' t have gotten a message downcall with no
* messages available .
*/
if ( nmsgs = = 0 )
panic ( " Message downcall invoked with no messages! " ) ;
/*
* Track time spent against the current process again and
* process any softirqs if they are waiting .
*/
irq_exit ( ) ;
set_irq_regs ( old_regs ) ;
}