blob: 1c7a94580c3f78b6d574f8c1038a179d69feb278 [file] [log] [blame]
Kumar Gala620165f2009-02-12 13:54:53 +00001/*
2 * Author: Kumar Gala <galak@kernel.crashing.org>
3 *
4 * Copyright 2009 Freescale Semiconductor Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version.
10 */
11
12#include <linux/stddef.h>
13#include <linux/kernel.h>
14#include <linux/smp.h>
15#include <linux/threads.h>
Benjamin Herrenschmidtb9f1cd72010-07-09 15:29:53 +100016#include <linux/percpu.h>
Kumar Gala620165f2009-02-12 13:54:53 +000017
18#include <asm/dbell.h>
19
20#ifdef CONFIG_SMP
Benjamin Herrenschmidtb9f1cd72010-07-09 15:29:53 +100021struct doorbell_cpu_info {
22 unsigned long messages; /* current messages bits */
23 unsigned int tag; /* tag value */
24};
Kumar Gala620165f2009-02-12 13:54:53 +000025
Benjamin Herrenschmidtb9f1cd72010-07-09 15:29:53 +100026static DEFINE_PER_CPU(struct doorbell_cpu_info, doorbell_cpu_info);
27
28void doorbell_setup_this_cpu(void)
Kumar Gala620165f2009-02-12 13:54:53 +000029{
Benjamin Herrenschmidtb9f1cd72010-07-09 15:29:53 +100030 struct doorbell_cpu_info *info = &__get_cpu_var(doorbell_cpu_info);
31
32 info->messages = 0;
33 info->tag = mfspr(SPRN_PIR) & 0x3fff;
34}
35
36void doorbell_message_pass(int target, int msg)
37{
38 struct doorbell_cpu_info *info;
Kumar Gala620165f2009-02-12 13:54:53 +000039 int i;
40
Benjamin Herrenschmidtb9f1cd72010-07-09 15:29:53 +100041 if (target < NR_CPUS) {
42 info = &per_cpu(doorbell_cpu_info, target);
43 set_bit(msg, &info->messages);
44 ppc_msgsnd(PPC_DBELL, 0, info->tag);
Kumar Gala620165f2009-02-12 13:54:53 +000045 }
Benjamin Herrenschmidtb9f1cd72010-07-09 15:29:53 +100046 else if (target == MSG_ALL_BUT_SELF) {
Kumar Gala620165f2009-02-12 13:54:53 +000047 for_each_online_cpu(i) {
48 if (i == smp_processor_id())
49 continue;
Benjamin Herrenschmidtb9f1cd72010-07-09 15:29:53 +100050 info = &per_cpu(doorbell_cpu_info, i);
51 set_bit(msg, &info->messages);
52 ppc_msgsnd(PPC_DBELL, 0, info->tag);
Kumar Gala620165f2009-02-12 13:54:53 +000053 }
54 }
55 else { /* target == MSG_ALL */
Benjamin Herrenschmidtb9f1cd72010-07-09 15:29:53 +100056 for_each_online_cpu(i) {
57 info = &per_cpu(doorbell_cpu_info, i);
58 set_bit(msg, &info->messages);
59 }
Kumar Gala620165f2009-02-12 13:54:53 +000060 ppc_msgsnd(PPC_DBELL, PPC_DBELL_MSG_BRDCAST, 0);
61 }
62}
Benjamin Herrenschmidte3145b32010-07-09 15:25:18 +100063
64void doorbell_exception(struct pt_regs *regs)
65{
Benjamin Herrenschmidtb9f1cd72010-07-09 15:29:53 +100066 struct doorbell_cpu_info *info = &__get_cpu_var(doorbell_cpu_info);
Benjamin Herrenschmidte3145b32010-07-09 15:25:18 +100067 int msg;
68
Benjamin Herrenschmidtb9f1cd72010-07-09 15:29:53 +100069 /* Warning: regs can be NULL when called from irq enable */
70
71 if (!info->messages || (num_online_cpus() < 2))
Benjamin Herrenschmidte3145b32010-07-09 15:25:18 +100072 return;
73
74 for (msg = 0; msg < 4; msg++)
Benjamin Herrenschmidtb9f1cd72010-07-09 15:29:53 +100075 if (test_and_clear_bit(msg, &info->messages))
Benjamin Herrenschmidte3145b32010-07-09 15:25:18 +100076 smp_message_recv(msg);
77}
78
79#else /* CONFIG_SMP */
80void doorbell_exception(struct pt_regs *regs)
81{
82 printk(KERN_WARNING "Received doorbell on non-smp system\n");
83}
84#endif /* CONFIG_SMP */
85