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 init_messaging(void)
  29{
  30        /* Allocate storage for messages in kernel space */
  31        HV_MsgState *state = this_cpu_ptr(&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("%s: stack overflow: %ld\n",
  63                                 __func__, sp - sizeof(struct thread_info));
  64                        dump_stack();
  65                }
  66        }
  67#endif
  68
  69        while (1) {
  70                HV_MsgState *state = this_cpu_ptr(&msg_state);
  71                rmi = hv_receive_message(*state, (HV_VirtAddr) message,
  72                                         sizeof(message));
  73                if (rmi.msglen == 0)
  74                        break;
  75
  76                if (rmi.msglen < 0)
  77                        panic("hv_receive_message failed: %d", rmi.msglen);
  78
  79                ++nmsgs;
  80
  81                if (rmi.source == HV_MSG_TILE) {
  82                        int tag;
  83
  84                        /* we just send tags for now */
  85                        BUG_ON(rmi.msglen != sizeof(int));
  86
  87                        tag = message[0];
  88#ifdef CONFIG_SMP
  89                        evaluate_message(message[0]);
  90#else
  91                        panic("Received IPI message %d in UP mode", tag);
  92#endif
  93                } else if (rmi.source == HV_MSG_INTR) {
  94                        HV_IntrMsg *him = (HV_IntrMsg *)message;
  95                        struct hv_driver_cb *cb =
  96                                (struct hv_driver_cb *)him->intarg;
  97                        cb->callback(cb, him->intdata);
  98                        __this_cpu_inc(irq_stat.irq_hv_msg_count);
  99                }
 100        }
 101
 102        /*
 103         * We shouldn't have gotten a message downcall with no
 104         * messages available.
 105         */
 106        if (nmsgs == 0)
 107                panic("Message downcall invoked with no messages!");
 108
 109        /*
 110         * Track time spent against the current process again and
 111         * process any softirqs if they are waiting.
 112         */
 113        irq_exit();
 114        set_irq_regs(old_regs);
 115}
 116