win-pvdrivers

view xenpci/evtchn.c @ 265:8fef16f8fc08

fix warnings on x64 build. Xen apparently limits PFNs to 32 bits, so make this limitation stand out a little more
author Andy Grover <andy.grover@oracle.com>
date Mon May 05 13:24:03 2008 -0700 (2008-05-05)
parents 2d25f964e1d1
children 3673f1f07746
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(_X86_)
23 #define xchg(p1, p2) _InterlockedExchange(p1, p2)
24 #define synch_clear_bit(p1, p2) _interlockedbittestandreset(p2, p1)
25 #define synch_set_bit(p1, p2) _interlockedbittestandset(p2, p1)
26 #define bit_scan_forward(p1, p2) _BitScanForward(p1, p2)
27 #else
28 #define xchg(p1, p2) _InterlockedExchange64(p1, p2)
29 #define synch_clear_bit(p1, p2) _interlockedbittestandreset64(p2, p1)
30 #define synch_set_bit(p1, p2) _interlockedbittestandset64(p2, p1)
31 #define bit_scan_forward(p1, p2) _BitScanForward64(p1, p2)
32 #endif
34 static VOID
35 EvtChn_DpcBounce(WDFDPC Dpc)
36 {
37 ev_action_t *Action;
39 Action = GetEvtChnDeviceData(Dpc)->Action;
40 Action->ServiceRoutine(NULL, Action->ServiceContext);
41 }
43 BOOLEAN
44 EvtChn_Interrupt(WDFINTERRUPT Interrupt, ULONG MessageID)
45 {
46 int cpu = KeGetCurrentProcessorNumber() & (MAX_VIRT_CPUS - 1);
47 vcpu_info_t *vcpu_info;
48 PXENPCI_DEVICE_DATA xpdd = GetDeviceData(WdfInterruptGetDevice(Interrupt));
49 shared_info_t *shared_info_area = xpdd->shared_info_area;
50 xen_ulong_t evt_words;
51 unsigned long evt_word;
52 unsigned long evt_bit;
53 unsigned int port;
54 ev_action_t *ev_action;
56 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ " (cpu = %d)\n", cpu));
58 UNREFERENCED_PARAMETER(MessageID);
60 vcpu_info = &shared_info_area->vcpu_info[cpu];
62 vcpu_info->evtchn_upcall_pending = 0;
64 evt_words = (xen_ulong_t)xchg((volatile xen_long_t *)&vcpu_info->evtchn_pending_sel, 0);
66 while (bit_scan_forward(&evt_word, evt_words))
67 {
68 evt_words &= ~(1 << evt_word);
69 while (bit_scan_forward(&evt_bit, shared_info_area->evtchn_pending[evt_word] & ~shared_info_area->evtchn_mask[evt_word]))
70 {
71 port = (evt_word << 5) + evt_bit;
72 ev_action = &xpdd->ev_actions[port];
73 if (ev_action->ServiceRoutine == NULL)
74 {
75 KdPrint((__DRIVER_NAME " Unhandled Event!!!\n"));
76 }
77 else
78 {
79 if (ev_action->DpcFlag)
80 {
81 // KdPrint((__DRIVER_NAME " --- Scheduling Dpc\n"));
82 WdfDpcEnqueue(ev_action->Dpc);
83 }
84 else
85 {
86 ev_action->ServiceRoutine(NULL, ev_action->ServiceContext);
87 }
88 }
89 synch_clear_bit(port, (volatile xen_long_t *)&shared_info_area->evtchn_pending[evt_word]);
90 }
91 }
93 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
95 /* Need to return FALSE so we can fall through to the scsiport ISR. */
96 return FALSE;
97 }
99 NTSTATUS
100 EvtChn_Bind(PVOID Context, evtchn_port_t Port, PKSERVICE_ROUTINE ServiceRoutine, PVOID ServiceContext)
101 {
102 WDFDEVICE Device = Context;
103 PXENPCI_DEVICE_DATA xpdd = GetDeviceData(Device);
105 KdPrint((__DRIVER_NAME " --> EvtChn_Bind (ServiceRoutine = %08X, ServiceContext = %08x)\n", ServiceRoutine, ServiceContext));
107 if(xpdd->ev_actions[Port].ServiceRoutine != NULL)
108 {
109 xpdd->ev_actions[Port].ServiceRoutine = NULL;
110 KeMemoryBarrier(); // make sure we don't call the old Service Routine with the new data...
111 KdPrint((__DRIVER_NAME " Handler for port %d already registered, replacing\n", Port));
112 }
114 xpdd->ev_actions[Port].DpcFlag = FALSE;
115 xpdd->ev_actions[Port].ServiceContext = ServiceContext;
116 KeMemoryBarrier();
117 xpdd->ev_actions[Port].ServiceRoutine = ServiceRoutine;
119 EvtChn_Unmask(Device, Port);
121 KdPrint((__DRIVER_NAME " <-- EvtChn_Bind\n"));
123 return STATUS_SUCCESS;
124 }
126 NTSTATUS
127 EvtChn_BindDpc(PVOID Context, evtchn_port_t Port, PKSERVICE_ROUTINE ServiceRoutine, PVOID ServiceContext)
128 {
129 WDFDEVICE Device = Context;
130 PXENPCI_DEVICE_DATA xpdd = GetDeviceData(Device);
131 WDF_DPC_CONFIG DpcConfig;
132 WDF_OBJECT_ATTRIBUTES DpcObjectAttributes;
134 KdPrint((__DRIVER_NAME " --> EvtChn_BindDpc\n"));
136 if(xpdd->ev_actions[Port].ServiceRoutine != NULL)
137 {
138 KdPrint((__DRIVER_NAME " Handler for port %d already registered, replacing\n", Port));
139 xpdd->ev_actions[Port].ServiceRoutine = NULL;
140 KeMemoryBarrier(); // make sure we don't call the old Service Routine with the new data...
141 }
143 xpdd->ev_actions[Port].ServiceContext = ServiceContext;
144 xpdd->ev_actions[Port].DpcFlag = TRUE;
146 WDF_DPC_CONFIG_INIT(&DpcConfig, EvtChn_DpcBounce);
147 WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&DpcObjectAttributes, EVTCHN_DEVICE_DATA);
148 DpcObjectAttributes.ParentObject = Device;
149 WdfDpcCreate(&DpcConfig, &DpcObjectAttributes, &xpdd->ev_actions[Port].Dpc);
150 GetEvtChnDeviceData(xpdd->ev_actions[Port].Dpc)->Action = &xpdd->ev_actions[Port];
152 KeMemoryBarrier(); // make sure that the new service routine is only called once the context is set up
153 xpdd->ev_actions[Port].ServiceRoutine = ServiceRoutine;
155 EvtChn_Unmask(Device, Port);
157 KdPrint((__DRIVER_NAME " <-- EvtChn_BindDpc\n"));
159 return STATUS_SUCCESS;
160 }
162 NTSTATUS
163 EvtChn_Unbind(PVOID Context, evtchn_port_t Port)
164 {
165 WDFDEVICE Device = Context;
166 PXENPCI_DEVICE_DATA xpdd = GetDeviceData(Device);
168 EvtChn_Mask(Context, Port);
169 xpdd->ev_actions[Port].ServiceRoutine = NULL;
170 KeMemoryBarrier();
171 xpdd->ev_actions[Port].ServiceContext = NULL;
173 if (xpdd->ev_actions[Port].DpcFlag)
174 WdfDpcCancel(xpdd->ev_actions[Port].Dpc, TRUE);
176 //KdPrint((__DRIVER_NAME " <-- EvtChn_UnBind\n"));
178 return STATUS_SUCCESS;
179 }
181 NTSTATUS
182 EvtChn_Mask(PVOID Context, evtchn_port_t Port)
183 {
184 WDFDEVICE Device = Context;
185 PXENPCI_DEVICE_DATA xpdd = GetDeviceData(Device);
186 //KdPrint((__DRIVER_NAME " --> EvtChn_Mask\n"));
188 synch_set_bit(Port,
189 (volatile xen_long_t *)&xpdd->shared_info_area->evtchn_mask[0]);
191 //KdPrint((__DRIVER_NAME " <-- EvtChn_Mask\n"));
193 return STATUS_SUCCESS;
194 }
196 NTSTATUS
197 EvtChn_Unmask(PVOID Context, evtchn_port_t Port)
198 {
199 WDFDEVICE Device = Context;
200 PXENPCI_DEVICE_DATA xpdd = GetDeviceData(Device);
201 //KdPrint((__DRIVER_NAME " --> EvtChn_Unmask\n"));
203 synch_clear_bit(Port,
204 (volatile xen_long_t *)&xpdd->shared_info_area->evtchn_mask[0]);
205 // should we kick off pending interrupts here too???
207 //KdPrint((__DRIVER_NAME " <-- EvtChn_Unmask\n"));
209 return STATUS_SUCCESS;
210 }
212 NTSTATUS
213 EvtChn_Notify(PVOID Context, evtchn_port_t Port)
214 {
215 struct evtchn_send send;
217 //KdPrint((__DRIVER_NAME " --> EvtChn_Notify\n"));
219 send.port = Port;
221 (void)HYPERVISOR_event_channel_op(Context, EVTCHNOP_send, &send);
223 //KdPrint((__DRIVER_NAME " <-- EvtChn_Notify\n"));
225 return STATUS_SUCCESS;
226 }
228 evtchn_port_t
229 EvtChn_AllocUnbound(PVOID Context, domid_t Domain)
230 {
231 evtchn_alloc_unbound_t op;
233 //KdPrint((__DRIVER_NAME " --> AllocUnbound\n"));
235 op.dom = DOMID_SELF;
236 op.remote_dom = Domain;
237 HYPERVISOR_event_channel_op(Context, EVTCHNOP_alloc_unbound, &op);
239 //KdPrint((__DRIVER_NAME " <-- AllocUnbound\n"));
241 return op.port;
242 }
244 evtchn_port_t
245 EvtChn_GetXenStorePort(WDFDEVICE Device)
246 {
247 evtchn_port_t Port;
249 KdPrint((__DRIVER_NAME " --> EvtChn_GetStorePort\n"));
251 Port = (evtchn_port_t)hvm_get_parameter(Device, HVM_PARAM_STORE_EVTCHN);
253 KdPrint((__DRIVER_NAME " <-- EvtChn_GetStorePort\n"));
255 return Port;
256 }
258 PVOID
259 EvtChn_GetXenStoreRingAddr(WDFDEVICE Device)
260 {
261 PHYSICAL_ADDRESS pa_xen_store_interface;
262 PVOID xen_store_interface;
264 xen_ulong_t xen_store_mfn;
266 KdPrint((__DRIVER_NAME " --> EvtChn_GetRingAddr\n"));
268 xen_store_mfn = (xen_ulong_t)hvm_get_parameter(Device, HVM_PARAM_STORE_PFN);
270 pa_xen_store_interface.QuadPart = xen_store_mfn << PAGE_SHIFT;
271 xen_store_interface = MmMapIoSpace(pa_xen_store_interface, PAGE_SIZE, MmCached);
273 KdPrint((__DRIVER_NAME " xen_store_mfn = %08x\n", xen_store_mfn));
274 //KdPrint((__DRIVER_NAME " xen_store_evtchn = %08x\n", xen_store_evtchn));
275 KdPrint((__DRIVER_NAME " xen_store_interface = %08x\n", xen_store_interface));
277 KdPrint((__DRIVER_NAME " <-- EvtChn_GetRingAddr\n"));
279 return xen_store_interface;
280 }
282 NTSTATUS
283 EvtChn_Init(WDFDEVICE Device)
284 {
285 PXENPCI_DEVICE_DATA xpdd = GetDeviceData(Device);
286 int i;
288 for (i = 0; i < NR_EVENTS; i++)
289 {
290 EvtChn_Mask(Device, i);
291 xpdd->ev_actions[i].ServiceRoutine = NULL;
292 xpdd->ev_actions[i].ServiceContext = NULL;
293 xpdd->ev_actions[i].Count = 0;
294 }
296 for (i = 0; i < 8; i++)
297 {
298 xpdd->shared_info_area->evtchn_pending[i] = 0;
299 }
301 for (i = 0; i < MAX_VIRT_CPUS; i++)
302 {
303 xpdd->shared_info_area->vcpu_info[i].evtchn_upcall_pending = 0;
304 xpdd->shared_info_area->vcpu_info[i].evtchn_pending_sel = 0;
305 }
307 return STATUS_SUCCESS;
308 }