On Mon, Jun 8, 2009 at 6:36 AM, Beng Heng, Ng <bengheng@xxxxxxxxxxxxxx> wrote:
> Certainly. I tried this on Xen 3.4.1 rc1 pre, changeset 19645. Most of
> these stuff are from Jean and his team. Hopefully more people can update
> their results.
>
> - Beng Heng
>
> Jun Koi wrote:
>> Hi Beng,
>>
>> Would you please send the patch you applied on top of Xen to the list?
>> I think many people are interested in that.
>>
>> Thanks,
>> Jun
>>
>>
>>
>
>
> diff -rupN --ignore-blank-lines-X diffignore
> a/linux-2.6.18-xen.hg/drivers/xen/pciback/controller.c
> b/linux-2.6.18-xen.hg/drivers/xen/pciback/controller.c
> --- a/linux-2.6.18-xen.hg/drivers/xen/pciback/controller.c 2009-06-07
> 20:48:21.000000000 -0400
> +++ b/linux-2.6.18-xen.hg/drivers/xen/pciback/controller.c 2009-06-07
> 19:04:11.000000000 -0400
> @@ -208,7 +208,7 @@ void pciback_release_pci_dev(struct pcib
> }
>
> 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 pcib
> 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 -rupN --ignore-blank-lines-X diffignore
> a/linux-2.6.18-xen.hg/drivers/xen/pciback/passthrough.c
> b/linux-2.6.18-xen.hg/drivers/xen/pciback/passthrough.c
> --- a/linux-2.6.18-xen.hg/drivers/xen/pciback/passthrough.c 2009-06-07
> 20:48:21.000000000 -0400
> +++ b/linux-2.6.18-xen.hg/drivers/xen/pciback/passthrough.c 2009-06-07
> 19:04:11.000000000 -0400
> @@ -88,7 +88,7 @@ void pciback_release_pci_dev(struct pcib
> 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 pcib
>
> 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 -rupN --ignore-blank-lines-X diffignore
> a/linux-2.6.18-xen.hg/drivers/xen/pciback/pciback.h
> b/linux-2.6.18-xen.hg/drivers/xen/pciback/pciback.h
> --- a/linux-2.6.18-xen.hg/drivers/xen/pciback/pciback.h 2009-06-07
> 20:48:21.000000000 -0400
> +++ b/linux-2.6.18-xen.hg/drivers/xen/pciback/pciback.h 2009-06-07
> 19:04:11.000000000 -0400
> @@ -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_s
> 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 pcib
> irqreturn_t pciback_handle_event(int irq, void *dev_id, struct pt_regs
> *regs);
> void pciback_do_op(void *data);
>
> +/* 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 -rupN --ignore-blank-lines-X diffignore
> a/linux-2.6.18-xen.hg/drivers/xen/pciback/pciback_ops.c
> b/linux-2.6.18-xen.hg/drivers/xen/pciback/pciback_ops.c
> --- a/linux-2.6.18-xen.hg/drivers/xen/pciback/pciback_ops.c 2009-06-07
> 20:48:21.000000000 -0400
> +++ b/linux-2.6.18-xen.hg/drivers/xen/pciback/pciback_ops.c 2009-06-07
> 19:04:11.000000000 -0400
> @@ -5,20 +5,189 @@
> */
> #include <linux/module.h>
> #include <linux/wait.h>
> +#include <linux/delay.h> /* For mdelay function */
> #include <asm/bitops.h>
> #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 +207,425 @@ void pciback_reset_device(struct pci_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, ®32);
> + 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, ®8);
> + 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, ®8);
> + 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 +720,51 @@ irqreturn_t pciback_handle_event(int irq
>
> 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 -rupN --ignore-blank-lines-X diffignore
> a/linux-2.6.18-xen.hg/drivers/xen/pciback/pci_stub.c
> b/linux-2.6.18-xen.hg/drivers/xen/pciback/pci_stub.c
> --- a/linux-2.6.18-xen.hg/drivers/xen/pciback/pci_stub.c 2009-06-07
> 20:48:21.000000000 -0400
> +++ b/linux-2.6.18-xen.hg/drivers/xen/pciback/pci_stub.c 2009-06-07
> 19:04:11.000000000 -0400
> @@ -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_de
> 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(stru
> 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
> * 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
> 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(s
> 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(struc
>
> 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
> * 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
> 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(struc
>
> 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 cha
> 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 dom
> 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 dom
> 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
> 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, i
> 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 d
> 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(struc
> 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
>
> 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
>
> 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 dev
> 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 de
> 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;
> - }
> + /* 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 = pcistub_device_id_add(domain, bus, slot, func);
> - 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;
>
> - /* if parsed<=0, we've reached the end of the string
> */
> - pos += parsed;
> - } while (parsed > 0 && pci_devs_to_hide[pos]);
> - }
> + 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 -rupN --ignore-blank-lines-X diffignore
> a/linux-2.6.18-xen.hg/drivers/xen/pciback/slot.c
> b/linux-2.6.18-xen.hg/drivers/xen/pciback/slot.c
> --- a/linux-2.6.18-xen.hg/drivers/xen/pciback/slot.c 2009-06-07
> 20:48:21.000000000 -0400
> +++ b/linux-2.6.18-xen.hg/drivers/xen/pciback/slot.c 2009-06-07
> 19:04:11.000000000 -0400
> @@ -109,7 +109,7 @@ void pciback_release_pci_dev(struct pcib
> 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 pcib
> 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 -rupN --ignore-blank-lines-X diffignore
> a/linux-2.6.18-xen.hg/drivers/xen/pciback/vpci.c
> b/linux-2.6.18-xen.hg/drivers/xen/pciback/vpci.c
> --- a/linux-2.6.18-xen.hg/drivers/xen/pciback/vpci.c 2009-06-07
> 20:48:21.000000000 -0400
> +++ b/linux-2.6.18-xen.hg/drivers/xen/pciback/vpci.c 2009-06-07
> 19:04:11.000000000 -0400
> @@ -162,7 +162,7 @@ void pciback_release_pci_dev(struct pcib
> 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 pcib
> 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 -rupN --ignore-blank-lines-X diffignore
> a/linux-2.6.18-xen.hg/include/linux/pci_ids.h
> b/linux-2.6.18-xen.hg/include/linux/pci_ids.h
> --- a/linux-2.6.18-xen.hg/include/linux/pci_ids.h 2009-06-07
> 20:48:23.000000000 -0400
> +++ b/linux-2.6.18-xen.hg/include/linux/pci_ids.h 2009-06-07
> 19:04:11.000000000 -0400
> @@ -2259,6 +2259,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 -rupN --ignore-blank-lines-X diffignore
> a/linux-2.6.18-xen.hg/include/linux/pci_regs.h
> b/linux-2.6.18-xen.hg/include/linux/pci_regs.h
> --- a/linux-2.6.18-xen.hg/include/linux/pci_regs.h 2009-06-07
> 20:48:23.000000000 -0400
> +++ b/linux-2.6.18-xen.hg/include/linux/pci_regs.h 2009-06-07
> 19:04:11.000000000 -0400
> @@ -201,6 +201,7 @@
> #define PCI_CAP_ID_SHPC 0x0C /* PCI Standard Hot-Plug Controller */
> #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
> @@ -229,6 +230,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
> (??) */
> @@ -346,6 +352,7 @@
> #define PCI_EXP_DEVCAP_PWR_IND 0x4000 /* Power Indicator Present */
> #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 */
> @@ -358,6 +365,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 */
> @@ -482,6 +490,17 @@
> #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
> +
> /* Single Root I/O Virtualization */
> #define PCI_SRIOV_CAP 0x04 /* SR-IOV Capabilities */
> #define PCI_SRIOV_CAP_VFM 0x01 /* VF Migration Capable */
> diff -rupN --ignore-blank-lines-X diffignore
> a/tools/firmware/hvmloader/hvmloader.c b/tools/firmware/hvmloader/hvmloader.c
> --- a/tools/firmware/hvmloader/hvmloader.c 2009-06-07 20:44:47.000000000
> -0400
> +++ b/tools/firmware/hvmloader/hvmloader.c 2009-06-07 19:04:11.000000000
> -0400
> @@ -673,6 +673,7 @@ int main(void)
> break;
> default:
> printf("No emulated VGA adaptor ...\n");
> + vgabios_sz = round_option_rom((*(uint8_t
> *)(VGABIOS_PHYSICAL_ADDRESS+2)) * 512);
> break;
> }
>
> diff -rupN --ignore-blank-lines-X diffignore a/tools/ioemu-remote/console.h
> b/tools/ioemu-remote/console.h
> --- a/tools/ioemu-remote/console.h 2009-06-07 21:14:47.000000000 -0400
> +++ b/tools/ioemu-remote/console.h 2009-06-07 19:04:11.000000000 -0400
> @@ -290,6 +290,9 @@ void vga_hw_update(void);
> void vga_hw_invalidate(void);
> void vga_hw_screen_dump(const char *filename);
>
> +void unset_vga_acc(void);
> +void set_vga_acc(void);
> +
> int is_graphic_console(void);
> int is_fixedsize_console(void);
> CharDriverState *text_console_init(const char *p);
> @@ -341,4 +344,9 @@ const char *readline_get_history(unsigne
> void readline_start(const char *prompt, int is_password,
> ReadLineFunc *readline_func, void *opaque);
>
> +/* intel.c */
> +int intel_enter(void);
> +int intel_leave(void);
> +void intel_display_init(DisplayState *ds);
> +
> #endif
> diff -rupN --ignore-blank-lines-X diffignore
> a/tools/ioemu-remote/hw/pass-through.c b/tools/ioemu-remote/hw/pass-through.c
> --- a/tools/ioemu-remote/hw/pass-through.c 2009-06-07 21:14:48.000000000
> -0400
> +++ b/tools/ioemu-remote/hw/pass-through.c 2009-06-07 19:04:11.000000000
> -0400
> @@ -90,6 +90,8 @@
> #include "qemu-xen.h"
> #include <unistd.h>
>
> +extern int vga_passthrough;
> +
> struct php_dev {
> struct pt_dev *pt_dev;
> uint8_t valid;
> @@ -1573,10 +1575,11 @@ static int pt_dev_is_virtfn(struct pci_d
>
> static int pt_register_regions(struct pt_dev *assigned_device)
> {
> - int i = 0;
> + int i = 0, ret = 0;
> uint32_t bar_data = 0;
> struct pci_dev *pci_dev = assigned_device->pci_dev;
> PCIDevice *d = &assigned_device->dev;
> + uint16_t class, vendor_id;
>
> /* Register PIO/MMIO BARs */
> for ( i = 0; i < PCI_BAR_ENTRIES; i++ )
> @@ -1632,6 +1635,25 @@ static int pt_register_regions(struct pt
> (uint32_t)(pci_dev->rom_size),
> (uint32_t)(pci_dev->rom_base_addr));
> }
>
> + /* Map legacy ioport and iomem, for specific devices */
> + vendor_id = pci_read_word(pci_dev, 0x00);
> + class = pci_read_word(pci_dev, 0x0a);
> +
> + PT_LOG("Real device vendor_id=0x%x class=0x%x\n", vendor_id, class);
> + if ( vga_passthrough && class == 0x0300 )
> + {
> + PT_LOG("add an intel graphic card\n");
> +
> + ret = xc_domain_ioport_mapping(xc_handle, domid, 0x3B0, 0x3B0, 0xb,
> DPCI_ADD_MAPPING);
> + ret = xc_domain_ioport_mapping(xc_handle, domid, 0x3C0, 0x3C0, 32,
> DPCI_ADD_MAPPING);
> + ret |= xc_domain_memory_mapping(xc_handle, domid, 0xa0, 0xa0, 32,
> DPCI_ADD_MAPPING);
> + if ( ret != 0 )
> + {
> + PT_LOG("legacy mapping failed!\n");
> + return ret;
> + }
> + }
> +
> return 0;
> }
>
> @@ -1640,6 +1662,7 @@ static void pt_unregister_regions(struct
> int i, type, ret;
> uint32_t e_size;
> PCIDevice *d = (PCIDevice*)assigned_device;
> + uint16_t class, vendor_id;
>
> for ( i = 0; i < PCI_NUM_REGIONS; i++ )
> {
> @@ -1681,6 +1704,24 @@ static void pt_unregister_regions(struct
>
> }
>
> + /* unmap legacy ioport and iomem, for specific devices */
> + vendor_id = pci_read_word(assigned_device->pci_dev, 0x00);
> + class = pci_read_word(assigned_device->pci_dev, 0x0a);
> +
> + PT_LOG("Real device vendor_id=0x%x class=0x%x\n", vendor_id, class);
> + if ( vga_passthrough && class == 0x0300 )
> + {
> + PT_LOG("remove an intel graphic card\n");
> +
> + ret = xc_domain_ioport_mapping(xc_handle, domid, 0x3B0, 0x3B0, 0xb,
> DPCI_REMOVE_MAPPING);
> + ret = xc_domain_ioport_mapping(xc_handle, domid, 0x3C0, 0x3C0, 32,
> DPCI_REMOVE_MAPPING);
> + ret |= xc_domain_memory_mapping(xc_handle, domid, 0xa0, 0xa0, 32,
> DPCI_REMOVE_MAPPING);
> + if ( ret != 0 )
> + {
> + PT_LOG("legacy unmapping failed !\n");
> + }
> + }
> +
> }
>
> static uint8_t find_cap_offset(struct pci_dev *pci_dev, uint8_t cap)
> @@ -3759,7 +3800,7 @@ static struct pt_dev * register_real_dev
> struct pci_config_cf8 machine_bdf;
> char *key, *val;
> int msi_translate, power_mgmt;
> -
> +
> PT_LOG("Assigning real physical device %02x:%02x.%x ...\n",
> r_bus, r_dev, r_func);
>
> @@ -3931,7 +3972,7 @@ static struct pt_dev * register_real_dev
> }
>
> out:
> - PT_LOG("Real physical device %02x:%02x.%x registered successfuly!\n"
> + PT_LOG("Real physical device %02x:%02x.%x registered successfully!\n"
> "IRQ type = %s\n", r_bus, r_dev, r_func,
> assigned_device->msi_trans_en? "MSI-INTx":"INTx");
>
> @@ -4113,3 +4154,47 @@ err:
> return status;
> }
>
> +u8 pt_pci_host_read_byte(int bus, int dev, int fn, u32 addr)
> +{
> + struct pci_dev *pci_dev;
> + u8 val;
> +
> + pci_dev = pci_get_dev(dpci_infos.pci_access, 0, bus, dev, fn);
> + if (!pci_dev)
> + return 0;
> +
> + val = pci_read_byte(pci_dev, addr);
> + pci_free_dev(pci_dev);
> +
> + return val;
> +}
> +
> +u16 pt_pci_host_read_word(int bus, int dev, int fn, u32 addr)
> +{
> + struct pci_dev *pci_dev;
> + u16 val;
> +
> + pci_dev = pci_get_dev(dpci_infos.pci_access, 0, bus, dev, fn);
> + if (!pci_dev)
> + return 0;
> +
> + val = pci_read_word(pci_dev, addr);
> + pci_free_dev(pci_dev);
> +
> + return val;
> +}
> +
> +u32 pt_pci_host_read_long(int bus, int dev, int fn, u32 addr)
> +{
> + struct pci_dev *pci_dev;
> + u32 val;
> +
> + pci_dev = pci_get_dev(dpci_infos.pci_access, 0, bus, dev, fn);
> + if (!pci_dev)
> + return 0;
> +
> + val = pci_read_long(pci_dev, addr);
> + pci_free_dev(pci_dev);
> +
> + return val;
> +}
> diff -rupN --ignore-blank-lines-X diffignore a/tools/ioemu-remote/hw/pc.c
> b/tools/ioemu-remote/hw/pc.c
> --- a/tools/ioemu-remote/hw/pc.c 2009-06-07 21:14:47.000000000 -0400
> +++ b/tools/ioemu-remote/hw/pc.c 2009-06-07 19:04:11.000000000 -0400
> @@ -65,6 +65,8 @@ void tpm_tis_init(SetIRQFunc *set_irq, v
> extern uint8_t *acpi_tables;
> extern size_t acpi_tables_len;
>
> +extern int vga_passthrough;
> +
> static fdctrl_t *floppy_controller;
> static RTCState *rtc_state;
> static PITState *pit;
> @@ -984,6 +986,7 @@ vga_bios_error:
>
> register_ioport_write(0xf0, 1, 1, ioportF0_write, NULL);
>
> + if (!vga_passthrough) {
> if (cirrus_vga_enabled) {
> if (pci_enabled) {
> pci_cirrus_vga_init(pci_bus,
> @@ -1010,6 +1013,7 @@ vga_bios_error:
> vga_ram_addr, vga_ram_size);
> }
> }
> + }
>
> #ifdef CONFIG_PASSTHROUGH
> /* Pass-through Initialization
> diff -rupN --ignore-blank-lines-X diffignore a/tools/ioemu-remote/hw/pci.c
> b/tools/ioemu-remote/hw/pci.c
> --- a/tools/ioemu-remote/hw/pci.c 2009-06-07 21:14:47.000000000 -0400
> +++ b/tools/ioemu-remote/hw/pci.c 2009-06-07 19:04:11.000000000 -0400
> @@ -28,11 +28,14 @@
> #include "virtio-net.h"
> #include "sysemu.h"
>
> +#include "pass-through.h"
> #include "exec-all.h"
> #include "qemu-xen.h"
>
> //#define DEBUG_PCI
>
> +extern int vga_passthrough;
> +
> struct PCIBus {
> int bus_num;
> int devfn_min;
> @@ -611,7 +614,24 @@ uint32_t pci_data_read(void *opaque, uin
> goto the_end;
> }
> config_addr = addr & 0xff;
> - val = pci_dev->config_read(pci_dev, config_addr, len);
> + if (vga_passthrough && pci_dev->devfn == 0x00) //Host Bridge
> + {
> + val = pci_dev->config_read(pci_dev, config_addr, len);
> +
> + if (config_addr == 0x52) // GMCH
> + val = pt_pci_host_read_word(0, 0, 0, 0x52);
> + if (config_addr == 0x02) // Device ID
> + {
> + if (len == 2)
> + val = pt_pci_host_read_word(0, 0, 0, 0x00);
> + else if (len == 4)
> + val = pt_pci_host_read_long(0, 0, 0, 0x00);
> + }
> + } else if (vga_passthrough && pci_dev->devfn == 0x10 && // intel graphic
> card
> + config_addr == 0xfc) // OpRegion address
> + val = 0; // force to fall back to SMI mode
> + else
> + val = pci_dev->config_read(pci_dev, config_addr, len);
> #if defined(DEBUG_PCI)
> printf("pci_config_read: %s: addr=%02x val=%08x len=%d\n",
> pci_dev->name, config_addr, val, len);
> diff -rupN --ignore-blank-lines-X diffignore a/tools/ioemu-remote/hw/vga.c
> b/tools/ioemu-remote/hw/vga.c
> --- a/tools/ioemu-remote/hw/vga.c 2009-06-07 21:14:47.000000000 -0400
> +++ b/tools/ioemu-remote/hw/vga.c 2009-06-07 19:04:11.000000000 -0400
> @@ -34,9 +34,9 @@
>
> #include "qemu-timer.h"
>
> -//#define DEBUG_VGA
> -//#define DEBUG_VGA_MEM
> -//#define DEBUG_VGA_REG
> +#define DEBUG_VGA
> +#define DEBUG_VGA_MEM
> +#define DEBUG_VGA_REG
>
> //#define DEBUG_BOCHS_VBE
>
> @@ -161,6 +161,18 @@ static uint8_t expand4to8[16];
> static void vga_bios_init(VGAState *s);
> static void vga_screen_dump(void *opaque, const char *filename);
>
> +static VGAState *xen_vga_state;
> +
> +void set_vga_acc(void)
> +{
> + set_vram_mapping(xen_vga_state, xen_vga_state->lfb_addr,
> xen_vga_state->lfb_end);
> +}
> +
> +void unset_vga_acc(void)
> +{
> + unset_vram_mapping(xen_vga_state);
> +}
> +
> static void vga_dumb_update_retrace_info(VGAState *s)
> {
> (void) s;
> @@ -2473,8 +2485,6 @@ static void vga_bios_init(VGAState *s)
> }
>
>
> -static VGAState *xen_vga_state;
> -
> /* Allocate video memory in the GPFN space */
> void xen_vga_populate_vram(uint64_t vram_addr, uint32_t vga_ram_size)
> {
> diff -rupN --ignore-blank-lines-X diffignore a/tools/ioemu-remote/intel.c
> b/tools/ioemu-remote/intel.c
> --- a/tools/ioemu-remote/intel.c 1969-12-31 19:00:00.000000000 -0500
> +++ b/tools/ioemu-remote/intel.c 2009-06-07 19:04:11.000000000 -0400
> @@ -0,0 +1,494 @@
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <stdint.h>
> +#include <sys/mman.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <fcntl.h>
> +#include <assert.h>
> +#include <signal.h>
> +#include <pci/pci.h>
> +
> +#include "qemu-common.h"
> +#include "console.h"
> +#include "sysemu.h"
> +
> +#define INTEL_DEBUG(format, args...) \
> + fprintf (stderr, "intel.c:%d:%s " format , __LINE__, __func__, ## args)
> +
> +#define TileW 128
> +#define TileH 8
> +
> +#define REG_DR_DSPASURF 0x7019C
> +#define REG_DR_DSPACNTR 0x70180
> +#define REG_DR_DSPASTRIDE 0x70188
> +#define REG_DR_PIPEACONF 0x70008
> +
> +#define REG_DR_DSPBSURF 0x7119C
> +#define REG_DR_DSPBCNTR 0x71180
> +#define REG_DR_DSPBSTRIDE 0x71188
> +#define REG_DR_PIPEBCONF 0x71008
> +
> +#define REG_DE_PIPEASRC 0x6001c
> +
> +extern int vga_passthrough;
> +uint32_t guest_framebuffer;
> +
> +static int display = 0;
> +
> +static int mmio_fd = -1;
> +static int mem_fd = -1;
> +static uint8_t *intel_mem = NULL;
> +static uint8_t *intel_mmio = NULL;
> +static int intel_force_full_update = 0;
> +static int intel_have_focus;
> +static int IntelPitch = 16;
> +static int IntelX = 1280;
> +static int IntelY = 1024;
> +static DisplayState *lds = NULL;
> +static uint8_t *old_data = NULL;
> +static uint32_t intel_fb_base, intel_mmio_base;
> +static uint32_t map_s, map_d, map_size;
> +static int refresh;
> +
> +static void set_data_mappings(void);
> +static void unset_data_mappings(int mapping);
> +static void set_data_pointer(void);
> +static void intel_resize(DisplayState *ds);
> +
> +static inline unsigned int intel_get_reg(unsigned int reg)
> +{
> + return *(unsigned int*)(intel_mmio + reg);
> +}
> +
> +static inline int is_linear(void)
> +{
> + unsigned int *dspacntr = (unsigned int *)(intel_mmio + REG_DR_DSPACNTR);
> + if (((*dspacntr) & (1 << 10)) == 0)
> + return 1;
> + else
> + return 0;
> +}
> +
> +static inline unsigned int intel_get_pitch(void)
> +{
> + unsigned int *dspastride = (unsigned int *)(intel_mmio +
> REG_DR_DSPASTRIDE);
> + return *dspastride;
> +}
> +
> +static inline unsigned int intel_get_offset(DisplaySurface *ds, int x, int y)
> +{
> + return (y * ds->width + x) * 4;
> +}
> +
> +static void intel_update_linear(DisplaySurface *ds, int x, int y, int w, int
> h)
> +{
> + int i, bpp = ds->pf.depth / 8;
> + unsigned char *s, *d;
> + s = ds->data;
> + d = (unsigned char *)(intel_mem + intel_get_reg(REG_DR_DSPASURF));
> + s += (ds->linesize * y) + bpp * x;
> + d += (ds->linesize * y) + bpp * x;
> + for (i = 0; i < h; i++) {
> + memcpy(d, s, w * bpp);
> + s += ds->linesize;
> + d += ds->linesize;
> + }
> +}
> +
> +static void intel_force_linear(int linesize)
> +{
> + unsigned int *dspacntr = (unsigned int *)(intel_mmio + REG_DR_DSPACNTR);
> + unsigned int *pipeaconf = (unsigned int *)(intel_mmio +
> REG_DR_PIPEACONF);
> + unsigned int *dspasurf = (unsigned int *)(intel_mmio + REG_DR_DSPASURF);
> + unsigned int *dspastride = (unsigned int *)(intel_mmio +
> REG_DR_DSPASTRIDE);
> +
> + unsigned int *dspbcntr = (unsigned int *)(intel_mmio + REG_DR_DSPBCNTR);
> + unsigned int *pipebconf = (unsigned int *)(intel_mmio +
> REG_DR_PIPEBCONF);
> + unsigned int *dspbsurf = (unsigned int *)(intel_mmio + REG_DR_DSPBSURF);
> + unsigned int *dspbstride = (unsigned int *)(intel_mmio +
> REG_DR_DSPBSTRIDE);
> +
> + unsigned int surfa = 0, surfb = 0, pipea = 0, pipeb = 0;
> + char pipebenabled = !!(*pipebconf & (1 << 30));
> +
> +
> + INTEL_DEBUG("DSPASURF CTRL: 0x%x\n", intel_get_reg(REG_DR_DSPACNTR));
> +
> + /* Disable surface */
> + pipea = *pipeaconf & (0x3 << 18);
> + *pipeaconf &= ~(0x3 << 18);
> + *dspacntr |= (1 << 31);
> + /* Address of the surface to map to */
> + surfa = *dspasurf;
> + *dspasurf = 0x00000000;
> + *dspacntr &= ~(1 << 31);
> + *dspasurf = 0x00000000;
> + *pipeaconf |= pipea;
> +
> + if (pipebenabled) {
> + INTEL_DEBUG("PIPEBCONF enabled.\n");
> +
> + /* Disable surface */
> + pipeb = *pipebconf & (0x3 << 18);
> + *pipebconf &= ~(0x3 << 18);
> + *dspbcntr |= (1 << 31);
> + /* Address of the surface to map to */
> + surfb = *dspbsurf;
> + *dspbsurf = 0x00000000;
> + *dspbcntr &= ~(1 << 31);
> + *dspbsurf = 0x00000000;
> + *pipebconf |= pipeb;
> + }
> +
> + usleep(20000);
> +
> + *pipeaconf &= ~(0x3 << 18);
> + /* Enable surface linear mode */
> + *dspacntr &= ~(1 << 10);
> + if (linesize) *dspastride = linesize;
> + *dspasurf = surfa;
> + *dspacntr |= (1 << 31);
> + *pipeaconf |= pipea;
> +
> + if (pipebenabled) {
> + *pipebconf &= ~(0x3 << 18);
> + /* Enable surface linear mode */
> + *dspbcntr &= ~(1 << 10);
> + if (linesize) *dspbstride = linesize;
> + *dspbsurf = surfb;
> + *dspbcntr |= (1 << 31);
> + *pipebconf |= pipeb;
> + }
> +
> + usleep(20000);
> +}
> +
> +static void intel_update(DisplayState *ds, int x, int y, int w, int h)
> +{
> + if (intel_have_focus && !old_data && !map_size)
> + intel_update_linear(ds->surface, x, y, w, h);
> +}
> +
> +static void set_fb_mapping(void)
> +{
> + DisplaySurface *surf = lds->surface;
> + int rc;
> + unsigned long nr_pfn;
> +
> + unset_vga_acc();
> + fprintf(stderr, "set_fb_mapping: %x %x\n", (intel_fb_base +
> intel_get_reg(REG_DR_DSPASURF)), guest_framebuffer);
> + nr_pfn = (surf->linesize * surf->height) >> TARGET_PAGE_BITS;
> +
> + rc = xc_domain_memory_mapping(xc_handle,
> + domid,
> + (guest_framebuffer >> TARGET_PAGE_BITS),
> + ((intel_fb_base + intel_get_reg(REG_DR_DSPASURF)) >>
> TARGET_PAGE_BITS),
> + nr_pfn,
> + DPCI_ADD_MAPPING);
> + if (rc) {
> + fprintf(stderr, "xc_domain_memory_mapping failed %d\n", rc);
> + return;
> + }
> + map_s = ((intel_fb_base + intel_get_reg(REG_DR_DSPASURF)) >>
> TARGET_PAGE_BITS);
> + map_d = (guest_framebuffer >> TARGET_PAGE_BITS);
> + map_size = nr_pfn;
> +}
> +
> +static void unset_fb_mapping(void)
> +{
> + int rc;
> +
> + fprintf(stderr, "unset_fb_mapping: %x %x\n", map_d, map_s);
> +
> + rc = xc_domain_memory_mapping(xc_handle,
> + domid,
> + map_d,
> + map_s,
> + map_size,
> + DPCI_REMOVE_MAPPING);
> + if (rc) {
> + fprintf(stderr, "xc_domain_memory_mapping failed %d\n", rc);
> + return;
> + }
> +
> + set_vga_acc();
> + map_s = 0;
> + map_d = 0;
> + map_size = 0;
> +}
> +
> +static void intel_setdata(DisplayState *ds)
> +{
> + if (map_size)
> + unset_fb_mapping();
> + set_fb_mapping();
> +}
> +
> +static void intel_resize_shared(DisplayState *ds, int w, int h, int depth,
> int linesize, void *pixels)
> +{
> + DisplaySurface *surf = ds->surface;
> +
> + if (!intel_have_focus) {
> + surf->width = w;
> + surf->height = h;
> + intel_resize(ds);
> + return;
> + }
> + if (depth == 32 && w == IntelX && h == IntelY)
> + surf->flags = QEMU_ALLOCATED_FLAG;
> + else
> + surf->flags &= ~QEMU_ALLOCATED_FLAG;
> + if (surf->flags & QEMU_ALLOCATED_FLAG) {
> + surf->width = w;
> + surf->height = h;
> + surf->pf.depth = 32;
> + surf->linesize = linesize;
> + /* adjust linesize */
> + intel_force_linear(linesize);
> + set_data_mappings();
> + if (refresh) {
> + memcpy(surf->data, pixels, surf->linesize * surf->height);
> + refresh = 0;
> + }
> + surf->data = pixels;
> + intel_setdata(ds);
> + } else {
> + surf->width = w;
> + surf->height = h;
> + intel_resize(ds);
> + }
> +}
> +
> +static void intel_resize(DisplayState *ds)
> +{
> + DisplaySurface *surf = ds->surface;
> + int old_linesize = surf->linesize;
> +
> + if (surf->pf.depth == 32 && surf->width == IntelX && surf->height ==
> IntelY)
> + surf->flags = QEMU_ALLOCATED_FLAG;
> + else
> + surf->flags &= ~QEMU_ALLOCATED_FLAG;
> +
> + if (is_buffer_shared(surf))
> + {
> + INTEL_DEBUG("intel_resize_shared: enable shared buffer, linesize %d\n",
> + surf->linesize);
> + intel_force_linear(surf->linesize);
> + set_data_mappings();
> + if (refresh)
> + {
> + // Pixels doesn't exist anymore ??
> + //memcpy(surf->data, pixels, surf->linesize * surf->height);
> + refresh = 0;
> + }
> + intel_setdata(ds);
> + return;
> + }
> +
> + INTEL_DEBUG("intel_resize: no shared buffer, linesize=%d\n",
> surf->linesize);
> + surf->linesize = intel_get_pitch();
> + if (map_size) {
> + unset_fb_mapping();
> + unset_data_mappings(1);
> + }
> + if (intel_have_focus && !is_linear()) {
> + intel_force_linear(0);
> + }
> + surf->flags &= ~QEMU_ALLOCATED_FLAG;
> + if (intel_have_focus && !old_data &&
> + surf->width * surf->height <= IntelX * IntelY)
> + set_data_mappings();
> + else if (intel_have_focus && old_data &&
> + surf->width * surf->height > IntelX * IntelY)
> + unset_data_mappings(0);
> + if (!old_data) {
> + qemu_free(surf->data);
> + surf->data = qemu_mallocz(surf->height * surf->linesize);
> + } else {
> + INTEL_DEBUG("intel_resize: set_data_pointer\n");
> + set_data_pointer();
> + }
> + if (intel_have_focus)
> + memset((unsigned char *)(intel_mem +
> intel_get_reg(REG_DR_DSPASURF)), 0x0, IntelX * IntelY);
> + if (refresh) {
> + if (old_data) {
> + unsigned char *s, *d;
> + int i;
> + s = old_data;
> + d = surf->data;
> + for (i = 0; i < surf->height; i++) {
> + memcpy(d, s, surf->width * 4);
> + s += old_linesize;
> + d += surf->linesize;
> + }
> + }
> + refresh = 0;
> + }
> +}
> +
> +static void intel_refresh(DisplayState *ds)
> +{
> + vga_hw_update();
> +}
> +
> +static void intel_init_mapping(void)
> +{
> + struct pci_access *pci_bus;
> + struct pci_dev *pci_dev;
> +
> + mmio_fd = open("/dev/mem", O_RDWR);
> + if (mmio_fd == -1)
> + {
> + perror("open");
> + exit(1);
> + }
> + mem_fd = open("/dev/mem", O_RDWR);
> + if (mem_fd == -1)
> + {
> + perror("open");
> + exit(1);
> + }
> +
> + pci_bus = pci_alloc();
> + pci_init(pci_bus);
> + pci_dev = pci_get_dev(pci_bus, 0, 0, 2, 0);
> + pci_fill_info(pci_dev, PCI_FILL_BASES);
> + intel_fb_base = pci_dev->base_addr[2] & 0xfffff000;
> + intel_mmio_base = pci_dev->base_addr[0] & 0xfffff000;
> + pci_free_dev(pci_dev);
> + pci_cleanup(pci_bus);
> +
> + INTEL_DEBUG("Map intel main mem 0x%x\n", intel_fb_base);
> + intel_mem = mmap(NULL, 0x10000000, PROT_READ | PROT_WRITE, MAP_SHARED,
> + mem_fd, intel_fb_base);
> + if (intel_mem == MAP_FAILED)
> + {
> + perror("mmap");
> + exit(1);
> + }
> +
> + INTEL_DEBUG("Map intel mmio 0x%x\n", intel_mmio_base);
> + intel_mmio = mmap(NULL, 4 * 1024 * 1024, PROT_READ | PROT_WRITE,
> MAP_SHARED,
> + mmio_fd, intel_mmio_base);
> + if (intel_mem == MAP_FAILED)
> + {
> + perror("mmap");
> + exit(1);
> + }
> +}
> +
> +static void set_data_pointer(void)
> +{
> + DisplaySurface *surf = lds->surface;
> +
> + surf->data = (unsigned char *)(intel_mem +
> intel_get_reg(REG_DR_DSPASURF));
> + surf->data = surf->data +
> + surf->linesize * ((IntelY - surf->height) / 2) +
> + 4 * ((IntelX - surf->width) / 2);
> +}
> +
> +static void set_data_mappings(void)
> +{
> + INTEL_DEBUG("set_data_mappings\n");
> + if (!old_data)
> + old_data = lds->surface->data;
> + set_data_pointer();
> +}
> +
> +static void unset_data_mappings(int mapping)
> +{
> + DisplaySurface *surf = lds->surface;
> + if (!old_data)
> + return;
> + if (mapping) {
> + uint8_t * buffer_pointer = surf->data;
> + surf->data = old_data;
> + old_data = NULL;
> + surf->data = realloc(surf->data, surf->linesize * surf->height);
> + memcpy(surf->data,
> + (unsigned char *)(intel_mem +
> intel_get_reg(REG_DR_DSPASURF)),
> + surf->linesize * surf->height);
> + memcpy(buffer_pointer,
> + surf->data,
> + surf->linesize * surf->height);
> + } else {
> + uint8_t * buffer_pointer = surf->data;
> + surf->data = old_data;
> + old_data = NULL;
> + surf->data = realloc(surf->data, surf->linesize * surf->height);
> + memcpy(surf->data,
> + buffer_pointer,
> + surf->linesize * surf->height);
> + }
> + INTEL_DEBUG("unset_data_mappings %d: success\n", mapping);
> +}
> +
> +static int intel_getfocus(void)
> +{
> + return intel_have_focus;
> +}
> +
> +static void intel_focus(int focus)
> +{
> + if (intel_have_focus == focus)
> + return;
> +
> + INTEL_DEBUG("intel_focus %d\n", focus);
> + intel_have_focus = focus;
> + if (focus) {
> + if (!is_linear()) {
> + IntelPitch = intel_get_reg(REG_DR_DSPASTRIDE);
> + IntelX = ((intel_get_reg(REG_DE_PIPEASRC) >> 16) & 0xfff) + 1;
> + IntelY = (intel_get_reg(REG_DE_PIPEASRC) & 0xfff) + 1;
> + INTEL_DEBUG("Resolution is %dx%d\n", IntelX, IntelY);
> + }
> + refresh = 1;
> + lds->listeners->dpy_resize = intel_resize;
> + lds->listeners->dpy_setdata = intel_setdata;
> + vga_hw_invalidate();
> + } else {
> + if (map_size) {
> + unset_fb_mapping();
> + unset_data_mappings(1);
> + } else if (old_data) {
> + unset_data_mappings(0);
> + }
> + lds->listeners->dpy_resize = NULL;
> + lds->listeners->dpy_setdata = NULL;
> + lds->surface->flags &= ~QEMU_ALLOCATED_FLAG;
> + }
> +}
> +
> +int intel_enter(void)
> +{
> + intel_focus(1);
> + return 1;
> +}
> +
> +int intel_leave(void)
> +{
> + intel_focus(0);
> + return 1;
> +}
> +
> +void intel_display_init(DisplayState *ds)
> +{
> + DisplaySurface *surf = ds->surface;
> +
> + INTEL_DEBUG("\n");
> +
> + intel_init_mapping();
> +
> + INTEL_DEBUG("Frambuffer is at 0x%x\n", intel_get_reg(REG_DR_DSPASURF));
> +
> + surf->flags = 0;
> + surf->width = 640;
> + surf->height = 480;
> + surf->pf.depth = 32;
> + intel_resize(ds);
> + lds = ds;
> +
> + ds->listeners->dpy_update = intel_update;
> + ds->listeners->dpy_resize = intel_resize;
> + ds->listeners->dpy_refresh = intel_refresh;
> +}
> \ No newline at end of file
> diff -rupN --ignore-blank-lines-X diffignore a/tools/ioemu-remote/vl.c
> b/tools/ioemu-remote/vl.c
> --- a/tools/ioemu-remote/vl.c 2009-06-07 21:14:47.000000000 -0400
> +++ b/tools/ioemu-remote/vl.c 2009-06-07 19:29:12.000000000 -0400
> @@ -233,6 +233,9 @@ CharDriverState *virtcon_hds[MAX_VIRTIO_
> #ifdef TARGET_I386
> int win2k_install_hack = 0;
> int rtc_td_hack = 0;
> +int vga_passthrough = 0;
> +const char *dom0_input = NULL;
> +int intel = 0;
> #endif
> int usb_enabled = 0;
> int smp_cpus = 1;
> @@ -4039,6 +4042,9 @@ static void help(int exitcode)
> "-disable-opengl disable OpenGL rendering, using SDL"
> #endif
> #endif
> + "-vga_passthrough enable graphics card passthrough\n"
> + "-dom0-input enable dom0 controlling qemu\n"
> + "-intel use intel gfx\n"
> "-portrait rotate graphical output 90 deg left (only PXA
> LCD)\n"
> "-vga [std|cirrus|vmware|none]\n"
> " select video card type\n"
> @@ -4275,6 +4281,9 @@ enum {
> QEMU_OPTION_domainname,
> QEMU_OPTION_acpi,
> QEMU_OPTION_vcpus,
> + QEMU_OPTION_vga_passthrough,
> + QEMU_OPTION_dom0_input,
> + QEMU_OPTION_intel,
>
> /* Debug/Expert options: */
> QEMU_OPTION_serial,
> @@ -4448,6 +4457,9 @@ static const QEMUOption qemu_options[] =
> { "pciemulation", HAS_ARG, QEMU_OPTION_pci_emulation },
> { "vncunused", 0, QEMU_OPTION_vncunused },
> { "vcpus", HAS_ARG, QEMU_OPTION_vcpus },
> + { "vga_passthrough", 0, QEMU_OPTION_vga_passthrough },
> + { "dom0-input", HAS_ARG, QEMU_OPTION_dom0_input },
> + { "intel", 0, QEMU_OPTION_intel },
> #if defined(CONFIG_XEN) && !defined(CONFIG_DM)
> { "xen-domid", HAS_ARG, QEMU_OPTION_xen_domid },
> { "xen-create", 0, QEMU_OPTION_xen_create },
> @@ -5281,6 +5293,15 @@ int main(int argc, char **argv, char **e
> case QEMU_OPTION_disable_opengl:
> opengl_enabled = 0;
> break;
> + case QEMU_OPTION_vga_passthrough:
> + vga_passthrough = 1;
> + break;
> + case QEMU_OPTION_dom0_input:
> + dom0_input = optarg;
> + break;
> + case QEMU_OPTION_intel:
> + intel = 1;
> + break;
> case QEMU_OPTION_direct_pci:
> direct_pci = optarg;
> break;
> @@ -5876,6 +5897,14 @@ int main(int argc, char **argv, char **e
> fprintf(stderr, "fatal: -nographic can't be used with -curses\n");
> exit(1);
> }
> +
> +#ifdef CONFIG_DM
> + if(vga_passthrough)
> + fprintf(stderr, "Replace if initializing dom0_driver\n" );
> +#else
> + dumb_display_init(ds);
> +#endif
> +
> } else {
> #if defined(CONFIG_CURSES)
> if (curses) {
> diff -rupN --ignore-blank-lines-X diffignore
> a/tools/ioemu-remote/xen-hooks.mak b/tools/ioemu-remote/xen-hooks.mak
> --- a/tools/ioemu-remote/xen-hooks.mak 2009-06-07 21:14:47.000000000 -0400
> +++ b/tools/ioemu-remote/xen-hooks.mak 2009-06-07 19:04:12.000000000 -0400
> @@ -35,6 +35,7 @@ OBJS += exec-dm.o
> OBJS += pci_emulation.o
> OBJS += helper2.o
> OBJS += battery_mgmt.o
> +OBJS += intel.o
>
> ifdef CONFIG_STUBDOM
> CPPFLAGS += $(TARGET_CPPFLAGS) -DNEED_CPU_H \
> diff -rupN --ignore-blank-lines-X diffignore a/tools/libxc/xc_hvm_build.c
> b/tools/libxc/xc_hvm_build.c
> --- a/tools/libxc/xc_hvm_build.c 2009-06-07 20:44:47.000000000 -0400
> +++ b/tools/libxc/xc_hvm_build.c 2009-06-07 19:04:12.000000000 -0400
> @@ -1,7 +1,3 @@
> -/******************************************************************************
> - * xc_hvm_build.c
> - */
> -
> #include <stddef.h>
> #include <inttypes.h>
> #include <stdlib.h>
> @@ -66,6 +62,82 @@ static void build_hvm_info(void *hvm_inf
> hvm_info->checksum = -sum;
> }
>
> +static int init_vgabios(int xc_handle,
> + uint32_t dom,
> + unsigned char *buffer,
> + uint32_t bios_size)
> +{
> + char *va_bios = NULL;
> + uint32_t va_size = 0;
> +
> + va_size = bios_size + bios_size % XC_PAGE_SIZE;
> + va_bios = xc_map_foreign_range(xc_handle, dom, va_size,
> + PROT_READ | PROT_WRITE, 0xC0);
> + if (!va_bios)
> + {
> + IPRINTF("Unable to map vga bios!\n");
> + return -1;
> + }
> +
> + if ( buffer != NULL)
> + memcpy(va_bios, buffer, bios_size);
> + else
> + memset(va_bios, 0, bios_size);
> +
> + munmap(va_bios, va_size);
> + return 0;
> +}
> +
> +static int setup_vga_pt(int xc_handle,
> + uint32_t dom)
> +{
> + int rc = 0;
> + unsigned char *bios = NULL;
> + int bios_size = 0;
> + char *c = NULL;
> + char checksum = 0;
> +
> + IPRINTF("Setting up vga passthrough.\n");
> +
> + /* Allocated 64K for the vga bios */
> + if (!(bios = malloc(64 * 1024))) {
> + IPRINTF("Error allocating memory for vga bios.\n");
> + return -1;
> + }
> +
> +#ifdef __linux__
> + bios_size = xc_get_vgabios(bios, 64 * 1024);
> +#else
> + bios_size = 0;
> +#endif /* __linux__ */
> +
> + if (bios_size == 0)
> + {
> + IPRINTF("vga bios size is 0!\n");
> + rc = -1;
> + goto error;
> + }
> +
> + /* Adjust the bios checksum */
> + for ( c = (char*)bios; c < ((char*)bios + bios_size); c++ )
> + checksum += *c;
> + if (checksum)
> + bios[bios_size - 1] -= checksum;
> + init_vgabios(xc_handle, dom, bios, bios_size);
> +
> +error:
> + free(bios);
> +
> + if( rc == -1 ) {
> + IPRINTF("Error setting up vga passthrough.\n");
> + }
> + else {
> + IPRINTF("Success setting up vga passthrough.\n");
> + }
> +
> + return rc;
> +}
> +
> static int loadelfimage(
> struct elf_binary *elf, int xch, uint32_t dom, unsigned long *parray)
> {
> @@ -381,7 +453,8 @@ int xc_hvm_build_target_mem(int xc_handl
> uint32_t domid,
> int memsize,
> int target,
> - const char *image_name)
> + const char *image_name,
> + int vga_pt_enabled)
> {
> char *image;
> int sts;
> @@ -392,6 +465,12 @@ int xc_hvm_build_target_mem(int xc_handl
> return -1;
>
> sts = xc_hvm_build_internal(xc_handle, domid, memsize, target, image,
> image_size);
> + if ( vga_pt_enabled ) {
> + sts |= setup_vga_pt(xc_handle, domid);
> + } else {
> + sts |= init_vgabios(xc_handle, domid, NULL, 0x800);
> + }
> +
>
> free(image);
>
> diff -rupN --ignore-blank-lines-X diffignore a/tools/libxc/xc_linux.c
> b/tools/libxc/xc_linux.c
> --- a/tools/libxc/xc_linux.c 2009-06-07 20:44:47.000000000 -0400
> +++ b/tools/libxc/xc_linux.c 2009-06-07 19:04:12.000000000 -0400
> @@ -562,6 +562,57 @@ int xc_gnttab_set_max_grants(int xcg_han
> return 0;
> }
>
> +int xc_get_vgabios(unsigned char *buf,
> + int len)
> +{
> + int mem;
> + uint32_t start, size = 0;
> + uint16_t magic = 0;
> +
> + start = 0xC0000;
> + if (len < size)
> + return 0;
> + if ((mem = open("/dev/mem", O_RDONLY)) < 0)
> + return 0;
> +
> + /*
> + ** Check if it a real bios extension.
> + ** The magic number is 0xAA55.
> + */
> + if (start != lseek(mem, start, SEEK_SET))
> + goto out;
> + if (read(mem, &magic, 2) != 2)
> + goto out;
> + if (magic != 0xAA55)
> + goto out;
> +
> + /* Find the size of the rom extension */
> + if (start != lseek(mem, start, SEEK_SET))
> + goto out;
> + if (lseek(mem, 2, SEEK_CUR) != (start + 2))
> + goto out;
> + if (read(mem, &size, 1) != 1)
> + goto out;
> + /* This size is in 512K */
> + size *= 512;
> +
> + /*
> + ** Set the file to the begining of the rombios,
> + ** to start the copy.
> + */
> + if (start != lseek(mem, start, SEEK_SET))
> + {
> + size = 0;
> + goto out;
> + }
> + if (size != read(mem, buf, size))
> + size = 0;
> +
> +out:
> + close(mem);
> + return size;
> +}
> +
> /*
> * Local variables:
> * mode: C
> diff -rupN --ignore-blank-lines-X diffignore a/tools/libxc/xenctrl.h
> b/tools/libxc/xenctrl.h
> --- a/tools/libxc/xenctrl.h 2009-06-07 20:44:47.000000000 -0400
> +++ b/tools/libxc/xenctrl.h 2009-06-07 19:04:12.000000000 -0400
> @@ -145,6 +145,10 @@ int xc_waitdomain(
> int *status,
> int options);
>
> +int xc_get_vgabios(
> + unsigned char *bios,
> + int len);
> +
> #endif /* __linux__ */
>
> /*
> diff -rupN --ignore-blank-lines-X diffignore a/tools/libxc/xenguest.h
> b/tools/libxc/xenguest.h
> --- a/tools/libxc/xenguest.h 2009-06-07 20:44:47.000000000 -0400
> +++ b/tools/libxc/xenguest.h 2009-06-07 19:04:12.000000000 -0400
> @@ -134,7 +134,8 @@ int xc_hvm_build_target_mem(int xc_handl
> uint32_t domid,
> int memsize,
> int target,
> - const char *image_name);
> + const char *image_name,
> + int vga_pt_enabled);
>
> int xc_hvm_build_mem(int xc_handle,
> uint32_t domid,
> diff -rupN --ignore-blank-lines-X diffignore
> a/tools/python/xen/lowlevel/xc/xc.c b/tools/python/xen/lowlevel/xc/xc.c
> --- a/tools/python/xen/lowlevel/xc/xc.c 2009-06-07 20:44:47.000000000 -0400
> +++ b/tools/python/xen/lowlevel/xc/xc.c 2009-06-07 19:04:12.000000000 -0400
> @@ -890,21 +890,21 @@ static PyObject *pyxc_hvm_build(XcObject
> int i;
> #endif
> char *image;
> - int memsize, target=-1, vcpus = 1, acpi = 0, apic = 1;
> + int memsize, target=-1, vcpus = 1, acpi = 0, apic = 1, vga_pt = 0;
>
> static char *kwd_list[] = { "domid",
> "memsize", "image", "target", "vcpus", "acpi",
> - "apic", NULL };
> - if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iis|iiii", kwd_list,
> + "apic", "vga_pt", NULL };
> + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iis|iiiii", kwd_list,
> &dom, &memsize, &image, &target, &vcpus,
> - &acpi, &apic) )
> + &acpi, &apic, &vga_pt) )
> return NULL;
>
> if ( target == -1 )
> target = memsize;
>
> if ( xc_hvm_build_target_mem(self->xc_handle, dom, memsize,
> - target, image) != 0 )
> + target, image, vga_pt) != 0 )
> return pyxc_error_to_exception();
>
> #if !defined(__ia64__)
> diff -rupN --ignore-blank-lines-X diffignore a/tools/python/xen/xend/image.py
> b/tools/python/xen/xend/image.py
> --- a/tools/python/xen/xend/image.py 2009-06-07 20:44:47.000000000 -0400
> +++ b/tools/python/xen/xend/image.py 2009-06-07 19:04:12.000000000 -0400
> @@ -279,6 +279,9 @@ class ImageHandler:
> vnc_config = {}
> has_vnc = int(vmConfig['platform'].get('vnc', 0)) != 0
> has_sdl = int(vmConfig['platform'].get('sdl', 0)) != 0
> + has_vga_passthrough =
> int(vmConfig['platform'].get('vga_passthrough', 0)) != 0
> + has_intel = int(vmConfig['platform'].get('intel', 0)) != 0
> +
> opengl = 1
> keymap = vmConfig['platform'].get("keymap")
> for dev_uuid in vmConfig['console_refs']:
> @@ -302,7 +305,7 @@ class ImageHandler:
> ret.append("-k")
> ret.append(keymap)
>
> - if has_vnc:
> + if has_vnc and not has_vga_passthrough:
> if not vnc_config:
> for key in ('vncunused', 'vnclisten', 'vncdisplay',
> 'vncpasswd'):
> @@ -353,6 +356,15 @@ class ImageHandler:
>
> if int(vmConfig['platform'].get('monitor', 0)) != 0:
> ret = ret + ['-monitor', 'vc']
> +
> + if has_vga_passthrough:
> + ret.append('-vga_passthrough')
> + dom0_input = str(vmConfig['platform'].get('dom0_input'))
> + ret = ret + ['-dom0-input', dom0_input]
> +
> + if has_intel:
> + ret.append('-intel')
> +
> return ret
>
> def getDeviceModelArgs(self, restore = False):
> @@ -754,7 +766,9 @@ class HVMImageHandler(ImageHandler):
> self.apic = int(vmConfig['platform'].get('apic', 0))
> self.acpi = int(vmConfig['platform'].get('acpi', 0))
> self.guest_os_type = vmConfig['platform'].get('guest_os_type')
> -
> + self.vga_pt = int(vmConfig['platform'].get('vga_passthrough', 0))
> + self.dom0_input = str(vmConfig['platform'].get('dom0_input'))
> + self.intel = int(vmConfig['platform'].get('intel', 0))
>
> # Return a list of cmd line args to the device models based on the
> # xm config file
> @@ -869,6 +883,7 @@ class HVMImageHandler(ImageHandler):
> log.debug("vcpus = %d", self.vm.getVCpuCount())
> log.debug("acpi = %d", self.acpi)
> log.debug("apic = %d", self.apic)
> + log.debug("vga_pt = %d", self.vga_pt)
>
> rc = xc.hvm_build(domid = self.vm.getDomid(),
> image = self.loader,
> @@ -876,7 +891,8 @@ class HVMImageHandler(ImageHandler):
> target = mem_mb,
> vcpus = self.vm.getVCpuCount(),
> acpi = self.acpi,
> - apic = self.apic)
> + apic = self.apic,
> + vga_pt = self.vga_pt)
> rc['notes'] = { 'SUSPEND_CANCEL': 1 }
>
> rc['store_mfn'] = xc.hvm_get_param(self.vm.getDomid(),
> diff -rupN --ignore-blank-lines-X diffignore
> a/tools/python/xen/xend/XendConfig.py b/tools/python/xen/xend/XendConfig.py
> --- a/tools/python/xen/xend/XendConfig.py 2009-06-07 20:44:47.000000000
> -0400
> +++ b/tools/python/xen/xend/XendConfig.py 2009-06-07 19:04:12.000000000
> -0400
> @@ -171,6 +171,9 @@ XENAPI_PLATFORM_CFG_TYPES = {
> 'pci_msitranslate': int,
> 'pci_power_mgmt': int,
> 'xen_platform_pci': int,
> + 'vga_passthrough': int,
> + 'dom0_input': str,
> + 'intel': int,
> }
>
> # Xen API console 'other_config' keys.
> diff -rupN --ignore-blank-lines-X diffignore a/tools/python/xen/xm/create.py
> b/tools/python/xen/xm/create.py
> --- a/tools/python/xen/xm/create.py 2009-06-07 20:44:47.000000000 -0400
> +++ b/tools/python/xen/xm/create.py 2009-06-07 19:04:12.000000000 -0400
> @@ -618,6 +618,18 @@ gopts.var('xen_platform_pci', val='0|1',
> fn=set_int, default=1,
> use="Is xen_platform_pci used?")
>
> +gopts.var('vga_passthrough', val='0|1',
> + fn=set_int, default=None,
> + use="Enable the passthrough for the graphic card.")
> +
> +gopts.var('dom0_input', val='DOM0_INPUT',
> + fn=set_value, default=None,
> + use="Input arguments for dom0 driver")
> +
> +gopts.var('intel', val='INTEL',
> + fn=set_int, default=None,
> + use="Use Intel GFX.")
> +
> def err(msg):
> """Print an error to stderr and exit.
> """
> @@ -932,7 +944,8 @@ def configure_hvm(config_image, vals):
> 'acpi', 'apic', 'usb', 'usbdevice', 'keymap', 'pci', 'hpet',
> 'guest_os_type', 'hap', 'opengl', 'cpuid', 'cpuid_check',
> 'viridian', 'xen_extended_power_mgmt', 'pci_msitranslate',
> - 'vpt_align', 'pci_power_mgmt', 'xen_platform_pci' ]
> + 'vpt_align', 'pci_power_mgmt', 'xen_platform_pci',
> + 'vga_passthrough', 'dom0_input', 'intel' ]
>
> for a in args:
> if a in vals.__dict__ and vals.__dict__[a] is not None:
>
> _______________________________________________
> Xen-devel mailing list
> Xen-devel@xxxxxxxxxxxxxxxxxxx
> http://lists.xensource.com/xen-devel
>
>
Where did this patch come from? I plan to try using a ati card with a
windows domU this week but first I need to port this patch to 2.6.29,
before I start I want to make sure I am working with the latest
version of the patch.
Andy
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel
|