[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] Experimental results for VGA passthrough
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
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |