VirtualBox

source: vbox/trunk/src/VBox/Runtime/r0drv/linux/mp-r0drv-linux.c@ 22508

Last change on this file since 22508 was 21337, checked in by vboxsync, 15 years ago

IPRT,HostDrv,AddDrv: Export public IPRT symbols for the linux kernel (pain).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.0 KB
Line 
1/* $Id: mp-r0drv-linux.c 21337 2009-07-07 14:58:27Z vboxsync $ */
2/** @file
3 * IPRT - Multiprocessor, Ring-0 Driver, Linux.
4 */
5
6/*
7 * Copyright (C) 2008 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 *
26 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
27 * Clara, CA 95054 USA or visit http://www.sun.com if you need
28 * additional information or have any questions.
29 */
30
31
32/*******************************************************************************
33* Header Files *
34*******************************************************************************/
35#include "the-linux-kernel.h"
36#include "internal/iprt.h"
37
38#include <iprt/mp.h>
39#include <iprt/cpuset.h>
40#include <iprt/err.h>
41#include <iprt/asm.h>
42#include "r0drv/mp-r0drv.h"
43
44
45RTDECL(RTCPUID) RTMpCpuId(void)
46{
47 return smp_processor_id();
48}
49RT_EXPORT_SYMBOL(RTMpCpuId);
50
51
52RTDECL(int) RTMpCpuIdToSetIndex(RTCPUID idCpu)
53{
54 return idCpu < NR_CPUS ? (int)idCpu : -1;
55}
56RT_EXPORT_SYMBOL(RTMpCpuIdToSetIndex);
57
58
59RTDECL(RTCPUID) RTMpCpuIdFromSetIndex(int iCpu)
60{
61 return iCpu < NR_CPUS ? (RTCPUID)iCpu : NIL_RTCPUID;
62}
63RT_EXPORT_SYMBOL(RTMpCpuIdFromSetIndex);
64
65
66RTDECL(RTCPUID) RTMpGetMaxCpuId(void)
67{
68 return NR_CPUS - 1; //???
69}
70RT_EXPORT_SYMBOL(RTMpGetMaxCpuId);
71
72
73RTDECL(bool) RTMpIsCpuPossible(RTCPUID idCpu)
74{
75#if defined(CONFIG_SMP)
76 if (RT_UNLIKELY(idCpu >= NR_CPUS))
77 return false;
78
79# if defined(cpu_possible)
80 return cpu_possible(idCpu);
81# else /* < 2.5.29 */
82 return idCpu < (RTCPUID)smp_num_cpus;
83# endif
84#else
85 return idCpu == RTMpCpuId();
86#endif
87}
88RT_EXPORT_SYMBOL(RTMpIsCpuPossible);
89
90
91RTDECL(PRTCPUSET) RTMpGetSet(PRTCPUSET pSet)
92{
93 RTCPUID idCpu;
94
95 RTCpuSetEmpty(pSet);
96 idCpu = RTMpGetMaxCpuId();
97 do
98 {
99 if (RTMpIsCpuPossible(idCpu))
100 RTCpuSetAdd(pSet, idCpu);
101 } while (idCpu-- > 0);
102 return pSet;
103}
104RT_EXPORT_SYMBOL(RTMpGetSet);
105
106
107RTDECL(RTCPUID) RTMpGetCount(void)
108{
109#ifdef CONFIG_SMP
110# if defined(CONFIG_HOTPLUG_CPU) /* introduced & uses cpu_present */
111 return num_present_cpus();
112# elif defined(num_possible_cpus)
113 return num_possible_cpus();
114# elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
115 return smp_num_cpus;
116# else
117 RTCPUSET Set;
118 RTMpGetSet(&Set);
119 return RTCpuSetCount(&Set);
120# endif
121#else
122 return 1;
123#endif
124}
125RT_EXPORT_SYMBOL(RTMpGetCount);
126
127
128RTDECL(bool) RTMpIsCpuOnline(RTCPUID idCpu)
129{
130#ifdef CONFIG_SMP
131 if (RT_UNLIKELY(idCpu >= NR_CPUS))
132 return false;
133# ifdef cpu_online
134 return cpu_online(idCpu);
135# else /* 2.4: */
136 return cpu_online_map & RT_BIT_64(idCpu);
137# endif
138#else
139 return idCpu == RTMpCpuId();
140#endif
141}
142RT_EXPORT_SYMBOL(RTMpIsCpuOnline);
143
144
145RTDECL(PRTCPUSET) RTMpGetOnlineSet(PRTCPUSET pSet)
146{
147#ifdef CONFIG_SMP
148 RTCPUID idCpu;
149
150 RTCpuSetEmpty(pSet);
151 idCpu = RTMpGetMaxCpuId();
152 do
153 {
154 if (RTMpIsCpuOnline(idCpu))
155 RTCpuSetAdd(pSet, idCpu);
156 } while (idCpu-- > 0);
157#else
158 RTCpuSetEmpty(pSet);
159 RTCpuSetAdd(pSet, RTMpCpuId());
160#endif
161 return pSet;
162}
163RT_EXPORT_SYMBOL(RTMpGetOnlineSet);
164
165
166RTDECL(RTCPUID) RTMpGetOnlineCount(void)
167{
168#ifdef CONFIG_SMP
169# if defined(num_online_cpus)
170 return num_online_cpus();
171# else
172 RTCPUSET Set;
173 RTMpGetOnlineSet(&Set);
174 return RTCpuSetCount(&Set);
175# endif
176#else
177 return 1;
178#endif
179}
180RT_EXPORT_SYMBOL(RTMpGetOnlineCount);
181
182
183RTDECL(bool) RTMpIsCpuWorkPending(void)
184{
185 /** @todo (not used on non-Windows platforms yet). */
186 return false;
187}
188RT_EXPORT_SYMBOL(RTMpIsCpuWorkPending);
189
190
191/**
192 * Wrapper between the native linux per-cpu callbacks and PFNRTWORKER
193 *
194 * @param pvInfo Pointer to the RTMPARGS package.
195 */
196static void rtmpLinuxWrapper(void *pvInfo)
197{
198 PRTMPARGS pArgs = (PRTMPARGS)pvInfo;
199 ASMAtomicIncU32(&pArgs->cHits);
200 pArgs->pfnWorker(RTMpCpuId(), pArgs->pvUser1, pArgs->pvUser2);
201}
202
203
204RTDECL(int) RTMpOnAll(PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2)
205{
206 int rc;
207 RTMPARGS Args;
208
209 Args.pfnWorker = pfnWorker;
210 Args.pvUser1 = pvUser1;
211 Args.pvUser2 = pvUser2;
212 Args.idCpu = NIL_RTCPUID;
213 Args.cHits = 0;
214
215#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
216 rc = on_each_cpu(rtmpLinuxWrapper, &Args, 1 /* wait */);
217#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
218 rc = on_each_cpu(rtmpLinuxWrapper, &Args, 0 /* retry */, 1 /* wait */);
219
220#else /* older kernels */
221
222# ifdef preempt_disable
223 preempt_disable();
224# endif
225 rc = smp_call_function(rtmpLinuxWrapper, &Args, 0 /* retry */, 1 /* wait */);
226 local_irq_disable();
227 rtmpLinuxWrapper(&Args);
228 local_irq_enable();
229# ifdef preempt_enable
230 preempt_enable();
231# endif
232#endif /* older kernels */
233 Assert(rc == 0); NOREF(rc);
234 return VINF_SUCCESS;
235}
236RT_EXPORT_SYMBOL(RTMpOnAll);
237
238
239RTDECL(int) RTMpOnOthers(PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2)
240{
241 int rc;
242 RTMPARGS Args;
243
244 Args.pfnWorker = pfnWorker;
245 Args.pvUser1 = pvUser1;
246 Args.pvUser2 = pvUser2;
247 Args.idCpu = NIL_RTCPUID;
248 Args.cHits = 0;
249
250#ifdef preempt_disable
251 preempt_disable();
252#endif
253#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
254 rc = smp_call_function(rtmpLinuxWrapper, &Args, 1 /* wait */);
255#else /* older kernels */
256 rc = smp_call_function(rtmpLinuxWrapper, &Args, 0 /* retry */, 1 /* wait */);
257#endif /* older kernels */
258#ifdef preempt_enable
259 preempt_enable();
260#endif
261
262 Assert(rc == 0); NOREF(rc);
263 return VINF_SUCCESS;
264}
265RT_EXPORT_SYMBOL(RTMpOnOthers);
266
267
268#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
269/**
270 * Wrapper between the native linux per-cpu callbacks and PFNRTWORKER
271 * employed by RTMpOnSpecific on older kernels that lacks smp_call_function_single.
272 *
273 * @param pvInfo Pointer to the RTMPARGS package.
274 */
275static void rtmpOnSpecificLinuxWrapper(void *pvInfo)
276{
277 PRTMPARGS pArgs = (PRTMPARGS)pvInfo;
278 RTCPUID idCpu = RTMpCpuId();
279
280 if (idCpu == pArgs->idCpu)
281 {
282 pArgs->pfnWorker(idCpu, pArgs->pvUser1, pArgs->pvUser2);
283 ASMAtomicIncU32(&pArgs->cHits);
284 }
285}
286#endif
287
288
289RTDECL(int) RTMpOnSpecific(RTCPUID idCpu, PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2)
290{
291 int rc;
292 RTMPARGS Args;
293
294 Args.pfnWorker = pfnWorker;
295 Args.pvUser1 = pvUser1;
296 Args.pvUser2 = pvUser2;
297 Args.idCpu = idCpu;
298 Args.cHits = 0;
299
300 if (!RTMpIsCpuPossible(idCpu))
301 return VERR_CPU_NOT_FOUND;
302
303# ifdef preempt_disable
304 preempt_disable();
305# endif
306 if (idCpu != RTMpCpuId())
307 {
308 if (RTMpIsCpuOnline(idCpu))
309 {
310#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
311 rc = smp_call_function_single(idCpu, rtmpLinuxWrapper, &Args, 1 /* wait */);
312#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
313 rc = smp_call_function_single(idCpu, rtmpLinuxWrapper, &Args, 0 /* retry */, 1 /* wait */);
314#else /* older kernels */
315 rc = smp_call_function(rtmpOnSpecificLinuxWrapper, &Args, 0 /* retry */, 1 /* wait */);
316#endif /* older kernels */
317 Assert(rc == 0);
318 rc = Args.cHits ? VINF_SUCCESS : VERR_CPU_OFFLINE;
319 }
320 else
321 rc = VERR_CPU_OFFLINE;
322 }
323 else
324 {
325 rtmpLinuxWrapper(&Args);
326 rc = VINF_SUCCESS;
327 }
328# ifdef preempt_enable
329 preempt_enable();
330# endif
331
332 NOREF(rc);
333 return rc;
334}
335RT_EXPORT_SYMBOL(RTMpOnSpecific);
336
337
338#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
339/**
340 * Dummy callback used by RTMpPokeCpu.
341 *
342 * @param pvInfo Ignored.
343 */
344static void rtmpLinuxPokeCpuCallback(void *pvInfo)
345{
346 NOREF(pvInfo);
347}
348#endif
349
350
351RTDECL(int) RTMpPokeCpu(RTCPUID idCpu)
352{
353#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
354 int rc;
355
356 if (!RTMpIsCpuPossible(idCpu))
357 return VERR_CPU_NOT_FOUND;
358 if (!RTMpIsCpuOnline(idCpu))
359 return VERR_CPU_OFFLINE;
360
361# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
362 rc = smp_call_function_single(idCpu, rtmpLinuxPokeCpuCallback, NULL, 0 /* wait */);
363# elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
364 rc = smp_call_function_single(idCpu, rtmpLinuxPokeCpuCallback, NULL, 0 /* retry */, 0 /* wait */);
365# else /* older kernels */
366# error oops
367# endif /* older kernels */
368 Assert(rc == 0);
369 return VINF_SUCCESS;
370
371#else /* older kernels */
372 /* no unicast here? */
373 return VERR_NOT_SUPPORTED;
374#endif /* older kernels */
375}
376RT_EXPORT_SYMBOL(RTMpPokeCpu);
377
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette