win-pvdrivers

view xenpci/evtchn.c @ 115:0d9e5303a8d2

- Fix 'unbind' so that the dpc (if any) is cancelled or completed before returning.
- Add code to make sure that no further calls will be made to ReturnPacket after _Halt is complete
Upgrading xennet.sys on a running system now appears to work properly again.
author James Harper <james.harper@bendigoit.com.au>
date Sat Jan 12 22:14:04 2008 +1100 (2008-01-12)
parents 652ccd25fc7e
children ff4d2a86b063
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"
21 #include "hypercall.h"
23 static VOID
24 EvtChn_DpcBounce(WDFDPC Dpc)
25 {
26 ev_action_t *Action;
28 Action = GetEvtChnDeviceData(Dpc)->Action;
29 Action->ServiceRoutine(NULL, Action->ServiceContext);
30 }
32 BOOLEAN
33 EvtChn_Interrupt(WDFINTERRUPT Interrupt, ULONG MessageID)
34 {
35 int cpu = KeGetCurrentProcessorNumber();
36 vcpu_info_t *vcpu_info;
37 PXENPCI_DEVICE_DATA xpdd = GetDeviceData(WdfInterruptGetDevice(Interrupt));
38 shared_info_t *shared_info_area = xpdd->shared_info_area;
39 unsigned long evt_words, evt_word;
40 unsigned long evt_bit;
41 unsigned long port;
42 ev_action_t *ev_action;
44 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ " (cpu = %d)\n", cpu));
46 UNREFERENCED_PARAMETER(MessageID);
48 vcpu_info = &shared_info_area->vcpu_info[cpu];
50 vcpu_info->evtchn_upcall_pending = 0;
52 evt_words = _InterlockedExchange((volatile LONG *)&vcpu_info->evtchn_pending_sel, 0);
54 while (_BitScanForward(&evt_word, evt_words))
55 {
56 evt_words &= ~(1 << evt_word);
57 while (_BitScanForward(&evt_bit, shared_info_area->evtchn_pending[evt_word] & ~shared_info_area->evtchn_mask[evt_word]))
58 {
59 port = (evt_word << 5) + evt_bit;
60 ev_action = &xpdd->ev_actions[port];
61 if (ev_action->ServiceRoutine == NULL)
62 {
63 KdPrint((__DRIVER_NAME " Unhandled Event!!!\n"));
64 }
65 else
66 {
67 if (ev_action->DpcFlag)
68 {
69 // KdPrint((__DRIVER_NAME " --- Scheduling Dpc\n"));
70 WdfDpcEnqueue(ev_action->Dpc);
71 }
72 else
73 {
74 ev_action->ServiceRoutine(NULL, ev_action->ServiceContext);
75 }
76 }
77 _interlockedbittestandreset((volatile LONG *)&shared_info_area->evtchn_pending[0], port);
78 }
79 }
81 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
83 return FALSE; // This needs to be FALSE so it can fall through to the scsiport ISR.
84 }
86 NTSTATUS
87 EvtChn_Bind(PVOID Context, evtchn_port_t Port, PKSERVICE_ROUTINE ServiceRoutine, PVOID ServiceContext)
88 {
89 WDFDEVICE Device = Context;
90 PXENPCI_DEVICE_DATA xpdd = GetDeviceData(Device);
92 KdPrint((__DRIVER_NAME " --> EvtChn_Bind (ServiceRoutine = %08X, ServiceContext = %08x)\n", ServiceRoutine, ServiceContext));
94 if(xpdd->ev_actions[Port].ServiceRoutine != NULL)
95 {
96 xpdd->ev_actions[Port].ServiceRoutine = NULL;
97 KeMemoryBarrier(); // make sure we don't call the old Service Routine with the new data...
98 KdPrint((__DRIVER_NAME " Handler for port %d already registered, replacing\n", Port));
99 }
101 xpdd->ev_actions[Port].DpcFlag = FALSE;
102 xpdd->ev_actions[Port].ServiceContext = ServiceContext;
103 KeMemoryBarrier();
104 xpdd->ev_actions[Port].ServiceRoutine = ServiceRoutine;
106 EvtChn_Unmask(Device, Port);
108 KdPrint((__DRIVER_NAME " <-- EvtChn_Bind\n"));
110 return STATUS_SUCCESS;
111 }
113 EvtChn_BindDpc(PVOID Context, evtchn_port_t Port, PKSERVICE_ROUTINE ServiceRoutine, PVOID ServiceContext)
114 {
115 WDFDEVICE Device = Context;
116 PXENPCI_DEVICE_DATA xpdd = GetDeviceData(Device);
117 WDF_DPC_CONFIG DpcConfig;
118 WDF_OBJECT_ATTRIBUTES DpcObjectAttributes;
120 KdPrint((__DRIVER_NAME " --> EvtChn_BindDpc\n"));
122 if(xpdd->ev_actions[Port].ServiceRoutine != NULL)
123 {
124 KdPrint((__DRIVER_NAME " Handler for port %d already registered, replacing\n", Port));
125 xpdd->ev_actions[Port].ServiceRoutine = NULL;
126 KeMemoryBarrier(); // make sure we don't call the old Service Routine with the new data...
127 }
129 xpdd->ev_actions[Port].ServiceContext = ServiceContext;
130 xpdd->ev_actions[Port].DpcFlag = TRUE;
132 WDF_DPC_CONFIG_INIT(&DpcConfig, EvtChn_DpcBounce);
133 WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&DpcObjectAttributes, EVTCHN_DEVICE_DATA);
134 DpcObjectAttributes.ParentObject = Device;
135 WdfDpcCreate(&DpcConfig, &DpcObjectAttributes, &xpdd->ev_actions[Port].Dpc);
136 GetEvtChnDeviceData(xpdd->ev_actions[Port].Dpc)->Action = &xpdd->ev_actions[Port];
137 // GetEvtChnDeviceData(xpdd->ev_actions[Port].Dpc)->shared_info_area = xpdd->shared_info_area;
138 // GetEvtChnDeviceData(xpdd->ev_actions[Port].Dpc)->port = Port;
140 KeMemoryBarrier(); // make sure that the new service routine is only called once the context is set up
141 xpdd->ev_actions[Port].ServiceRoutine = ServiceRoutine;
143 EvtChn_Unmask(Device, Port);
145 KdPrint((__DRIVER_NAME " <-- EvtChn_BindDpc\n"));
147 return STATUS_SUCCESS;
148 }
150 NTSTATUS
151 EvtChn_Unbind(PVOID Context, evtchn_port_t Port)
152 {
153 WDFDEVICE Device = Context;
154 PXENPCI_DEVICE_DATA xpdd = GetDeviceData(Device);
156 EvtChn_Mask(Context, Port);
157 xpdd->ev_actions[Port].ServiceRoutine = NULL;
158 KeMemoryBarrier();
159 xpdd->ev_actions[Port].ServiceContext = NULL;
161 if (xpdd->ev_actions[Port].DpcFlag)
162 WdfDpcCancel(xpdd->ev_actions[Port].Dpc, TRUE);
164 //KdPrint((__DRIVER_NAME " <-- EvtChn_UnBind\n"));
166 return STATUS_SUCCESS;
167 }
169 NTSTATUS
170 EvtChn_Mask(PVOID Context, evtchn_port_t Port)
171 {
172 WDFDEVICE Device = Context;
173 PXENPCI_DEVICE_DATA xpdd = GetDeviceData(Device);
174 //KdPrint((__DRIVER_NAME " --> EvtChn_Mask\n"));
176 _interlockedbittestandset(
177 (volatile LONG *)&xpdd->shared_info_area->evtchn_mask[0], Port);
179 //KdPrint((__DRIVER_NAME " <-- EvtChn_Mask\n"));
181 return STATUS_SUCCESS;
182 }
184 NTSTATUS
185 EvtChn_Unmask(PVOID Context, evtchn_port_t Port)
186 {
187 WDFDEVICE Device = Context;
188 PXENPCI_DEVICE_DATA xpdd = GetDeviceData(Device);
189 //KdPrint((__DRIVER_NAME " --> EvtChn_Unmask\n"));
191 _interlockedbittestandreset(
192 (volatile LONG *)&xpdd->shared_info_area->evtchn_mask[0], Port);
193 // should we kick off pending interrupts here too???
195 //KdPrint((__DRIVER_NAME " <-- EvtChn_Unmask\n"));
197 return STATUS_SUCCESS;
198 }
200 NTSTATUS
201 EvtChn_Notify(PVOID Context, evtchn_port_t Port)
202 {
203 struct evtchn_send send;
205 //KdPrint((__DRIVER_NAME " --> EvtChn_Notify\n"));
207 send.port = Port;
209 (void)HYPERVISOR_event_channel_op(Context, EVTCHNOP_send, &send);
211 //KdPrint((__DRIVER_NAME " <-- EvtChn_Notify\n"));
213 return STATUS_SUCCESS;
214 }
216 evtchn_port_t
217 EvtChn_AllocUnbound(PVOID Context, domid_t Domain)
218 {
219 evtchn_alloc_unbound_t op;
221 //KdPrint((__DRIVER_NAME " --> AllocUnbound\n"));
223 op.dom = DOMID_SELF;
224 op.remote_dom = Domain;
225 HYPERVISOR_event_channel_op(Context, EVTCHNOP_alloc_unbound, &op);
227 //KdPrint((__DRIVER_NAME " <-- AllocUnbound\n"));
229 return op.port;
230 }
232 evtchn_port_t
233 EvtChn_GetXenStorePort(WDFDEVICE Device)
234 {
235 evtchn_port_t Port;
237 //KdPrint((__DRIVER_NAME " --> EvtChn_GetStorePort\n"));
239 Port = (evtchn_port_t)hvm_get_parameter(Device, HVM_PARAM_STORE_EVTCHN);
241 //KdPrint((__DRIVER_NAME " <-- EvtChn_GetStorePort\n"));
243 return Port;
244 }
246 PVOID
247 EvtChn_GetXenStoreRingAddr(WDFDEVICE Device)
248 {
249 PHYSICAL_ADDRESS pa_xen_store_interface;
250 PVOID xen_store_interface;
252 ULONG xen_store_mfn;
254 //KdPrint((__DRIVER_NAME " --> EvtChn_GetRingAddr\n"));
256 xen_store_mfn = (ULONG)hvm_get_parameter(Device, HVM_PARAM_STORE_PFN);
258 pa_xen_store_interface.QuadPart = xen_store_mfn << PAGE_SHIFT;
259 xen_store_interface = MmMapIoSpace(pa_xen_store_interface, PAGE_SIZE, MmNonCached);
261 //KdPrint((__DRIVER_NAME " xen_store_mfn = %08x\n", xen_store_mfn));
262 //KdPrint((__DRIVER_NAME " xen_store_evtchn = %08x\n", xen_store_evtchn));
263 //KdPrint((__DRIVER_NAME " xen_store_interface = %08x\n", xen_store_interface));
265 //KeInitializeEvent(&xenbus_waitevent, NotificationEvent, FALSE);
267 //KdPrint((__DRIVER_NAME " <-- EvtChn_GetRingAddr\n"));
269 return xen_store_interface;
270 }
272 NTSTATUS
273 EvtChn_Init(WDFDEVICE Device)
274 {
275 PXENPCI_DEVICE_DATA xpdd = GetDeviceData(Device);
276 int i;
278 for (i = 0; i < NR_EVENTS; i++)
279 {
280 EvtChn_Mask(Device, i);
281 xpdd->ev_actions[i].ServiceRoutine = NULL;
282 xpdd->ev_actions[i].ServiceContext = NULL;
283 xpdd->ev_actions[i].Count = 0;
284 }
286 for (i = 0; i < 8; i++)
287 {
288 xpdd->shared_info_area->evtchn_pending[i] = 0;
289 }
291 for (i = 0; i < MAX_VIRT_CPUS; i++)
292 {
293 xpdd->shared_info_area->vcpu_info[i].evtchn_upcall_pending = 0;
294 xpdd->shared_info_area->vcpu_info[i].evtchn_pending_sel = 0;
295 }
297 return STATUS_SUCCESS;
298 }