1867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf/*
2867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf * Copyright 2010 Tilera Corporation. All Rights Reserved.
3867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf *
4867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf *   This program is free software; you can redistribute it and/or
5867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf *   modify it under the terms of the GNU General Public License
6867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf *   as published by the Free Software Foundation, version 2.
7867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf *
8867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf *   This program is distributed in the hope that it will be useful, but
9867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf *   WITHOUT ANY WARRANTY; without even the implied warranty of
10867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
11867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf *   NON INFRINGEMENT.  See the GNU General Public License for
12867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf *   more details.
13867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf */
14867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf
15867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf#include <linux/percpu.h>
16867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf#include <linux/smp.h>
17867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf#include <linux/hardirq.h>
18867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf#include <linux/ptrace.h>
19867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf#include <asm/hv_driver.h>
20867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf#include <asm/irq_regs.h>
210707ad30d10110aebc01a5a64fb63f4b32d20b73Chris Metcalf#include <asm/traps.h>
22867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf#include <hv/hypervisor.h>
23867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf#include <arch/interrupts.h>
24867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf
25867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf/* All messages are stored here */
26867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalfstatic DEFINE_PER_CPU(HV_MsgState, msg_state);
27867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf
280707ad30d10110aebc01a5a64fb63f4b32d20b73Chris Metcalfvoid __cpuinit init_messaging(void)
29867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf{
30867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf	/* Allocate storage for messages in kernel space */
31867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf	HV_MsgState *state = &__get_cpu_var(msg_state);
32867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf	int rc = hv_register_message_state(state);
33867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf	if (rc != HV_OK)
34867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf		panic("hv_register_message_state: error %d", rc);
35867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf
36867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf	/* Make sure downcall interrupts will be enabled. */
375d966115de84c22cd4df029cb00be0e51fab6c10Chris Metcalf	arch_local_irq_unmask(INT_INTCTRL_K);
38867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf}
39867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf
40867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalfvoid hv_message_intr(struct pt_regs *regs, int intnum)
41867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf{
42867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf	/*
43867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf	 * We enter with interrupts disabled and leave them disabled,
44867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf	 * to match expectations of called functions (e.g.
45867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf	 * do_ccupdate_local() in mm/slab.c).  This is also consistent
46867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf	 * with normal call entry for device interrupts.
47867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf	 */
48867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf
49867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf	int message[HV_MAX_MESSAGE_SIZE/sizeof(int)];
50867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf	HV_RcvMsgInfo rmi;
51867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf	int nmsgs = 0;
52867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf
53867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf	/* Track time spent here in an interrupt context */
54867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf	struct pt_regs *old_regs = set_irq_regs(regs);
55867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf	irq_enter();
56867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf
57867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf#ifdef CONFIG_DEBUG_STACKOVERFLOW
58867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf	/* Debugging check for stack overflow: less than 1/8th stack free? */
59867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf	{
60867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf		long sp = stack_pointer - (long) current_thread_info();
61867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf		if (unlikely(sp < (sizeof(struct thread_info) + STACK_WARN))) {
620707ad30d10110aebc01a5a64fb63f4b32d20b73Chris Metcalf			pr_emerg("hv_message_intr: "
63867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf			       "stack overflow: %ld\n",
64867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf			       sp - sizeof(struct thread_info));
65867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf			dump_stack();
66867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf		}
67867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf	}
68867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf#endif
69867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf
70867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf	while (1) {
71867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf		rmi = hv_receive_message(__get_cpu_var(msg_state),
72867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf					 (HV_VirtAddr) message,
73867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf					 sizeof(message));
74867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf		if (rmi.msglen == 0)
75867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf			break;
76867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf
77867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf		if (rmi.msglen < 0)
78867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf			panic("hv_receive_message failed: %d", rmi.msglen);
79867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf
80867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf		++nmsgs;
81867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf
82867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf		if (rmi.source == HV_MSG_TILE) {
83867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf			int tag;
84867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf
85867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf			/* we just send tags for now */
86867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf			BUG_ON(rmi.msglen != sizeof(int));
87867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf
88867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf			tag = message[0];
89867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf#ifdef CONFIG_SMP
90867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf			evaluate_message(message[0]);
91867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf#else
92867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf			panic("Received IPI message %d in UP mode", tag);
93867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf#endif
94867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf		} else if (rmi.source == HV_MSG_INTR) {
95867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf			HV_IntrMsg *him = (HV_IntrMsg *)message;
96867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf			struct hv_driver_cb *cb =
97867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf				(struct hv_driver_cb *)him->intarg;
98867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf			cb->callback(cb, him->intdata);
99867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf			__get_cpu_var(irq_stat).irq_hv_msg_count++;
100867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf		}
101867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf	}
102867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf
103867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf	/*
104867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf	 * We shouldn't have gotten a message downcall with no
105867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf	 * messages available.
106867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf	 */
107867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf	if (nmsgs == 0)
108867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf		panic("Message downcall invoked with no messages!");
109867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf
110867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf	/*
111867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf	 * Track time spent against the current process again and
112867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf	 * process any softirqs if they are waiting.
113867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf	 */
114867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf	irq_exit();
115867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf	set_irq_regs(old_regs);
116867e359b97c970a60626d5d76bbe2a8fadbf38fbChris Metcalf}
117