win-pvdrivers

annotate xenpci/xenpci_highsync.c @ 910:1ee7940af105

Fix compilation under older DDK
author James Harper <james.harper@bendigoit.com.au>
date Fri Apr 29 23:56:03 2011 +1000 (2011-04-29)
parents 44029b09876a
children fe04dbceb0b2
rev   line source
james@529 1 /*
james@529 2 PV Drivers for Windows Xen HVM Domains
james@529 3 Copyright (C) 2007 James Harper
james@529 4
james@529 5 This program is free software; you can redistribute it and/or
james@529 6 modify it under the terms of the GNU General Public License
james@529 7 as published by the Free Software Foundation; either version 2
james@529 8 of the License, or (at your option) any later version.
james@529 9
james@529 10 This program is distributed in the hope that it will be useful,
james@529 11 but WITHOUT ANY WARRANTY; without even the implied warranty of
james@529 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
james@529 13 GNU General Public License for more details.
james@529 14
james@529 15 You should have received a copy of the GNU General Public License
james@529 16 along with this program; if not, write to the Free Software
james@529 17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
james@529 18 */
james@529 19
james@529 20 #include "xenpci.h"
james@529 21
james@716 22 /* Not really necessary but keeps PREfast happy */
james@910 23 #if (VER_PRODUCTBUILD >= 7600)
james@716 24 static KDEFERRED_ROUTINE XenPci_HighSyncCallFunction0;
james@716 25 static KDEFERRED_ROUTINE XenPci_HighSyncCallFunctionN;
james@818 26 #endif
james@716 27
james@537 28 /*
james@537 29 we need these intrinsics as even going to HIGH_LEVEL doesn't ensure that interrupts are completely disabled
james@537 30 */
james@537 31 #pragma intrinsic(_disable)
james@537 32 #pragma intrinsic(_enable)
james@537 33
james@529 34 struct {
james@529 35 volatile ULONG do_spin;
james@809 36 volatile LONG nr_procs_at_dispatch_level;
james@809 37 volatile LONG nr_spinning_at_sync_level;
james@529 38 KDPC dpcs[MAX_VIRT_CPUS];
james@529 39 KEVENT highsync_complete_event;
james@536 40 KIRQL sync_level;
james@529 41 PXENPCI_HIGHSYNC_FUNCTION function0;
james@529 42 PXENPCI_HIGHSYNC_FUNCTION functionN;
james@529 43 PVOID context;
james@529 44 } typedef highsync_info_t;
james@529 45
james@880 46 static VOID
james@529 47 XenPci_HighSyncCallFunction0(
james@529 48 PRKDPC Dpc,
james@529 49 PVOID Context,
james@529 50 PVOID SystemArgument1,
james@529 51 PVOID SystemArgument2)
james@529 52 {
james@529 53 highsync_info_t *highsync_info = Context;
james@529 54 ULONG ActiveProcessorCount;
james@529 55 KIRQL old_irql;
james@529 56
james@529 57 UNREFERENCED_PARAMETER(Dpc);
james@529 58 UNREFERENCED_PARAMETER(SystemArgument1);
james@529 59 UNREFERENCED_PARAMETER(SystemArgument2);
james@529 60
james@529 61 FUNCTION_ENTER();
james@818 62 #if (NTDDI_VERSION >= NTDDI_WINXP)
james@529 63 ActiveProcessorCount = (ULONG)KeNumberProcessors;
james@818 64 #else
james@818 65 ActiveProcessorCount = (ULONG)*KeNumberProcessors;
james@818 66 #endif
james@809 67 InterlockedIncrement(&highsync_info->nr_procs_at_dispatch_level);
james@809 68 if (highsync_info->sync_level > DISPATCH_LEVEL)
james@809 69 {
james@809 70 while (highsync_info->nr_procs_at_dispatch_level < (LONG)ActiveProcessorCount)
james@809 71 {
james@809 72 KeStallExecutionProcessor(1);
james@809 73 KeMemoryBarrier();
james@809 74 }
james@809 75 }
james@537 76 _disable(); //__asm cli;
james@536 77 KeRaiseIrql(highsync_info->sync_level, &old_irql);
james@809 78 while (highsync_info->nr_spinning_at_sync_level < (LONG)ActiveProcessorCount - 1)
james@529 79 {
james@529 80 KeStallExecutionProcessor(1);
james@529 81 KeMemoryBarrier();
james@529 82 }
james@529 83 highsync_info->function0(highsync_info->context);
james@529 84 KeLowerIrql(old_irql);
james@537 85 _enable(); //__asm sti;
james@529 86 highsync_info->do_spin = FALSE;
james@529 87 KeMemoryBarrier();
james@529 88 /* wait for all the other processors to complete spinning, just in case it matters */
james@809 89 while (highsync_info->nr_spinning_at_sync_level)
james@529 90 {
james@529 91 KeStallExecutionProcessor(1);
james@529 92 KeMemoryBarrier();
james@529 93 }
james@809 94 InterlockedDecrement(&highsync_info->nr_procs_at_dispatch_level);
james@901 95 /* wait until nr_procs_at_dispatch_level drops to 0 indicating that nothing else requires highsync_info */
james@902 96 while (highsync_info->nr_procs_at_dispatch_level)
james@901 97 {
james@901 98 KeStallExecutionProcessor(1);
james@901 99 KeMemoryBarrier();
james@901 100 }
james@529 101 KeSetEvent(&highsync_info->highsync_complete_event, IO_NO_INCREMENT, FALSE);
james@529 102
james@529 103 FUNCTION_EXIT();
james@529 104 }
james@529 105
james@529 106 static VOID
james@529 107 XenPci_HighSyncCallFunctionN(
james@529 108 PRKDPC Dpc,
james@529 109 PVOID Context,
james@529 110 PVOID SystemArgument1,
james@529 111 PVOID SystemArgument2)
james@529 112 {
james@529 113 highsync_info_t *highsync_info = Context;
james@809 114 ULONG ActiveProcessorCount;
james@529 115 KIRQL old_irql;
james@529 116
james@529 117 UNREFERENCED_PARAMETER(Dpc);
james@529 118 UNREFERENCED_PARAMETER(SystemArgument1);
james@529 119 UNREFERENCED_PARAMETER(SystemArgument2);
james@529 120
james@529 121 FUNCTION_ENTER();
james@529 122 FUNCTION_MSG("(CPU = %d)\n", KeGetCurrentProcessorNumber());
james@529 123
james@529 124 KdPrint((__DRIVER_NAME " CPU %d spinning...\n", KeGetCurrentProcessorNumber()));
james@809 125 InterlockedIncrement(&highsync_info->nr_procs_at_dispatch_level);
james@809 126 if (highsync_info->sync_level > DISPATCH_LEVEL)
james@809 127 {
james@818 128 #if (NTDDI_VERSION >= NTDDI_WINXP)
james@809 129 ActiveProcessorCount = (ULONG)KeNumberProcessors;
james@818 130 #else
james@818 131 ActiveProcessorCount = (ULONG)*KeNumberProcessors;
james@818 132 #endif
james@809 133 while (highsync_info->nr_procs_at_dispatch_level < (LONG)ActiveProcessorCount)
james@809 134 {
james@809 135 KeStallExecutionProcessor(1);
james@809 136 KeMemoryBarrier();
james@809 137 }
james@809 138 }
james@771 139 _disable(); //__asm cli;
james@536 140 KeRaiseIrql(highsync_info->sync_level, &old_irql);
james@809 141 InterlockedIncrement(&highsync_info->nr_spinning_at_sync_level);
james@529 142 while(highsync_info->do_spin)
james@529 143 {
james@529 144 KeStallExecutionProcessor(1);
james@529 145 KeMemoryBarrier();
james@529 146 }
james@529 147 highsync_info->functionN(highsync_info->context);
james@529 148 KeLowerIrql(old_irql);
james@771 149 _enable(); //__asm sti;
james@809 150 InterlockedDecrement(&highsync_info->nr_spinning_at_sync_level);
james@809 151 InterlockedDecrement(&highsync_info->nr_procs_at_dispatch_level);
james@529 152 FUNCTION_EXIT();
james@529 153 return;
james@529 154 }
james@529 155
james@529 156 VOID
james@529 157 XenPci_HighSync(PXENPCI_HIGHSYNC_FUNCTION function0, PXENPCI_HIGHSYNC_FUNCTION functionN, PVOID context)
james@529 158 {
james@529 159 ULONG ActiveProcessorCount;
james@529 160 ULONG i;
james@529 161 highsync_info_t *highsync_info;
james@529 162 KIRQL old_irql;
james@529 163
james@529 164 UNREFERENCED_PARAMETER(context);
james@529 165 FUNCTION_ENTER();
james@529 166
james@529 167 highsync_info = ExAllocatePoolWithTag(NonPagedPool, sizeof(highsync_info_t), XENPCI_POOL_TAG);
james@529 168 RtlZeroMemory(highsync_info, sizeof(highsync_info_t));
james@529 169 KeInitializeEvent(&highsync_info->highsync_complete_event, SynchronizationEvent, FALSE);
james@529 170 highsync_info->function0 = function0;
james@529 171 highsync_info->functionN = functionN;
james@529 172 highsync_info->context = context;
james@536 173 highsync_info->sync_level = HIGH_LEVEL;
james@529 174
james@818 175 #if (NTDDI_VERSION >= NTDDI_WINXP)
james@529 176 ActiveProcessorCount = (ULONG)KeNumberProcessors;
james@818 177 #else
james@818 178 ActiveProcessorCount = (ULONG)*KeNumberProcessors;
james@818 179 #endif
james@529 180
james@529 181 /* Go to HIGH_LEVEL to prevent any races with Dpc's on the current processor */
james@536 182 KeRaiseIrql(highsync_info->sync_level, &old_irql);
james@529 183
james@529 184 highsync_info->do_spin = TRUE;
james@529 185 for (i = 0; i < ActiveProcessorCount; i++)
james@529 186 {
james@529 187 if (i == 0)
james@529 188 KeInitializeDpc(&highsync_info->dpcs[i], XenPci_HighSyncCallFunction0, highsync_info);
james@529 189 else
james@529 190 KeInitializeDpc(&highsync_info->dpcs[i], XenPci_HighSyncCallFunctionN, highsync_info);
james@529 191 KeSetTargetProcessorDpc(&highsync_info->dpcs[i], (CCHAR)i);
james@529 192 KeSetImportanceDpc(&highsync_info->dpcs[i], HighImportance);
james@529 193 KdPrint((__DRIVER_NAME " queuing Dpc for CPU %d\n", i));
james@529 194 KeInsertQueueDpc(&highsync_info->dpcs[i], NULL, NULL);
james@529 195 }
james@529 196 KdPrint((__DRIVER_NAME " All Dpc's queued\n"));
james@536 197
james@529 198 KeMemoryBarrier();
james@529 199 KeLowerIrql(old_irql);
james@529 200
james@529 201 KdPrint((__DRIVER_NAME " Waiting for highsync_complete_event\n"));
james@529 202 KeWaitForSingleObject(&highsync_info->highsync_complete_event, Executive, KernelMode, FALSE, NULL);
james@902 203 #if (NTDDI_VERSION >= NTDDI_WINXP)
james@902 204 KeFlushQueuedDpcs();
james@902 205 #else
james@902 206 {
james@902 207 /* just wait 1 second until all DPC's finish - not ideal but it's only for W2K */
james@902 208 LARGE_INTEGER interval;
james@902 209 interval.QuadPart = -1 * 1000 * 1000 * 10; /* 1 second */
james@902 210 KeDelayExecutionThread(KernelMode, FALSE, &interval);
james@902 211 }
james@902 212 #endif
james@900 213 ExFreePoolWithTag(highsync_info, XENPCI_POOL_TAG);
james@529 214 FUNCTION_EXIT();
james@529 215 }