source: mainline/kernel/arch/sparc64/src/smp/sun4u/ipi.c@ c5429fe

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since c5429fe was c5429fe, checked in by Jakub Jermar <jakub@…>, 7 years ago

Disambiguate architecture specific doxygroups

  • Property mode set to 100644
File size: 5.5 KB
Line 
1/*
2 * Copyright (c) 2006 Jakub Jermar
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup kernel_sparc64
30 * @{
31 */
32/** @file
33 */
34
35#include <smp/ipi.h>
36#include <arch/barrier.h>
37#include <arch/smp/sun4u/ipi.h>
38#include <assert.h>
39#include <cpu.h>
40#include <arch.h>
41#include <arch/cpu.h>
42#include <arch/asm.h>
43#include <config.h>
44#include <mm/tlb.h>
45#include <smp/smp_call.h>
46#include <arch/interrupt.h>
47#include <arch/trap/interrupt.h>
48#include <barrier.h>
49#include <preemption.h>
50#include <time/delay.h>
51#include <panic.h>
52
53/** Set the contents of the outgoing interrupt vector data.
54 *
55 * The first data item (data 0) will be set to the value of func, the
56 * rest of the vector will contain zeros.
57 *
58 * This is a helper function used from within the cross_call function.
59 *
60 * @param func value the first data item of the vector will be set to
61 */
62static inline void set_intr_w_data(void (*func)(void))
63{
64#if defined (US)
65 asi_u64_write(ASI_INTR_W, ASI_UDB_INTR_W_DATA_0, (uintptr_t) func);
66 asi_u64_write(ASI_INTR_W, ASI_UDB_INTR_W_DATA_1, 0);
67 asi_u64_write(ASI_INTR_W, ASI_UDB_INTR_W_DATA_2, 0);
68#elif defined (US3)
69 asi_u64_write(ASI_INTR_W, VA_INTR_W_DATA_0, (uintptr_t) func);
70 asi_u64_write(ASI_INTR_W, VA_INTR_W_DATA_1, 0);
71 asi_u64_write(ASI_INTR_W, VA_INTR_W_DATA_2, 0);
72 asi_u64_write(ASI_INTR_W, VA_INTR_W_DATA_3, 0);
73 asi_u64_write(ASI_INTR_W, VA_INTR_W_DATA_4, 0);
74 asi_u64_write(ASI_INTR_W, VA_INTR_W_DATA_5, 0);
75 asi_u64_write(ASI_INTR_W, VA_INTR_W_DATA_6, 0);
76 asi_u64_write(ASI_INTR_W, VA_INTR_W_DATA_7, 0);
77#endif
78}
79
80/** Invoke function on another processor.
81 *
82 * Currently, only functions without arguments are supported.
83 * Supporting more arguments in the future should be no big deal.
84 *
85 * Interrupts must be disabled prior to this call.
86 *
87 * @param mid MID of the target processor.
88 * @param func Function to be invoked.
89 */
90static void cross_call(int mid, void (*func)(void))
91{
92 uint64_t status;
93 bool done;
94
95 /*
96 * This function might enable interrupts for a while.
97 * In order to prevent migration to another processor,
98 * we explicitly disable preemption.
99 */
100
101 preemption_disable();
102
103 status = asi_u64_read(ASI_INTR_DISPATCH_STATUS, 0);
104 if (status & INTR_DISPATCH_STATUS_BUSY)
105 panic("Interrupt Dispatch Status busy bit set\n");
106
107 assert(!(pstate_read() & PSTATE_IE_BIT));
108
109 do {
110 set_intr_w_data(func);
111 asi_u64_write(ASI_INTR_W,
112 (mid << INTR_VEC_DISPATCH_MID_SHIFT) |
113 VA_INTR_W_DISPATCH, 0);
114
115 membar();
116
117 do {
118 status = asi_u64_read(ASI_INTR_DISPATCH_STATUS, 0);
119 } while (status & INTR_DISPATCH_STATUS_BUSY);
120
121 done = !(status & INTR_DISPATCH_STATUS_NACK);
122 if (!done) {
123 /*
124 * Prevent deadlock.
125 */
126 (void) interrupts_enable();
127 delay(20 + (tick_read() & 0xff));
128 (void) interrupts_disable();
129 }
130 } while (!done);
131
132 preemption_enable();
133}
134
135/*
136 * Deliver IPI to all processors except the current one.
137 *
138 * The sparc64 architecture does not support any group addressing
139 * which is found, for instance, on ia32 and amd64. Therefore we
140 * need to simulate the broadcast by sending the message to
141 * all target processors step by step.
142 *
143 * We assume that interrupts are disabled.
144 *
145 * @param ipi IPI number.
146 */
147void ipi_broadcast_arch(int ipi)
148{
149 unsigned int i;
150
151 void (*func)(void);
152
153 switch (ipi) {
154 case IPI_TLB_SHOOTDOWN:
155 func = tlb_shootdown_ipi_recv;
156 break;
157 default:
158 panic("Unknown IPI (%d).\n", ipi);
159 break;
160 }
161
162 /*
163 * As long as we don't support hot-plugging
164 * or hot-unplugging of CPUs, we can walk
165 * the cpus array and read processor's MID
166 * without locking.
167 */
168
169 for (i = 0; i < config.cpu_active; i++) {
170 if (&cpus[i] == CPU)
171 continue; /* skip the current CPU */
172
173 cross_call(cpus[i].arch.mid, func);
174 }
175}
176
177/*
178 * Deliver an IPI to the specified processors (except the current one).
179 *
180 * Interrupts must be disabled.
181 *
182 * @param cpu_id Destination cpu id (index into cpus array). Must not
183 * be the current cpu.
184 * @param ipi IPI number.
185 */
186void ipi_unicast_arch(unsigned int cpu_id, int ipi)
187{
188 assert(&cpus[cpu_id] != CPU);
189
190 if (ipi == IPI_SMP_CALL) {
191 cross_call(cpus[cpu_id].arch.mid, smp_call_ipi_recv);
192 } else {
193 panic("Unknown IPI (%d).\n", ipi);
194 return;
195 }
196}
197
198/** @}
199 */
Note: See TracBrowser for help on using the repository browser.