lin
2025-03-21 c2c82c91f6acd44c57766034b6ced0c53c164a55
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
/*
 * 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>
#include <asm/traps.h>
#include <hv/hypervisor.h>
#include <arch/interrupts.h>
 
/* All messages are stored here */
static DEFINE_PER_CPU(HV_MsgState, msg_state);
 
void init_messaging(void)
{
   /* Allocate storage for messages in kernel space */
   HV_MsgState *state = this_cpu_ptr(&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. */
   arch_local_irq_unmask(INT_INTCTRL_K);
}
 
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))) {
           pr_emerg("%s: stack overflow: %ld\n",
                __func__, sp - sizeof(struct thread_info));
           dump_stack();
       }
   }
#endif
 
   while (1) {
       HV_MsgState *state = this_cpu_ptr(&msg_state);
       rmi = hv_receive_message(*state, (HV_VirtAddr) message,
                    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);
           __this_cpu_inc(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);
}