win-pvdrivers

view xenpci/evtchn.c @ 380:5b2a37528899

using hypercall3's again, add support in mingw. remove duplicate code from evtchn.c
author Andy Grover <andy.grover@oracle.com>
date Wed Jul 09 12:33:23 2008 -0700 (2008-07-09)
parents 2ff96a909c28
children 3ffdcb607981
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 #define xchg(p1, p2) InterlockedExchange((xen_long_t * volatile)p1, p2)
24 /* rest implemented in mingw_extras.c */
25 #elif defined(_X86_)
26 #define xchg(p1, p2) _InterlockedExchange(p1, p2)
27 #define synch_clear_bit(p1, p2) _interlockedbittestandreset(p2, p1)
28 #define synch_set_bit(p1, p2) _interlockedbittestandset(p2, p1)
29 #define bit_scan_forward(p1, p2) _BitScanForward(p1, p2)
30 #else
31 #define xchg(p1, p2) _InterlockedExchange64(p1, p2)
32 #define synch_clear_bit(p1, p2) _interlockedbittestandreset64(p2, p1)
33 #define synch_set_bit(p1, p2) _interlockedbittestandset64(p2, p1)
34 #define bit_scan_forward(p1, p2) _BitScanForward64(p1, p2)
35 #endif
37 static DDKAPI VOID
38 EvtChn_DpcBounce(PRKDPC Dpc, PVOID Context, PVOID SystemArgument1, PVOID SystemArgument2)
39 {
40 ev_action_t *action = Context;
42 UNREFERENCED_PARAMETER(Dpc);
43 UNREFERENCED_PARAMETER(SystemArgument1);
44 UNREFERENCED_PARAMETER(SystemArgument2);
46 //KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
48 if (action->type == EVT_ACTION_TYPE_IRQ)
49 {
50 //KdPrint((__DRIVER_NAME " Calling interrupt vector %02x\n", action->vector));
51 sw_interrupt((UCHAR)action->vector);
52 }
53 else
54 {
55 action->ServiceRoutine(NULL, action->ServiceContext);
56 }
57 //KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
58 }
60 static DDKAPI BOOLEAN
61 EvtChn_Interrupt(PKINTERRUPT Interrupt, PVOID Context)
62 {
63 int cpu = KeGetCurrentProcessorNumber() & (MAX_VIRT_CPUS - 1);
64 vcpu_info_t *vcpu_info;
65 PXENPCI_DEVICE_DATA xpdd = (PXENPCI_DEVICE_DATA)Context;
66 shared_info_t *shared_info_area = xpdd->shared_info_area;
67 xen_ulong_t evt_words;
68 unsigned long evt_word;
69 unsigned long evt_bit;
70 unsigned int port;
71 ev_action_t *ev_action;
72 BOOLEAN handled = FALSE;
74 //KdPrint((__DRIVER_NAME " --> " __FUNCTION__ " (cpu = %d)\n", cpu));
76 UNREFERENCED_PARAMETER(Interrupt);
78 vcpu_info = &shared_info_area->vcpu_info[cpu];
80 vcpu_info->evtchn_upcall_pending = 0;
82 evt_words = (xen_ulong_t)xchg((volatile xen_long_t *)&vcpu_info->evtchn_pending_sel, 0);
84 while (bit_scan_forward(&evt_word, evt_words))
85 {
86 evt_words &= ~(1 << evt_word);
87 while (bit_scan_forward(&evt_bit, shared_info_area->evtchn_pending[evt_word] & ~shared_info_area->evtchn_mask[evt_word]))
88 {
89 handled = TRUE;
90 port = (evt_word << 5) + evt_bit;
91 ev_action = &xpdd->ev_actions[port];
92 switch (ev_action->type)
93 {
94 case EVT_ACTION_TYPE_NORMAL:
95 ev_action->ServiceRoutine(NULL, ev_action->ServiceContext);
96 break;
97 case EVT_ACTION_TYPE_DPC:
98 case EVT_ACTION_TYPE_IRQ: /* we have to call the IRQ from DPC or we risk mucking up IRQLs */
99 KeInsertQueueDpc(&ev_action->Dpc, NULL, NULL);
100 break;
101 default:
102 KdPrint((__DRIVER_NAME " Unhandled Event!!!\n"));
103 break;
104 }
105 synch_clear_bit(port, (volatile xen_long_t *)&shared_info_area->evtchn_pending[evt_word]);
106 }
107 }
109 //KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
111 return handled;
112 }
114 NTSTATUS
115 EvtChn_Bind(PVOID Context, evtchn_port_t Port, PKSERVICE_ROUTINE ServiceRoutine, PVOID ServiceContext)
116 {
117 PXENPCI_DEVICE_DATA xpdd = Context;
119 KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
121 if (xpdd->ev_actions[Port].type != EVT_ACTION_TYPE_EMPTY)
122 {
123 xpdd->ev_actions[Port].type = EVT_ACTION_TYPE_EMPTY;
124 KeMemoryBarrier(); // make sure we don't call the old Service Routine with the new data...
125 KdPrint((__DRIVER_NAME " Handler for port %d already registered, replacing\n", Port));
126 }
128 xpdd->ev_actions[Port].ServiceRoutine = ServiceRoutine;
129 xpdd->ev_actions[Port].ServiceContext = ServiceContext;
130 xpdd->ev_actions[Port].xpdd = xpdd;
131 KeMemoryBarrier();
132 xpdd->ev_actions[Port].type = EVT_ACTION_TYPE_NORMAL;
134 EvtChn_Unmask(Context, Port);
136 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
138 return STATUS_SUCCESS;
139 }
141 NTSTATUS
142 EvtChn_BindDpc(PVOID Context, evtchn_port_t Port, PKSERVICE_ROUTINE ServiceRoutine, PVOID ServiceContext)
143 {
144 PXENPCI_DEVICE_DATA xpdd = Context;
146 KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
148 if (xpdd->ev_actions[Port].type != EVT_ACTION_TYPE_EMPTY)
149 {
150 xpdd->ev_actions[Port].type = EVT_ACTION_TYPE_EMPTY;
151 KeMemoryBarrier(); // make sure we don't call the old Service Routine with the new data...
152 KdPrint((__DRIVER_NAME " Handler for port %d already registered, replacing\n", Port));
153 }
155 xpdd->ev_actions[Port].ServiceRoutine = ServiceRoutine;
156 xpdd->ev_actions[Port].ServiceContext = ServiceContext;
157 xpdd->ev_actions[Port].xpdd = xpdd;
158 KeInitializeDpc(&xpdd->ev_actions[Port].Dpc, EvtChn_DpcBounce, &xpdd->ev_actions[Port]);
159 KeMemoryBarrier(); // make sure that the new service routine is only called once the context is set up
160 xpdd->ev_actions[Port].type = EVT_ACTION_TYPE_DPC;
162 EvtChn_Unmask(Context, Port);
164 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
166 return STATUS_SUCCESS;
167 }
169 NTSTATUS
170 EvtChn_BindIrq(PVOID Context, evtchn_port_t Port, ULONG vector)
171 {
172 PXENPCI_DEVICE_DATA xpdd = Context;
174 KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
176 if (xpdd->ev_actions[Port].type != EVT_ACTION_TYPE_EMPTY)
177 {
178 xpdd->ev_actions[Port].type = EVT_ACTION_TYPE_EMPTY;
179 KeMemoryBarrier(); // make sure we don't call the old Service Routine with the new data...
180 KdPrint((__DRIVER_NAME " Handler for port %d already registered, replacing\n", Port));
181 }
183 KeInitializeDpc(&xpdd->ev_actions[Port].Dpc, EvtChn_DpcBounce, &xpdd->ev_actions[Port]);
184 xpdd->ev_actions[Port].vector = vector;
185 xpdd->ev_actions[Port].xpdd = xpdd;
186 KeMemoryBarrier();
187 xpdd->ev_actions[Port].type = EVT_ACTION_TYPE_IRQ;
189 EvtChn_Unmask(Context, Port);
191 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
193 return STATUS_SUCCESS;
194 }
196 NTSTATUS
197 EvtChn_Unbind(PVOID Context, evtchn_port_t Port)
198 {
199 PXENPCI_DEVICE_DATA xpdd = Context;
201 EvtChn_Mask(Context, Port);
202 xpdd->ev_actions[Port].ServiceRoutine = NULL;
203 KeMemoryBarrier();
204 xpdd->ev_actions[Port].ServiceContext = NULL;
206 if (xpdd->ev_actions[Port].type == EVT_ACTION_TYPE_DPC)
207 KeRemoveQueueDpc(&xpdd->ev_actions[Port].Dpc);
209 return STATUS_SUCCESS;
210 }
212 NTSTATUS
213 EvtChn_Mask(PVOID Context, evtchn_port_t Port)
214 {
215 PXENPCI_DEVICE_DATA xpdd = Context;
217 synch_set_bit(Port,
218 (volatile xen_long_t *)&xpdd->shared_info_area->evtchn_mask[0]);
219 return STATUS_SUCCESS;
220 }
222 NTSTATUS
223 EvtChn_Unmask(PVOID Context, evtchn_port_t Port)
224 {
225 PXENPCI_DEVICE_DATA xpdd = Context;
227 synch_clear_bit(Port,
228 (volatile xen_long_t *)&xpdd->shared_info_area->evtchn_mask[0]);
229 return STATUS_SUCCESS;
230 }
232 NTSTATUS
233 EvtChn_Notify(PVOID Context, evtchn_port_t Port)
234 {
235 PXENPCI_DEVICE_DATA xpdd = Context;
236 struct evtchn_send send;
238 send.port = Port;
239 (void)HYPERVISOR_event_channel_op(xpdd, EVTCHNOP_send, &send);
240 return STATUS_SUCCESS;
241 }
243 evtchn_port_t
244 EvtChn_AllocUnbound(PVOID Context, domid_t Domain)
245 {
246 PXENPCI_DEVICE_DATA xpdd = Context;
247 evtchn_alloc_unbound_t op;
248 op.dom = DOMID_SELF;
249 op.remote_dom = Domain;
250 HYPERVISOR_event_channel_op(xpdd, EVTCHNOP_alloc_unbound, &op);
251 return op.port;
252 }
254 static VOID
255 EvtChn_Connect(PXENPCI_DEVICE_DATA xpdd)
256 {
257 int i;
259 KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
261 for (i = 0; i < NR_EVENTS; i++)
262 {
263 EvtChn_Mask(xpdd, i);
264 xpdd->ev_actions[i].type = EVT_ACTION_TYPE_EMPTY;
265 xpdd->ev_actions[i].Count = 0;
266 }
268 for (i = 0; i < 8; i++)
269 {
270 xpdd->shared_info_area->evtchn_pending[i] = 0;
271 }
273 for (i = 0; i < MAX_VIRT_CPUS; i++)
274 {
275 xpdd->shared_info_area->vcpu_info[i].evtchn_upcall_pending = 0;
276 xpdd->shared_info_area->vcpu_info[i].evtchn_pending_sel = 0;
277 xpdd->shared_info_area->vcpu_info[i].evtchn_upcall_mask = 1;
278 }
280 hvm_set_parameter(xpdd, HVM_PARAM_CALLBACK_IRQ, xpdd->irq_number);
282 for (i = 0; i < MAX_VIRT_CPUS; i++)
283 {
284 xpdd->shared_info_area->vcpu_info[i].evtchn_upcall_mask = 0;
285 }
287 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
288 }
290 NTSTATUS
291 EvtChn_Init(PXENPCI_DEVICE_DATA xpdd)
292 {
293 NTSTATUS status;
295 EvtChn_Connect(xpdd);
297 status = IoConnectInterrupt(
298 &xpdd->interrupt,
299 EvtChn_Interrupt,
300 xpdd,
301 NULL,
302 xpdd->irq_vector,
303 xpdd->irq_level,
304 xpdd->irq_level,
305 LevelSensitive,
306 TRUE,
307 xpdd->irq_affinity,
308 FALSE);
310 if (!NT_SUCCESS(status))
311 {
312 KdPrint((__DRIVER_NAME " IoConnectInterrupt failed 0x%08x\n", status));
313 return status;
314 }
315 return status;
316 }
318 NTSTATUS
319 EvtChn_Shutdown(PXENPCI_DEVICE_DATA xpdd)
320 {
321 #if (NTDDI_VERSION < NTDDI_WINXP)
322 int i;
323 #endif
325 IoDisconnectInterrupt(xpdd->interrupt);
327 #if (NTDDI_VERSION >= NTDDI_WINXP)
328 KeFlushQueuedDpcs();
329 #else
330 for (i = 0; i < NR_EVENTS; i++)
331 {
332 if (xpdd->ev_actions[i].type == EVT_ACTION_TYPE_DPC || xpdd->ev_actions[i].type == EVT_ACTION_TYPE_IRQ)
333 {
334 KeRemoveQueueDpc(&xpdd->ev_actions[i].Dpc);
335 }
336 }
337 #endif
339 return STATUS_SUCCESS;
340 }