win-pvdrivers

view xenpci/evtchn.c @ 340:2be08f708250

move KeGetCurrentProcessorNumber fix to xenpci.h
Add kdprints to new functions with inline asm to make sure they get verified to work properly
Add missing intrinsic to gnttbl.c
Add next file to makefile
author Andy Grover <andy.grover@oracle.com>
date Sun Jun 22 18:14:30 2008 -0700 (2008-06-22)
parents 72acaf6e4668
children 744c19115142
line source
1 /*
2 PV Drivers for Windows Xen HVM Domains
3 Copyright (C) 2007 James Harper
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
20 #include "xenpci.h"
22 #if defined(__MINGW32__)
23 /* mingw-runtime 3.13 lacks certain lowlevel intrinsics */
24 NTSTATUS BitScanForward(unsigned long *index, unsigned long mask)
25 {
26 int i;
28 for (i = 0; i < sizeof(unsigned long)*8; i++)
29 {
30 if (mask & (1 << i)) {
31 *index = i + 1;
32 KdPrint((__FUNC__ __LINE__ " Check that I work as expected!\n"));
33 return 1;
34 }
35 }
37 KdPrint((__FUNC__ __LINE__ " Check that I work as expected!\n"));
39 return 0;
40 }
42 /**
43 From linux include/asm-i386/bitops.h
44 */
45 static inline int test_and_set_bit(int nr, volatile long * addr)
46 {
47 int oldbit;
49 __asm__ __volatile__( "lock;"
50 "btsl %2,%1\n\tsbbl %0,%0"
51 :"=r" (oldbit),"+m" (*(volatile long *) addr)
52 :"Ir" (nr) : "memory");
54 KdPrint((__FUNC__ " Check that I work as expected!\n"));
56 return oldbit;
57 }
58 static inline int test_and_clear_bit(int nr, volatile long * addr)
59 {
60 int oldbit;
62 __asm__ __volatile__( "lock;"
63 "btrl %2,%1\n\tsbbl %0,%0"
64 :"=r" (oldbit),"+m" (*(volatile long *) addr)
65 :"Ir" (nr) : "memory");
67 KdPrint((__FUNC__ " Check that I work as expected!\n"));
69 return oldbit;
70 }
72 #define xchg(p1, p2) InterlockedExchange((xen_long_t * volatile)p1, p2)
73 #define synch_clear_bit(p1, p2) test_and_clear_bit(p1, p2)
74 #define synch_set_bit(p1, p2) test_and_set_bit(p1, p2)
75 #define bit_scan_forward(p1, p2) BitScanForward(p1, p2)
77 #elif defined(_WIN32)
78 #define xchg(p1, p2) _InterlockedExchange(p1, p2)
79 #define synch_clear_bit(p1, p2) _interlockedbittestandreset(p2, p1)
80 #define synch_set_bit(p1, p2) _interlockedbittestandset(p2, p1)
81 #define bit_scan_forward(p1, p2) _BitScanForward(p1, p2)
85 #else
86 #define xchg(p1, p2) _InterlockedExchange64(p1, p2)
87 #define synch_clear_bit(p1, p2) _interlockedbittestandreset64(p2, p1)
88 #define synch_set_bit(p1, p2) _interlockedbittestandset64(p2, p1)
89 #define bit_scan_forward(p1, p2) _BitScanForward64(p1, p2)
90 #endif
92 static DDKAPI VOID
93 EvtChn_DpcBounce(PRKDPC Dpc, PVOID Context, PVOID SystemArgument1, PVOID SystemArgument2)
94 {
95 ev_action_t *action = Context;
97 UNREFERENCED_PARAMETER(Dpc);
98 UNREFERENCED_PARAMETER(SystemArgument1);
99 UNREFERENCED_PARAMETER(SystemArgument2);
101 if (action->type == EVT_ACTION_TYPE_IRQ)
102 sw_interrupt((UCHAR)action->vector);
103 else
104 action->ServiceRoutine(NULL, action->ServiceContext);
105 }
107 static DDKAPI BOOLEAN
108 EvtChn_Interrupt(PKINTERRUPT Interrupt, PVOID Context)
109 {
110 int cpu = KeGetCurrentProcessorNumber() & (MAX_VIRT_CPUS - 1);
111 vcpu_info_t *vcpu_info;
112 PXENPCI_DEVICE_DATA xpdd = (PXENPCI_DEVICE_DATA)Context;
113 shared_info_t *shared_info_area = xpdd->shared_info_area;
114 xen_ulong_t evt_words;
115 unsigned long evt_word;
116 unsigned long evt_bit;
117 unsigned int port;
118 ev_action_t *ev_action;
120 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ " (cpu = %d)\n", cpu));
122 UNREFERENCED_PARAMETER(Interrupt);
124 vcpu_info = &shared_info_area->vcpu_info[cpu];
126 vcpu_info->evtchn_upcall_pending = 0;
128 evt_words = (xen_ulong_t)xchg((volatile xen_long_t *)&vcpu_info->evtchn_pending_sel, 0);
130 while (bit_scan_forward(&evt_word, evt_words))
131 {
132 evt_words &= ~(1 << evt_word);
133 while (bit_scan_forward(&evt_bit, shared_info_area->evtchn_pending[evt_word] & ~shared_info_area->evtchn_mask[evt_word]))
134 {
135 port = (evt_word << 5) + evt_bit;
136 ev_action = &xpdd->ev_actions[port];
137 switch (ev_action->type)
138 {
139 case EVT_ACTION_TYPE_NORMAL:
140 ev_action->ServiceRoutine(NULL, ev_action->ServiceContext);
141 break;
142 case EVT_ACTION_TYPE_DPC:
143 case EVT_ACTION_TYPE_IRQ: /* we have to call the IRQ from DPC or we risk mucking up IRQLs */
144 KeInsertQueueDpc(&ev_action->Dpc, NULL, NULL);
145 break;
146 default:
147 KdPrint((__DRIVER_NAME " Unhandled Event!!!\n"));
148 break;
149 }
150 synch_clear_bit(port, (volatile xen_long_t *)&shared_info_area->evtchn_pending[evt_word]);
151 }
152 }
154 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
156 return TRUE;
157 }
159 NTSTATUS
160 EvtChn_Bind(PVOID Context, evtchn_port_t Port, PKSERVICE_ROUTINE ServiceRoutine, PVOID ServiceContext)
161 {
162 PXENPCI_DEVICE_DATA xpdd = Context;
164 KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
166 if (xpdd->ev_actions[Port].type != EVT_ACTION_TYPE_EMPTY)
167 {
168 xpdd->ev_actions[Port].type = EVT_ACTION_TYPE_EMPTY;
169 KeMemoryBarrier(); // make sure we don't call the old Service Routine with the new data...
170 KdPrint((__DRIVER_NAME " Handler for port %d already registered, replacing\n", Port));
171 }
173 xpdd->ev_actions[Port].ServiceRoutine = ServiceRoutine;
174 xpdd->ev_actions[Port].ServiceContext = ServiceContext;
175 KeMemoryBarrier();
176 xpdd->ev_actions[Port].type = EVT_ACTION_TYPE_NORMAL;
178 EvtChn_Unmask(Context, Port);
180 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
182 return STATUS_SUCCESS;
183 }
185 NTSTATUS
186 EvtChn_BindDpc(PVOID Context, evtchn_port_t Port, PKSERVICE_ROUTINE ServiceRoutine, PVOID ServiceContext)
187 {
188 PXENPCI_DEVICE_DATA xpdd = Context;
190 KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
192 if (xpdd->ev_actions[Port].type != EVT_ACTION_TYPE_EMPTY)
193 {
194 xpdd->ev_actions[Port].type = EVT_ACTION_TYPE_EMPTY;
195 KeMemoryBarrier(); // make sure we don't call the old Service Routine with the new data...
196 KdPrint((__DRIVER_NAME " Handler for port %d already registered, replacing\n", Port));
197 }
199 xpdd->ev_actions[Port].ServiceRoutine = ServiceRoutine;
200 xpdd->ev_actions[Port].ServiceContext = ServiceContext;
201 KeInitializeDpc(&xpdd->ev_actions[Port].Dpc, EvtChn_DpcBounce, &xpdd->ev_actions[Port]);
202 KeMemoryBarrier(); // make sure that the new service routine is only called once the context is set up
203 xpdd->ev_actions[Port].type = EVT_ACTION_TYPE_DPC;
205 EvtChn_Unmask(Context, Port);
207 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
209 return STATUS_SUCCESS;
210 }
212 NTSTATUS
213 EvtChn_BindIrq(PVOID Context, evtchn_port_t Port, ULONG vector)
214 {
215 PXENPCI_DEVICE_DATA xpdd = Context;
217 KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
219 if (xpdd->ev_actions[Port].type != EVT_ACTION_TYPE_EMPTY)
220 {
221 xpdd->ev_actions[Port].type = EVT_ACTION_TYPE_EMPTY;
222 KeMemoryBarrier(); // make sure we don't call the old Service Routine with the new data...
223 KdPrint((__DRIVER_NAME " Handler for port %d already registered, replacing\n", Port));
224 }
226 KeInitializeDpc(&xpdd->ev_actions[Port].Dpc, EvtChn_DpcBounce, &xpdd->ev_actions[Port]);
227 xpdd->ev_actions[Port].vector = vector;
228 KeMemoryBarrier();
229 xpdd->ev_actions[Port].type = EVT_ACTION_TYPE_IRQ;
231 EvtChn_Unmask(Context, Port);
233 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
235 return STATUS_SUCCESS;
236 }
238 NTSTATUS
239 EvtChn_Unbind(PVOID Context, evtchn_port_t Port)
240 {
241 PXENPCI_DEVICE_DATA xpdd = Context;
243 EvtChn_Mask(Context, Port);
244 xpdd->ev_actions[Port].ServiceRoutine = NULL;
245 KeMemoryBarrier();
246 xpdd->ev_actions[Port].ServiceContext = NULL;
248 if (xpdd->ev_actions[Port].type == EVT_ACTION_TYPE_DPC)
249 KeRemoveQueueDpc(&xpdd->ev_actions[Port].Dpc);
251 return STATUS_SUCCESS;
252 }
254 NTSTATUS
255 EvtChn_Mask(PVOID Context, evtchn_port_t Port)
256 {
257 PXENPCI_DEVICE_DATA xpdd = Context;
259 synch_set_bit(Port,
260 (volatile xen_long_t *)&xpdd->shared_info_area->evtchn_mask[0]);
261 return STATUS_SUCCESS;
262 }
264 NTSTATUS
265 EvtChn_Unmask(PVOID Context, evtchn_port_t Port)
266 {
267 PXENPCI_DEVICE_DATA xpdd = Context;
269 synch_clear_bit(Port,
270 (volatile xen_long_t *)&xpdd->shared_info_area->evtchn_mask[0]);
271 return STATUS_SUCCESS;
272 }
274 NTSTATUS
275 EvtChn_Notify(PVOID Context, evtchn_port_t Port)
276 {
277 PXENPCI_DEVICE_DATA xpdd = Context;
278 struct evtchn_send send;
280 send.port = Port;
281 (void)HYPERVISOR_event_channel_op(xpdd, EVTCHNOP_send, &send);
282 return STATUS_SUCCESS;
283 }
285 evtchn_port_t
286 EvtChn_AllocUnbound(PVOID Context, domid_t Domain)
287 {
288 PXENPCI_DEVICE_DATA xpdd = Context;
289 evtchn_alloc_unbound_t op;
290 op.dom = DOMID_SELF;
291 op.remote_dom = Domain;
292 HYPERVISOR_event_channel_op(xpdd, EVTCHNOP_alloc_unbound, &op);
293 return op.port;
294 }
296 NTSTATUS
297 EvtChn_Init(PXENPCI_DEVICE_DATA xpdd)
298 {
299 NTSTATUS status;
300 int i;
302 KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
304 for (i = 0; i < NR_EVENTS; i++)
305 {
306 EvtChn_Mask(xpdd, i);
307 xpdd->ev_actions[i].type = EVT_ACTION_TYPE_EMPTY;
308 xpdd->ev_actions[i].Count = 0;
309 }
311 for (i = 0; i < 8; i++)
312 {
313 xpdd->shared_info_area->evtchn_pending[i] = 0;
314 }
316 for (i = 0; i < MAX_VIRT_CPUS; i++)
317 {
318 xpdd->shared_info_area->vcpu_info[i].evtchn_upcall_pending = 0;
319 xpdd->shared_info_area->vcpu_info[i].evtchn_pending_sel = 0;
320 xpdd->shared_info_area->vcpu_info[i].evtchn_upcall_mask = 1;
321 }
323 status = IoConnectInterrupt(
324 &xpdd->interrupt,
325 EvtChn_Interrupt,
326 xpdd,
327 NULL,
328 xpdd->irq_vector,
329 xpdd->irq_level,
330 xpdd->irq_level,
331 LevelSensitive,
332 TRUE, /* this is a bit of a hack to make xenvbd work */
333 xpdd->irq_affinity,
334 FALSE);
336 if (!NT_SUCCESS(status))
337 {
338 KdPrint((__DRIVER_NAME " IoConnectInterrupt failed 0x%08x\n", status));
339 return status;
340 }
342 hvm_set_parameter(xpdd, HVM_PARAM_CALLBACK_IRQ, xpdd->irq_number);
344 for (i = 0; i < MAX_VIRT_CPUS; i++)
345 {
346 xpdd->shared_info_area->vcpu_info[i].evtchn_upcall_mask = 0;
347 }
349 KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
351 return status;
352 }
354 NTSTATUS
355 EvtChn_Shutdown(PXENPCI_DEVICE_DATA xpdd)
356 {
357 UNREFERENCED_PARAMETER(xpdd);
359 return STATUS_SUCCESS;
360 }