412ad5bac323727b4073056113e1d8e0faf60db3vboxsync/* $Id$ */
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync/** @file
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * IPRT - Multiprocessor Event Notifications, Ring-0 Driver, Linux.
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync */
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync/*
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync * Copyright (C) 2008-2015 Oracle Corporation
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync *
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * available from http://www.virtualbox.org. This file is free software;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * you can redistribute it and/or modify it under the terms of the GNU
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * General Public License (GPL) as published by the Free Software
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync *
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * The contents of this file may alternatively be used under the terms
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * of the Common Development and Distribution License Version 1.0
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * VirtualBox OSE distribution, in which case the provisions of the
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * CDDL are applicable instead of those of the GPL.
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync *
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * You may elect to license modified versions of this file under the
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * terms and conditions of either the GPL or the CDDL or both.
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync */
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync/*******************************************************************************
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync* Header Files *
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync*******************************************************************************/
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync#include "the-linux-kernel.h"
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsync#include "internal/iprt.h"
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
6d3ac076ef46c81505ba351196f9f9e7df338a53vboxsync#include <iprt/asm-amd64-x86.h>
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync#include <iprt/err.h>
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync#include <iprt/cpuset.h>
f2054a43ed4a624a04100921b1de7ec86974ddcfvboxsync#include <iprt/thread.h>
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync#include "r0drv/mp-r0drv.h"
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 71) && defined(CONFIG_SMP)
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync/*******************************************************************************
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync* Internal Functions *
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync*******************************************************************************/
412ad5bac323727b4073056113e1d8e0faf60db3vboxsyncstatic int rtMpNotificationLinuxCallback(struct notifier_block *pNotifierBlock, unsigned long ulNativeEvent, void *pvCpu);
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync/*******************************************************************************
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync* Global Variables *
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync*******************************************************************************/
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync/**
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * The notifier block we use for registering the callback.
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync */
412ad5bac323727b4073056113e1d8e0faf60db3vboxsyncstatic struct notifier_block g_NotifierBlock =
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync{
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync .notifier_call = rtMpNotificationLinuxCallback,
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync .next = NULL,
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync .priority = 0
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync};
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsync# ifdef CPU_DOWN_FAILED
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync/**
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * The set of CPUs we've seen going offline recently.
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync */
412ad5bac323727b4073056113e1d8e0faf60db3vboxsyncstatic RTCPUSET g_MpPendingOfflineSet;
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsync# endif
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
181fd68b3b1a282817d722139f2a5090bb0876a9vboxsync/**
181fd68b3b1a282817d722139f2a5090bb0876a9vboxsync * The native callback.
181fd68b3b1a282817d722139f2a5090bb0876a9vboxsync *
181fd68b3b1a282817d722139f2a5090bb0876a9vboxsync * @returns NOTIFY_DONE.
181fd68b3b1a282817d722139f2a5090bb0876a9vboxsync * @param pNotifierBlock Pointer to g_NotifierBlock.
181fd68b3b1a282817d722139f2a5090bb0876a9vboxsync * @param ulNativeEvent The native event.
181fd68b3b1a282817d722139f2a5090bb0876a9vboxsync * @param pvCpu The cpu id cast into a pointer value.
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync *
181fd68b3b1a282817d722139f2a5090bb0876a9vboxsync * @remarks This can fire with preemption enabled and on any CPU.
181fd68b3b1a282817d722139f2a5090bb0876a9vboxsync */
181fd68b3b1a282817d722139f2a5090bb0876a9vboxsyncstatic int rtMpNotificationLinuxCallback(struct notifier_block *pNotifierBlock, unsigned long ulNativeEvent, void *pvCpu)
181fd68b3b1a282817d722139f2a5090bb0876a9vboxsync{
181fd68b3b1a282817d722139f2a5090bb0876a9vboxsync bool fProcessEvent = false;
181fd68b3b1a282817d722139f2a5090bb0876a9vboxsync RTCPUID idCpu = (uintptr_t)pvCpu;
181fd68b3b1a282817d722139f2a5090bb0876a9vboxsync NOREF(pNotifierBlock);
181fd68b3b1a282817d722139f2a5090bb0876a9vboxsync
931774aba1ecbdb5498169349e6ddb224e4861f0vboxsync /*
931774aba1ecbdb5498169349e6ddb224e4861f0vboxsync * Note that redhat/CentOS ported _some_ of the FROZEN macros
931774aba1ecbdb5498169349e6ddb224e4861f0vboxsync * back to their 2.6.18-92.1.10.el5 kernel but actually don't
931774aba1ecbdb5498169349e6ddb224e4861f0vboxsync * use them. Thus we have to test for both CPU_TASKS_FROZEN and
931774aba1ecbdb5498169349e6ddb224e4861f0vboxsync * the individual event variants.
931774aba1ecbdb5498169349e6ddb224e4861f0vboxsync */
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync switch (ulNativeEvent)
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync {
931774aba1ecbdb5498169349e6ddb224e4861f0vboxsync /*
931774aba1ecbdb5498169349e6ddb224e4861f0vboxsync * Pick up online events or failures to go offline.
931774aba1ecbdb5498169349e6ddb224e4861f0vboxsync * Ignore failure events for CPUs we didn't see go offline.
931774aba1ecbdb5498169349e6ddb224e4861f0vboxsync */
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsync# ifdef CPU_DOWN_FAILED
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync case CPU_DOWN_FAILED:
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsync# if defined(CPU_TASKS_FROZEN) && defined(CPU_DOWN_FAILED_FROZEN)
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync case CPU_DOWN_FAILED_FROZEN:
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsync# endif
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync if (!RTCpuSetIsMember(&g_MpPendingOfflineSet, idCpu))
181fd68b3b1a282817d722139f2a5090bb0876a9vboxsync break; /* fProcessEvents = false */
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync /* fall thru */
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsync# endif
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync case CPU_ONLINE:
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsync# if defined(CPU_TASKS_FROZEN) && defined(CPU_ONLINE_FROZEN)
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync case CPU_ONLINE_FROZEN:
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsync# endif
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsync# ifdef CPU_DOWN_FAILED
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync RTCpuSetDel(&g_MpPendingOfflineSet, idCpu);
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsync# endif
181fd68b3b1a282817d722139f2a5090bb0876a9vboxsync fProcessEvent = true;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync break;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
931774aba1ecbdb5498169349e6ddb224e4861f0vboxsync /*
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync * Pick the earliest possible offline event.
931774aba1ecbdb5498169349e6ddb224e4861f0vboxsync * The only important thing here is that we get the event and that
931774aba1ecbdb5498169349e6ddb224e4861f0vboxsync * it's exactly one.
931774aba1ecbdb5498169349e6ddb224e4861f0vboxsync */
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsync# ifdef CPU_DOWN_PREPARE
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync case CPU_DOWN_PREPARE:
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsync# if defined(CPU_TASKS_FROZEN) && defined(CPU_DOWN_PREPARE_FROZEN)
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync case CPU_DOWN_PREPARE_FROZEN:
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsync# endif
181fd68b3b1a282817d722139f2a5090bb0876a9vboxsync fProcessEvent = true;
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsync# else
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync case CPU_DEAD:
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsync# if defined(CPU_TASKS_FROZEN) && defined(CPU_DEAD_FROZEN)
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync case CPU_DEAD_FROZEN:
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsync# endif
181fd68b3b1a282817d722139f2a5090bb0876a9vboxsync /* Don't process CPU_DEAD notifications. */
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync# endif
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsync# ifdef CPU_DOWN_FAILED
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync RTCpuSetAdd(&g_MpPendingOfflineSet, idCpu);
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsync# endif
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync break;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync }
f2054a43ed4a624a04100921b1de7ec86974ddcfvboxsync
181fd68b3b1a282817d722139f2a5090bb0876a9vboxsync if (!fProcessEvent)
181fd68b3b1a282817d722139f2a5090bb0876a9vboxsync return NOTIFY_DONE;
f2054a43ed4a624a04100921b1de7ec86974ddcfvboxsync
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync switch (ulNativeEvent)
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync {
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync# ifdef CPU_DOWN_FAILED
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync case CPU_DOWN_FAILED:
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync# if defined(CPU_TASKS_FROZEN) && defined(CPU_DOWN_FAILED_FROZEN)
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync case CPU_DOWN_FAILED_FROZEN:
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync# endif
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync# endif
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync case CPU_ONLINE:
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync# if defined(CPU_TASKS_FROZEN) && defined(CPU_ONLINE_FROZEN)
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync case CPU_ONLINE_FROZEN:
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync# endif
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync rtMpNotificationDoCallbacks(RTMPEVENT_ONLINE, idCpu);
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync break;
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync# ifdef CPU_DOWN_PREPARE
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync case CPU_DOWN_PREPARE:
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync# if defined(CPU_TASKS_FROZEN) && defined(CPU_DOWN_PREPARE_FROZEN)
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync case CPU_DOWN_PREPARE_FROZEN:
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync# endif
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync rtMpNotificationDoCallbacks(RTMPEVENT_OFFLINE, idCpu);
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync break;
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync# endif
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync }
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync
e12099475d7cc455a4cd3f8e36eba8c4851ee9d7vboxsync return NOTIFY_DONE;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync}
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
5eda82e218d35ae0691febd531e1bfc0324cc4a6vboxsyncDECLHIDDEN(int) rtR0MpNotificationNativeInit(void)
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync{
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync int rc;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsync# ifdef CPU_DOWN_FAILED
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync RTCpuSetEmpty(&g_MpPendingOfflineSet);
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsync# endif
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync rc = register_cpu_notifier(&g_NotifierBlock);
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync AssertMsgReturn(!rc, ("%d\n", rc), RTErrConvertFromErrno(rc));
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync return VINF_SUCCESS;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync}
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
5eda82e218d35ae0691febd531e1bfc0324cc4a6vboxsyncDECLHIDDEN(void) rtR0MpNotificationNativeTerm(void)
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync{
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync unregister_cpu_notifier(&g_NotifierBlock);
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync}
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync#else /* Not supported / Not needed */
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
5eda82e218d35ae0691febd531e1bfc0324cc4a6vboxsyncDECLHIDDEN(int) rtR0MpNotificationNativeInit(void)
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync{
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync return VINF_SUCCESS;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync}
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
5eda82e218d35ae0691febd531e1bfc0324cc4a6vboxsyncDECLHIDDEN(void) rtR0MpNotificationNativeTerm(void)
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync{
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync}
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync#endif /* Not supported / Not needed */
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync