win-pvdrivers

annotate xenpci/xenpci_pdo.c @ 705:b620a1b82e0b

Fixed a problem with interrupt delivery where there were >8 CPU's
author James Harper <james.harper@bendigoit.com.au>
date Tue Dec 08 21:08:12 2009 +1100 (2009-12-08)
parents 93b98effc8e7
children 5bdb7251370c
rev   line source
james@259 1 /*
james@259 2 PV Drivers for Windows Xen HVM Domains
james@259 3 Copyright (C) 2007 James Harper
james@259 4
james@259 5 This program is free software; you can redistribute it and/or
james@259 6 modify it under the terms of the GNU General Public License
james@259 7 as published by the Free Software Foundation; either version 2
james@259 8 of the License, or (at your option) any later version.
james@259 9
james@259 10 This program is distributed in the hope that it will be useful,
james@259 11 but WITHOUT ANY WARRANTY; without even the implied warranty of
james@259 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
james@259 13 GNU General Public License for more details.
james@259 14
james@259 15 You should have received a copy of the GNU General Public License
james@259 16 along with this program; if not, write to the Free Software
james@259 17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
james@259 18 */
james@259 19
james@259 20 #include "xenpci.h"
james@259 21 #include <stdlib.h>
james@267 22 #include <io/ring.h>
james@259 23
james@259 24 #pragma warning(disable : 4200) // zero-sized array
james@267 25 #pragma warning(disable: 4127) // conditional expression is constant
james@259 26
james@536 27 /*
james@536 28 Called at PASSIVE_LEVEL(?)
james@536 29 Called during restore
james@536 30 */
james@536 31 static ULONG
james@536 32 XenPci_ReadBackendState(PXENPCI_PDO_DEVICE_DATA xppdd)
james@536 33 {
james@536 34 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
james@536 35 char path[128];
james@536 36 char *value;
james@536 37 char *err;
james@536 38 ULONG backend_state;
james@536 39
james@536 40 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "%s/state", xppdd->backend_path);
james@536 41 err = XenBus_Read(xpdd, XBT_NIL, path, &value);
james@536 42 if (err)
james@536 43 {
james@536 44 XenPci_FreeMem(err);
james@536 45 return XenbusStateUnknown;
james@536 46 }
james@536 47 else
james@536 48 {
james@536 49 backend_state = atoi(value);
james@536 50 XenPci_FreeMem(value);
james@536 51 return backend_state;
james@536 52 }
james@536 53 }
james@536 54
james@617 55 static NTSTATUS
james@617 56 XenPciPdo_ReconfigureCompletionRoutine(
james@617 57 PDEVICE_OBJECT device_object,
james@617 58 PIRP irp,
james@617 59 PVOID context)
james@617 60 {
james@617 61 UNREFERENCED_PARAMETER(device_object);
james@617 62
james@617 63 if (irp->PendingReturned)
james@617 64 {
james@617 65 KeSetEvent ((PKEVENT)context, IO_NO_INCREMENT, FALSE);
james@617 66 }
james@617 67 return STATUS_MORE_PROCESSING_REQUIRED;
james@617 68 }
james@617 69
james@536 70 static VOID
james@624 71 XenPci_UpdateBackendState(PVOID context)
james@536 72 {
james@536 73 WDFDEVICE device = context;
james@536 74 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
james@536 75 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
james@536 76 ULONG new_backend_state;
james@536 77
james@624 78 FUNCTION_ENTER();
james@536 79
james@624 80 ExAcquireFastMutex(&xppdd->backend_state_mutex);
james@624 81
james@536 82 new_backend_state = XenPci_ReadBackendState(xppdd);
james@536 83 if (new_backend_state == XenbusStateUnknown)
james@536 84 {
james@536 85 if (xpdd->suspend_state != SUSPEND_STATE_NONE)
james@624 86 {
james@624 87 ExReleaseFastMutex(&xppdd->backend_state_mutex);
james@536 88 return;
james@624 89 }
james@624 90 KdPrint(("Failed to read path, assuming closed\n"));
james@536 91 new_backend_state = XenbusStateClosed;
james@536 92 }
james@536 93
james@536 94 if (xppdd->backend_state == new_backend_state)
james@536 95 {
james@536 96 KdPrint((__DRIVER_NAME " state unchanged\n"));
james@624 97 ExReleaseFastMutex(&xppdd->backend_state_mutex);
james@536 98 return;
james@536 99 }
james@536 100
james@536 101 xppdd->backend_state = new_backend_state;
james@536 102
james@536 103 switch (xppdd->backend_state)
james@536 104 {
james@536 105 case XenbusStateUnknown:
james@624 106 KdPrint((__DRIVER_NAME " Backend State Changed to Unknown\n"));
james@536 107 break;
james@536 108
james@536 109 case XenbusStateInitialising:
james@624 110 KdPrint((__DRIVER_NAME " Backend State Changed to Initialising\n"));
james@536 111 break;
james@536 112
james@536 113 case XenbusStateInitWait:
james@624 114 KdPrint((__DRIVER_NAME " Backend State Changed to InitWait\n"));
james@536 115 break;
james@536 116
james@536 117 case XenbusStateInitialised:
james@624 118 KdPrint((__DRIVER_NAME " Backend State Changed to Initialised\n"));
james@536 119 break;
james@536 120
james@536 121 case XenbusStateConnected:
james@624 122 KdPrint((__DRIVER_NAME " Backend State Changed to Connected\n"));
james@536 123 break;
james@536 124
james@536 125 case XenbusStateClosing:
james@624 126 KdPrint((__DRIVER_NAME " Backend State Changed to Closing\n"));
james@692 127 if (xppdd->frontend_state != XenbusStateClosing)
james@692 128 {
james@692 129 KdPrint((__DRIVER_NAME " Requesting eject\n"));
james@692 130 WdfPdoRequestEject(device);
james@692 131 }
james@536 132 break;
james@536 133
james@536 134 case XenbusStateClosed:
james@624 135 KdPrint((__DRIVER_NAME " Backend State Changed to Closed\n"));
james@536 136 break;
james@617 137
james@536 138 default:
james@624 139 KdPrint((__DRIVER_NAME " Backend State Changed to Undefined = %d\n", xppdd->backend_state));
james@536 140 break;
james@536 141 }
james@536 142
james@536 143 KeSetEvent(&xppdd->backend_state_event, 1, FALSE);
james@536 144
james@624 145 ExReleaseFastMutex(&xppdd->backend_state_mutex);
james@624 146 FUNCTION_EXIT();
james@536 147
james@536 148 return;
james@536 149 }
james@536 150
james@624 151 static VOID
james@624 152 XenPci_BackendStateHandler(char *path, PVOID context)
james@624 153 {
james@624 154 UNREFERENCED_PARAMETER(path);
james@624 155
james@624 156 /* check that path == device/id/state */
james@624 157 //RtlStringCbPrintfA(path, ARRAY_SIZE(path), "%s/state", xppdd->path);
james@624 158
james@624 159 XenPci_UpdateBackendState(context);
james@624 160 }
james@624 161
james@536 162 static NTSTATUS
james@536 163 XenPci_GetBackendAndAddWatch(WDFDEVICE device)
james@536 164 {
james@536 165 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
james@536 166 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
james@536 167 char path[128];
james@536 168 PCHAR res;
james@536 169 PCHAR value;
james@536 170
james@624 171 FUNCTION_ENTER();
james@536 172 /* Get backend path */
james@536 173 RtlStringCbPrintfA(path, ARRAY_SIZE(path),
james@536 174 "%s/backend", xppdd->path);
james@536 175 res = XenBus_Read(xpdd, XBT_NIL, path, &value);
james@536 176 if (res)
james@536 177 {
james@536 178 KdPrint((__DRIVER_NAME " Failed to read backend path\n"));
james@536 179 XenPci_FreeMem(res);
james@536 180 return STATUS_UNSUCCESSFUL;
james@536 181 }
james@536 182 RtlStringCbCopyA(xppdd->backend_path, ARRAY_SIZE(xppdd->backend_path), value);
james@536 183 XenPci_FreeMem(value);
james@536 184
james@536 185 /* Add watch on backend state */
james@536 186 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "%s/state", xppdd->backend_path);
james@624 187 XenBus_AddWatch(xpdd, XBT_NIL, path, XenPci_BackendStateHandler, device);
james@624 188
james@624 189 FUNCTION_EXIT();
james@536 190 return STATUS_SUCCESS;
james@536 191 }
james@536 192
james@551 193 static NTSTATUS
james@551 194 XenConfig_InitConfigPage(WDFDEVICE device)
james@536 195 {
james@551 196 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
james@536 197 //PXENCONFIG_DEVICE_DATA xcdd = (PXENCONFIG_DEVICE_DATA)device_object->DeviceExtension;
james@536 198 //PXENPCI_PDO_DEVICE_DATA xppdd = (PXENPCI_PDO_DEVICE_DATA)device_object->DeviceExtension;
james@536 199 //PXENPCI_DEVICE_DATA xpdd = xppdd->bus_fdo->DeviceExtension;
james@536 200 PUCHAR ptr;
james@536 201 PDEVICE_OBJECT curr, prev;
james@536 202 PDRIVER_OBJECT fdo_driver_object;
james@536 203 PUCHAR fdo_driver_extension;
james@536 204
james@536 205 FUNCTION_ENTER();
james@536 206
james@551 207 ptr = MmGetMdlVirtualAddress(xppdd->config_page_mdl);
james@536 208 curr = IoGetAttachedDeviceReference(WdfDeviceWdmGetDeviceObject(device));
james@536 209 //curr = WdfDeviceWdmGetAttachedDevice(device);
james@536 210 while (curr != NULL)
james@536 211 {
james@536 212 fdo_driver_object = curr->DriverObject;
james@536 213 KdPrint((__DRIVER_NAME " fdo_driver_object = %p\n", fdo_driver_object));
james@536 214 if (fdo_driver_object)
james@536 215 {
james@536 216 fdo_driver_extension = IoGetDriverObjectExtension(fdo_driver_object, UlongToPtr(XEN_INIT_DRIVER_EXTENSION_MAGIC));
james@536 217 KdPrint((__DRIVER_NAME " fdo_driver_extension = %p\n", fdo_driver_extension));
james@536 218 if (fdo_driver_extension)
james@536 219 {
james@536 220 memcpy(ptr, fdo_driver_extension, PAGE_SIZE);
james@536 221 ObDereferenceObject(curr);
james@536 222 break;
james@536 223 }
james@536 224 }
james@536 225 prev = curr;
james@536 226 curr = IoGetLowerDeviceObject(curr);
james@536 227 ObDereferenceObject(prev);
james@536 228 }
james@536 229
james@536 230 FUNCTION_EXIT();
james@536 231
james@551 232 return STATUS_SUCCESS;
james@536 233 }
james@536 234
james@536 235 static NTSTATUS
james@536 236 XenPci_EvtChn_Bind(PVOID context, evtchn_port_t Port, PXEN_EVTCHN_SERVICE_ROUTINE ServiceRoutine, PVOID ServiceContext)
james@536 237 {
james@536 238 WDFDEVICE device = context;
james@536 239 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
james@536 240 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
james@536 241
james@536 242 return EvtChn_Bind(xpdd, Port, ServiceRoutine, ServiceContext);
james@536 243 }
james@536 244
james@536 245 static NTSTATUS
james@536 246 XenPci_EvtChn_BindDpc(PVOID context, evtchn_port_t Port, PXEN_EVTCHN_SERVICE_ROUTINE ServiceRoutine, PVOID ServiceContext)
james@536 247 {
james@536 248 WDFDEVICE device = context;
james@536 249 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
james@536 250 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
james@536 251
james@536 252 return EvtChn_BindDpc(xpdd, Port, ServiceRoutine, ServiceContext);
james@536 253 }
james@536 254
james@536 255 static NTSTATUS
james@536 256 XenPci_EvtChn_Unbind(PVOID context, evtchn_port_t Port)
james@536 257 {
james@536 258 WDFDEVICE device = context;
james@536 259 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
james@536 260 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
james@536 261
james@536 262 return EvtChn_Unbind(xpdd, Port);
james@536 263 }
james@536 264
james@536 265 static NTSTATUS
james@536 266 XenPci_EvtChn_Mask(PVOID context, evtchn_port_t Port)
james@536 267 {
james@536 268 WDFDEVICE device = context;
james@536 269 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
james@536 270 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
james@536 271
james@536 272 return EvtChn_Mask(xpdd, Port);
james@536 273 }
james@536 274
james@536 275 static NTSTATUS
james@536 276 XenPci_EvtChn_Unmask(PVOID context, evtchn_port_t Port)
james@536 277 {
james@536 278 WDFDEVICE device = context;
james@536 279 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
james@536 280 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
james@536 281
james@536 282 return EvtChn_Unmask(xpdd, Port);
james@536 283 }
james@536 284
james@536 285 static NTSTATUS
james@536 286 XenPci_EvtChn_Notify(PVOID context, evtchn_port_t Port)
james@536 287 {
james@536 288 WDFDEVICE device = context;
james@536 289 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
james@536 290 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
james@536 291
james@536 292 return EvtChn_Notify(xpdd, Port);
james@536 293 }
james@536 294
james@536 295 static BOOLEAN
james@561 296 XenPci_EvtChn_AckEvent(PVOID context, evtchn_port_t port, BOOLEAN *last_interrupt)
james@536 297 {
james@536 298 WDFDEVICE device = context;
james@536 299 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
james@536 300 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
james@536 301
james@561 302 return EvtChn_AckEvent(xpdd, port, last_interrupt);
james@536 303 }
james@536 304
james@536 305 typedef struct {
james@536 306 PXEN_EVTCHN_SYNC_ROUTINE sync_routine;
james@536 307 PVOID sync_context;
james@536 308 } sync_context_t;
james@536 309
james@536 310 static BOOLEAN
james@536 311 XenPci_EvtChn_Sync_Routine(WDFINTERRUPT interrupt, WDFCONTEXT context)
james@536 312 {
james@536 313 sync_context_t *wdf_sync_context = context;
james@536 314 UNREFERENCED_PARAMETER(interrupt);
james@536 315 return wdf_sync_context->sync_routine(wdf_sync_context->sync_context);
james@536 316 }
james@536 317
james@536 318 static BOOLEAN
james@536 319 XenPci_EvtChn_Sync(PVOID context, PXEN_EVTCHN_SYNC_ROUTINE sync_routine, PVOID sync_context)
james@536 320 {
james@536 321 WDFDEVICE device = context;
james@536 322 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
james@536 323 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
james@536 324 sync_context_t wdf_sync_context;
james@536 325
james@536 326 wdf_sync_context.sync_routine = sync_routine;
james@536 327 wdf_sync_context.sync_context = sync_context;
james@536 328
james@536 329 return WdfInterruptSynchronize(xpdd->interrupt, XenPci_EvtChn_Sync_Routine, &wdf_sync_context);
james@536 330 }
james@536 331
james@536 332 static grant_ref_t
james@536 333 XenPci_GntTbl_GrantAccess(PVOID context, domid_t domid, uint32_t frame, int readonly, grant_ref_t ref)
james@536 334 {
james@536 335 WDFDEVICE device = context;
james@536 336 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
james@536 337 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
james@536 338
james@536 339 return GntTbl_GrantAccess(xpdd, domid, frame, readonly, ref);
james@536 340 }
james@536 341
james@536 342 static BOOLEAN
james@536 343 XenPci_GntTbl_EndAccess(PVOID context, grant_ref_t ref, BOOLEAN keepref)
james@536 344 {
james@536 345 WDFDEVICE device = context;
james@536 346 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
james@536 347 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
james@536 348
james@536 349 return GntTbl_EndAccess(xpdd, ref, keepref);
james@536 350 }
james@536 351
james@536 352 static VOID
james@536 353 XenPci_GntTbl_PutRef(PVOID context, grant_ref_t ref)
james@536 354 {
james@536 355 WDFDEVICE device = context;
james@536 356 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
james@536 357 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
james@536 358
james@536 359 GntTbl_PutRef(xpdd, ref);
james@536 360 }
james@536 361
james@536 362 static grant_ref_t
james@536 363 XenPci_GntTbl_GetRef(PVOID context)
james@536 364 {
james@536 365 WDFDEVICE device = context;
james@536 366 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
james@536 367 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
james@536 368
james@536 369 return GntTbl_GetRef(xpdd);
james@536 370 }
james@536 371
james@536 372 PCHAR
james@536 373 XenPci_XenBus_Read(PVOID context, xenbus_transaction_t xbt, char *path, char **value)
james@536 374 {
james@536 375 WDFDEVICE device = context;
james@536 376 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
james@536 377 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
james@536 378 return XenBus_Read(xpdd, xbt, path, value);
james@536 379 }
james@536 380
james@536 381 PCHAR
james@536 382 XenPci_XenBus_Write(PVOID context, xenbus_transaction_t xbt, char *path, char *value)
james@536 383 {
james@536 384 WDFDEVICE device = context;
james@536 385 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
james@536 386 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
james@536 387 return XenBus_Write(xpdd, xbt, path, value);
james@536 388 }
james@536 389
james@536 390 PCHAR
james@536 391 XenPci_XenBus_Printf(PVOID context, xenbus_transaction_t xbt, char *path, char *fmt, ...)
james@536 392 {
james@536 393 //PXENPCI_PDO_DEVICE_DATA xppdd = Context;
james@536 394 //PXENPCI_DEVICE_DATA xpdd = xppdd->bus_fdo->DeviceExtension;
james@536 395 //return XenBus_Printf(xpdd, xbt, path, value);
james@536 396 UNREFERENCED_PARAMETER(context);
james@536 397 UNREFERENCED_PARAMETER(xbt);
james@536 398 UNREFERENCED_PARAMETER(path);
james@536 399 UNREFERENCED_PARAMETER(fmt);
james@536 400 return NULL;
james@536 401 }
james@536 402
james@536 403 PCHAR
james@536 404 XenPci_XenBus_StartTransaction(PVOID context, xenbus_transaction_t *xbt)
james@536 405 {
james@536 406 WDFDEVICE device = context;
james@536 407 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
james@536 408 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
james@536 409 return XenBus_StartTransaction(xpdd, xbt);
james@536 410 }
james@536 411
james@536 412 PCHAR
james@536 413 XenPci_XenBus_EndTransaction(PVOID context, xenbus_transaction_t xbt, int abort, int *retry)
james@536 414 {
james@536 415 WDFDEVICE device = context;
james@536 416 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
james@536 417 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
james@536 418 return XenBus_EndTransaction(xpdd, xbt, abort, retry);
james@536 419 }
james@536 420
james@536 421 PCHAR
james@536 422 XenPci_XenBus_List(PVOID context, xenbus_transaction_t xbt, char *prefix, char ***contents)
james@536 423 {
james@536 424 WDFDEVICE device = context;
james@536 425 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
james@536 426 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
james@536 427 return XenBus_List(xpdd, xbt, prefix, contents);
james@536 428 }
james@536 429
james@536 430 PCHAR
james@536 431 XenPci_XenBus_AddWatch(PVOID context, xenbus_transaction_t xbt, char *path, PXENBUS_WATCH_CALLBACK ServiceRoutine, PVOID ServiceContext)
james@536 432 {
james@536 433 WDFDEVICE device = context;
james@536 434 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
james@536 435 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
james@536 436 PCHAR retval;
james@536 437
james@536 438 FUNCTION_ENTER();
james@536 439 retval = XenBus_AddWatch(xpdd, xbt, path, ServiceRoutine, ServiceContext);
james@536 440 if (retval == NULL)
james@536 441 {
james@536 442 KdPrint((__DRIVER_NAME " XenPci_XenBus_AddWatch - %s = NULL\n", path));
james@536 443 }
james@536 444 else
james@536 445 {
james@536 446 KdPrint((__DRIVER_NAME " XenPci_XenBus_AddWatch - %s = %s\n", path, retval));
james@536 447 }
james@536 448 FUNCTION_EXIT();
james@536 449 return retval;
james@536 450 }
james@536 451
james@536 452 PCHAR
james@536 453 XenPci_XenBus_RemWatch(PVOID context, xenbus_transaction_t xbt, char *path, PXENBUS_WATCH_CALLBACK ServiceRoutine, PVOID ServiceContext)
james@536 454 {
james@536 455 WDFDEVICE device = context;
james@536 456 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
james@536 457 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
james@536 458 return XenBus_RemWatch(xpdd, xbt, path, ServiceRoutine, ServiceContext);
james@536 459 }
james@536 460
james@536 461 /*
james@536 462 Called at PASSIVE_LEVEL
james@536 463 Called during restore
james@536 464 */
james@536 465
james@536 466 static NTSTATUS
james@536 467 XenPci_ChangeFrontendState(WDFDEVICE device, ULONG frontend_state_set, ULONG backend_state_response, ULONG maximum_wait_ms)
james@536 468 {
james@536 469 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
james@536 470 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
james@536 471 LARGE_INTEGER timeout;
james@536 472 ULONG remaining;
james@536 473 ULONG thiswait;
james@536 474 char path[128];
james@536 475
james@624 476 FUNCTION_ENTER();
james@538 477
james@538 478 xppdd->frontend_state = frontend_state_set;
james@536 479
james@536 480 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "%s/state", xppdd->path);
james@536 481 XenBus_Printf(xpdd, XBT_NIL, path, "%d", frontend_state_set);
james@536 482
james@536 483 remaining = maximum_wait_ms;
james@536 484
james@536 485 while (xppdd->backend_state != backend_state_response)
james@536 486 {
james@536 487 thiswait = min((LONG)remaining, 1000); // 1 second or remaining time, whichever is less
james@536 488 timeout.QuadPart = (LONGLONG)-1 * thiswait * 1000 * 10;
james@536 489 if (KeWaitForSingleObject(&xppdd->backend_state_event, Executive, KernelMode, FALSE, &timeout) == STATUS_TIMEOUT)
james@536 490 {
james@624 491 /* it's possible that the workitems are blocked because the pagefile isn't available. Lets just re-read the backend value for now */
james@624 492 XenPci_UpdateBackendState(device);
james@536 493 remaining -= thiswait;
james@536 494 if (remaining == 0)
james@536 495 {
james@536 496 KdPrint((__DRIVER_NAME " Timed out waiting for %d!\n", backend_state_response));
james@536 497 return STATUS_UNSUCCESSFUL;
james@536 498 }
james@536 499 KdPrint((__DRIVER_NAME " Still waiting for %d (currently %d)...\n", backend_state_response, xppdd->backend_state));
james@536 500 }
james@536 501 }
james@624 502 FUNCTION_EXIT();
james@536 503 return STATUS_SUCCESS;
james@536 504 }
james@536 505
james@536 506 static NTSTATUS
james@536 507 XenPci_XenConfigDevice(WDFDEVICE device);
james@536 508
james@536 509 static NTSTATUS
james@536 510 XenPci_XenShutdownDevice(PVOID context)
james@536 511 {
james@536 512 WDFDEVICE device = context;
james@536 513 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
james@536 514 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
james@536 515 PUCHAR in_ptr;
james@536 516 ULONG i;
james@536 517 UCHAR type;
james@536 518 PVOID setting;
james@536 519 PVOID value;
james@536 520 PVOID value2;
james@536 521
james@536 522 FUNCTION_ENTER();
james@536 523
james@536 524 if (xppdd->backend_state == XenbusStateConnected)
james@536 525 {
james@536 526 XenPci_ChangeFrontendState(device, XenbusStateClosing, XenbusStateClosing, 30000);
james@536 527 if (xppdd->backend_state == XenbusStateClosing)
james@536 528 XenPci_ChangeFrontendState(device, XenbusStateClosed, XenbusStateClosed, 30000);
james@536 529 if (xppdd->backend_state == XenbusStateClosed)
james@536 530 XenPci_ChangeFrontendState(device, XenbusStateInitialising, XenbusStateInitWait, 30000);
james@536 531 }
james@536 532 else
james@536 533 {
james@536 534 if (xppdd->backend_state == XenbusStateClosing)
james@536 535 XenPci_ChangeFrontendState(device, XenbusStateClosed, XenbusStateClosed, 30000);
james@536 536 }
james@536 537
james@536 538 if (xppdd->assigned_resources_start != NULL)
james@536 539 {
james@536 540 ADD_XEN_INIT_RSP(&xppdd->assigned_resources_ptr, XEN_INIT_TYPE_END, NULL, NULL, NULL);
james@536 541 in_ptr = xppdd->assigned_resources_start;
james@536 542 while((type = GET_XEN_INIT_RSP(&in_ptr, &setting, &value, &value2)) != XEN_INIT_TYPE_END)
james@536 543 {
james@536 544 switch (type)
james@536 545 {
james@536 546 case XEN_INIT_TYPE_RING: /* frontend ring */
james@536 547 FreePages(value);
james@536 548 break;
james@536 549 case XEN_INIT_TYPE_EVENT_CHANNEL: /* frontend event channel */
james@617 550 case XEN_INIT_TYPE_EVENT_CHANNEL_DPC: /* frontend event channel bound to dpc */
james@536 551 case XEN_INIT_TYPE_EVENT_CHANNEL_IRQ: /* frontend event channel bound to irq */
james@536 552 EvtChn_Unbind(xpdd, PtrToUlong(value));
james@536 553 EvtChn_Close(xpdd, PtrToUlong(value));
james@536 554 break;
james@536 555 case XEN_INIT_TYPE_GRANT_ENTRIES:
james@536 556 for (i = 0; i < PtrToUlong(setting); i++)
james@536 557 GntTbl_EndAccess(xpdd, ((grant_ref_t *)value)[i], FALSE);
james@536 558 break;
james@536 559 }
james@536 560 }
james@536 561 ExFreePoolWithTag(xppdd->assigned_resources_start, XENPCI_POOL_TAG);
james@536 562 xppdd->assigned_resources_start = NULL;
james@536 563 }
james@536 564
james@536 565 FUNCTION_EXIT();
james@536 566
james@536 567 return STATUS_SUCCESS;
james@536 568 }
james@536 569
james@536 570 struct dummy_sring {
james@536 571 RING_IDX req_prod, req_event;
james@536 572 RING_IDX rsp_prod, rsp_event;
james@536 573 uint8_t pad[48];
james@536 574 };
james@536 575
james@536 576 static NTSTATUS
james@536 577 XenPci_XenConfigDeviceSpecifyBuffers(WDFDEVICE device, PUCHAR src, PUCHAR dst)
james@536 578 {
james@536 579 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
james@536 580 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
james@536 581 NTSTATUS status = STATUS_SUCCESS;
james@536 582 ULONG i;
james@536 583 char path[128];
james@536 584 PCHAR setting, value;
james@536 585 PCHAR res;
james@536 586 PVOID address;
james@536 587 UCHAR type;
james@551 588 PUCHAR in_ptr;
james@551 589 PUCHAR out_ptr;
james@536 590 XENPCI_VECTORS vectors;
james@536 591 ULONG event_channel;
james@536 592 ULONG run_type = 0;
james@536 593 PMDL ring;
james@536 594 grant_ref_t gref;
james@536 595 BOOLEAN done_xenbus_init = FALSE;
james@536 596 PVOID value2;
james@551 597 BOOLEAN active = TRUE;
james@551 598 BOOLEAN dont_config = FALSE;
james@536 599
james@536 600 FUNCTION_ENTER();
james@536 601
james@536 602 in_ptr = src;
james@536 603 out_ptr = dst;
james@536 604
james@536 605 // always add vectors
james@536 606 vectors.magic = XEN_DATA_MAGIC;
james@536 607 vectors.length = sizeof(XENPCI_VECTORS);
james@536 608 vectors.context = device;
james@536 609 vectors.EvtChn_Bind = XenPci_EvtChn_Bind;
james@536 610 vectors.EvtChn_BindDpc = XenPci_EvtChn_BindDpc;
james@536 611 vectors.EvtChn_Unbind = XenPci_EvtChn_Unbind;
james@536 612 vectors.EvtChn_Mask = XenPci_EvtChn_Mask;
james@536 613 vectors.EvtChn_Unmask = XenPci_EvtChn_Unmask;
james@536 614 vectors.EvtChn_Notify = XenPci_EvtChn_Notify;
james@536 615 vectors.EvtChn_AckEvent = XenPci_EvtChn_AckEvent;
james@536 616 vectors.EvtChn_Sync = XenPci_EvtChn_Sync;
james@536 617 vectors.GntTbl_GetRef = XenPci_GntTbl_GetRef;
james@536 618 vectors.GntTbl_PutRef = XenPci_GntTbl_PutRef;
james@536 619 vectors.GntTbl_GrantAccess = XenPci_GntTbl_GrantAccess;
james@536 620 vectors.GntTbl_EndAccess = XenPci_GntTbl_EndAccess;
james@536 621 vectors.XenPci_XenConfigDevice = XenPci_XenConfigDevice;
james@536 622 vectors.XenPci_XenShutdownDevice = XenPci_XenShutdownDevice;
james@536 623 strncpy(vectors.path, xppdd->path, 128);
james@536 624 strncpy(vectors.backend_path, xppdd->backend_path, 128);
james@536 625 //vectors.pdo_event_channel = xpdd->pdo_event_channel;
james@536 626 vectors.XenBus_Read = XenPci_XenBus_Read;
james@536 627 vectors.XenBus_Write = XenPci_XenBus_Write;
james@536 628 vectors.XenBus_Printf = XenPci_XenBus_Printf;
james@536 629 vectors.XenBus_StartTransaction = XenPci_XenBus_StartTransaction;
james@536 630 vectors.XenBus_EndTransaction = XenPci_XenBus_EndTransaction;
james@536 631 vectors.XenBus_List = XenPci_XenBus_List;
james@536 632 vectors.XenBus_AddWatch = XenPci_XenBus_AddWatch;
james@536 633 vectors.XenBus_RemWatch = XenPci_XenBus_RemWatch;
james@536 634
james@536 635 ADD_XEN_INIT_RSP(&out_ptr, XEN_INIT_TYPE_QEMU_PROTOCOL_VERSION, NULL, UlongToPtr(qemu_protocol_version), NULL);
james@536 636
james@536 637 ADD_XEN_INIT_RSP(&out_ptr, XEN_INIT_TYPE_VECTORS, NULL, &vectors, NULL);
james@536 638 ADD_XEN_INIT_RSP(&out_ptr, XEN_INIT_TYPE_STATE_PTR, NULL, &xppdd->device_state, NULL);
james@536 639
james@551 640 if (!qemu_filtered)
james@551 641 active = FALSE;
james@551 642
james@551 643 while((type = GET_XEN_INIT_REQ(&in_ptr, (PVOID)&setting, (PVOID)&value, (PVOID)&value2)) != XEN_INIT_TYPE_END)
james@551 644 {
james@551 645 BOOLEAN condition;
james@551 646 PCHAR xb_value;
james@551 647 switch (type)
james@551 648 {
james@551 649 case XEN_INIT_TYPE_MATCH_FRONT:
james@551 650 case XEN_INIT_TYPE_MATCH_BACK:
james@551 651 if (type == XEN_INIT_TYPE_MATCH_FRONT)
james@551 652 {
james@551 653 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "%s/%s", xppdd->path, setting);
james@551 654 }
james@551 655 else
james@551 656 {
james@551 657 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "%s/%s", xppdd->backend_path, setting);
james@551 658 }
james@551 659 KdPrint((__DRIVER_NAME " testing path = %s\n", path));
james@551 660 res = XenBus_Read(xpdd, XBT_NIL, path, &xb_value);
james@551 661 if (res)
james@551 662 {
james@551 663 KdPrint((__DRIVER_NAME " read failed (%s)\n", res));
james@551 664 XenPci_FreeMem(res);
james@551 665 }
james@551 666 else
james@551 667 {
james@551 668 KdPrint((__DRIVER_NAME " testing %s vs %s\n", xb_value, value));
james@551 669 if (PtrToUlong(value2) & XEN_INIT_MATCH_TYPE_IF_MATCH)
james@551 670 condition = (strcmp(xb_value, value) == 0)?TRUE:FALSE;
james@551 671 else
james@551 672 condition = (strcmp(xb_value, value) != 0)?TRUE:FALSE;
james@551 673 KdPrint((__DRIVER_NAME " condition = %d\n", condition));
james@551 674
james@551 675 if ((PtrToUlong(value2) & XEN_INIT_MATCH_TYPE_ONLY_IF_QEMU_HIDE) && qemu_protocol_version && condition)
james@551 676 condition = FALSE;
james@551 677
james@551 678 if (condition)
james@551 679 {
james@551 680 if (PtrToUlong(value2) & XEN_INIT_MATCH_TYPE_SET_INACTIVE)
james@551 681 {
james@551 682 active = FALSE;
james@551 683 KdPrint((__DRIVER_NAME " set inactive\n"));
james@551 684 }
james@551 685 if (PtrToUlong(value2) & XEN_INIT_MATCH_TYPE_DONT_CONFIG)
james@551 686 {
james@551 687 dont_config = TRUE;
james@551 688 KdPrint((__DRIVER_NAME " set inactive with dont config\n"));
james@551 689 }
james@551 690 }
james@551 691 XenPci_FreeMem(xb_value);
james@551 692 }
james@551 693 break;
james@551 694 }
james@551 695 }
james@551 696 if (dont_config)
james@551 697 {
james@551 698 ADD_XEN_INIT_RSP(&out_ptr, XEN_INIT_TYPE_END, NULL, NULL, NULL);
james@551 699 FUNCTION_EXIT();
james@551 700 return status;
james@551 701 }
james@551 702
james@536 703 // first pass, possibly before state == Connected
james@551 704 in_ptr = src;
james@536 705 while((type = GET_XEN_INIT_REQ(&in_ptr, (PVOID)&setting, (PVOID)&value, (PVOID)&value2)) != XEN_INIT_TYPE_END)
james@536 706 {
james@536 707 if (!done_xenbus_init)
james@536 708 {
james@551 709 if (XenPci_ChangeFrontendState(device, XenbusStateInitialising, XenbusStateInitWait, 2000) != STATUS_SUCCESS)
james@536 710 {
james@536 711 status = STATUS_UNSUCCESSFUL;
james@536 712 goto error;
james@536 713 }
james@536 714 done_xenbus_init = TRUE;
james@536 715 }
james@536 716
james@536 717 ADD_XEN_INIT_REQ(&xppdd->requested_resources_ptr, type, setting, value, value2);
james@536 718
james@536 719 switch (type)
james@536 720 {
james@536 721 case XEN_INIT_TYPE_RUN:
james@536 722 run_type++;
james@536 723 break;
james@536 724 case XEN_INIT_TYPE_WRITE_STRING: /* frontend setting = value */
james@536 725 //KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_WRITE_STRING - %s = %s\n", setting, value));
james@536 726 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "%s/%s", xppdd->path, setting);
james@536 727 XenBus_Printf(xpdd, XBT_NIL, path, "%s", value);
james@536 728 break;
james@536 729 case XEN_INIT_TYPE_RING: /* frontend ring */
james@536 730 /* we only allocate and do the SHARED_RING_INIT here */
james@536 731 if ((ring = AllocatePage()) != 0)
james@536 732 {
james@536 733 address = MmGetMdlVirtualAddress(ring);
james@536 734 //KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_RING - %s = %p\n", setting, address));
james@536 735 SHARED_RING_INIT((struct dummy_sring *)address);
james@536 736 if ((gref = GntTbl_GrantAccess(
james@536 737 xpdd, 0, (ULONG)*MmGetMdlPfnArray(ring), FALSE, INVALID_GRANT_REF)) != INVALID_GRANT_REF)
james@536 738 {
james@536 739 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "%s/%s", xppdd->path, setting);
james@536 740 XenBus_Printf(xpdd, XBT_NIL, path, "%d", gref);
james@536 741 ADD_XEN_INIT_RSP(&out_ptr, type, setting, address, NULL);
james@536 742 ADD_XEN_INIT_RSP(&xppdd->assigned_resources_ptr, type, setting, ring, NULL);
james@536 743 // add the grant entry too so it gets freed automatically
james@536 744 __ADD_XEN_INIT_UCHAR(&xppdd->assigned_resources_ptr, XEN_INIT_TYPE_GRANT_ENTRIES);
james@536 745 __ADD_XEN_INIT_ULONG(&xppdd->assigned_resources_ptr, 1);
james@536 746 __ADD_XEN_INIT_ULONG(&xppdd->assigned_resources_ptr, gref);
james@536 747 }
james@536 748 else
james@536 749 {
james@536 750 FreePages(ring);
james@536 751 status = STATUS_UNSUCCESSFUL;
james@536 752 goto error;
james@536 753 }
james@536 754 }
james@536 755 else
james@536 756 {
james@536 757 status = STATUS_UNSUCCESSFUL;
james@536 758 goto error;
james@536 759 }
james@536 760 break;
james@536 761 case XEN_INIT_TYPE_EVENT_CHANNEL: /* frontend event channel */
james@617 762 case XEN_INIT_TYPE_EVENT_CHANNEL_DPC: /* frontend event channel bound to dpc */
james@536 763 case XEN_INIT_TYPE_EVENT_CHANNEL_IRQ: /* frontend event channel bound to irq */
james@536 764 if ((event_channel = EvtChn_AllocUnbound(xpdd, 0)) != 0)
james@536 765 {
james@617 766 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_EVENT_CHANNEL - %s = %d\n", setting, event_channel));
james@536 767 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "%s/%s", xppdd->path, setting);
james@536 768 XenBus_Printf(xpdd, XBT_NIL, path, "%d", event_channel);
james@536 769 ADD_XEN_INIT_RSP(&out_ptr, type, setting, UlongToPtr(event_channel), NULL);
james@536 770 ADD_XEN_INIT_RSP(&xppdd->assigned_resources_ptr, type, setting, UlongToPtr(event_channel), NULL);
james@536 771 if (type == XEN_INIT_TYPE_EVENT_CHANNEL_IRQ)
james@536 772 {
james@536 773 EvtChn_BindIrq(xpdd, event_channel, xppdd->irq_vector, path);
james@536 774 }
james@617 775 else if (type == XEN_INIT_TYPE_EVENT_CHANNEL_DPC)
james@617 776 {
james@617 777 #pragma warning(suppress:4055)
james@617 778 EvtChn_BindDpc(xpdd, event_channel, (PXEN_EVTCHN_SERVICE_ROUTINE)value, value2);
james@617 779 }
james@536 780 else
james@536 781 {
james@537 782 #pragma warning(suppress:4055)
james@536 783 EvtChn_Bind(xpdd, event_channel, (PXEN_EVTCHN_SERVICE_ROUTINE)value, value2);
james@536 784 }
james@536 785 }
james@536 786 else
james@536 787 {
james@536 788 status = STATUS_UNSUCCESSFUL;
james@536 789 goto error;
james@536 790 }
james@536 791 break;
james@536 792 }
james@536 793 }
james@536 794 if (!NT_SUCCESS(status))
james@536 795 {
james@536 796 goto error;
james@536 797 }
james@536 798 // If XEN_INIT_TYPE_RUN was specified more than once then we skip XenbusStateInitialised here and go straight to XenbusStateConnected at the end
james@536 799 if (run_type == 1)
james@536 800 {
james@551 801 if (XenPci_ChangeFrontendState(device, XenbusStateInitialised, XenbusStateConnected, 2000) != STATUS_SUCCESS)
james@536 802 {
james@536 803 status = STATUS_UNSUCCESSFUL;
james@536 804 goto error;
james@536 805 }
james@536 806 }
james@536 807
james@536 808 // second pass, possibly after state == Connected
james@536 809 in_ptr = src;
james@536 810 while((type = GET_XEN_INIT_REQ(&in_ptr, (PVOID)&setting, (PVOID)&value, (PVOID)&value2)) != XEN_INIT_TYPE_END)
james@536 811 {
james@536 812 switch(type)
james@536 813 {
james@536 814 case XEN_INIT_TYPE_READ_STRING_BACK:
james@536 815 case XEN_INIT_TYPE_READ_STRING_FRONT:
james@536 816 if (type == XEN_INIT_TYPE_READ_STRING_FRONT)
james@536 817 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "%s/%s", xppdd->path, setting);
james@536 818 else
james@536 819 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "%s/%s", xppdd->backend_path, setting);
james@536 820 res = XenBus_Read(xpdd, XBT_NIL, path, &value);
james@536 821 if (res)
james@536 822 {
james@617 823 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_READ_STRING - %s = <failed>\n", setting));
james@536 824 XenPci_FreeMem(res);
james@617 825 ADD_XEN_INIT_RSP(&out_ptr, type, setting, "", "");
james@536 826 }
james@536 827 else
james@536 828 {
james@536 829 //KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_READ_STRING - %s = %s\n", setting, value));
james@536 830 ADD_XEN_INIT_RSP(&out_ptr, type, setting, value, value2);
james@536 831 XenPci_FreeMem(value);
james@536 832 }
james@536 833 break;
james@536 834 case XEN_INIT_TYPE_VECTORS:
james@536 835 // this is always done so ignore the request
james@536 836 break;
james@536 837 case XEN_INIT_TYPE_GRANT_ENTRIES:
james@536 838 //KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_GRANT_ENTRIES - %d\n", PtrToUlong(value)));
james@536 839 __ADD_XEN_INIT_UCHAR(&out_ptr, type);
james@536 840 __ADD_XEN_INIT_UCHAR(&xppdd->assigned_resources_ptr, type);
james@536 841 __ADD_XEN_INIT_ULONG(&out_ptr, PtrToUlong(value));
james@536 842 __ADD_XEN_INIT_ULONG(&xppdd->assigned_resources_ptr, PtrToUlong(value));
james@536 843 for (i = 0; i < PtrToUlong(value); i++)
james@536 844 {
james@536 845 gref = GntTbl_GetRef(xpdd);
james@536 846 __ADD_XEN_INIT_ULONG(&out_ptr, gref);
james@536 847 __ADD_XEN_INIT_ULONG(&xppdd->assigned_resources_ptr, gref);
james@536 848 }
james@536 849 break;
james@536 850 }
james@536 851 }
james@551 852 if (active)
james@551 853 {
james@551 854 ADD_XEN_INIT_RSP(&out_ptr, XEN_INIT_TYPE_ACTIVE, NULL, NULL, NULL);
james@551 855 }
james@536 856 ADD_XEN_INIT_RSP(&out_ptr, XEN_INIT_TYPE_END, NULL, NULL, NULL);
james@536 857
james@536 858 if (run_type)
james@536 859 {
james@551 860 if (XenPci_ChangeFrontendState(device, XenbusStateConnected, XenbusStateConnected, 2000) != STATUS_SUCCESS)
james@536 861 {
james@536 862 status = STATUS_UNSUCCESSFUL;
james@536 863 goto error;
james@536 864 }
james@536 865 }
james@536 866 FUNCTION_EXIT();
james@536 867 return status;
james@551 868
james@536 869 error:
james@551 870 XenPci_ChangeFrontendState(device, XenbusStateInitialising, XenbusStateInitWait, 2000);
james@536 871 FUNCTION_EXIT_STATUS(status);
james@536 872 return status;
james@536 873 }
james@536 874
james@536 875 static NTSTATUS
james@536 876 XenPci_XenConfigDevice(WDFDEVICE device)
james@536 877 {
james@536 878 NTSTATUS status;
james@536 879 PUCHAR src, dst;
james@536 880 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
james@536 881
james@536 882 src = ExAllocatePoolWithTag(NonPagedPool, xppdd->config_page_length, XENPCI_POOL_TAG);
james@536 883 dst = MmMapIoSpace(xppdd->config_page_phys, xppdd->config_page_length, MmNonCached);
james@536 884 memcpy(src, dst, xppdd->config_page_length);
james@536 885
james@536 886 status = XenPci_XenConfigDeviceSpecifyBuffers(device, src, dst);
james@536 887
james@536 888 MmUnmapIoSpace(dst, xppdd->config_page_length);
james@536 889 ExFreePoolWithTag(src, XENPCI_POOL_TAG);
james@536 890
james@536 891 return status;
james@536 892 }
james@536 893
james@536 894 static NTSTATUS
james@536 895 XenPciPdo_EvtDeviceWdmIrpPreprocess_START_DEVICE(WDFDEVICE device, PIRP irp)
james@536 896 {
james@536 897 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
james@536 898 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
james@536 899 PIO_STACK_LOCATION stack;
james@536 900 PCM_PARTIAL_RESOURCE_LIST prl;
james@536 901 PCM_PARTIAL_RESOURCE_DESCRIPTOR prd;
james@536 902 ULONG i;
james@551 903 //char path[128];
james@551 904 //PMDL mdl;
james@536 905
james@536 906 FUNCTION_ENTER();
james@536 907 KdPrint((__DRIVER_NAME " %s\n", xppdd->path));
james@536 908
james@536 909 stack = IoGetCurrentIrpStackLocation(irp);
james@536 910
james@536 911 prl = &stack->Parameters.StartDevice.AllocatedResources->List[0].PartialResourceList;
james@536 912 for (i = 0; i < prl->Count; i++)
james@536 913 {
james@536 914 prd = & prl->PartialDescriptors[i];
james@536 915 switch (prd->Type)
james@536 916 {
james@536 917 case CmResourceTypeMemory:
james@536 918 if (prd->u.Memory.Start.QuadPart == xpdd->platform_mmio_addr.QuadPart && prd->u.Memory.Length == 0)
james@536 919 {
james@551 920 prd->u.Memory.Start.QuadPart = MmGetMdlPfnArray(xppdd->config_page_mdl)[0] << PAGE_SHIFT;
james@551 921 prd->u.Memory.Length = MmGetMdlByteCount(xppdd->config_page_mdl);
james@536 922 }
james@536 923 else if (prd->u.Memory.Start.QuadPart == xpdd->platform_mmio_addr.QuadPart + 1 && prd->u.Memory.Length == 0)
james@536 924 {
james@536 925 RtlZeroMemory(prd, sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
james@536 926 prd->Type = CmResourceTypeInterrupt;
james@536 927 prd->ShareDisposition = CmResourceShareShared;
james@536 928 prd->Flags = (xpdd->irq_mode == Latched)?CM_RESOURCE_INTERRUPT_LATCHED:CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
steve@621 929 prd->u.Interrupt.Level = 0; // Set group and level to zero (group = upper word)
steve@621 930 prd->u.Interrupt.Level = xpdd->irq_number & 0xffff; // Only set the lower word
james@536 931 prd->u.Interrupt.Vector = xpdd->irq_number;
james@705 932 prd->u.Interrupt.Affinity = xpdd->irq_affinity; //KeQueryActiveProcessors();
james@536 933 xppdd->irq_number = xpdd->irq_number;
james@536 934 }
james@536 935 break;
james@536 936 }
james@536 937 }
james@536 938
james@536 939 prl = &stack->Parameters.StartDevice.AllocatedResourcesTranslated->List[0].PartialResourceList;
james@536 940 for (i = 0; i < prl->Count; i++)
james@536 941 {
james@536 942 prd = & prl->PartialDescriptors[i];
james@536 943 switch (prd->Type)
james@536 944 {
james@536 945 case CmResourceTypeMemory:
james@536 946 KdPrint((__DRIVER_NAME " CmResourceTypeMemory (%d)\n", i));
james@536 947 KdPrint((__DRIVER_NAME " Start = %08x, Length = %d\n", prd->u.Memory.Start.LowPart, prd->u.Memory.Length));
james@536 948 if (prd->u.Memory.Start.QuadPart == xpdd->platform_mmio_addr.QuadPart)
james@536 949 {
james@536 950 if (prd->u.Memory.Length == 0)
james@536 951 {
james@551 952 KdPrint((__DRIVER_NAME " pfn[0] = %08x\n", (ULONG)MmGetMdlPfnArray(xppdd->config_page_mdl)[0]));
james@551 953 prd->u.Memory.Start.QuadPart = (ULONGLONG)MmGetMdlPfnArray(xppdd->config_page_mdl)[0] << PAGE_SHIFT;
james@551 954 prd->u.Memory.Length = MmGetMdlByteCount(xppdd->config_page_mdl);
james@536 955 KdPrint((__DRIVER_NAME " New Start = %08x%08x, Length = %d\n", prd->u.Memory.Start.HighPart, prd->u.Memory.Start.LowPart, prd->u.Memory.Length));
james@536 956 }
james@536 957 xppdd->config_page_phys = prd->u.Memory.Start;
james@536 958 xppdd->config_page_length = prd->u.Memory.Length;
james@536 959 xppdd->requested_resources_start = xppdd->requested_resources_ptr = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE, XENPCI_POOL_TAG);
james@634 960 //xppdd->assigned_resources_start = xppdd->assigned_resources_ptr = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE, XENPCI_POOL_TAG);
james@536 961
james@551 962 #if 0
james@536 963 status = XenPci_XenConfigDevice(device);
james@536 964 if (!NT_SUCCESS(status))
james@536 965 {
james@536 966 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "%s/state", xppdd->backend_path);
james@624 967 XenBus_RemWatch(xpdd, XBT_NIL, path, XenPci_BackendStateHandler, device);
james@702 968 FUNCTION_EXIT_STATUS(status);
james@536 969 return status;
james@536 970 }
james@551 971 #endif
james@536 972 }
james@536 973 else if (prd->u.Memory.Start.QuadPart == xpdd->platform_mmio_addr.QuadPart + 1 && prd->u.Memory.Length == 0)
james@536 974 {
james@536 975 RtlZeroMemory(prd, sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
james@536 976 prd->Type = CmResourceTypeInterrupt;
james@536 977 prd->ShareDisposition = CmResourceShareShared;
james@536 978 prd->Flags = (xpdd->irq_mode == Latched)?CM_RESOURCE_INTERRUPT_LATCHED:CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
steve@621 979 prd->u.Interrupt.Level = 0; // Set group and level to zero (group = upper word)
steve@621 980 prd->u.Interrupt.Level = xpdd->irq_level & 0xffff; // Only set the lower word
james@536 981 prd->u.Interrupt.Vector = xpdd->irq_vector;
james@705 982 prd->u.Interrupt.Affinity = xpdd->irq_affinity; //KeQueryActiveProcessors();
james@536 983 xppdd->irq_vector = xpdd->irq_vector;
james@536 984 xppdd->irq_level = xpdd->irq_level;
james@536 985 }
james@536 986 break;
james@536 987 }
james@536 988 }
james@536 989
james@536 990 IoSkipCurrentIrpStackLocation(irp);
james@536 991
james@536 992 FUNCTION_EXIT();
james@536 993
james@536 994 return WdfDeviceWdmDispatchPreprocessedIrp(device, irp);
james@536 995 }
james@536 996
james@536 997 #if 0
james@536 998 static NTSTATUS
james@536 999 XenPciPdo_EvtDeviceResourcesQuery(WDFDEVICE device, WDFCMRESLIST resources)
james@536 1000 {
james@536 1001 }
james@536 1002 #endif
james@536 1003
james@536 1004 static NTSTATUS
james@536 1005 XenPciPdo_EvtDeviceResourceRequirementsQuery(WDFDEVICE device, WDFIORESREQLIST requirements_list)
james@536 1006 {
james@536 1007 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
james@536 1008 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
james@536 1009 WDFIORESLIST res_list;
james@536 1010 IO_RESOURCE_DESCRIPTOR ird;
james@536 1011
james@538 1012 //FUNCTION_ENTER();
james@536 1013
james@536 1014 WdfIoResourceRequirementsListSetInterfaceType(requirements_list, PNPBus);
james@536 1015
james@536 1016 WdfIoResourceListCreate(requirements_list, WDF_NO_OBJECT_ATTRIBUTES, &res_list);
james@536 1017 ird.Option = 0;
james@536 1018 ird.Type = CmResourceTypeMemory;
james@536 1019 ird.ShareDisposition = CmResourceShareShared;
james@536 1020 ird.Flags = CM_RESOURCE_MEMORY_READ_WRITE | CM_RESOURCE_MEMORY_CACHEABLE;
james@536 1021 ird.u.Memory.MinimumAddress.QuadPart = xpdd->platform_mmio_addr.QuadPart;
james@536 1022 ird.u.Memory.MaximumAddress.QuadPart = xpdd->platform_mmio_addr.QuadPart;
james@536 1023 ird.u.Memory.Length = 0;
james@536 1024 ird.u.Memory.Alignment = 1; //PAGE_SIZE;
james@536 1025 WdfIoResourceListAppendDescriptor(res_list, &ird);
james@536 1026
james@536 1027 ird.Option = 0;
james@536 1028 ird.Type = CmResourceTypeMemory;
james@536 1029 ird.ShareDisposition = CmResourceShareShared;
james@536 1030 ird.Flags = CM_RESOURCE_MEMORY_READ_WRITE | CM_RESOURCE_MEMORY_CACHEABLE;
james@536 1031 ird.u.Memory.MinimumAddress.QuadPart = xpdd->platform_mmio_addr.QuadPart + 1;
james@536 1032 ird.u.Memory.MaximumAddress.QuadPart = xpdd->platform_mmio_addr.QuadPart + 1;
james@536 1033 ird.u.Memory.Length = 0;
james@536 1034 ird.u.Memory.Alignment = 1; //PAGE_SIZE;
james@536 1035 WdfIoResourceListAppendDescriptor(res_list, &ird);
james@536 1036
james@536 1037 WdfIoResourceRequirementsListAppendIoResList(requirements_list, res_list);
james@536 1038
james@538 1039 //FUNCTION_EXIT();
james@538 1040
james@538 1041 return STATUS_SUCCESS;
james@538 1042 }
james@538 1043
james@538 1044 NTSTATUS
james@538 1045 XenPciPdo_EvtDeviceD0Entry(WDFDEVICE device, WDF_POWER_DEVICE_STATE previous_state)
james@538 1046 {
james@538 1047 NTSTATUS status = STATUS_SUCCESS;
james@551 1048 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
james@551 1049 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
james@551 1050 CHAR path[128];
james@538 1051
james@538 1052 FUNCTION_ENTER();
james@538 1053
james@538 1054 switch (previous_state)
james@538 1055 {
james@538 1056 case WdfPowerDeviceD0:
james@538 1057 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
james@538 1058 break;
james@538 1059 case WdfPowerDeviceD1:
james@538 1060 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
james@538 1061 break;
james@538 1062 case WdfPowerDeviceD2:
james@538 1063 KdPrint((__DRIVER_NAME " WdfPowerDeviceD2\n"));
james@538 1064 break;
james@538 1065 case WdfPowerDeviceD3:
james@538 1066 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3\n"));
james@538 1067 break;
james@538 1068 case WdfPowerDeviceD3Final:
james@538 1069 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3Final\n"));
james@538 1070 break;
james@538 1071 case WdfPowerDevicePrepareForHibernation:
james@538 1072 KdPrint((__DRIVER_NAME " WdfPowerDevicePrepareForHibernation\n"));
james@538 1073 break;
james@538 1074 default:
james@538 1075 KdPrint((__DRIVER_NAME " Unknown WdfPowerDevice state %d\n", previous_state));
james@538 1076 break;
james@538 1077 }
james@634 1078
james@551 1079 if (previous_state == WdfPowerDevicePrepareForHibernation
james@551 1080 || (previous_state == WdfPowerDeviceD3 && xppdd->hiber_usage_kludge))
james@551 1081 {
james@551 1082 KdPrint((__DRIVER_NAME " starting up from hibernation\n"));
james@551 1083 }
james@551 1084 else
james@551 1085 {
james@551 1086 }
james@551 1087
james@634 1088 if (previous_state == WdfPowerDevicePrepareForHibernation || previous_state == WdfPowerDeviceD3 || previous_state == WdfPowerDeviceD3Final)
james@634 1089 {
james@634 1090 xppdd->requested_resources_ptr = xppdd->requested_resources_start;
james@634 1091 xppdd->assigned_resources_start = xppdd->assigned_resources_ptr = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE, XENPCI_POOL_TAG);
james@634 1092 }
james@634 1093
james@551 1094 XenConfig_InitConfigPage(device);
james@551 1095
james@551 1096 status = XenPci_GetBackendAndAddWatch(device);
james@551 1097 if (!NT_SUCCESS(status))
james@551 1098 {
james@551 1099 WdfDeviceSetFailed(device, WdfDeviceFailedNoRestart);
james@702 1100 FUNCTION_EXIT_STATUS(status);
james@551 1101 return status;
james@551 1102 }
james@551 1103 status = XenPci_XenConfigDevice(device);
james@551 1104 if (!NT_SUCCESS(status))
james@551 1105 {
james@551 1106 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "%s/state", xppdd->backend_path);
james@624 1107 XenBus_RemWatch(xpdd, XBT_NIL, path, XenPci_BackendStateHandler, device);
james@551 1108 WdfDeviceSetFailed(device, WdfDeviceFailedNoRestart);
james@702 1109 FUNCTION_EXIT_STATUS(status);
james@551 1110 return status;
james@551 1111 }
james@538 1112
james@536 1113 FUNCTION_EXIT();
james@536 1114
james@538 1115 return status;
james@538 1116 }
james@538 1117
james@538 1118 NTSTATUS
james@538 1119 XenPciPdo_EvtDeviceD0Exit(WDFDEVICE device, WDF_POWER_DEVICE_STATE target_state)
james@538 1120 {
james@538 1121 NTSTATUS status = STATUS_SUCCESS;
james@538 1122 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
james@538 1123 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
james@538 1124 char path[128];
james@538 1125
james@538 1126 UNREFERENCED_PARAMETER(device);
james@538 1127 UNREFERENCED_PARAMETER(target_state);
james@538 1128
james@538 1129 FUNCTION_ENTER();
james@538 1130
james@538 1131 KdPrint((__DRIVER_NAME " path = %s\n", xppdd->path));
james@538 1132
james@538 1133
james@538 1134 switch (target_state)
james@538 1135 {
james@538 1136 case WdfPowerDeviceD0:
james@538 1137 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
james@538 1138 break;
james@538 1139 case WdfPowerDeviceD1:
james@538 1140 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
james@538 1141 break;
james@538 1142 case WdfPowerDeviceD2:
james@538 1143 KdPrint((__DRIVER_NAME " WdfPowerDeviceD2\n"));
james@538 1144 break;
james@538 1145 case WdfPowerDeviceD3:
james@538 1146 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3\n"));
james@538 1147 break;
james@538 1148 case WdfPowerDeviceD3Final:
james@538 1149 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3Final\n"));
james@538 1150 break;
james@538 1151 case WdfPowerDevicePrepareForHibernation:
james@538 1152 KdPrint((__DRIVER_NAME " WdfPowerDevicePrepareForHibernation\n"));
james@538 1153 break;
james@538 1154 default:
james@538 1155 KdPrint((__DRIVER_NAME " Unknown WdfPowerDevice state %d\n", target_state));
james@538 1156 break;
james@538 1157 }
james@692 1158
james@538 1159 if (target_state == WdfPowerDevicePrepareForHibernation
james@538 1160 || (target_state == WdfPowerDeviceD3 && xppdd->hiber_usage_kludge))
james@538 1161 {
james@538 1162 KdPrint((__DRIVER_NAME " not powering down as we are hibernating\n"));
james@538 1163 }
james@538 1164 else
james@538 1165 {
james@538 1166 status = XenPci_XenShutdownDevice(device);
james@538 1167 }
amir@679 1168
amir@679 1169 /* Remove watch on backend state */
amir@679 1170 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "%s/state", xppdd->backend_path);
amir@679 1171 XenBus_RemWatch(xpdd, XBT_NIL, path, XenPci_BackendStateHandler, device);
amir@679 1172
james@538 1173 FUNCTION_EXIT();
james@538 1174
james@538 1175 return status;
james@538 1176 }
james@538 1177
james@538 1178 NTSTATUS
james@551 1179 XenPciPdo_EvtDevicePrepareHardware(WDFDEVICE device, WDFCMRESLIST resources_raw, WDFCMRESLIST resources_translated)
james@538 1180 {
james@538 1181 NTSTATUS status = STATUS_SUCCESS;
james@551 1182
james@538 1183 UNREFERENCED_PARAMETER(device);
james@538 1184 UNREFERENCED_PARAMETER(resources_raw);
james@538 1185 UNREFERENCED_PARAMETER(resources_translated);
james@538 1186
james@538 1187 FUNCTION_ENTER();
james@538 1188 FUNCTION_EXIT();
james@538 1189
james@538 1190 return status;
james@538 1191 }
james@538 1192
james@538 1193 NTSTATUS
james@538 1194 XenPciPdo_EvtDeviceReleaseHardware(WDFDEVICE device, WDFCMRESLIST resources_translated)
james@538 1195 {
james@538 1196 NTSTATUS status = STATUS_SUCCESS;
james@538 1197
james@538 1198 UNREFERENCED_PARAMETER(device);
james@538 1199 UNREFERENCED_PARAMETER(resources_translated);
james@538 1200
james@538 1201 FUNCTION_ENTER();
james@538 1202 FUNCTION_EXIT();
james@538 1203
james@538 1204 return status;
james@538 1205 }
james@538 1206
james@538 1207 static VOID
james@538 1208 XenPciPdo_EvtDeviceUsageNotification(WDFDEVICE device, WDF_SPECIAL_FILE_TYPE notification_type, BOOLEAN is_in_notification_path)
james@538 1209 {
james@538 1210 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
james@538 1211
james@538 1212 FUNCTION_ENTER();
james@538 1213
james@538 1214 KdPrint((__DRIVER_NAME " path = %s\n", xppdd->path));
james@538 1215 switch (notification_type)
james@538 1216 {
james@538 1217 case WdfSpecialFilePaging:
james@538 1218 KdPrint((__DRIVER_NAME " notification_type = Paging, flag = %d\n", is_in_notification_path));
james@538 1219 break;
james@538 1220 case WdfSpecialFileHibernation:
james@538 1221 xppdd->hiber_usage_kludge = is_in_notification_path;
james@538 1222 KdPrint((__DRIVER_NAME " notification_type = Hibernation, flag = %d\n", is_in_notification_path));
james@538 1223 break;
james@538 1224 case WdfSpecialFileDump:
james@538 1225 KdPrint((__DRIVER_NAME " notification_type = Dump, flag = %d\n", is_in_notification_path));
james@538 1226 break;
james@538 1227 default:
james@538 1228 KdPrint((__DRIVER_NAME " notification_type = %d, flag = %d\n", notification_type, is_in_notification_path));
james@538 1229 break;
james@538 1230 }
james@538 1231
james@538 1232 FUNCTION_EXIT();
james@536 1233 }
james@536 1234
james@536 1235 NTSTATUS
james@536 1236 XenPci_EvtChildListCreateDevice(WDFCHILDLIST child_list,
james@536 1237 PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER identification_header,
james@536 1238 PWDFDEVICE_INIT child_init)
james@536 1239 {
james@536 1240 NTSTATUS status = STATUS_SUCCESS;
james@536 1241 WDF_OBJECT_ATTRIBUTES child_attributes;
james@536 1242 WDFDEVICE child_device;
james@536 1243 PXENPCI_PDO_IDENTIFICATION_DESCRIPTION identification = (PXENPCI_PDO_IDENTIFICATION_DESCRIPTION)identification_header;
james@536 1244 WDF_DEVICE_PNP_CAPABILITIES child_pnp_capabilities;
james@536 1245 DECLARE_UNICODE_STRING_SIZE(buffer, 512);
james@536 1246 DECLARE_CONST_UNICODE_STRING(location, L"Xen Bus");
james@536 1247 PXENPCI_PDO_DEVICE_DATA xppdd;
james@536 1248 PXENPCI_DEVICE_DATA xpdd = GetXpdd(WdfChildListGetDevice(child_list));
james@536 1249 WDF_QUERY_INTERFACE_CONFIG interface_config;
james@536 1250 BUS_INTERFACE_STANDARD bus_interface;
james@536 1251 WDF_PDO_EVENT_CALLBACKS pdo_callbacks;
james@538 1252 WDF_PNPPOWER_EVENT_CALLBACKS child_pnp_power_callbacks;
james@536 1253 UCHAR pnp_minor_functions[] = { IRP_MN_START_DEVICE };
james@538 1254 WDF_DEVICE_POWER_CAPABILITIES child_power_capabilities;
james@536 1255
james@536 1256 FUNCTION_ENTER();
james@536 1257
james@536 1258 WdfDeviceInitSetDeviceType(child_init, FILE_DEVICE_UNKNOWN);
james@536 1259
james@536 1260 WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&child_pnp_power_callbacks);
james@536 1261 child_pnp_power_callbacks.EvtDeviceD0Entry = XenPciPdo_EvtDeviceD0Entry;
james@538 1262 //child_pnp_power_callbacks.EvtDeviceD0EntryPostInterruptsEnabled = XenPciPdo_EvtDeviceD0EntryPostInterruptsEnabled;
james@536 1263 child_pnp_power_callbacks.EvtDeviceD0Exit = XenPciPdo_EvtDeviceD0Exit;
james@538 1264 //child_pnp_power_callbacks.EvtDeviceD0ExitPreInterruptsDisabled = XenPciPdo_EvtDeviceD0ExitPreInterruptsDisabled;
james@536 1265 child_pnp_power_callbacks.EvtDevicePrepareHardware = XenPciPdo_EvtDevicePrepareHardware;
james@536 1266 child_pnp_power_callbacks.EvtDeviceReleaseHardware = XenPciPdo_EvtDeviceReleaseHardware;
james@538 1267 child_pnp_power_callbacks.EvtDeviceUsageNotification = XenPciPdo_EvtDeviceUsageNotification;
james@536 1268 WdfDeviceInitSetPnpPowerEventCallbacks(child_init, &child_pnp_power_callbacks);
james@538 1269
james@536 1270 KdPrint((__DRIVER_NAME " device = '%s', index = '%d', path = '%s'\n",
james@536 1271 identification->device, identification->index, identification->path));
james@536 1272
james@536 1273 status = WdfDeviceInitAssignWdmIrpPreprocessCallback(child_init, XenPciPdo_EvtDeviceWdmIrpPreprocess_START_DEVICE,
james@536 1274 IRP_MJ_PNP, pnp_minor_functions, ARRAY_SIZE(pnp_minor_functions));
james@536 1275 if (!NT_SUCCESS(status))
james@536 1276 {
james@536 1277 return status;
james@536 1278 }
james@536 1279
james@536 1280 WDF_PDO_EVENT_CALLBACKS_INIT(&pdo_callbacks);
james@536 1281 //pdo_callbacks.EvtDeviceResourcesQuery = XenPciPdo_EvtDeviceResourcesQuery;
james@536 1282 pdo_callbacks.EvtDeviceResourceRequirementsQuery = XenPciPdo_EvtDeviceResourceRequirementsQuery;
james@536 1283 //pdo_callbacks.EvtDeviceEject = XenPciPdo_EvtDeviceEject;
james@536 1284 //pdo_callbacks.EvtDeviceSetLock = XenPciPdo_EvtDeviceSetLock;
james@536 1285 WdfPdoInitSetEventCallbacks(child_init, &pdo_callbacks);
james@536 1286
james@536 1287 RtlUnicodeStringPrintf(&buffer, L"xen\\%S", identification->device);
james@536 1288 status = WdfPdoInitAssignDeviceID(child_init, &buffer);
james@536 1289 if (!NT_SUCCESS(status))
james@536 1290 {
james@536 1291 return status;
james@536 1292 }
james@536 1293 status = WdfPdoInitAddHardwareID(child_init, &buffer);
james@536 1294 if (!NT_SUCCESS(status))
james@536 1295 {
james@536 1296 return status;
james@536 1297 }
james@536 1298 status = WdfPdoInitAddCompatibleID(child_init, &buffer);
james@536 1299 if (!NT_SUCCESS(status))
james@536 1300 {
james@536 1301 return status;
james@536 1302 }
james@536 1303
james@536 1304 RtlUnicodeStringPrintf(&buffer, L"%02d", identification->index);
james@536 1305 status = WdfPdoInitAssignInstanceID(child_init, &buffer);
james@536 1306 if (!NT_SUCCESS(status))
james@536 1307 {
james@536 1308 return status;
james@536 1309 }
james@536 1310
james@536 1311 RtlUnicodeStringPrintf(&buffer, L"Xen %S device #%d", identification->device, identification->index);
james@536 1312 status = WdfPdoInitAddDeviceText(child_init, &buffer, &location, 0x0409);
james@536 1313 if (!NT_SUCCESS(status))
james@536 1314 {
james@536 1315 return status;
james@536 1316 }
james@536 1317 WdfPdoInitSetDefaultLocale(child_init, 0x0409);
james@538 1318
james@538 1319 WdfDeviceInitSetPowerNotPageable(child_init);
james@536 1320
james@536 1321 WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&child_attributes, XENPCI_PDO_DEVICE_DATA);
james@536 1322 status = WdfDeviceCreate(&child_init, &child_attributes, &child_device);
james@536 1323 if (!NT_SUCCESS(status))
james@536 1324 {
james@536 1325 return status;
james@536 1326 }
james@536 1327
james@536 1328 xppdd = GetXppdd(child_device);
james@536 1329
james@536 1330 xppdd->wdf_device = child_device;
james@536 1331 xppdd->wdf_device_bus_fdo = WdfChildListGetDevice(child_list);
james@536 1332
james@551 1333 xppdd->config_page_mdl = AllocateUncachedPage();
james@551 1334
james@536 1335 xppdd->device_state.magic = XEN_DEVICE_STATE_MAGIC;
james@536 1336 xppdd->device_state.length = sizeof(XENPCI_DEVICE_STATE);
james@536 1337 xppdd->device_state.suspend_resume_state_pdo = SR_STATE_RUNNING;
james@536 1338 xppdd->device_state.suspend_resume_state_fdo = SR_STATE_RUNNING;
james@536 1339 xppdd->device_state.pdo_event_channel = xpdd->pdo_event_channel;
james@536 1340 WdfDeviceSetSpecialFileSupport(child_device, WdfSpecialFilePaging, TRUE);
james@536 1341 WdfDeviceSetSpecialFileSupport(child_device, WdfSpecialFileHibernation, TRUE);
james@536 1342 WdfDeviceSetSpecialFileSupport(child_device, WdfSpecialFileDump, TRUE);
james@536 1343
james@536 1344 WDF_DEVICE_PNP_CAPABILITIES_INIT(&child_pnp_capabilities);
james@536 1345 child_pnp_capabilities.LockSupported = WdfFalse;
james@536 1346 child_pnp_capabilities.EjectSupported = WdfTrue;
james@536 1347 child_pnp_capabilities.Removable = WdfTrue;
james@536 1348 child_pnp_capabilities.DockDevice = WdfFalse;
james@536 1349 child_pnp_capabilities.UniqueID = WdfFalse;
james@536 1350 child_pnp_capabilities.SilentInstall = WdfTrue;
james@536 1351 child_pnp_capabilities.SurpriseRemovalOK = WdfTrue;
james@536 1352 child_pnp_capabilities.HardwareDisabled = WdfFalse;
james@536 1353 WdfDeviceSetPnpCapabilities(child_device, &child_pnp_capabilities);
james@536 1354
james@538 1355 WDF_DEVICE_POWER_CAPABILITIES_INIT(&child_power_capabilities);
james@538 1356 child_power_capabilities.DeviceD1 = WdfTrue;
james@538 1357 child_power_capabilities.WakeFromD1 = WdfTrue;
james@538 1358 child_power_capabilities.DeviceWake = PowerDeviceD1;
james@538 1359 child_power_capabilities.DeviceState[PowerSystemWorking] = PowerDeviceD1;
james@538 1360 child_power_capabilities.DeviceState[PowerSystemSleeping1] = PowerDeviceD1;
james@538 1361 child_power_capabilities.DeviceState[PowerSystemSleeping2] = PowerDeviceD2;
james@538 1362 child_power_capabilities.DeviceState[PowerSystemSleeping3] = PowerDeviceD2;
james@538 1363 child_power_capabilities.DeviceState[PowerSystemHibernate] = PowerDeviceD3;
james@538 1364 child_power_capabilities.DeviceState[PowerSystemShutdown] = PowerDeviceD3;
james@538 1365 WdfDeviceSetPowerCapabilities(child_device, &child_power_capabilities);
james@536 1366
james@536 1367 bus_interface.Size = sizeof(BUS_INTERFACE_STANDARD);
james@536 1368 bus_interface.Version = 1; //BUS_INTERFACE_STANDARD_VERSION;
james@536 1369 bus_interface.Context = xppdd;
james@537 1370 bus_interface.InterfaceReference = WdfDeviceInterfaceReferenceNoOp;
james@537 1371 bus_interface.InterfaceDereference = WdfDeviceInterfaceDereferenceNoOp;
james@536 1372 bus_interface.TranslateBusAddress = XenPci_BIS_TranslateBusAddress;
james@536 1373 bus_interface.GetDmaAdapter = XenPci_BIS_GetDmaAdapter;
james@536 1374 bus_interface.SetBusData = XenPci_BIS_SetBusData;
james@536 1375 bus_interface.GetBusData = XenPci_BIS_GetBusData;
james@536 1376 WDF_QUERY_INTERFACE_CONFIG_INIT(&interface_config, (PINTERFACE)&bus_interface, &GUID_BUS_INTERFACE_STANDARD, NULL);
james@536 1377 status = WdfDeviceAddQueryInterface(child_device, &interface_config);
james@536 1378 if (!NT_SUCCESS(status))
james@536 1379 {
james@536 1380 return status;
james@536 1381 }
james@536 1382
james@536 1383 RtlStringCbCopyA(xppdd->path, ARRAY_SIZE(xppdd->path), identification->path);
james@536 1384 RtlStringCbCopyA(xppdd->device, ARRAY_SIZE(xppdd->device), identification->device);
james@536 1385 xppdd->index = identification->index;
james@536 1386 KeInitializeEvent(&xppdd->backend_state_event, SynchronizationEvent, FALSE);
james@624 1387 ExInitializeFastMutex(&xppdd->backend_state_mutex);
james@536 1388 xppdd->backend_state = XenbusStateUnknown;
james@538 1389 xppdd->frontend_state = XenbusStateUnknown;
james@536 1390 xppdd->backend_path[0] = '\0';
james@536 1391
james@536 1392 FUNCTION_EXIT();
james@536 1393
james@536 1394 return status;
james@536 1395 }
james@536 1396
james@536 1397 static __forceinline VOID
james@536 1398 XenPci_Pdo_ChangeSuspendState(WDFDEVICE device, ULONG new_state)
james@536 1399 {
james@536 1400 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
james@536 1401 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
james@536 1402
james@536 1403 FUNCTION_ENTER();
james@536 1404 KdPrint((__DRIVER_NAME " setting pdo state to %d\n", new_state));
james@536 1405 xppdd->device_state.suspend_resume_state_pdo = new_state;
james@536 1406 KeMemoryBarrier();
james@536 1407 KdPrint((__DRIVER_NAME " Notifying event channel %d\n", xpdd->pdo_event_channel));
james@536 1408 EvtChn_Notify(xpdd, xpdd->pdo_event_channel);
james@536 1409 while(xppdd->device_state.suspend_resume_state_fdo != xppdd->device_state.suspend_resume_state_pdo)
james@536 1410 {
james@536 1411 KdPrint((__DRIVER_NAME " waiting...\n"));
james@536 1412 KeWaitForSingleObject(&xpdd->pdo_suspend_event, Executive, KernelMode, FALSE, NULL);
james@536 1413 }
james@536 1414 KdPrint((__DRIVER_NAME " fdo state set to %d\n", new_state));
james@536 1415 FUNCTION_EXIT();
james@536 1416 }
james@536 1417
james@536 1418 /* called at PASSIVE_LEVEL */
james@536 1419 NTSTATUS
james@536 1420 XenPci_Pdo_Suspend(WDFDEVICE device)
james@536 1421 {
james@536 1422 NTSTATUS status = STATUS_SUCCESS;
james@536 1423 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
james@536 1424 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
james@536 1425 //LARGE_INTEGER wait_time;
james@536 1426 char path[128];
james@536 1427 PUCHAR in_ptr;
james@536 1428 UCHAR type;
james@536 1429 PVOID setting;
james@536 1430 PVOID value;
james@536 1431 PVOID value2;
james@536 1432
james@536 1433 KdPrint((__DRIVER_NAME " --> " __FUNCTION__ " (%s)\n", xppdd->path));
james@536 1434
james@536 1435 if (xppdd->backend_state == XenbusStateConnected)
james@536 1436 {
james@536 1437 xppdd->restart_on_resume = TRUE;
james@536 1438 XenPci_Pdo_ChangeSuspendState(device, SR_STATE_SUSPENDING);
james@536 1439
james@536 1440 XenPci_ChangeFrontendState(device, XenbusStateClosing, XenbusStateClosing, 30000);
james@536 1441 XenPci_ChangeFrontendState(device, XenbusStateClosed, XenbusStateClosed, 30000);
james@536 1442 XenPci_ChangeFrontendState(device, XenbusStateInitialising, XenbusStateInitWait, 30000);
james@536 1443
james@536 1444 if (xppdd->assigned_resources_start != NULL)
james@536 1445 {
james@536 1446 in_ptr = xppdd->assigned_resources_ptr;
james@536 1447 ADD_XEN_INIT_RSP(&in_ptr, XEN_INIT_TYPE_END, NULL, NULL, NULL);
james@536 1448 in_ptr = xppdd->assigned_resources_start;
james@536 1449 while((type = GET_XEN_INIT_RSP(&in_ptr, &setting, &value, &value2)) != XEN_INIT_TYPE_END)
james@536 1450 {
james@536 1451 switch (type)
james@536 1452 {
james@536 1453 case XEN_INIT_TYPE_EVENT_CHANNEL: /* frontend event channel */
james@617 1454 case XEN_INIT_TYPE_EVENT_CHANNEL_DPC: /* frontend event channel bound to dpc */
james@536 1455 case XEN_INIT_TYPE_EVENT_CHANNEL_IRQ: /* frontend event channel bound to irq */
james@536 1456 EvtChn_Unbind(xpdd, PtrToUlong(value));
james@536 1457 EvtChn_Close(xpdd, PtrToUlong(value));
james@536 1458 break;
james@536 1459 }
james@536 1460 }
james@536 1461 }
james@536 1462
james@536 1463 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "%s/state", xppdd->backend_path);
james@624 1464 XenBus_RemWatch(xpdd, XBT_NIL, path, XenPci_BackendStateHandler, xppdd);
james@536 1465 }
james@536 1466 else
james@536 1467 {
james@536 1468 xppdd->restart_on_resume = FALSE;
james@536 1469 }
james@536 1470
james@536 1471 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
james@536 1472
james@536 1473 return status;
james@536 1474 }
james@536 1475
james@536 1476 NTSTATUS
james@536 1477 XenPci_Pdo_Resume(WDFDEVICE device)
james@536 1478 {
james@536 1479 NTSTATUS status = STATUS_SUCCESS;
james@536 1480 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
james@536 1481 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
james@536 1482 ULONG old_backend_state;
james@536 1483 PUCHAR src, dst;
james@536 1484
james@536 1485 FUNCTION_ENTER();
james@536 1486 KdPrint((__DRIVER_NAME " path = %s\n", xppdd->path));
james@536 1487
james@536 1488 xppdd->device_state.pdo_event_channel = xpdd->pdo_event_channel;
james@536 1489 old_backend_state = xppdd->backend_state;
james@536 1490
james@536 1491 if (xppdd->restart_on_resume)
james@536 1492 {
james@536 1493 status = XenPci_GetBackendAndAddWatch(device);
james@536 1494
james@536 1495 if (XenPci_ChangeFrontendState(device, XenbusStateInitialising, XenbusStateInitWait, 30000) != STATUS_SUCCESS)
james@536 1496 {
james@536 1497 KdPrint((__DRIVER_NAME " Failed to change frontend state to Initialising\n"));
james@536 1498 // this is probably an unrecoverable situation...
james@702 1499 FUNCTION_EXIT();
james@536 1500 return STATUS_UNSUCCESSFUL;
james@536 1501 }
james@536 1502 if (xppdd->assigned_resources_ptr)
james@536 1503 {
james@536 1504 // reset things - feed the 'requested resources' back in
james@536 1505 ADD_XEN_INIT_REQ(&xppdd->requested_resources_ptr, XEN_INIT_TYPE_END, NULL, NULL, NULL);
james@536 1506 src = xppdd->requested_resources_start;
james@536 1507 xppdd->requested_resources_ptr = xppdd->requested_resources_start = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE, XENPCI_POOL_TAG);;
james@536 1508 xppdd->assigned_resources_ptr = xppdd->assigned_resources_start;
james@536 1509
james@536 1510 dst = MmMapIoSpace(xppdd->config_page_phys, xppdd->config_page_length, MmNonCached);
james@536 1511
james@536 1512 status = XenPci_XenConfigDeviceSpecifyBuffers(device, src, dst);
james@536 1513
james@536 1514 MmUnmapIoSpace(dst, xppdd->config_page_length);
james@536 1515 ExFreePoolWithTag(src, XENPCI_POOL_TAG);
james@536 1516 }
james@536 1517 if (XenPci_ChangeFrontendState(device, XenbusStateConnected, XenbusStateConnected, 30000) != STATUS_SUCCESS)
james@536 1518 {
james@536 1519 // this is definitely an unrecoverable situation...
james@536 1520 KdPrint((__DRIVER_NAME " Failed to change frontend state to connected\n"));
james@702 1521 FUNCTION_EXIT();
james@536 1522 return STATUS_UNSUCCESSFUL;
james@536 1523 }
james@536 1524 XenPci_Pdo_ChangeSuspendState(device, SR_STATE_RESUMING);
james@536 1525 XenPci_Pdo_ChangeSuspendState(device, SR_STATE_RUNNING);
james@536 1526 }
james@536 1527
james@536 1528 FUNCTION_EXIT();
james@536 1529
james@536 1530 return STATUS_SUCCESS;
james@536 1531 }