]> xenbits.xen.org Git - xenclient/linux-2.6.27-pq.git/commitdiff
Add pciback FLR support.
authorJean Guyader <jean.guyader@eu.citrix.com>
Thu, 9 Apr 2009 15:20:56 +0000 (16:20 +0100)
committerJean Guyader <jean.guyader@eu.citrix.com>
Thu, 9 Apr 2009 15:20:56 +0000 (16:20 +0100)
Add xen acpi wmi support.

master/pciback-flr [new file with mode: 0644]
master/series
master/xen-acpi-wmi [new file with mode: 0644]

diff --git a/master/pciback-flr b/master/pciback-flr
new file mode 100644 (file)
index 0000000..e39ef4b
--- /dev/null
@@ -0,0 +1,1411 @@
+diff --git a/drivers/xen/pciback/controller.c b/drivers/xen/pciback/controller.c
+index 294e48f..4c1aaf3 100644
+--- a/drivers/xen/pciback/controller.c
++++ b/drivers/xen/pciback/controller.c
+@@ -208,7 +208,7 @@ void pciback_release_pci_dev(struct pciback_device *pdev, struct pci_dev *dev)
+       }
+       spin_unlock_irqrestore(&dev_data->lock, flags);
+-      pcistub_put_pci_dev(found_dev);
++      pcistub_put_pci_dev(found_dev, 0);
+ }
+ int pciback_init_devices(struct pciback_device *pdev)
+@@ -396,7 +396,7 @@ void pciback_release_devices(struct pciback_device *pdev)
+               list_for_each_entry_safe(dev_entry, d,
+                                        &cntrl_entry->dev_list, list) {
+                       list_del(&dev_entry->list);
+-                      pcistub_put_pci_dev(dev_entry->dev);
++                      pcistub_put_pci_dev(dev_entry->dev, 0);
+                       kfree(dev_entry);
+               }
+               list_del(&cntrl_entry->list);
+diff --git a/drivers/xen/pciback/passthrough.c b/drivers/xen/pciback/passthrough.c
+index 9e7a0c4..b9948a5 100644
+--- a/drivers/xen/pciback/passthrough.c
++++ b/drivers/xen/pciback/passthrough.c
+@@ -88,7 +88,7 @@ void pciback_release_pci_dev(struct pciback_device *pdev, struct pci_dev *dev)
+       spin_unlock_irqrestore(&dev_data->lock, flags);
+       if (found_dev)
+-              pcistub_put_pci_dev(found_dev);
++              pcistub_put_pci_dev(found_dev, 1);
+ }
+ int pciback_init_devices(struct pciback_device *pdev)
+@@ -157,7 +157,7 @@ void pciback_release_devices(struct pciback_device *pdev)
+       list_for_each_entry_safe(dev_entry, t, &dev_data->dev_list, list) {
+               list_del(&dev_entry->list);
+-              pcistub_put_pci_dev(dev_entry->dev);
++              pcistub_put_pci_dev(dev_entry->dev, 1);
+               kfree(dev_entry);
+       }
+diff --git a/drivers/xen/pciback/pci_stub.c b/drivers/xen/pciback/pci_stub.c
+index 6345b39..486034f 100644
+--- a/drivers/xen/pciback/pci_stub.c
++++ b/drivers/xen/pciback/pci_stub.c
+@@ -24,10 +24,28 @@ wait_queue_head_t aer_wait_queue;
+ * We want to avoid in middle of AER ops, pciback devices is being removed
+ */
+ static DECLARE_RWSEM(pcistub_sem);
+-module_param_named(hide, pci_devs_to_hide, charp, 0444);
++module_param_named(hide, pci_devs_to_hide, charp, S_IRUGO);
++
++static char *pci_devs_use_sbr = NULL;
++module_param_named(sbr, pci_devs_use_sbr, charp, S_IRUGO);
++
++static char *pci_devs_use_d3r = NULL;
++module_param_named(d3r, pci_devs_use_d3r, charp, S_IRUGO);
++
++static char *pci_devs_no_flr = NULL;
++module_param_named(noflr, pci_devs_no_flr, charp, S_IRUGO);
++
++/* Device id list holding different device type listings
++ * for hiding devices and reset logic.
++ */
++#define PCIBACK_ID_TYPE_HIDE  1
++#define PCIBACK_ID_TYPE_SBR   2
++#define PCIBACK_ID_TYPE_D3R   3
++#define PCIBACK_ID_TYPE_NOFLR 4
+ struct pcistub_device_id {
+       struct list_head slot_list;
++      int type;
+       int domain;
+       unsigned char bus;
+       unsigned int devfn;
+@@ -56,6 +74,8 @@ static LIST_HEAD(pcistub_devices);
+ static int initialize_devices = 0;
+ static LIST_HEAD(seized_devices);
++static int disable_all_flr = 0;
++
+ static struct pcistub_device *pcistub_device_alloc(struct pci_dev *dev)
+ {
+       struct pcistub_device *psdev;
+@@ -78,6 +98,23 @@ static struct pcistub_device *pcistub_device_alloc(struct pci_dev *dev)
+       return psdev;
+ }
++static struct pciback_dev_data *pcistub_dev_data_alloc(struct pci_dev *dev)
++{
++      struct pciback_dev_data *dev_data;
++
++      dev_dbg(&dev->dev, "pcistub_dev_data_alloc\n");
++
++      dev_data = kzalloc(sizeof(*dev_data) + dev->cfg_size, GFP_ATOMIC);
++      if (!dev_data)
++              return NULL;
++              
++      pci_set_drvdata(dev, dev_data);
++
++      dev_data->cfg_space = (u8*)(dev_data) + sizeof(*dev_data);
++
++      return dev_data;
++}
++
+ /* Don't call this directly as it's called by pcistub_device_put */
+ static void pcistub_device_release(struct kref *kref)
+ {
+@@ -200,7 +237,7 @@ struct pci_dev *pcistub_get_pci_dev(struct pciback_device *pdev,
+       return found_dev;
+ }
+-void pcistub_put_pci_dev(struct pci_dev *dev)
++void pcistub_put_pci_dev(struct pci_dev *dev, int do_flr)
+ {
+       struct pcistub_device *psdev, *found_psdev = NULL;
+       unsigned long flags;
+@@ -220,6 +257,13 @@ void pcistub_put_pci_dev(struct pci_dev *dev)
+       * pcistub and pciback when AER is in processing
+       */
+       down_write(&pcistub_sem);
++
++      /* For pass-through devices, do an FLR (or approximate) for the device
++       * before it is put back and ready for the next domain
++       */
++      if (!disable_all_flr && do_flr)
++              pciback_flr_device(dev);
++
+       /* Cleanup our device
+        * (so it's ready for the next domain)
+        */
+@@ -235,6 +279,43 @@ void pcistub_put_pci_dev(struct pci_dev *dev)
+       up_write(&pcistub_sem);
+ }
++struct pci_dev *pcistub_ref_pci_dev(struct pci_dev *dev)
++{
++      struct pcistub_device *psdev;
++      struct pci_dev *found_dev = NULL;
++      unsigned long flags;
++
++      spin_lock_irqsave(&pcistub_devices_lock, flags);
++
++      list_for_each_entry(psdev, &pcistub_devices, dev_list) {
++              if (psdev->dev == dev) {
++                      pcistub_device_get(psdev); /* just a ref count */
++                      found_dev = psdev->dev;
++                      break;
++              }
++      }
++
++      spin_unlock_irqrestore(&pcistub_devices_lock, flags);
++      return found_dev;
++}
++
++void pcistub_unref_pci_dev(struct pci_dev *dev)
++{
++      struct pcistub_device *psdev;
++      unsigned long flags;
++
++      spin_lock_irqsave(&pcistub_devices_lock, flags);
++
++      list_for_each_entry(psdev, &pcistub_devices, dev_list) {
++              if (psdev->dev == dev) {
++                      pcistub_device_get(psdev); /* just an unref count */
++                      break;
++              }
++      }
++
++      spin_unlock_irqrestore(&pcistub_devices_lock, flags);
++}
++
+ static int __devinit pcistub_match_one(struct pci_dev *dev,
+                                      struct pcistub_device_id *pdev_id)
+ {
+@@ -255,7 +336,7 @@ static int __devinit pcistub_match_one(struct pci_dev *dev,
+       return 0;
+ }
+-static int __devinit pcistub_match(struct pci_dev *dev)
++static int __devinit pcistub_match(struct pci_dev *dev, int type)
+ {
+       struct pcistub_device_id *pdev_id;
+       unsigned long flags;
+@@ -263,6 +344,8 @@ static int __devinit pcistub_match(struct pci_dev *dev)
+       spin_lock_irqsave(&device_ids_lock, flags);
+       list_for_each_entry(pdev_id, &pcistub_device_ids, slot_list) {
++              if (pdev_id->type != type)
++                      continue;
+               if (pcistub_match_one(dev, pdev_id)) {
+                       found = 1;
+                       break;
+@@ -285,12 +368,11 @@ static int __devinit pcistub_init_device(struct pci_dev *dev)
+        * would need to be called somewhere to free the memory allocated
+        * here and then to call kfree(pci_get_drvdata(psdev->dev)).
+        */
+-      dev_data = kzalloc(sizeof(*dev_data), GFP_ATOMIC);
++      dev_data = pcistub_dev_data_alloc(dev);
+       if (!dev_data) {
+               err = -ENOMEM;
+               goto out;
+       }
+-      pci_set_drvdata(dev, dev_data);
+       dev_dbg(&dev->dev, "initializing config\n");
+@@ -317,6 +399,22 @@ static int __devinit pcistub_init_device(struct pci_dev *dev)
+       dev_dbg(&dev->dev, "reset device\n");
+       pciback_reset_device(dev);
++      /* Classify the device so we know if it is PCI/PCIe and if it is
++       * a bridge - this information is used for FLR logic. Also store 
++       * values if SBR/D3R reset logic was requested.
++       */
++      pciback_classify_device(dev);
++      dev_data->no_flr = pcistub_match(dev, PCIBACK_ID_TYPE_NOFLR);
++      if (!dev_data->no_flr) {
++              dev_data->use_sbr = pcistub_match(dev, PCIBACK_ID_TYPE_SBR);
++              dev_data->use_d3r = pcistub_match(dev, PCIBACK_ID_TYPE_D3R);
++      }
++
++      /* Store the config space here where the device is off and ready to be 
++       * exported before any FLRs or other resets are done
++       */
++      pciback_store_config_space(dev);
++
+       return 0;
+       config_release:
+@@ -414,7 +512,7 @@ static int __devinit pcistub_probe(struct pci_dev *dev,
+       dev_dbg(&dev->dev, "probing...\n");
+-      if (pcistub_match(dev)) {
++      if (pcistub_match(dev, PCIBACK_ID_TYPE_HIDE)) {
+               if (dev->hdr_type != PCI_HEADER_TYPE_NORMAL
+                   && dev->hdr_type != PCI_HEADER_TYPE_BRIDGE) {
+@@ -851,7 +949,7 @@ static inline int str_to_quirk(const char *buf, int *domain, int *bus, int
+       return -EINVAL;
+ }
+-static int pcistub_device_id_add(int domain, int bus, int slot, int func)
++static int pcistub_device_id_add(int domain, int bus, int slot, int func, int type)
+ {
+       struct pcistub_device_id *pci_dev_id;
+       unsigned long flags;
+@@ -860,12 +958,13 @@ static int pcistub_device_id_add(int domain, int bus, int slot, int func)
+       if (!pci_dev_id)
+               return -ENOMEM;
++      pci_dev_id->type = type;
+       pci_dev_id->domain = domain;
+       pci_dev_id->bus = bus;
+       pci_dev_id->devfn = PCI_DEVFN(slot, func);
+-      pr_debug("pciback: wants to seize %04x:%02x:%02x.%01x\n",
+-               domain, bus, slot, func);
++      pr_debug("pciback: adding device ID type: %d for %04x:%02x:%02x.%01x\n",
++               type, domain, bus, slot, func);
+       spin_lock_irqsave(&device_ids_lock, flags);
+       list_add_tail(&pci_dev_id->slot_list, &pcistub_device_ids);
+@@ -874,7 +973,7 @@ static int pcistub_device_id_add(int domain, int bus, int slot, int func)
+       return 0;
+ }
+-static int pcistub_device_id_remove(int domain, int bus, int slot, int func)
++static int pcistub_device_id_remove(int domain, int bus, int slot, int func, int type)
+ {
+       struct pcistub_device_id *pci_dev_id, *t;
+       int devfn = PCI_DEVFN(slot, func);
+@@ -884,7 +983,7 @@ static int pcistub_device_id_remove(int domain, int bus, int slot, int func)
+       spin_lock_irqsave(&device_ids_lock, flags);
+       list_for_each_entry_safe(pci_dev_id, t, &pcistub_device_ids, slot_list) {
+-              if (pci_dev_id->domain == domain
++              if (pci_dev_id->type == type && pci_dev_id->domain == domain
+                   && pci_dev_id->bus == bus && pci_dev_id->devfn == devfn) {
+                       /* Don't break; here because it's possible the same
+                        * slot could be in the list more than once
+@@ -939,6 +1038,32 @@ static int pcistub_reg_add(int domain, int bus, int slot, int func, int reg,
+       return err;
+ }
++static int pcistub_device_do_flr(int domain, int bus, int slot, int func)
++{
++      int err = 0;
++      struct pcistub_device *psdev;
++      struct pci_dev *dev;
++
++      psdev = pcistub_device_find(domain, bus, slot, func);
++      if (!psdev || !psdev->dev) {
++              err = -ENODEV;
++              goto out;
++      }
++      dev = psdev->dev;
++
++      /* Do an FLR (or approximate) for the device on demand and 
++       * reload config
++       */
++      if (!disable_all_flr) {
++              pciback_flr_device(dev);
++      }
++      else
++              dev_dbg(&dev->dev, "FLR disabled for all devices\n");
++
++out:
++      return err;
++}
++
+ static ssize_t pcistub_slot_add(struct device_driver *drv, const char *buf,
+                               size_t count)
+ {
+@@ -949,7 +1074,7 @@ static ssize_t pcistub_slot_add(struct device_driver *drv, const char *buf,
+       if (err)
+               goto out;
+-      err = pcistub_device_id_add(domain, bus, slot, func);
++      err = pcistub_device_id_add(domain, bus, slot, func, PCIBACK_ID_TYPE_HIDE);
+       out:
+       if (!err)
+@@ -969,7 +1094,7 @@ static ssize_t pcistub_slot_remove(struct device_driver *drv, const char *buf,
+       if (err)
+               goto out;
+-      err = pcistub_device_id_remove(domain, bus, slot, func);
++      err = pcistub_device_id_remove(domain, bus, slot, func, PCIBACK_ID_TYPE_HIDE);
+       out:
+       if (!err)
+@@ -987,6 +1112,10 @@ static ssize_t pcistub_slot_show(struct device_driver *drv, char *buf)
+       spin_lock_irqsave(&device_ids_lock, flags);
+       list_for_each_entry(pci_dev_id, &pcistub_device_ids, slot_list) {
++              /* only want devices set for hide, not reset entries */
++              if (pci_dev_id->type != PCIBACK_ID_TYPE_HIDE)
++                      continue;
++
+               if (count >= PAGE_SIZE)
+                       break;
+@@ -1068,7 +1197,7 @@ static ssize_t pcistub_quirk_show(struct device_driver *drv, char *buf)
+ DRIVER_ATTR(quirks, S_IRUSR | S_IWUSR, pcistub_quirk_show, pcistub_quirk_add);
+-static ssize_t permissive_add(struct device_driver *drv, const char *buf,
++static ssize_t pcistub_permissive_add(struct device_driver *drv, const char *buf,
+                             size_t count)
+ {
+       int domain, bus, slot, func;
+@@ -1109,7 +1238,7 @@ static ssize_t permissive_add(struct device_driver *drv, const char *buf,
+       return err;
+ }
+-static ssize_t permissive_show(struct device_driver *drv, char *buf)
++static ssize_t pcistub_permissive_show(struct device_driver *drv, char *buf)
+ {
+       struct pcistub_device *psdev;
+       struct pciback_dev_data *dev_data;
+@@ -1132,7 +1261,68 @@ static ssize_t permissive_show(struct device_driver *drv, char *buf)
+       return count;
+ }
+-DRIVER_ATTR(permissive, S_IRUSR | S_IWUSR, permissive_show, permissive_add);
++DRIVER_ATTR(permissive, S_IRUSR | S_IWUSR, pcistub_permissive_show, pcistub_permissive_add);
++
++static ssize_t pcistub_do_flr(struct device_driver *drv, const char *buf,
++                                 size_t count)
++{
++      int domain, bus, slot, func;
++      int err;
++
++      err = str_to_slot(buf, &domain, &bus, &slot, &func);
++      if (err)
++              goto out;
++
++      err = pcistub_device_do_flr(domain, bus, slot, func);
++
++out:
++      if (!err)
++              err = count;
++      return err;
++}
++
++DRIVER_ATTR(do_flr, S_IWUSR, NULL, pcistub_do_flr);
++
++static ssize_t pcistub_resets(struct device_driver *drv, const char *buf,
++                                 size_t count)
++{
++      int domain, bus, slot, func;
++      int type, err = 0;
++
++      /* string begins with reset type specifier sbr=|dr3=|noflr= */
++      if (!strncmp(buf, "sbr=", 4)) {
++              type = PCIBACK_ID_TYPE_SBR;
++              buf += 4;
++      } else if (!strncmp(buf, "d3r=", 4)) {
++              type = PCIBACK_ID_TYPE_D3R;
++              buf += 4;
++      } else if (!strncmp(buf, "noflr=", 6)) {
++              type = PCIBACK_ID_TYPE_NOFLR;
++              buf += 6;
++      } else {
++              err = -EINVAL;
++              goto out;
++      }
++
++      /* check special wildcard noflr */
++      if (type == PCIBACK_ID_TYPE_NOFLR && !strncmp(buf, "(*)", 3)) {
++              disable_all_flr = 1;
++              goto out;
++      }
++
++      err = str_to_slot(buf, &domain, &bus, &slot, &func);
++      if (err)
++              goto out;
++
++      err = pcistub_device_id_add(domain, bus, slot, func, type);
++
++out:
++      if (!err)
++              err = count;
++      return err;
++}
++
++DRIVER_ATTR(resets, S_IWUSR, NULL, pcistub_resets);
+ #ifdef CONFIG_PCI_MSI
+@@ -1158,6 +1348,8 @@ static void pcistub_exit(void)
+       driver_remove_file(&pciback_pci_driver.driver, &driver_attr_slots);
+       driver_remove_file(&pciback_pci_driver.driver, &driver_attr_quirks);
+       driver_remove_file(&pciback_pci_driver.driver, &driver_attr_permissive);
++      driver_remove_file(&pciback_pci_driver.driver, &driver_attr_do_flr);
++      driver_remove_file(&pciback_pci_driver.driver, &driver_attr_resets);
+       pci_unregister_driver(&pciback_pci_driver);
+       WARN_ON(unregister_msi_get_owner(pciback_get_owner));
+@@ -1165,35 +1357,27 @@ static void pcistub_exit(void)
+ static int __init pcistub_init(void)
+ {
+-      int pos = 0;
+       int err = 0;
+-      int domain, bus, slot, func;
+-      int parsed;
+-
+-      if (pci_devs_to_hide && *pci_devs_to_hide) {
+-              do {
+-                      parsed = 0;
+-
+-                      err = sscanf(pci_devs_to_hide + pos,
+-                                   " (%x:%x:%x.%x) %n",
+-                                   &domain, &bus, &slot, &func, &parsed);
+-                      if (err != 4) {
+-                              domain = 0;
+-                              err = sscanf(pci_devs_to_hide + pos,
+-                                           " (%x:%x.%x) %n",
+-                                           &bus, &slot, &func, &parsed);
+-                              if (err != 3)
+-                                      goto parse_error;
+-                      }
+-
+-                      err = pcistub_device_id_add(domain, bus, slot, func);
+-                      if (err)
+-                              goto out;
+-                      /* if parsed<=0, we've reached the end of the string */
+-                      pos += parsed;
+-              } while (parsed > 0 && pci_devs_to_hide[pos]);
+-      }
++      /* Parse device lists for hide, sbr, and d3r */
++      err = pciback_parse_device_params(pci_devs_to_hide, PCIBACK_ID_TYPE_HIDE, pcistub_device_id_add);
++      if (err)
++              goto out;
++
++      err = pciback_parse_device_params(pci_devs_use_sbr, PCIBACK_ID_TYPE_SBR, pcistub_device_id_add);
++      if (err)
++              goto out;
++
++      err = pciback_parse_device_params(pci_devs_use_d3r, PCIBACK_ID_TYPE_D3R, pcistub_device_id_add);
++      if (err)
++              goto out;
++
++      if (pci_devs_no_flr && *pci_devs_no_flr && !strncmp(pci_devs_no_flr, "(*)", 3))
++              disable_all_flr = 1; /* check special wildcard noflr */
++      else
++              err = pciback_parse_device_params(pci_devs_no_flr, PCIBACK_ID_TYPE_NOFLR, pcistub_device_id_add);
++      if (err)
++              goto out;
+       /* If we're the first PCI Device Driver to register, we're the
+        * first one to get offered PCI devices as they become
+@@ -1217,6 +1401,12 @@ static int __init pcistub_init(void)
+       if (!err)
+               err = driver_create_file(&pciback_pci_driver.driver,
+                                        &driver_attr_permissive);
++      if (!err)
++              err = driver_create_file(&pciback_pci_driver.driver,
++                                       &driver_attr_do_flr);
++      if (!err)
++              err = driver_create_file(&pciback_pci_driver.driver,
++                                       &driver_attr_resets);
+       if (!err)
+               err = register_msi_get_owner(pciback_get_owner);
+@@ -1225,11 +1415,6 @@ static int __init pcistub_init(void)
+       out:
+       return err;
+-
+-      parse_error:
+-      printk(KERN_ERR "pciback: Error parsing pci_devs_to_hide at \"%s\"\n",
+-             pci_devs_to_hide + pos);
+-      return -EINVAL;
+ }
+ #ifndef MODULE
+diff --git a/drivers/xen/pciback/pciback.h b/drivers/xen/pciback/pciback.h
+index b2cb031..5cd967c 100644
+--- a/drivers/xen/pciback/pciback.h
++++ b/drivers/xen/pciback/pciback.h
+@@ -25,6 +25,14 @@ struct pci_dev_entry {
+ #define _PCIB_op_pending      (1)
+ #define PCIB_op_pending               (1<<(_PCIB_op_pending))
++#define PCIBACK_TYPE_UNKNOWN       0
++#define PCIBACK_TYPE_PCIe_ENDPOINT 1
++#define PCIBACK_TYPE_PCIe_BRIDGE   2
++#define PCIBACK_TYPE_PCI_BRIDGE    3
++#define PCIBACK_TYPE_PCI           4
++
++#define DEV_CLASS_PCI_PCI_BRIDGE 0x0604
++
+ struct pciback_device {
+       void *pci_dev_data;
+       spinlock_t dev_lock;
+@@ -48,6 +56,13 @@ struct pciback_dev_data {
+       struct list_head config_fields;
+       int permissive;
+       int warned_on_write;
++      u32 dev_type;
++      int no_flr;
++      int exp_flr_offset;
++      int af_flr_offset;
++      int use_sbr;
++      int use_d3r;
++      u8 *cfg_space; /* saved config space for device */
+ };
+ /* Get/Put PCI Devices that are hidden from the PCI Backend Domain */
+@@ -56,11 +71,25 @@ struct pci_dev *pcistub_get_pci_dev_by_slot(struct pciback_device *pdev,
+                                           int slot, int func);
+ struct pci_dev *pcistub_get_pci_dev(struct pciback_device *pdev,
+                                   struct pci_dev *dev);
+-void pcistub_put_pci_dev(struct pci_dev *dev);
++void pcistub_put_pci_dev(struct pci_dev *dev, int do_flr);
++
++/* Reference/unreference PCI Devices and stubs without changing the state */
++struct pci_dev *pcistub_ref_pci_dev(struct pci_dev *dev);
++void pcistub_unref_pci_dev(struct pci_dev *dev);
++
++/* Store/reload config space for devices */
++void pciback_store_config_space(struct pci_dev *dev);
++void pciback_reload_config_space(struct pci_dev *dev);
+ /* Ensure a device is turned off or reset */
+ void pciback_reset_device(struct pci_dev *pdev);
++/* Do a function level reset (or approximage functionality) for device */
++void pciback_flr_device(struct pci_dev *dev);
++
++/* Helper to classify the device type */
++void pciback_classify_device(struct pci_dev *dev);
++
+ /* Access a virtual configuration space for a PCI device */
+ int pciback_config_init(void);
+ int pciback_config_init_dev(struct pci_dev *dev);
+@@ -102,6 +131,10 @@ void pciback_release_devices(struct pciback_device *pdev);
+ irqreturn_t pciback_handle_event(int irq, void *dev_id);
+ void pciback_do_op(struct work_struct *work);
++/* Parse and load device specific module parameters */
++int pciback_parse_device_params(const char *device_args, int type,
++                                      int (*add_func) (int domain, int bus, int slot, int func, int type));
++
+ int pciback_xenbus_register(void);
+ void pciback_xenbus_unregister(void);
+diff --git a/drivers/xen/pciback/pciback_ops.c b/drivers/xen/pciback/pciback_ops.c
+index d6b9bf9..ff61476 100644
+--- a/drivers/xen/pciback/pciback_ops.c
++++ b/drivers/xen/pciback/pciback_ops.c
+@@ -9,16 +9,184 @@
+ #include <xen/evtchn.h>
+ #include "pciback.h"
++#define PCIBACK_VENDOR_INTEL     0x8086
++#define PCIBACK_CLASS_ID_USB     0x0c03
++#define PCIBACK_CLASS_ID_VGA     0x0300
++#define PCIBACK_USB_FLRCTRL      0x4
++
++#define PCIBACK_IGFX_CAP09_OFFSET    0xa4
++#define PCIBACK_IGFX_CAP13_OFFSET    0xa4
++
++#define PCIBACK_IGFX_MEDIARST        0x0d
++#define PCIBACK_IGFX_MEDIARST_OFFSET 0xc0
++
+ int verbose_request = 0;
+ module_param(verbose_request, int, 0644);
++struct pcistub_sbr_entry {
++      struct list_head dev_list;
++      struct pci_dev *dev;
++};
++
++struct pcistub_sbr_list {
++      struct list_head dev_list;
++      struct pci_dev *bridge;
++      struct pci_dev *dev;
++      int find_all;
++      int err;
++};
++
++/* Used to store the config state so it can be restored after
++ * resets.
++ */
++void pciback_store_config_space(struct pci_dev *dev)
++{
++      struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
++      u32 *ptr = (u32*)dev_data->cfg_space;
++      int i, count = dev->cfg_size/sizeof(u32);
++      
++      for (i = 0; i < count; i += sizeof(u32), ptr++)
++              pci_read_config_dword(dev, i, ptr);
++}
++
++/* Used to reload the config state after resets.
++ */
++void pciback_reload_config_space(struct pci_dev *dev)
++{
++      struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
++      u32 *ptr = (u32*)dev_data->cfg_space;
++      int i, val, count = dev->cfg_size/sizeof(u32);
++
++      for (i = 0; i < count; i += sizeof(u32), ptr++) {
++              pci_read_config_dword(dev, i, &val);
++              if (val != *ptr)
++                      pci_write_config_dword(dev, i, *ptr);
++      }
++}
++
++static void pciback_walk_bus_cb(struct pci_dev *dev, void *userdata)
++{
++      struct pcistub_sbr_list *list = (struct pcistub_sbr_list*)userdata;
++      struct pcistub_sbr_entry *entry;
++      struct pci_dev *dev_tmp;
++      
++      if (list->err != 0)
++              return;
++
++      /* For PCIe endpoints we are only looking for co-assigned functions */
++      if (!list->find_all &&
++              (dev->bus->number != list->dev->bus->number ||
++               PCI_SLOT(dev->devfn) != PCI_SLOT(list->dev->devfn)))
++              return;
++
++      dev_tmp = pcistub_ref_pci_dev(dev);
++      if (dev_tmp == NULL) {
++              /* not controlled by pciback, fail */
++              list->err = ENXIO;
++              return;
++      }
++
++      entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
++      if (entry == NULL) {
++              pcistub_unref_pci_dev(dev_tmp);
++              list->err = ENOMEM;
++              return;
++      }
++
++      entry->dev = dev_tmp;
++      list_add_tail(&entry->dev_list, &list->dev_list);
++}
++
++static void pciback_cleanup_sbr_list(struct pcistub_sbr_list *list)
++{
++      struct pcistub_sbr_entry *entry;
++
++      list_for_each_entry(entry, &list->dev_list, dev_list) {
++              pcistub_unref_pci_dev(entry->dev);
++              kfree(entry);
++      }
++}
++
++/* Routine to find all devices and bridges that need to be reset
++ * during a secondary bus reset. For PCIe this is simply all the
++ * functions on the particular device. For PCI this is all devices
++ * and bridges below the topmost PCI/PCI-X bridge. Note for PCI, 
++ * there is at least one something->PCI/PCI-X bridge to find since
++ * the device is not on the host bus 0 and is on a PCI bus.
++ */
++static int pciback_get_sbr_list(struct pci_dev *dev, 
++      struct pcistub_sbr_list *list, int pcie_endpoint)
++{
++      struct pci_dev *bridge = dev->bus->self;
++      struct pci_dev *last = NULL;
++      int exp_pos;
++      u16 exp_caps = 0;
++
++      list->err = 0;
++      list->dev = dev;
++      INIT_LIST_HEAD(&list->dev_list);
++
++      if (!pcie_endpoint) {
++              while (bridge) {
++                      /* Looking for the uppermost PCI/PCI-X bridge. If it is not PCIe then 
++                       * this is a PCI/PCI-X bridge. If it is PCIe then except the PCIe to 
++                       * PCI/PCI-X type 7, the rest of the bridge types are PCIe so the last 
++                       * bridge encountered was the topmost PCI/PCI-X bridge.
++                       */
++                      exp_pos = pci_find_capability(bridge, PCI_CAP_ID_EXP);
++                      if (exp_pos != 0) {
++                              pci_read_config_word(bridge, exp_pos + PCI_EXP_FLAGS, &exp_caps);
++                              if (((exp_caps & PCI_EXP_FLAGS_TYPE) >> 4) != PCI_EXP_TYPE_PCI_BRIDGE)
++                                      break; /* don't want it in the list if it is a PCIe bridge */
++                      }
++                      last = bridge;
++                      bridge = last->bus->self;
++              }
++              list->bridge = last;
++              list->find_all = 1; /* find all devices/bridges below the topmost */
++      }
++      else {
++              if (bridge) {
++                      /* For PCIe, SBR logic is limited to PCIe endpoints behind a root/switch
++                       * port.
++                       */
++                      exp_pos = pci_find_capability(bridge, PCI_CAP_ID_EXP);
++                      if (likely(exp_pos != 0)) {
++                              pci_read_config_word(bridge, exp_pos + PCI_EXP_FLAGS, &exp_caps);
++                              exp_caps = ((exp_caps & PCI_EXP_FLAGS_TYPE) >> 4);
++                              if (exp_caps == PCI_EXP_TYPE_ROOT_PORT ||
++                                      exp_caps == PCI_EXP_TYPE_UPSTREAM ||
++                                      exp_caps == PCI_EXP_TYPE_DOWNSTREAM)
++                                      last = bridge;
++                      }
++              }
++              list->bridge = last;
++              list->find_all = 0; /* find just functions on this slot */
++      }
++
++      /* Sanity check, there may not be any appropriate bridge to reset */
++      if (!list->bridge) {
++              dev_dbg(&dev->dev, "No appropriate bridge to reset\n");
++              return ENXIO;
++      }
++
++      pci_walk_bus(list->bridge->subordinate, pciback_walk_bus_cb, list);
++
++      if (list->err) {
++              pciback_cleanup_sbr_list(list);
++              return list->err;
++      }
++
++      return 0;
++}
++
+ /* Ensure a device is "turned off" and ready to be exported.
+  * (Also see pciback_config_reset to ensure virtual configuration space is
+  * ready to be re-exported)
+  */
+ void pciback_reset_device(struct pci_dev *dev)
+ {
+-      u16 cmd;
++      u16 cmd = 0;
+       /* Disable devices (but not bridges) */
+       if (dev->hdr_type == PCI_HEADER_TYPE_NORMAL) {
+@@ -38,6 +206,425 @@ void pciback_reset_device(struct pci_dev *dev)
+               }
+       }
+ }
++
++/* Do a PCIe type function level reset for a single function on this
++ * device.
++ */
++static void pciback_do_pcie_flr(struct pci_dev *dev, int exp_pos)
++{
++      u16 status = 0;
++      
++      dev_dbg(&dev->dev, "doing PCIe FLR\n"); 
++
++      pci_block_user_cfg_access(dev);
++
++      /* Wait for Transaction Pending bit clean */
++      msleep(100);
++      pci_read_config_word(dev, exp_pos + PCI_EXP_DEVSTA, &status);
++      if (status & PCI_EXP_DEVSTA_TRPND) {
++              dev_dbg(&dev->dev, "Busy after 100ms while trying to reset; sleeping for 1 second\n");
++              ssleep(1);
++              pci_read_config_word(dev, exp_pos + PCI_EXP_DEVSTA, &status);
++              if (status & PCI_EXP_DEVSTA_TRPND)
++                      dev_warn(&dev->dev, "Still busy after 1s; proceeding with reset anyway\n");
++      }
++
++      pci_write_config_word(dev, exp_pos + PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_BCR_FLR);
++      mdelay(200);
++
++      pciback_reload_config_space(dev);
++
++      pci_unblock_user_cfg_access(dev);
++}
++
++/* Do a PCI type function level reset for a single function on this
++ * device. This uses the Advanced Features Capability extensions to
++ * the PCI spec.
++ */
++static void pciback_do_pci_flr(struct pci_dev *dev, int af_pos, int clear_cmd)
++{
++      u8 status = 0;
++
++      dev_dbg(&dev->dev, "doing PCI FLR\n");
++
++      pci_block_user_cfg_access(dev);
++
++      /* Clear the command register to prevent new transactions */
++      if (clear_cmd)
++              pci_write_config_word(dev, PCI_COMMAND, 0);
++
++      /* Wait for Transaction Pending bit clean */
++      msleep(100);
++      pci_read_config_byte(dev, af_pos + PCI_AF_STA, &status);
++      if (status & PCI_AF_STA_TP) {
++              dev_dbg(&dev->dev, "Busy after 100ms while trying to reset; sleeping for 1 second\n");
++              ssleep(1);
++              pci_read_config_byte(dev, af_pos + PCI_AF_STA, &status);
++              if (status & PCI_AF_STA_TP)
++                      dev_warn(&dev->dev, "Still busy after 1s; proceeding with reset anyway\n");
++      }
++
++      pci_write_config_byte(dev, af_pos + PCI_AF_CTRL, PCI_AF_CTRL_FLR);
++      mdelay(200);
++
++      pciback_reload_config_space(dev);
++
++      pci_unblock_user_cfg_access(dev);
++}
++
++/* Vendor specific resets. These can be set in the vendor specific
++ * capabilities structures. Currently only the Intel USB and iGFX
++ * reset is supported.
++ */
++static int pciback_do_vendor_specific_reset(struct pci_dev *dev)
++{
++      struct pci_dev *gmch;
++      int vendor_pos, i;
++      u32 reg32 = 0;
++      u16 device_id, cmd;     
++      u8 reg8 = 0;
++
++      dev_dbg(&dev->dev, "doing vendor specific resets\n");   
++
++      if (dev->vendor != PCIBACK_VENDOR_INTEL)
++              return -ENXIO;
++
++      if ((dev->class >> 8) == PCIBACK_CLASS_ID_VGA) {
++              if (dev->bus->number != 0 || dev->devfn != PCI_DEVFN(2,0))
++                      return -ENXIO;
++
++              /* Locate the GMCH (north bridge) and test for specific Intel devices */
++              gmch = pci_get_bus_and_slot(0, PCI_DEVFN(0,0));
++              if (!gmch)
++                      return -ENXIO;
++
++              device_id = gmch->device;
++              pci_dev_put(gmch);
++
++              if (device_id != PCI_DEVICE_ID_INTEL_GMCHGM45)
++                      return -ENXIO;
++
++              /* Correct device and platform, assume vendor specific offset */
++              pci_read_config_dword(dev, PCIBACK_IGFX_CAP09_OFFSET, &reg32);
++              if ((reg32 & 0x000000FF) != PCI_CAP_ID_VNDR ||
++                      ((reg32 >> 16) & 0x000000FF) != 0x06 ||
++                      ((reg32 >> 24) & 0x000000F0) != 0x20)
++                      return -ENXIO;
++
++              vendor_pos = PCIBACK_IGFX_CAP09_OFFSET;
++      } else if ((dev->class >> 8) == PCIBACK_CLASS_ID_USB) {
++              vendor_pos = pci_find_capability(dev, PCI_CAP_ID_VNDR);
++              if (vendor_pos == 0)
++                      return -ENXIO;
++      }
++      else
++              return -ENXIO;  
++
++      if ((dev->class >> 8) == PCIBACK_CLASS_ID_VGA) {
++              pci_write_config_byte(dev, PCIBACK_IGFX_MEDIARST_OFFSET, PCIBACK_IGFX_MEDIARST);
++              for (i = 0; i <= 10; i++) {
++                      msleep(100);
++                      pci_read_config_byte(dev, PCIBACK_IGFX_MEDIARST_OFFSET, &reg8);
++                      if ((reg8 & 0x01) == 0)
++                              break;
++                      if (i == 10) {
++                              dev_warn(&dev->dev, "media not reset after 1s; skipping FLR\n");
++                              goto out;
++                      }
++              }
++        
++              /* This specific reset will hang if the command register does not have
++               * memory space access enabled */
++              pci_read_config_word(dev, PCI_COMMAND, &cmd);
++              pci_write_config_word(dev, PCI_COMMAND, (cmd | PCI_COMMAND_MEMORY));
++              /* The rest is the same as a PCI AF FLR - use the same routine */
++              pciback_do_pci_flr(dev, vendor_pos, 0);
++              pci_write_config_word(dev, PCI_COMMAND, cmd);
++      } else {
++              pci_block_user_cfg_access(dev);
++
++              pci_write_config_byte(dev, vendor_pos + PCIBACK_USB_FLRCTRL, 1);
++              mdelay(200);
++
++              pciback_reload_config_space(dev);
++
++              pci_unblock_user_cfg_access(dev);
++      }
++
++out:
++      return 0;
++}
++
++/* Use a D0-D3-D0 device state transition to reset the device. This
++ * is a good enough reset for some devices (like NICs).
++ */
++static int pciback_do_dstate_transition_reset(struct pci_dev *dev)
++{
++      int pm_pos;
++      u32 pm_ctl = 0;
++
++      pm_pos = pci_find_capability(dev, PCI_CAP_ID_PM);
++      if (pm_pos == 0)
++              return -ENXIO;
++
++      dev_dbg(&dev->dev, "doing Dstate transition reset\n");  
++
++      /* No_Soft_Reset - When set 1, this bit indicates that devices
++       * transitioning from D3hot to D0 because of PowerState commands 
++       * do not perform an internal reset.
++       */
++      pci_read_config_dword(dev, pm_pos + PCI_PM_CTRL, &pm_ctl);
++      if (pm_ctl & PCI_PM_CTRL_NO_SOFT_RESET)
++              return -ENXIO;
++      
++      pci_block_user_cfg_access(dev);
++
++      pm_ctl &= ~PCI_PM_CTRL_STATE_MASK;
++      pm_ctl |= PCI_PM_CTRL_D3HOT;
++      pci_write_config_word(dev, pm_pos + PCI_PM_CTRL, pm_ctl);
++      mdelay(10);
++
++      pm_ctl &= ~PCI_PM_CTRL_STATE_MASK;
++      pm_ctl |= PCI_PM_CTRL_D0;
++      pci_write_config_word(dev, pm_pos + PCI_PM_CTRL, pm_ctl);
++      mdelay(10);
++
++      pciback_reload_config_space(dev);
++
++      pci_unblock_user_cfg_access(dev);
++      
++      return 0;
++}
++
++/* Do a secondary bus reset on a bridge. This is only done if all
++ * co-assignment rules are satisfied and if it was explicitly 
++ * requested via pciback parameters.
++ */
++static int pciback_do_secondary_bus_reset(struct pci_dev *dev, u32 dev_type)
++{
++      struct pcistub_sbr_list sbr_list;
++      struct pcistub_sbr_entry *entry;
++      u16 pci_bctl = 0;
++      int err = 0;
++
++      /* Call helper to get the device list needed for the device type. */
++      err = pciback_get_sbr_list(dev, &sbr_list,
++                      (dev_type == PCIBACK_TYPE_PCIe_ENDPOINT ? 1 : 0));
++      if (err) {
++              dev_warn(&dev->dev, 
++                      "secondary bus reset failed for device - all functions need to be co-assigned - err: %d\n", err);
++              return err;
++      }
++
++      pci_block_user_cfg_access(dev);
++
++      /* Reset the secondary bus and restore the PCI space for all the devfn found above.
++       */
++      pci_read_config_word(sbr_list.bridge, PCI_BRIDGE_CONTROL, &pci_bctl);
++      pci_write_config_word(sbr_list.bridge, PCI_BRIDGE_CONTROL, pci_bctl | PCI_BRIDGE_CTL_BUS_RESET);
++      msleep(200);
++      pci_write_config_word(sbr_list.bridge, PCI_BRIDGE_CONTROL, pci_bctl);
++      msleep(200);
++      
++      list_for_each_entry(entry, &sbr_list.dev_list, dev_list) {
++              pciback_reload_config_space(entry->dev);
++      }
++      
++      pci_unblock_user_cfg_access(dev);
++
++      pciback_cleanup_sbr_list(&sbr_list);
++
++      return 0;
++}
++
++/* This function is used to do a function level reset on a singe 
++ * device/function. FLRs must be done on devices before they are 
++ * unassigned from one domain and passed through to another. The 
++ * preferred method is to do an actual FLR on the device but the 
++ * functionality may not be present or exposed. In the later case
++ * we attempt to locate the capability even though it is not 
++ * chained into the capabilities list.
++ *
++ * In some cases, there is no way to perform the actual FLR so we 
++ * fall back to some alternate methods (which are not as effective
++ * or useful).
++ */
++void pciback_flr_device(struct pci_dev *dev)
++{
++      struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
++      int err = 0;
++
++      if (dev_data->no_flr) {
++              dev_dbg(&dev->dev, "FLR disabled for device\n");
++              return;
++      }
++      dev_dbg(&dev->dev, "FLR invoked for device\n");
++
++      do {
++              /* First, always try to do an FLR */
++              if (dev_data->dev_type == PCIBACK_TYPE_PCIe_ENDPOINT &&
++                      dev_data->exp_flr_offset != 0) {
++                      pciback_do_pcie_flr(dev, dev_data->exp_flr_offset);
++                      break;
++              }
++              if (dev_data->dev_type == PCIBACK_TYPE_PCI &&
++                      dev_data->af_flr_offset != 0) {
++                      pciback_do_pci_flr(dev, dev_data->af_flr_offset, 1);
++                      break;
++              }
++              
++              /* Next for integrated devices on the host bus 0, try some other methods */
++              if (dev->bus->number == 0) {
++                      err = pciback_do_vendor_specific_reset(dev);
++                      if (err && dev_data->use_d3r)
++                              err = pciback_do_dstate_transition_reset(dev);
++                      if (err)
++                              dev_warn(&dev->dev, "FLR functionality not supported; "
++                                              "attempts to use vendor FLR or D-states unsuccessful\n");
++                      break;
++              }
++
++              /* Else attempt a secondary bus reset if all conditions are met */
++              if (dev_data->use_sbr) {
++                      err = pciback_do_secondary_bus_reset(dev, dev_data->dev_type);
++                      if (err)
++                              dev_warn(&dev->dev, "FLR functionality not supported; "
++                                              "attempts to use secondary bus reset unsuccessful;\n");
++                      break;
++              }
++
++              err = -ENODEV;          
++      } while (0);
++
++      if (err)
++              dev_warn(&dev->dev, "FLR not performed for device\n");
++}
++
++/* Helper used to location the FLR capabilities for a PCIe device.
++ * When the capability cannot be found in the chain but is present,
++ * special logic is used to attempt to locate functionality.
++ *
++ * returns: the offset to the capability, zero if not found.
++ */
++static int pciback_find_pcie_flr_caps(struct pci_dev *dev)
++{
++      int exp_pos;
++      u32 cap = 0;
++
++      /* First look for the PCIe FLR capabilities using the capabilities list */
++      exp_pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
++      if (exp_pos) {
++              pci_read_config_dword(dev, exp_pos + PCI_EXP_DEVCAP, &cap);
++              if (cap & PCI_EXP_DEVCAP_FLR) {
++                      return exp_pos;
++              }
++      }
++
++      return 0;
++}
++
++/* Helper used to location the AF FLR capabilities for a PCI device.
++ * When the capability cannot be found in the chain but is present,
++ * special logic is used to attempt to locate functionality.
++ *
++ * returns: the offset to the capability, zero if not found.
++ */
++static int pciback_find_pci_flr_caps(struct pci_dev *dev)
++{
++      struct pci_dev *gmch;
++      int af_pos;
++      u16 device_id;
++      u8 cap = 0, reg8 = 0;
++
++      /* First look for the PCI AF capabilities for FLR using the capabilities list. This
++       * is only used on the devices on the root/host bus (integrated devices). 
++       */
++      if (dev->bus->number != 0)
++              return 0;
++
++      af_pos = pci_find_capability(dev, PCI_CAP_ID_AF);
++      if (af_pos) {
++              pci_read_config_byte(dev, af_pos + PCI_AF_DEVCAP, &cap);
++              if (cap & PCI_AF_CAP_FLR) {
++                      return af_pos;
++              }
++      }
++
++      /* Next look for the unchained AF capabilities for FLR using specific 
++       * logic. Currently only the graphics device on the Intel Q45 etc 
++       * systems has special logic for locating the hidden FLR caps.
++     */
++      do {
++              if (dev->bus->number != 0 || dev->devfn != PCI_DEVFN(2,0) ||
++                      dev->vendor != PCIBACK_VENDOR_INTEL || (dev->class >> 8) != PCIBACK_CLASS_ID_VGA)
++                      break;
++
++              /* Locate the GMCH (north bridge) and test for specific Intel devices */
++              gmch = pci_get_bus_and_slot(0, PCI_DEVFN(0,0));
++              if (!gmch)
++                      break;
++
++              device_id = gmch->device;
++              pci_dev_put(gmch);
++
++              if (device_id != PCI_DEVICE_ID_INTEL_GMCHQ45 &&
++                      device_id != PCI_DEVICE_ID_INTEL_GMCHG45 &&
++                      device_id != PCI_DEVICE_ID_INTEL_GMCHG41)
++                      break;
++              
++              /* Correct device and platform, assume AF offset */
++              af_pos = PCIBACK_IGFX_CAP13_OFFSET;
++              pci_read_config_byte(dev, af_pos + PCI_AF_LENFLD, &reg8);
++              if (reg8 == PCI_AF_LENGTH) {
++                      pci_read_config_byte(dev, af_pos + PCI_AF_DEVCAP, &cap);
++                      if (cap & PCI_AF_CAP_FLR) {
++                              return af_pos;
++                      }
++              }
++      } while (0);
++
++      /* Else not found */
++      return 0;
++}
++
++/* Classify the device, specifically determine if it is PCIe/PCI 
++ * and whether it is a PCIe endpoint, bridge, or other PCI device. 
++ */
++void pciback_classify_device(struct pci_dev *dev)
++{
++      struct pciback_dev_data *dev_data;
++      int exp_pos;
++      u16 exp_caps = 0;
++
++      dev_data = pci_get_drvdata(dev);
++      dev_data->dev_type = PCIBACK_TYPE_UNKNOWN;
++
++      exp_pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
++      
++      if ((dev->class >> 8) != DEV_CLASS_PCI_PCI_BRIDGE) {
++              if (exp_pos != 0) {
++                      dev_data->dev_type = PCIBACK_TYPE_PCIe_ENDPOINT;
++                      dev_data->exp_flr_offset = pciback_find_pcie_flr_caps(dev);
++              } else {
++                      dev_data->dev_type = PCIBACK_TYPE_PCI;
++                      dev_data->af_flr_offset = pciback_find_pci_flr_caps(dev);
++              }
++              goto classify_done;
++      }
++      
++      if (exp_pos == 0) {
++              dev_data->dev_type = PCIBACK_TYPE_PCI_BRIDGE;
++              goto classify_done;
++      }
++
++      pci_read_config_word(dev, exp_pos + PCI_EXP_FLAGS, &exp_caps);
++      dev_data->dev_type = (((exp_caps & PCI_EXP_FLAGS_TYPE) >> 4) == PCI_EXP_TYPE_PCI_BRIDGE) ? PCIBACK_TYPE_PCI_BRIDGE : PCIBACK_TYPE_PCIe_BRIDGE;
++
++classify_done:
++
++      return;
++}
++
+ extern wait_queue_head_t aer_wait_queue;
+ extern struct workqueue_struct *pciback_wq;
+ /*
+@@ -132,3 +719,51 @@ irqreturn_t pciback_handle_event(int irq, void *dev_id)
+       return IRQ_HANDLED;
+ }
++
++/* Helper routine used to parse command line parameters passed to the 
++ * pciback module from the boot loader. These params all have the form
++ * of a list of one or more devices, e.g.:
++ * (XXXX:XX:XX.X)(XXXX:XX:XX.X)
++ * Which is: (domain/segment:bus:dev.func)
++ */
++int pciback_parse_device_params(const char *device_args, int type, 
++                      int (*add_func) (int domain, int bus, int slot, int func, int type))
++{
++      int pos = 0;
++      int err = 0;
++      int domain, bus, slot, func;
++      int parsed;
++
++      if (device_args && *device_args) {
++              do {
++                      parsed = 0;
++
++                      err = sscanf(device_args + pos,
++                                   " (%x:%x:%x.%x) %n",
++                                   &domain, &bus, &slot, &func, &parsed);
++                      if (err != 4) {
++                              domain = 0;
++                              err = sscanf(device_args + pos,
++                                           " (%x:%x.%x) %n",
++                                           &bus, &slot, &func, &parsed);
++                              if (err != 3)
++                                      goto parse_error;
++                      }
++
++                      err = add_func(domain, bus, slot, func, type);
++                      if (err)
++                              goto out;
++
++                      /* if parsed<=0, we've reached the end of the string */
++                      pos += parsed;
++              } while (parsed > 0 && device_args[pos]);
++      }
++
++out:
++      return err;
++
++parse_error:
++      printk(KERN_ERR "pciback: Error parsing device parameters \"%s\" at \"%s\"\n",
++             device_args, device_args + pos);
++      return -EINVAL;
++}
+diff --git a/drivers/xen/pciback/slot.c b/drivers/xen/pciback/slot.c
+index 105a8b6..9c66633 100644
+--- a/drivers/xen/pciback/slot.c
++++ b/drivers/xen/pciback/slot.c
+@@ -109,7 +109,7 @@ void pciback_release_pci_dev(struct pciback_device *pdev, struct pci_dev *dev)
+       spin_unlock_irqrestore(&slot_dev->lock, flags);
+       if (found_dev)
+-              pcistub_put_pci_dev(found_dev);
++              pcistub_put_pci_dev(found_dev, 0);
+ }
+ int pciback_init_devices(struct pciback_device *pdev)
+@@ -149,7 +149,7 @@ void pciback_release_devices(struct pciback_device *pdev)
+               for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
+                       dev = slot_dev->slots[bus][slot];
+                       if (dev != NULL)
+-                              pcistub_put_pci_dev(dev);
++                              pcistub_put_pci_dev(dev, 0);
+               }
+       kfree(slot_dev);
+diff --git a/drivers/xen/pciback/vpci.c b/drivers/xen/pciback/vpci.c
+index a5b7ece..259e71d 100644
+--- a/drivers/xen/pciback/vpci.c
++++ b/drivers/xen/pciback/vpci.c
+@@ -162,7 +162,7 @@ void pciback_release_pci_dev(struct pciback_device *pdev, struct pci_dev *dev)
+       spin_unlock_irqrestore(&vpci_dev->lock, flags);
+       if (found_dev)
+-              pcistub_put_pci_dev(found_dev);
++              pcistub_put_pci_dev(found_dev, 0);
+ }
+ int pciback_init_devices(struct pciback_device *pdev)
+@@ -202,7 +202,7 @@ void pciback_release_devices(struct pciback_device *pdev)
+               list_for_each_entry_safe(e, tmp, &vpci_dev->dev_list[slot],
+                                        list) {
+                       list_del(&e->list);
+-                      pcistub_put_pci_dev(e->dev);
++                      pcistub_put_pci_dev(e->dev, 0);
+                       kfree(e);
+               }
+       }
+diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
+index 12080a3..4a6eba5 100644
+--- a/include/linux/pci_ids.h
++++ b/include/linux/pci_ids.h
+@@ -2495,6 +2495,14 @@
+ #define PCI_DEVICE_ID_INTEL_IXP2800   0x9004
+ #define PCI_DEVICE_ID_INTEL_S21152BB  0xb152
++#define PCI_DEVICE_ID_INTEL_GMCHQ45 0x2e10
++#define PCI_DEVICE_ID_INTEL_GMCHG45 0x2e20
++#define PCI_DEVICE_ID_INTEL_MCHP45  0x2e20
++#define PCI_DEVICE_ID_INTEL_GMCHG41 0x2e30
++#define PCI_DEVICE_ID_INTEL_GMCHGM45 0x2a40
++
++#define PCI_DEVICE_ID_INTEL_GMCHG41 0x2e30
++
+ #define PCI_VENDOR_ID_SCALEMP         0x8686
+ #define PCI_DEVICE_ID_SCALEMP_VSMP_CTL        0x1010
+diff --git a/include/linux/pci_regs.h b/include/linux/pci_regs.h
+index 450684f..97812c6 100644
+--- a/include/linux/pci_regs.h
++++ b/include/linux/pci_regs.h
+@@ -210,6 +210,7 @@
+ #define  PCI_CAP_ID_AGP3      0x0E    /* AGP Target PCI-PCI bridge */
+ #define  PCI_CAP_ID_EXP       0x10    /* PCI Express */
+ #define  PCI_CAP_ID_MSIX      0x11    /* MSI-X */
++#define  PCI_CAP_ID_AF      0x13    /* Advanced Features Capability */
+ #define PCI_CAP_LIST_NEXT     1       /* Next capability in the list */
+ #define PCI_CAP_FLAGS         2       /* Capability defined flags (16 bits) */
+ #define PCI_CAP_SIZEOF                4
+@@ -239,6 +240,11 @@
+ #define  PCI_PM_CTRL_DATA_SEL_MASK    0x1e00  /* Data select (??) */
+ #define  PCI_PM_CTRL_DATA_SCALE_MASK  0x6000  /* Data scale (??) */
+ #define  PCI_PM_CTRL_PME_STATUS       0x8000  /* PME pin status */
++#define  PCI_PM_CTRL_DATA_DSTATE_MASK 0x3     /* D0 - D3 */
++#define  PCI_PM_CTRL_D0 0x0
++#define  PCI_PM_CTRL_D1 0x1
++#define  PCI_PM_CTRL_D2 0x2
++#define  PCI_PM_CTRL_D3HOT 0x3
+ #define PCI_PM_PPB_EXTENSIONS 6       /* PPB support extensions (??) */
+ #define  PCI_PM_PPB_B2_B3     0x40    /* Stop clock when in D3hot (??) */
+ #define  PCI_PM_BPCC_ENABLE   0x80    /* Bus power/clock control enable (??) */
+@@ -377,6 +383,7 @@
+ #define  PCI_EXP_DEVCAP_RBER  0x8000  /* Role-Based Error Reporting */
+ #define  PCI_EXP_DEVCAP_PWR_VAL       0x3fc0000 /* Slot Power Limit Value */
+ #define  PCI_EXP_DEVCAP_PWR_SCL       0xc000000 /* Slot Power Limit Scale */
++#define  PCI_EXP_DEVCAP_FLR     0x10000000 /* Function Level Reset */
+ #define PCI_EXP_DEVCTL                8       /* Device Control */
+ #define  PCI_EXP_DEVCTL_CERE  0x0001  /* Correctable Error Reporting En. */
+ #define  PCI_EXP_DEVCTL_NFERE 0x0002  /* Non-Fatal Error Reporting Enable */
+@@ -389,6 +396,7 @@
+ #define  PCI_EXP_DEVCTL_AUX_PME       0x0400  /* Auxiliary Power PM Enable */
+ #define  PCI_EXP_DEVCTL_NOSNOOP_EN 0x0800  /* Enable No Snoop */
+ #define  PCI_EXP_DEVCTL_READRQ        0x7000  /* Max_Read_Request_Size */
++#define  PCI_EXP_DEVCTL_BCR_FLR 0x8000  /* Bridge Configuration Retry / FLR */
+ #define PCI_EXP_DEVSTA                10      /* Device Status */
+ #define  PCI_EXP_DEVSTA_CED   0x01    /* Correctable Error Detected */
+ #define  PCI_EXP_DEVSTA_NFED  0x02    /* Non-Fatal Error Detected */
+@@ -419,6 +427,10 @@
+ #define  PCI_EXP_RTCTL_CRSSVE 0x10    /* CRS Software Visibility Enable */
+ #define PCI_EXP_RTCAP         30      /* Root Capabilities */
+ #define PCI_EXP_RTSTA         32      /* Root Status */
++#define PCI_EXP_DEVCAP2               36      /* Device Capabilities 2 */
++#define  PCI_EXP_DEVCAP2_ARI  0x20    /* Alternative Routing-ID */
++#define PCI_EXP_DEVCTL2               40      /* Device Control 2 */
++#define  PCI_EXP_DEVCTL2_ARI  0x20    /* Alternative Routing-ID */
+ /* Extended Capabilities (PCI-X 2.0 and Express) */
+ #define PCI_EXT_CAP_ID(header)                (header & 0x0000ffff)
+@@ -429,6 +441,7 @@
+ #define PCI_EXT_CAP_ID_VC     2
+ #define PCI_EXT_CAP_ID_DSN    3
+ #define PCI_EXT_CAP_ID_PWR    4
++#define PCI_EXT_CAP_ID_ARI    14
+ /* Advanced Error Reporting */
+ #define PCI_ERR_UNCOR_STATUS  4       /* Uncorrectable Error Status */
+@@ -536,5 +549,25 @@
+ #define HT_CAPTYPE_GEN3               0xD0    /* Generation 3 hypertransport configuration */
+ #define HT_CAPTYPE_PM         0xE0    /* Hypertransport powermanagement configuration */
++/* Alternative Routing-ID Interpretation */
++#define PCI_ARI_CAP                   0x04    /* ARI Capability Register */
++#define  PCI_ARI_CAP_MFVC     0x0001  /* MFVC Function Groups Capability */
++#define  PCI_ARI_CAP_ACS      0x0002  /* ACS Function Groups Capability */
++#define  PCI_ARI_CAP_NFN(x)   (((x) >> 8) & 0xff) /* Next Function Number */
++#define PCI_ARI_CTRL          0x06    /* ARI Control Register */
++#define  PCI_ARI_CTRL_MFVC    0x0001  /* MFVC Function Groups Enable */
++#define  PCI_ARI_CTRL_ACS     0x0002  /* ACS Function Groups Enable */
++#define  PCI_ARI_CTRL_FG(x)   (((x) >> 4) & 7) /* Function Group */
++
++/* Advanced Features Capability */
++#define PCI_AF_LENFLD    0x02 /* Device length offset */
++#define  PCI_AF_LENGTH   0x06
++#define PCI_AF_DEVCAP    0x03 /* Device capabilities offset */
++#define  PCI_AF_CAP_TP   0x01
++#define  PCI_AF_CAP_FLR  0x02
++#define PCI_AF_CTRL      0x04 /* Device CTRL offset */
++#define  PCI_AF_CTRL_FLR 0x01
++#define PCI_AF_STA       0x05 /* Device STATUS offset */
++#define  PCI_AF_STA_TP   0x01
+ #endif /* LINUX_PCI_REGS_H */
index a24c116daf0a0d6723dec4ca56a508ea04520e33..7f1cd7a547b9d44a71bae82e81ad31cc8b36b73f 100644 (file)
@@ -245,3 +245,9 @@ dom0-swap-extra-debugging
 oom-debugging
 oom-debug-me-harder
 sysrq-loglevel
+
+#
+# XenClient
+#
+xen-acpi-wmi
+pciback-flr
diff --git a/master/xen-acpi-wmi b/master/xen-acpi-wmi
new file mode 100644 (file)
index 0000000..77d2a20
--- /dev/null
@@ -0,0 +1,1013 @@
+diff -Nur linux-2.6-a/drivers/acpi/ec.c linux-2.6-b/drivers/acpi/ec.c
+--- linux-2.6-a/drivers/acpi/ec.c      2009-04-07 16:52:00.000000000 -0400
++++ linux-2.6-b/drivers/acpi/ec.c      2009-04-07 16:36:54.000000000 -0400
+@@ -123,6 +123,12 @@
+ int acpi_ec_intr = 1; /* Default is interrupt mode */
++static u32 wmi_event_data_index = 0;
++extern u8 in_query_wmi_event_data;
++extern const u8 wmi_ec_max_data_size;
++extern u32 wmi_ec_port_data_size;
++extern u8 wmi_ec_port_data[32];
++
+ /* --------------------------------------------------------------------------
+                              Transaction Management
+    -------------------------------------------------------------------------- */
+@@ -377,6 +383,22 @@
+       result = acpi_ec_transaction(ec, &t, 0);
+       *data = d;
++
++        /* HACK ALERT
++         * Please refer to wmi.c for an explanation on why we added this hack.
++         */
++         if ( in_query_wmi_event_data == TRUE ) {
++                 if ( address == 0x2b ) {
++                         wmi_event_data_index = 0;
++                         memset(wmi_ec_port_data, 0, wmi_ec_max_data_size);
++                         wmi_ec_port_data_size = *data;
++                 } else if ( (address == 0x2c) && (wmi_event_data_index < wmi_ec_port_data_size)
++                         && (wmi_event_data_index < wmi_ec_max_data_size) ) {
++                         wmi_ec_port_data[wmi_event_data_index] = *data;
++                         wmi_event_data_index++;
++                 }
++        }
++
+       return result;
+ }
+diff -Nur linux-2.6-a/drivers/acpi/wmi.c linux-2.6-b/drivers/acpi/wmi.c
+--- linux-2.6-a/drivers/acpi/wmi.c     2009-04-07 15:31:56.000000000 -0400
++++ linux-2.6-b/drivers/acpi/wmi.c     2009-04-07 17:29:43.000000000 -0400
+@@ -1,13 +1,18 @@
+ /*
+  *  ACPI-WMI mapping driver
+  *
+- *  Copyright (C) 2007-2008 Carlos Corbacho <carlos@strangeworlds.co.uk>
++ *  Copyright (C) 2007-2008 Carlos Corbacho <carlos <at> strangeworlds.co.uk>
+  *
+- *  GUID parsing code from ldm.c is:
+- *   Copyright (C) 2001,2002 Richard Russon <ldm@flatcap.org>
+- *   Copyright (c) 2001-2007 Anton Altaparmakov
+- *   Copyright (C) 2001,2002 Jakob Kemi <jakob.kemi@telia.com>
++ *  Modifications:
++ *  Copyright (c) 2009 Kamala Narasimhan - Citrix Systems, Inc.
+  *
++ *  Following modifications where made to fit our usecase -
++ *  a) Route WMI events to acpid.
++ *  b) Remove exports not required for our usecase, remove notification 
++ *      installation/uninstallation code (as we now route events to acpid).
++ *  c) Minor device id issue.
++ *  d) Remove GUID parsing code as our usecase does not require supporting
++ *     36 char guid input.
+  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  *
+  *  This program is free software; you can redistribute it and/or modify
+@@ -32,6 +37,7 @@
+ #include <linux/types.h>
+ #include <linux/list.h>
+ #include <linux/acpi.h>
++#include <linux/dmi.h>
+ #include <acpi/acpi_bus.h>
+ #include <acpi/acpi_drivers.h>
+@@ -45,8 +51,6 @@
+ #undef PREFIX
+ #define PREFIX "ACPI: WMI: "
+-static DEFINE_MUTEX(wmi_data_lock);
+-
+ struct guid_block {
+       char guid[16];
+       union {
+@@ -64,11 +68,25 @@
+       struct list_head list;
+       struct guid_block gblock;
+       acpi_handle handle;
+-      wmi_notify_handler handler;
+-      void *handler_data;
+ };
+ static struct wmi_block wmi_blocks;
++static DEFINE_MUTEX(wmi_mutex);
++
++/* 
++ * YIKEES!  HACK ALERT
++ * Due to buffer dereferencing bugs at firmware layer, some firmware(s)
++ * (Dell in specific) return all 0s for wmi event data when
++ * queried through _WED.  To work around this firmware bug and provide
++ * appropriate event data to guest firmware, we will sniff the embedded
++ * controller port access to addresses 0x2b and 0x2c and slap that data
++ * at the beginning of _WED return buffer which would otherwise be all 0s. 
++ */
++static u8 enable_wmi_event_data_hack = FALSE;
++u8 in_query_wmi_event_data = FALSE;
++const u8 wmi_ec_max_data_size = 32;
++u32 wmi_ec_port_data_size = 0;
++u8 wmi_ec_port_data[32];
+ /*
+  * If the GUID data block is marked as expensive, we must enable and
+@@ -82,133 +100,27 @@
+ static int acpi_wmi_remove(struct acpi_device *device, int type);
+ static int acpi_wmi_add(struct acpi_device *device);
+-static const struct acpi_device_id wmi_device_ids[] = {
+-      {"PNP0C14", 0},
+-      {"pnp0c14", 0},
+-      {"", 0},
+-};
+-MODULE_DEVICE_TABLE(acpi, wmi_device_ids);
+-
+ static struct acpi_driver acpi_wmi_driver = {
+       .name = "wmi",
+       .class = ACPI_WMI_CLASS,
+-      .ids = wmi_device_ids,
++      .ids = "PNP0C14, pnp0c14",
+       .ops = {
+               .add = acpi_wmi_add,
+               .remove = acpi_wmi_remove,
+               },
+ };
+-/*
+- * GUID parsing functions
+- */
+-
+-/**
+- * wmi_parse_hexbyte - Convert a ASCII hex number to a byte
+- * @src:  Pointer to at least 2 characters to convert.
+- *
+- * Convert a two character ASCII hex string to a number.
+- *
+- * Return:  0-255  Success, the byte was parsed correctly
+- *          -1     Error, an invalid character was supplied
+- */
+-static int wmi_parse_hexbyte(const u8 *src)
+-{
+-      unsigned int x; /* For correct wrapping */
+-      int h;
+-
+-      /* high part */
+-      x = src[0];
+-      if (x - '0' <= '9' - '0') {
+-              h = x - '0';
+-      } else if (x - 'a' <= 'f' - 'a') {
+-              h = x - 'a' + 10;
+-      } else if (x - 'A' <= 'F' - 'A') {
+-              h = x - 'A' + 10;
+-      } else {
+-              return -1;
+-      }
+-      h <<= 4;
+-
+-      /* low part */
+-      x = src[1];
+-      if (x - '0' <= '9' - '0')
+-              return h | (x - '0');
+-      if (x - 'a' <= 'f' - 'a')
+-              return h | (x - 'a' + 10);
+-      if (x - 'A' <= 'F' - 'A')
+-              return h | (x - 'A' + 10);
+-      return -1;
+-}
+-
+-/**
+- * wmi_swap_bytes - Rearrange GUID bytes to match GUID binary
+- * @src:   Memory block holding binary GUID (16 bytes)
+- * @dest:  Memory block to hold byte swapped binary GUID (16 bytes)
+- *
+- * Byte swap a binary GUID to match it's real GUID value
+- */
+-static void wmi_swap_bytes(u8 *src, u8 *dest)
+-{
+-      int i;
+-
+-      for (i = 0; i <= 3; i++)
+-              memcpy(dest + i, src + (3 - i), 1);
+-
+-      for (i = 0; i <= 1; i++)
+-              memcpy(dest + 4 + i, src + (5 - i), 1);
+-
+-      for (i = 0; i <= 1; i++)
+-              memcpy(dest + 6 + i, src + (7 - i), 1);
+-
+-      memcpy(dest + 8, src + 8, 8);
+-}
+-
+-/**
+- * wmi_parse_guid - Convert GUID from ASCII to binary
+- * @src:   36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
+- * @dest:  Memory block to hold binary GUID (16 bytes)
+- *
+- * N.B. The GUID need not be NULL terminated.
+- *
+- * Return:  'true'   @dest contains binary GUID
+- *          'false'  @dest contents are undefined
+- */
+-static bool wmi_parse_guid(const u8 *src, u8 *dest)
+-{
+-      static const int size[] = { 4, 2, 2, 2, 6 };
+-      int i, j, v;
+-
+-      if (src[8]  != '-' || src[13] != '-' ||
+-              src[18] != '-' || src[23] != '-')
+-              return false;
+-
+-      for (j = 0; j < 5; j++, src++) {
+-              for (i = 0; i < size[j]; i++, src += 2, *dest++ = v) {
+-                      v = wmi_parse_hexbyte(src);
+-                      if (v < 0)
+-                              return false;
+-              }
+-      }
+-
+-      return true;
+-}
+-
+ static bool find_guid(const char *guid_string, struct wmi_block **out)
+ {
+-      char tmp[16], guid_input[16];
+       struct wmi_block *wblock;
+       struct guid_block *block;
+       struct list_head *p;
+-      wmi_parse_guid(guid_string, tmp);
+-      wmi_swap_bytes(tmp, guid_input);
+-
+       list_for_each(p, &wmi_blocks.list) {
+               wblock = list_entry(p, struct wmi_block, list);
+               block = &wblock->gblock;
+-              if (memcmp(block->guid, guid_input, 16) == 0) {
++              if (memcmp(block->guid, guid_string, 16) == 0) {
+                       if (out)
+                               *out = wblock;
+                       return 1;
+@@ -217,12 +129,46 @@
+       return 0;
+ }
++static acpi_status wmi_enable_event_data_blocks(int enable)
++{
++        struct list_head *p;
++        struct guid_block *gblock;
++        struct wmi_block *wblock;
++        char method[5];
++        struct acpi_object_list input;
++        union acpi_object params[1];
++        acpi_status status;
++
++        list_for_each(p, &wmi_blocks.list) {
++                wblock = list_entry(p, struct wmi_block, list);
++                gblock = &wblock->gblock;
++
++                if (gblock->flags & ACPI_WMI_EVENT) {
++                        input.count = 1;
++                        input.pointer = params;
++                        params[0].type = ACPI_TYPE_INTEGER;
++                        params[0].integer.value = enable;
++
++                        snprintf(method, 5, "WE%02X", gblock->notify_id);
++                        status = acpi_evaluate_object(wblock->handle, method, &input, NULL);
++
++                        if (status != AE_OK && status != AE_NOT_FOUND) {
++                                printk(KERN_INFO PREFIX "Event block %s enable failed\n", method);
++                                return status;
++                        } else 
++                                return AE_OK;
++                }
++        }
++
++        return AE_OK; /* if we don't have a wmi block (though odd), just return success */
++}
++
+ /*
+  * Exported WMI functions
+  */
+ /**
+  * wmi_evaluate_method - Evaluate a WMI method
+- * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
++ * @guid_string: 16 byte guid 
+  * @instance: Instance index
+  * @method_id: Method ID to call
+  * &in: Buffer containing input for the method call
+@@ -247,7 +193,7 @@
+       block = &wblock->gblock;
+       handle = wblock->handle;
+-      if (!(block->flags & ACPI_WMI_METHOD))
++        if (!(block->flags & ACPI_WMI_METHOD))
+               return AE_BAD_DATA;
+       if (block->instance_count < instance)
+@@ -282,7 +228,7 @@
+ /**
+  * wmi_query_block - Return contents of a WMI block
+- * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
++ * @guid_string: 16 byte guid 
+  * @instance: Instance index
+  * &out: Empty buffer to return the contents of the data block to
+  *
+@@ -338,10 +284,10 @@
+                * expensive, but have no corresponding WCxx method. So we
+                * should not fail if this happens.
+                */
+-              wc_status = acpi_get_handle(handle, wc_method, &wc_handle);
+-              if (ACPI_SUCCESS(wc_status))
+-                      wc_status = acpi_evaluate_object(handle, wc_method,
+-                              &wc_input, NULL);
++               wc_status = acpi_get_handle(handle, wc_method, &wc_handle);
++               if (ACPI_SUCCESS(wc_status))
++                       wc_status = acpi_evaluate_object(handle, wc_method,
++                               &wc_input, NULL);
+       }
+       strcpy(method, "WQ");
+@@ -365,7 +311,7 @@
+ /**
+  * wmi_set_block - Write to a WMI block
+- * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
++ * @guid_string: 16 byte guid 
+  * @instance: Instance index
+  * &in: Buffer containing new values for the data block
+  *
+@@ -417,61 +363,6 @@
+ EXPORT_SYMBOL_GPL(wmi_set_block);
+ /**
+- * wmi_install_notify_handler - Register handler for WMI events
+- * @handler: Function to handle notifications
+- * @data: Data to be returned to handler when event is fired
+- *
+- * Register a handler for events sent to the ACPI-WMI mapper device.
+- */
+-acpi_status wmi_install_notify_handler(const char *guid,
+-wmi_notify_handler handler, void *data)
+-{
+-      struct wmi_block *block;
+-
+-      if (!guid || !handler)
+-              return AE_BAD_PARAMETER;
+-
+-      find_guid(guid, &block);
+-      if (!block)
+-              return AE_NOT_EXIST;
+-
+-      if (block->handler)
+-              return AE_ALREADY_ACQUIRED;
+-
+-      block->handler = handler;
+-      block->handler_data = data;
+-
+-      return AE_OK;
+-}
+-EXPORT_SYMBOL_GPL(wmi_install_notify_handler);
+-
+-/**
+- * wmi_uninstall_notify_handler - Unregister handler for WMI events
+- *
+- * Unregister handler for events sent to the ACPI-WMI mapper device.
+- */
+-acpi_status wmi_remove_notify_handler(const char *guid)
+-{
+-      struct wmi_block *block;
+-
+-      if (!guid)
+-              return AE_BAD_PARAMETER;
+-
+-      find_guid(guid, &block);
+-      if (!block)
+-              return AE_NOT_EXIST;
+-
+-      if (!block->handler)
+-              return AE_NULL_ENTRY;
+-
+-      block->handler = NULL;
+-      block->handler_data = NULL;
+-
+-      return AE_OK;
+-}
+-EXPORT_SYMBOL_GPL(wmi_remove_notify_handler);
+-
+-/**
+  * wmi_get_event_data - Get WMI data associated with an event
+  *
+  * @event - Event to find
+@@ -486,6 +377,8 @@
+       struct guid_block *gblock;
+       struct wmi_block *wblock;
+       struct list_head *p;
++        acpi_status status;
++        uint count;
+       input.count = 1;
+       input.pointer = params;
+@@ -497,27 +390,31 @@
+               gblock = &wblock->gblock;
+               if ((gblock->flags & ACPI_WMI_EVENT) &&
+-                      (gblock->notify_id == event))
+-                      return acpi_evaluate_object(wblock->handle, "_WED",
++                      (gblock->notify_id == event)) {
++                        mutex_lock(&wmi_mutex);
++                        if ( enable_wmi_event_data_hack == TRUE ) {
++                                wmi_ec_port_data_size = 0;
++                                memset(wmi_ec_port_data, 0, 32); 
++                                in_query_wmi_event_data = TRUE;
++                        }
++                      status = acpi_evaluate_object(wblock->handle, "_WED",
+                               &input, out);
++                        if ( enable_wmi_event_data_hack == TRUE ) {
++                                for ( count = 0; count < wmi_ec_port_data_size; count++)
++                                        ((char *)((union acpi_object *) 
++                                        out->pointer)->buffer.pointer)[count] 
++                                        = wmi_ec_port_data[count];
++                                in_query_wmi_event_data = FALSE;
++                        }
++                        mutex_unlock(&wmi_mutex);
++                        return status;
++                }
+       }
+       return AE_NOT_FOUND;
+ }
+ EXPORT_SYMBOL_GPL(wmi_get_event_data);
+-/**
+- * wmi_has_guid - Check if a GUID is available
+- * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
+- *
+- * Check if a given GUID is defined by _WDG
+- */
+-bool wmi_has_guid(const char *guid_string)
+-{
+-      return find_guid(guid_string, NULL);
+-}
+-EXPORT_SYMBOL_GPL(wmi_has_guid);
+-
+ /*
+  * Parse the _WDG method for the GUID data blocks
+  */
+@@ -621,12 +518,7 @@
+               if ((block->flags & ACPI_WMI_EVENT) &&
+                       (block->notify_id == event)) {
+-                      if (wblock->handler)
+-                              wblock->handler(event, wblock->handler_data);
+-
+-                      acpi_bus_generate_netlink_event(
+-                              device->pnp.device_class, device->dev.bus_id,
+-                              event, 0);
++                        acpi_bus_generate_proc_event(device, event, 0);
+                       break;
+               }
+       }
+@@ -640,6 +532,7 @@
+       acpi_remove_address_space_handler(device->handle,
+                               ACPI_ADR_SPACE_EC, &acpi_wmi_ec_space_handler);
++        wmi_enable_event_data_blocks(0);
+       return 0;
+ }
+@@ -659,26 +552,33 @@
+                                                   ACPI_ADR_SPACE_EC,
+                                                   &acpi_wmi_ec_space_handler,
+                                                   NULL, NULL);
+-      if (ACPI_FAILURE(status))
++      if (ACPI_FAILURE(status)) {
++                printk(KERN_ERR PREFIX "Error installing EC region handler\n");
+               return -ENODEV;
++        }
+       status = parse_wdg(device->handle);
+       if (ACPI_FAILURE(status)) {
+-              printk(KERN_ERR PREFIX "Error installing EC region handler\n");
++              printk(KERN_ERR PREFIX "parse_wdg failed!\n");
+               return -ENODEV;
+       }
++        /* No need to check and fail if wmi_enable_event_data_blocks should fail.
++         * wmi_enable_event_data_blocks will print an error message.
++         */
++        wmi_enable_event_data_blocks(1);
+       return result;
+ }
+ static int __init acpi_wmi_init(void)
+ {
+       acpi_status result;
++        char *dmi_sys_info;
+       INIT_LIST_HEAD(&wmi_blocks.list);
+-      if (acpi_disabled)
+-              return -ENODEV;
++        if (acpi_disabled)
++                return -ENODEV;
+       result = acpi_bus_register_driver(&acpi_wmi_driver);
+@@ -688,6 +588,13 @@
+               printk(KERN_INFO PREFIX "Mapper loaded\n");
+       }
++        dmi_sys_info = dmi_get_system_info(DMI_SYS_VENDOR);
++        if ( dmi_sys_info == NULL ) 
++                return result;
++
++        if ( strstr(dmi_sys_info, "Dell") != NULL ) 
++                enable_wmi_event_data_hack = TRUE;
++         
+       return result;
+ }
+diff -Nur linux-2.6-a/drivers/xen/acpi-wmi/acpi-wmi.c linux-2.6-b/drivers/xen/acpi-wmi/acpi-wmi.c
+--- linux-2.6-a/drivers/xen/acpi-wmi/acpi-wmi.c        1969-12-31 19:00:00.000000000 -0500
++++ linux-2.6-b/drivers/xen/acpi-wmi/acpi-wmi.c        2009-04-07 16:23:07.000000000 -0400
+@@ -0,0 +1,352 @@
++/******************************************************************************
++ * drivers/xen/acpi-wmi/acpi-wmi.c
++ * 
++ * Copyright (c) 2009 Kamala Narasimhan
++ * Copyright (c) 2009 Citrix Systems, Inc.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License version 2
++ * as published by the Free Software Foundation; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (the "Software"), to deal in the Software without
++ * restriction, including without limitation the rights to use, copy, modify,
++ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
++ * and to permit persons to whom the Software is furnished to do so, subject to
++ * the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
++ * IN THE SOFTWARE.
++ */
++
++/* Xen acpi-wmi implementation provides the interface required for userspace 
++ * module (qemu) to communicate with acpi wmi wrapper kernel driver.
++ * Upon receiving request from qemu to call a WMI method or query or set WMI
++ * data, it communicates the request to kernel acpi wmi layer which then 
++ * interacts with the base firmware to get the necessary information/execute
++ * relevant AML method etc.  The result returned by the base firmware is then
++ * communicated back to the userspace module (qemu). 
++ */
++
++#include <linux/module.h>
++#include <linux/miscdevice.h>
++#include <linux/acpi.h>
++#include <asm/uaccess.h>
++#include <xen/public/acpi-wmi.h>
++
++/* #define XEN_WMI_DEBUG */
++
++static bool xen_wmi_misc_dev_registered = false;
++static int xen_wmi_ioctl(struct inode *inode, struct file *filp, 
++                         unsigned int cmd, unsigned long arg);
++
++static struct file_operations xen_wmi_fops = {
++    .owner = THIS_MODULE,
++    .ioctl = xen_wmi_ioctl,
++};
++
++static struct miscdevice xen_wmi_misc = {
++        .minor    = MISC_DYNAMIC_MINOR,
++        .name     = XEN_WMI_DEVICE_NAME,
++        .fops     = &xen_wmi_fops,
++};
++
++/*
++ * xen_wmi_copy_input_buffer
++ */
++int xen_wmi_copy_input_buffer(xen_wmi_buffer_t *user_buf, struct acpi_buffer *acpi_buf)
++{
++    if ( user_buf->length <= 0 )
++        return XEN_WMI_SUCCESS; 
++
++    acpi_buf->pointer = kmalloc(user_buf->length, GFP_KERNEL);
++    if ( acpi_buf->pointer == NULL )
++    {
++        printk("XEN WMI: xen_wmi_copy_input_buffer - Buffer allocation failure\n");
++        return XEN_WMI_NOT_ENOUGH_MEMORY; 
++    }
++
++    if ( copy_from_user(acpi_buf->pointer,
++                        (char __user *)user_buf->pointer,
++                        user_buf->length) )
++    {
++        printk("XEN WMI: Unable to copy input buffer argument\n");
++        kfree(acpi_buf->pointer);
++        return XEN_WMI_EFAULT;
++    }
++
++    acpi_buf->length = user_buf->length; 
++    return XEN_WMI_SUCCESS; 
++}
++
++/*
++ * xen_wmi_copy_output_buffer
++ */
++int xen_wmi_copy_output_buffer(struct acpi_buffer *acpi_buf, xen_wmi_buffer_t *user_buf)
++{
++    /* IMPORTANT NOTE:  It is a little short sighted to assume that the return type
++     * will not be anything other than buffer type.  A follow-up check-in will
++     * cover more types. 
++     */
++
++    union acpi_object *acpi_obj = acpi_buf->pointer;
++
++    if ( acpi_obj == NULL )
++    {
++        printk("XEN WMI: Invalid acpi buffer!\n");
++        return XEN_WMI_EFAULT;
++    }
++
++    if ( acpi_obj->type != ACPI_TYPE_BUFFER )
++    {
++        printk("XEN WMI: Unsupported acpi return object type - %d\n", acpi_obj->type);
++        return XEN_WMI_UNSUPPORTED_TYPE;
++    }
++
++    if ( copy_to_user((char __user *) user_buf->copied_length, &acpi_obj->buffer.length, sizeof(size_t)) )
++    {
++        printk("XEN WMI: Invalid copied length user buffer!\n");
++        return XEN_WMI_INVALID_ARGUMENT;
++    }
++
++    if ( user_buf->length < acpi_obj->buffer.length ) 
++    {
++        printk("XEN WMI: Required buffer length is - %d\n", acpi_obj->buffer.length);
++        printk("XEN WMI: Passed in length is - %d\n", user_buf->length);
++        return XEN_WMI_BUFFER_TOO_SMALL;
++    }
++
++    if ( copy_to_user((char __user *) user_buf->pointer, acpi_obj->buffer.pointer, acpi_obj->buffer.length) )
++    {
++        printk("XEN WMI: Invalid user output buffer\n");
++        return XEN_WMI_NOT_ENOUGH_MEMORY; 
++    }
++
++    return XEN_WMI_SUCCESS; 
++} 
++
++#ifdef XEN_WMI_DEBUG
++
++/*
++ * xen_wmi_print_buffer
++ */
++void xen_wmi_print_buffer(struct acpi_buffer *acpi_buf)
++{
++    int count;
++    union acpi_object *acpi_obj = acpi_buf->pointer;
++
++    if ( acpi_obj == NULL || acpi_obj->type != ACPI_TYPE_BUFFER )
++    {
++        printk("XEN WMI: Unsupported output buffer data!\n");
++        return ;
++    }
++
++    printk("XEN WMI: Output buffer length is - %d\n", acpi_obj->buffer.length);
++    printk("XEN WMI:  Buffer:  ");
++    for (count=0; count < acpi_obj->buffer.length; count++)
++        printk("%d  ", ((byte *)(acpi_obj->buffer.pointer))[count]);
++    printk("\n");
++}
++
++#endif /* XEN_WMI_DEBUG */
++
++/*
++ * xen_wmi_invoke_method 
++ */
++int xen_wmi_invoke_method(xen_wmi_obj_invocation_data_t *obj_inv_data)
++{
++    int result;
++    struct acpi_buffer in_buf, *in_arg = NULL, out_buf = {ACPI_ALLOCATE_BUFFER, NULL};
++
++    result = xen_wmi_copy_input_buffer(&obj_inv_data->xen_wmi_arg.xen_wmi_method_arg.in_buf,
++                                       &in_buf); 
++    if ( result != XEN_WMI_SUCCESS )
++        return result;
++
++    if ( in_buf.length > 0 ) 
++        in_arg = &in_buf;
++
++    result = wmi_evaluate_method(obj_inv_data->guid, 
++                 obj_inv_data->xen_wmi_arg.xen_wmi_method_arg.instance, 
++                 obj_inv_data->xen_wmi_arg.xen_wmi_method_arg.method_id, 
++                 in_arg, &out_buf);
++
++    if ( in_arg != NULL )
++        kfree(in_buf.pointer);
++
++    if ( out_buf.length > 0  && result == XEN_WMI_SUCCESS )
++    {
++#ifdef XEN_WMI_DEBUG
++        xen_wmi_print_buffer(&out_buf);
++#endif
++        result = xen_wmi_copy_output_buffer(&out_buf,
++                                            &obj_inv_data->xen_wmi_arg.xen_wmi_method_arg.out_buf);
++        kfree(out_buf.pointer); 
++    }
++    else if ( result != XEN_WMI_SUCCESS )
++        printk("XEN WMI- Invoke WMI method failed with error - %d\n", result);
++
++    return result;
++} 
++
++/*
++ * xen_wmi_query_object
++ */
++int xen_wmi_query_object(xen_wmi_obj_invocation_data_t *obj_inv_data)
++{
++    int result; 
++    struct acpi_buffer out_buf = {ACPI_ALLOCATE_BUFFER, NULL};
++
++    result = wmi_query_block(obj_inv_data->guid, 
++                             obj_inv_data->xen_wmi_arg.xen_wmi_query_obj_arg.instance,
++                             &out_buf);
++
++    if ( out_buf.length > 0 && result == XEN_WMI_SUCCESS )
++    {
++#ifdef XEN_WMI_DEBUG
++        xen_wmi_print_buffer(&out_buf);
++#endif
++        result = xen_wmi_copy_output_buffer(&out_buf,
++                                            &obj_inv_data->xen_wmi_arg.xen_wmi_query_obj_arg.out_buf);
++        kfree(out_buf.pointer);
++    }
++    else
++        printk("XEN WMI - Query WMI object failed with error - %d; output buffer length - %d\n",
++               result, out_buf.length);
++
++    return result;
++}
++
++/*
++ * xen_wmi_set_object
++ */
++int xen_wmi_set_object(xen_wmi_obj_invocation_data_t *obj_inv_data) 
++{
++    int result;
++    struct acpi_buffer in_buf;
++
++    if ( obj_inv_data->xen_wmi_arg.xen_wmi_set_obj_arg.in_buf.length <= 0 )
++        return XEN_WMI_INVALID_ARGUMENT;
++
++    result = xen_wmi_copy_input_buffer(&obj_inv_data->xen_wmi_arg.xen_wmi_set_obj_arg.in_buf,
++                                       &in_buf);
++    if ( result != XEN_WMI_SUCCESS )
++        return result;
++
++    result = wmi_set_block(obj_inv_data->guid, 
++                           obj_inv_data->xen_wmi_arg.xen_wmi_set_obj_arg.instance,
++                           &in_buf); 
++    if ( result != XEN_WMI_SUCCESS )
++        printk("XEN WMI: Set object failed with error - %d\n", result);
++
++    kfree(in_buf.pointer);
++    return result;
++}
++
++/*
++ * xen_wmi_get_event_data 
++ */
++int xen_wmi_get_event_data(xen_wmi_obj_invocation_data_t *obj_inv_data) 
++{
++    int result;
++    struct acpi_buffer out_buf = {ACPI_ALLOCATE_BUFFER, NULL};
++
++    result = wmi_get_event_data(obj_inv_data->xen_wmi_arg.xen_wmi_event_data_arg.event_id,
++                       &out_buf);
++
++    if ( out_buf.length > 0 && result == XEN_WMI_SUCCESS )
++    {
++#ifdef XEN_WMI_DEBUG
++        xen_wmi_print_buffer(&out_buf);
++#endif
++        result = xen_wmi_copy_output_buffer(&out_buf,
++                                            &obj_inv_data->xen_wmi_arg.xen_wmi_event_data_arg.out_buf);
++        kfree(out_buf.pointer);
++    }
++    else
++        printk("XEN WMI: Get event data failed with error - %d\n", result);
++
++    return result;
++}
++
++/*
++ * xen_wmi_ioctl 
++ */
++static int xen_wmi_ioctl(struct inode *inode, struct file *filp,
++                         unsigned int cmd, unsigned long arg)
++{
++    xen_wmi_obj_invocation_data_t obj_inv_data;
++
++#ifdef XEN_WMI_DEBUG
++    printk("XEN WMI:  In xen_wmi_ioctl - %d\n", cmd);
++#endif
++
++    memset(&obj_inv_data, 0, sizeof(obj_inv_data));
++    if ( copy_from_user(&obj_inv_data, (char __user *)arg, sizeof(obj_inv_data)) )
++    {
++        printk("XEN WMI: Invalid object invocation parameter\n");
++        return XEN_WMI_EFAULT;
++    }
++ 
++    switch ( cmd ) 
++    {
++        case XEN_WMI_IOCTL_CALL_METHOD:
++            return xen_wmi_invoke_method(&obj_inv_data);
++        case XEN_WMI_IOCTL_QUERY_OBJECT:
++            return xen_wmi_query_object(&obj_inv_data); 
++        case XEN_WMI_IOCTL_SET_OBJECT:
++            return xen_wmi_set_object(&obj_inv_data); 
++        case XEN_WMI_IOCTL_GET_EVENT_DATA:
++            return xen_wmi_get_event_data(&obj_inv_data); 
++    }
++
++    return XEN_WMI_ENOIOCTLCMD;
++}
++
++/*
++ * xen_wmi_init 
++ */
++static int __init xen_wmi_init(void)
++{
++    int ret;
++
++    ret = misc_register(&xen_wmi_misc);
++    if ( ret < 0 )
++        printk("XEN WMI: misc_register failed with error - %d\n", ret);
++    else
++        xen_wmi_misc_dev_registered = true;
++
++#ifdef XEN_WMI_DEBUG
++    printk("XEN WMI: xen-acpi-wmi misc_register succeeded!\n"); 
++#endif
++    return ret;
++}
++
++/*
++ * xen_wmi_exit 
++ */
++static void xen_wmi_exit(void)
++{
++    int ret;
++
++    if ( xen_wmi_misc_dev_registered == false )
++        return;
++
++    if ( (ret = misc_deregister(&xen_wmi_misc)) < 0 )
++        printk("XEN WMI: misc_deregister failed with error - %d\n", ret); 
++}
++
++module_init(xen_wmi_init);
++module_exit(xen_wmi_exit);
++MODULE_LICENSE("Dual BSD/GPL");
++
+diff -Nur linux-2.6-a/drivers/xen/acpi-wmi/Makefile linux-2.6-b/drivers/xen/acpi-wmi/Makefile
+--- linux-2.6-a/drivers/xen/acpi-wmi/Makefile  1969-12-31 19:00:00.000000000 -0500
++++ linux-2.6-b/drivers/xen/acpi-wmi/Makefile  2009-04-07 16:23:07.000000000 -0400
+@@ -0,0 +1,2 @@
++
++obj-y := acpi-wmi.o
+diff -Nur linux-2.6-a/drivers/xen/Kconfig linux-2.6-b/drivers/xen/Kconfig
+--- linux-2.6-a/drivers/xen/Kconfig    2009-04-07 16:51:58.000000000 -0400
++++ linux-2.6-b/drivers/xen/Kconfig    2009-04-07 16:25:37.000000000 -0400
+@@ -265,6 +265,13 @@
+         Specify the total number of virtual devices (i.e. both frontend
+         and backend) that you want the kernel to be able to service.
++config XEN_ACPI_WMI_WRAPPER
++        tristate "Xen ACPI WMI wrapper driver"
++        depends on ACPI_WMI
++        help
++          Facilitates OEM specific hotkey implementation within
++          guest space.
++
+ choice
+       prompt "Xen version compatibility"
+       default XEN_COMPAT_030002_AND_LATER
+diff -Nur linux-2.6-a/drivers/xen/Makefile linux-2.6-b/drivers/xen/Makefile
+--- linux-2.6-a/drivers/xen/Makefile   2009-04-07 16:52:14.000000000 -0400
++++ linux-2.6-b/drivers/xen/Makefile   2009-04-07 16:26:11.000000000 -0400
+@@ -30,3 +30,4 @@
+ obj-$(CONFIG_XEN_NETDEV_ACCEL_SFC_UTIL)               += sfc_netutil/
+ obj-$(CONFIG_XEN_NETDEV_ACCEL_SFC_FRONTEND)   += sfc_netfront/
+ obj-$(CONFIG_XEN_NETDEV_ACCEL_SFC_BACKEND)    += sfc_netback/
++obj-$(CONFIG_XEN_ACPI_WMI_WRAPPER)              += acpi-wmi/
+diff -Nur linux-2.6-a/include/xen/public/acpi-wmi.h linux-2.6-b/include/xen/public/acpi-wmi.h
+--- linux-2.6-a/include/xen/public/acpi-wmi.h  1969-12-31 19:00:00.000000000 -0500
++++ linux-2.6-b/include/xen/public/acpi-wmi.h  2009-04-07 16:44:29.000000000 -0400
+@@ -0,0 +1,94 @@
++/******************************************************************************
++ * acpi-wmi.h
++ *
++ * Interface to /proc/misc/xen-acpi-wmi
++ *
++ * Copyright (c) 2009 Kamala Narasimhan
++ * Copyright (c) 2009 Citrix Systems, Inc.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License version 2
++ * as published by the Free Software Foundation; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (the "Software"), to deal in the Software without
++ * restriction, including without limitation the rights to use, copy, modify,
++ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
++ * and to permit persons to whom the Software is furnished to do so, subject to
++ * the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
++ * IN THE SOFTWARE.
++ */
++
++
++#ifndef _XEN_WMI_ACPI
++#define _XEN_WMI_ACPI
++
++/*
++ * Userspace Interface
++ */
++
++#define XEN_WMI_DEVICE_NAME              "xen-acpi-wmi"
++#define XEN_WMI_GUID_SIZE                16
++
++#define XEN_WMI_SUCCESS                  0
++#define XEN_WMI_UNSUPPORTED_TYPE        -1
++#define XEN_WMI_BUFFER_TOO_SMALL        -11
++#define XEN_WMI_NOT_ENOUGH_MEMORY       -12
++#define XEN_WMI_EFAULT                  -14
++#define XEN_WMI_INVALID_ARGUMENT        -22
++#define XEN_WMI_ENOIOCTLCMD             -515
++ 
++#define XEN_WMI_IOCTL_CALL_METHOD        100
++#define XEN_WMI_IOCTL_QUERY_OBJECT       101
++#define XEN_WMI_IOCTL_SET_OBJECT         102
++#define XEN_WMI_IOCTL_GET_EVENT_DATA     103
++
++typedef unsigned char byte;
++
++typedef struct xen_wmi_buffer {
++    size_t       length; 
++    void        *pointer;
++    size_t      *copied_length;
++} xen_wmi_buffer_t;
++
++typedef struct xen_wmi_obj_invocation_data { 
++    byte                       guid[XEN_WMI_GUID_SIZE];
++    union {
++        struct {
++            ushort             instance;
++            uint               method_id;
++            xen_wmi_buffer_t   in_buf;
++            xen_wmi_buffer_t   out_buf;
++        } xen_wmi_method_arg;
++
++        struct {
++            ushort             instance;
++            xen_wmi_buffer_t   out_buf;
++        } xen_wmi_query_obj_arg;
++
++        struct {
++            ushort             instance;
++            xen_wmi_buffer_t   in_buf;
++        } xen_wmi_set_obj_arg;
++
++        struct {
++            ushort             event_id;
++            xen_wmi_buffer_t   out_buf;
++        } xen_wmi_event_data_arg;
++    } xen_wmi_arg;
++} xen_wmi_obj_invocation_data_t;
++
++#endif /* _XEN_WMI_ACPI */
++