win-pvdrivers

changeset 385:e556065b2f1a

Fixed IRQL bug on restore
author James Harper <james.harper@bendigoit.com.au>
date Fri Jul 11 11:19:12 2008 +1000 (2008-07-11)
parents 448011e246d3
children 193ef493dfcb
files xenpci/gnttbl.c xenpci/xenbus.c xenpci/xenpci.h xenpci/xenpci_fdo.c xenpci/xenpci_pdo.c
line diff
     1.1 --- a/xenpci/gnttbl.c	Wed Jul 09 22:12:56 2008 +1000
     1.2 +++ b/xenpci/gnttbl.c	Fri Jul 11 11:19:12 2008 +1000
     1.3 @@ -23,13 +23,19 @@ VOID
     1.4  GntTbl_PutRef(PVOID Context, grant_ref_t ref)
     1.5  {
     1.6    PXENPCI_DEVICE_DATA xpdd = Context;
     1.7 -  KIRQL OldIrql;
     1.8 +  KIRQL OldIrql = PASSIVE_LEVEL;
     1.9  
    1.10 -  ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
    1.11 -  KeAcquireSpinLock(&xpdd->grant_lock, &OldIrql);
    1.12 +  if (xpdd->suspend_state != SUSPEND_STATE_HIGH_IRQL)
    1.13 +  {
    1.14 +    ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
    1.15 +    KeAcquireSpinLock(&xpdd->grant_lock, &OldIrql);
    1.16 +  }
    1.17    xpdd->gnttab_list[ref] = xpdd->gnttab_list[0];
    1.18    xpdd->gnttab_list[0]  = ref;
    1.19 -  KeReleaseSpinLock(&xpdd->grant_lock, OldIrql);
    1.20 +  if (xpdd->suspend_state != SUSPEND_STATE_HIGH_IRQL)
    1.21 +  {
    1.22 +    KeReleaseSpinLock(&xpdd->grant_lock, OldIrql);
    1.23 +  }
    1.24  }
    1.25  
    1.26  grant_ref_t
    1.27 @@ -37,13 +43,21 @@ GntTbl_GetRef(PVOID Context)
    1.28  {
    1.29    PXENPCI_DEVICE_DATA xpdd = Context;
    1.30    unsigned int ref;
    1.31 -  KIRQL OldIrql;
    1.32 +  KIRQL OldIrql = PASSIVE_LEVEL;
    1.33 +  
    1.34 +  UNREFERENCED_PARAMETER(OldIrql);
    1.35  
    1.36 -  ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
    1.37 -  KeAcquireSpinLock(&xpdd->grant_lock, &OldIrql);
    1.38 +  if (xpdd->suspend_state != SUSPEND_STATE_HIGH_IRQL)
    1.39 +  {
    1.40 +    ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
    1.41 +    KeAcquireSpinLock(&xpdd->grant_lock, &OldIrql);
    1.42 +  }
    1.43    ref = xpdd->gnttab_list[0];
    1.44    xpdd->gnttab_list[0] = xpdd->gnttab_list[ref];
    1.45 -  KeReleaseSpinLock(&xpdd->grant_lock, OldIrql);
    1.46 +  if (xpdd->suspend_state != SUSPEND_STATE_HIGH_IRQL)
    1.47 +  {
    1.48 +    KeReleaseSpinLock(&xpdd->grant_lock, OldIrql);
    1.49 +  }
    1.50  
    1.51    return ref;
    1.52  }
    1.53 @@ -182,6 +196,7 @@ GntTbl_InitMap(PXENPCI_DEVICE_DATA xpdd)
    1.54    {
    1.55      if (grant_frames > xpdd->max_grant_frames)
    1.56      {
    1.57 +      /* this won't actually work as it will be called at HIGH_IRQL and the free and unmap functions won't work... */
    1.58        ExFreePoolWithTag(xpdd->gnttab_list, XENPCI_POOL_TAG);
    1.59        MmUnmapIoSpace(xpdd->gnttab_table, PAGE_SIZE * xpdd->max_grant_frames);
    1.60        xpdd->gnttab_list = NULL;
     2.1 --- a/xenpci/xenbus.c	Wed Jul 09 22:12:56 2008 +1000
     2.2 +++ b/xenpci/xenbus.c	Fri Jul 11 11:19:12 2008 +1000
     2.3 @@ -385,8 +385,8 @@ XenBus_Close(PXENPCI_DEVICE_DATA xpdd)
     2.4  
     2.5    xpdd->XenBus_ShuttingDown = TRUE;
     2.6  
     2.7 -  KeSetEvent(&xpdd->XenBus_ReadThreadEvent, 1, FALSE);
     2.8 -  KeSetEvent(&xpdd->XenBus_WatchThreadEvent, 1, FALSE);
     2.9 +  KeSetEvent(&xpdd->XenBus_ReadThreadEvent, IO_NO_INCREMENT, FALSE);
    2.10 +  KeSetEvent(&xpdd->XenBus_WatchThreadEvent, IO_NO_INCREMENT, FALSE);
    2.11    ObReferenceObjectByHandle(xpdd->XenBus_ReadThreadHandle, THREAD_ALL_ACCESS, NULL, KernelMode, &WaitArray[0], NULL);
    2.12    ObReferenceObjectByHandle(xpdd->XenBus_WatchThreadHandle, THREAD_ALL_ACCESS, NULL, KernelMode, &WaitArray[1], NULL);
    2.13    KeWaitForSingleObject(WaitArray[0], Executive, KernelMode, FALSE, NULL);
    2.14 @@ -491,7 +491,7 @@ XenBus_ReadThreadProc(PVOID StartContext
    2.15            MASK_XENSTORE_IDX(xpdd->xen_store_interface->rsp_cons),
    2.16            msg.len + sizeof(msg));
    2.17          xpdd->xen_store_interface->rsp_cons += msg.len + sizeof(msg);
    2.18 -        KeSetEvent(&xpdd->req_info[msg.req_id].WaitEvent, 1, FALSE);
    2.19 +        KeSetEvent(&xpdd->req_info[msg.req_id].WaitEvent, IO_NO_INCREMENT, FALSE);
    2.20        }
    2.21        else // a watch: add to watch ring and signal watch thread
    2.22        {
    2.23 @@ -518,7 +518,7 @@ XenBus_ReadThreadProc(PVOID StartContext
    2.24  
    2.25          ExFreePoolWithTag(payload, XENPCI_POOL_TAG);
    2.26          //KdPrint((__DRIVER_NAME " +++ Watch Path = %s Token = %s\n", path, token));
    2.27 -        KeSetEvent(&xpdd->XenBus_WatchThreadEvent, 1, FALSE);
    2.28 +        KeSetEvent(&xpdd->XenBus_WatchThreadEvent, IO_NO_INCREMENT, FALSE);
    2.29        }
    2.30      }
    2.31    }
    2.32 @@ -565,7 +565,7 @@ XenBus_WatchThreadProc(PVOID StartContex
    2.33        entry->Count++;
    2.34        entry->ServiceRoutine(xpdd->XenBus_WatchRing[xpdd->XenBus_WatchRingReadIndex].Path, entry->ServiceContext);
    2.35        entry->Running = 0;
    2.36 -      KeSetEvent(&entry->CompleteEvent, 1, FALSE);
    2.37 +      KeSetEvent(&entry->CompleteEvent, IO_NO_INCREMENT, FALSE);
    2.38      }
    2.39    }
    2.40  }    
    2.41 @@ -828,7 +828,7 @@ XenBus_Interrupt(PKINTERRUPT Interrupt, 
    2.42  
    2.43  //  KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
    2.44  
    2.45 -  KeSetEvent(&xpdd->XenBus_ReadThreadEvent, 1, FALSE);
    2.46 +  KeSetEvent(&xpdd->XenBus_ReadThreadEvent, IO_NO_INCREMENT, FALSE);
    2.47  
    2.48  //  KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
    2.49  
     3.1 --- a/xenpci/xenpci.h	Wed Jul 09 22:12:56 2008 +1000
     3.2 +++ b/xenpci/xenpci.h	Fri Jul 11 11:19:12 2008 +1000
     3.3 @@ -158,6 +158,11 @@ static __inline void REVERT_PNP_STATE(PX
     3.4  
     3.5  #define SHUTDOWN_RING_SIZE 128
     3.6  
     3.7 +#define SUSPEND_STATE_NONE      0 /* no suspend in progress */
     3.8 +#define SUSPEND_STATE_SCHEDULED 1 /* suspend scheduled */
     3.9 +#define SUSPEND_STATE_HIGH_IRQL 2 /* all processors are at high IRQL and spinning */
    3.10 +#define SUSPEND_STATE_RESUMING  3
    3.11 +
    3.12  typedef struct {  
    3.13    XENPCI_COMMON common;
    3.14    
    3.15 @@ -214,7 +219,7 @@ typedef struct {
    3.16  
    3.17    LIST_ENTRY child_list;
    3.18    
    3.19 -  int suspending;
    3.20 +  int suspend_state;
    3.21    
    3.22    UNICODE_STRING interface_name;
    3.23    BOOLEAN interface_open;
     4.1 --- a/xenpci/xenpci_fdo.c	Wed Jul 09 22:12:56 2008 +1000
     4.2 +++ b/xenpci/xenpci_fdo.c	Fri Jul 11 11:19:12 2008 +1000
     4.3 @@ -303,9 +303,16 @@ XenBus_ShutdownIoCancel(PDEVICE_OBJECT d
     4.4    KdPrint((__DRIVER_NAME " <-- " __FUNCTION__"\n"));
     4.5  }
     4.6  
     4.7 +struct {
     4.8 +  volatile ULONG do_spin;
     4.9 +  volatile LONG nr_spinning;
    4.10 +  KEVENT stopped_spinning_event;
    4.11 +} typedef SUSPEND_INFO, *PSUSPEND_INFO;
    4.12 +
    4.13  static DDKAPI VOID
    4.14  XenPci_CompleteResume(PDEVICE_OBJECT device_object, PVOID context)
    4.15  {
    4.16 +  PSUSPEND_INFO suspend_info = context;
    4.17    PXENPCI_DEVICE_DATA xpdd;
    4.18    PXEN_CHILD child;
    4.19  
    4.20 @@ -314,6 +321,13 @@ XenPci_CompleteResume(PDEVICE_OBJECT dev
    4.21  
    4.22    xpdd = (PXENPCI_DEVICE_DATA)device_object->DeviceExtension;
    4.23  
    4.24 +  while (suspend_info->nr_spinning != 0)
    4.25 +  {
    4.26 +    KdPrint((__DRIVER_NAME "     %d processors are still spinning\n", suspend_info->nr_spinning));
    4.27 +    KeWaitForSingleObject(&suspend_info->stopped_spinning_event, Executive, KernelMode, FALSE, NULL);
    4.28 +  }
    4.29 +  KdPrint((__DRIVER_NAME "     all other processors have stopped spinning\n"));
    4.30 +
    4.31    XenBus_Resume(xpdd);
    4.32  
    4.33    for (child = (PXEN_CHILD)xpdd->child_list.Flink; child != (PXEN_CHILD)&xpdd->child_list; child = (PXEN_CHILD)child->entry.Flink)
    4.34 @@ -321,18 +335,14 @@ XenPci_CompleteResume(PDEVICE_OBJECT dev
    4.35      XenPci_Resume(child->context->common.pdo);
    4.36      child->context->device_state.resume_state = RESUME_STATE_FRONTEND_RESUME;
    4.37      // how can we signal children that they are ready to restart again?
    4.38 +    // maybe we can fake an interrupt?
    4.39    }
    4.40  
    4.41 -  xpdd->suspending = 0;
    4.42 +  xpdd->suspend_state = SUSPEND_STATE_NONE;
    4.43  
    4.44    KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
    4.45  }
    4.46  
    4.47 -struct {
    4.48 -  volatile ULONG do_spin;
    4.49 -  volatile LONG nr_spinning;
    4.50 -} typedef SUSPEND_INFO, *PSUSPEND_INFO;
    4.51 -
    4.52  /* Called at DISPATCH_LEVEL */
    4.53  static DDKAPI VOID
    4.54  XenPci_Suspend(
    4.55 @@ -348,6 +358,7 @@ XenPci_Suspend(
    4.56    int cancelled;
    4.57    PIO_WORKITEM work_item;
    4.58    PXEN_CHILD child;
    4.59 +  int i;
    4.60    //PUCHAR gnttbl_backup[PAGE_SIZE * NR_GRANT_FRAMES];
    4.61  
    4.62    UNREFERENCED_PARAMETER(Dpc);
    4.63 @@ -363,14 +374,17 @@ XenPci_Suspend(
    4.64      KeMemoryBarrier();
    4.65      while(suspend_info->do_spin)
    4.66      {
    4.67 -      HYPERVISOR_yield(xpdd);
    4.68 -      /* we should be able to wait more nicely than this... */
    4.69 +      for (i = 0; i < 65536; i++)
    4.70 +        __asm { hlt }
    4.71 +      KeMemoryBarrier();
    4.72 +      /* can't call HYPERVISOR_yield() here as the stubs will be reset and we will crash */
    4.73      }
    4.74      KeMemoryBarrier();
    4.75      InterlockedDecrement(&suspend_info->nr_spinning);    
    4.76      KdPrint((__DRIVER_NAME "     ...done spinning\n"));
    4.77 -    KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n", KeGetCurrentProcessorNumber()));
    4.78 +    KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ " (cpu = %d)\n", KeGetCurrentProcessorNumber()));
    4.79      KeLowerIrql(old_irql);
    4.80 +    KeSetEvent(&suspend_info->stopped_spinning_event, IO_NO_INCREMENT, FALSE);
    4.81      return;
    4.82    }
    4.83    ActiveProcessorCount = (ULONG)KeNumberProcessors;
    4.84 @@ -380,10 +394,13 @@ XenPci_Suspend(
    4.85    KdPrint((__DRIVER_NAME "     waiting for all other processors to spin\n"));
    4.86    while (suspend_info->nr_spinning < (LONG)ActiveProcessorCount - 1)
    4.87    {
    4.88 +      __asm { hlt }
    4.89        HYPERVISOR_yield(xpdd);
    4.90    }
    4.91    KdPrint((__DRIVER_NAME "     all other processors are spinning\n"));
    4.92  
    4.93 +  xpdd->suspend_state = SUSPEND_STATE_HIGH_IRQL;
    4.94 +  
    4.95    KdPrint((__DRIVER_NAME "     calling suspend\n"));
    4.96    cancelled = hvm_shutdown(Context, SHUTDOWN_suspend);
    4.97    KdPrint((__DRIVER_NAME "     back from suspend, cancelled = %d\n", cancelled));
    4.98 @@ -392,7 +409,7 @@ XenPci_Suspend(
    4.99    
   4.100    GntTbl_InitMap(Context);
   4.101  
   4.102 -  /* this enabled interrupts again too */  
   4.103 +  /* this enables interrupts again too */  
   4.104    EvtChn_Init(xpdd);
   4.105  
   4.106    for (child = (PXEN_CHILD)xpdd->child_list.Flink; child != (PXEN_CHILD)&xpdd->child_list; child = (PXEN_CHILD)child->entry.Flink)
   4.107 @@ -400,18 +417,14 @@ XenPci_Suspend(
   4.108      child->context->device_state.resume_state = RESUME_STATE_BACKEND_RESUME;
   4.109    }
   4.110  
   4.111 +  xpdd->suspend_state = SUSPEND_STATE_RESUMING;
   4.112    KeLowerIrql(old_irql);
   4.113    
   4.114    KdPrint((__DRIVER_NAME "     waiting for all other processors to stop spinning\n"));
   4.115    suspend_info->do_spin = 0;
   4.116 -  while (suspend_info->nr_spinning != 0)
   4.117 -  {
   4.118 -    HYPERVISOR_yield(xpdd);
   4.119 -  }
   4.120 -  KdPrint((__DRIVER_NAME "     all other processors have stopped spinning\n"));
   4.121  
   4.122  	work_item = IoAllocateWorkItem(xpdd->common.fdo);
   4.123 -	IoQueueWorkItem(work_item, XenPci_CompleteResume, DelayedWorkQueue, NULL);
   4.124 +	IoQueueWorkItem(work_item, XenPci_CompleteResume, DelayedWorkQueue, suspend_info);
   4.125    
   4.126    KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
   4.127  }
   4.128 @@ -429,11 +442,12 @@ XenPci_BeginSuspend(PXENPCI_DEVICE_DATA 
   4.129  
   4.130    KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
   4.131  
   4.132 -  if (!xpdd->suspending)
   4.133 +  if (xpdd->suspend_state == SUSPEND_STATE_NONE)
   4.134    {
   4.135 -    xpdd->suspending = 1;
   4.136 +    xpdd->suspend_state = SUSPEND_STATE_SCHEDULED;
   4.137      suspend_info = ExAllocatePoolWithTag(NonPagedPool, sizeof(SUSPEND_INFO), XENPCI_POOL_TAG);
   4.138      RtlZeroMemory(suspend_info, sizeof(SUSPEND_INFO));
   4.139 +    KeInitializeEvent(&suspend_info->stopped_spinning_event, SynchronizationEvent, FALSE);
   4.140      suspend_info->do_spin = 1;
   4.141  
   4.142      // I think we need to synchronise with the interrupt here...
     5.1 --- a/xenpci/xenpci_pdo.c	Wed Jul 09 22:12:56 2008 +1000
     5.2 +++ b/xenpci/xenpci_pdo.c	Fri Jul 11 11:19:12 2008 +1000
     5.3 @@ -106,7 +106,7 @@ XenPci_BackEndStateHandler(char *Path, P
     5.4    err = XenBus_Read(xpdd, XBT_NIL, Path, &value);
     5.5    if (err)
     5.6    {
     5.7 -    if (xpdd->suspending)
     5.8 +    if (xpdd->suspend_state != SUSPEND_STATE_NONE)
     5.9        return;
    5.10      KdPrint(("Failed to read %s, assuming closed\n", path, err));
    5.11      new_backend_state = XenbusStateClosed;