linux/arch/tile/kernel/messaging.c
<<
>>
Prefs
   1/*
   2 * Copyright 2010 Tilera Corporation. All Rights Reserved.
   3 *
   4 *   This program is free software; you can redistribute it and/or
   5 *   modify it under the terms of the GNU General Public License
   6 *   as published by the Free Software Foundation, version 2.
   7 *
   8 *   This program is distributed in the hope that it will be useful, but
   9 *   WITHOUT ANY WARRANTY; without even the implied warranty of
  10 *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
  11 *   NON INFRINGEMENT.  See the GNU General Public License for
  12 *   more details.
  13 */
  14
  15#include <linux/percpu.h>
  16#include <linux/smp.h>
  17#include <linux/hardirq.h>
  18#include <linux/ptrace.h>
  19#include <asm/hv_driver.h>
  20#include <asm/irq_regs.h>
  21#include <asm/traps.h>
  22#include <hv/hypervisor.h>
  23#include <arch/interrupts.h>
  24
  25/* All messages are stored here */
  26static DEFINE_PER_CPU(HV_MsgState, msg_state);
  27
  28void __cpuinit init_messaging(void)
  29{
  30        /* Allocate storage for messages in kernel space */
  31        HV_MsgState *state = &__get_cpu_var(msg_state);
  32        int rc = hv_register_message_state(state);
  33        if (rc != HV_OK)
  34                panic("hv_register_message_state: error %d", rc);
  35
  36        /* Make sure downcall interrupts will be enabled. */
  37        arch_local_irq_unmask(INT_INTCTRL_K);
  38}
  39
  40void hv_message_intr(struct pt_regs *regs, int intnum)
  41{
  42        /*
  43         * We enter with interrupts disabled and leave them disabled,
  44         * to match expectations of called functions (e.g.
  45         * do_ccupdate_local() in mm/slab.c).  This is also consistent
  46         * with normal call entry for device interrupts.
  47         */
  48
  49        int message[HV_MAX_MESSAGE_SIZE/sizeof(int)];
  50        HV_RcvMsgInfo rmi;
  51        int nmsgs = 0;
  52
  53        /* Track time spent here in an interrupt context */
  54        struct pt_regs *old_regs = set_irq_regs(regs);
  55        irq_enter();
  56
  57#ifdef CONFIG_DEBUG_STACKOVERFLOW
  58        /* Debugging check for stack overflow: less than 1/8th stack free? */
  59        {
  60                long sp = stack_pointer - (long) current_thread_info();
  61                if (unlikely(sp < (sizeof(struct thread_info) + STACK_WARN))) {
  62                        pr_emerg("hv_message_intr: "
  63                               "stack overflow: %ld\n",
  64                               sp - sizeof(struct thread_info));
  65                        dump_stack();
  66                }
  67        }
  68#endif
  69
  70        while (1) {
  71                rmi = hv_receive_message(__get_cpu_var(msg_state),
  72                                         (HV_VirtAddr) message,
  73                                         sizeof(message));
  74                if (rmi.msglen == 0)
  75                        break;
  76
  77                if (rmi.msglen < 0)
  78                        panic("hv_receive_message failed: %d", rmi.msglen);
  79
  80                ++nmsgs;
  81
  82                if (rmi.source == HV_MSG_TILE) {
  83                        int tag;
  84
  85                        /* we just send tags for now */
  86                        BUG_ON(rmi.msglen != sizeof(int));
  87
  88                        tag = message[0];
  89#ifdef CONFIG_SMP
  90                        evaluate_message(message[0]);
  91#else
  92                        panic("Received IPI message %d in UP mode", tag);
  93#endif
  94                } else if (rmi.source == HV_MSG_INTR) {
  95                        HV_IntrMsg *him = (HV_IntrMsg *)message;
  96                        struct hv_driver_cb *cb =
  97                                (struct hv_driver_cb *)him->intarg;
  98                        cb->callback(cb, him->intdata);
  99                        __get_cpu_var(irq_stat).irq_hv_msg_count++;
 100                }
 101        }
 102
 103        /*
 104         * We shouldn't have gotten a message downcall with no
 105         * messages available.
 106         */
 107        if (nmsgs == 0)
 108                panic("Message downcall invoked with no messages!");
 109
 110        /*
 111         * Track time spent against the current process again and
 112         * process any softirqs if they are waiting.
 113         */
 114        irq_exit();
 115        set_irq_regs(old_regs);
 116}
 117