diff -r c783f340bef8 -r f4e09625f1dd linux-2.6-xen-sparse/drivers/xen/pciback/pci_stub.c --- a/linux-2.6-xen-sparse/drivers/xen/pciback/pci_stub.c Tue Apr 11 08:58:04 2006 +++ b/linux-2.6-xen-sparse/drivers/xen/pciback/pci_stub.c Tue Apr 11 17:40:03 2006 @@ -76,7 +76,7 @@ /* Clean-up the device */ pciback_reset_device(psdev->dev); - pciback_config_free(psdev->dev); + pciback_config_free_dev(psdev->dev); kfree(pci_get_drvdata(psdev->dev)); pci_set_drvdata(psdev->dev, NULL); @@ -95,33 +95,10 @@ kref_put(&psdev->kref, pcistub_device_release); } -static struct pci_dev *pcistub_device_get_pci_dev(struct pciback_device *pdev, - struct pcistub_device *psdev) -{ - struct pci_dev *pci_dev = NULL; - unsigned long flags; - - pcistub_device_get(psdev); - - spin_lock_irqsave(&psdev->lock, flags); - if (!psdev->pdev) { - psdev->pdev = pdev; - pci_dev = psdev->dev; - } - spin_unlock_irqrestore(&psdev->lock, flags); - - if (!pci_dev) - pcistub_device_put(psdev); - - return pci_dev; -} - -struct pci_dev *pcistub_get_pci_dev_by_slot(struct pciback_device *pdev, - int domain, int bus, - int slot, int func) -{ - struct pcistub_device *psdev; - struct pci_dev *found_dev = NULL; +static struct pcistub_device *pcistub_device_find(int domain, int bus, + int slot, int func) +{ + struct pcistub_device *psdev = NULL; unsigned long flags; spin_lock_irqsave(&pcistub_devices_lock, flags); @@ -131,12 +108,53 @@ && domain == pci_domain_nr(psdev->dev->bus) && bus == psdev->dev->bus->number && PCI_DEVFN(slot, func) == psdev->dev->devfn) { - found_dev = pcistub_device_get_pci_dev(pdev, psdev); - break; - } - } - + pcistub_device_get(psdev); + goto out; + } + } + + /* didn't find it */ + psdev = NULL; + + out: spin_unlock_irqrestore(&pcistub_devices_lock, flags); + return psdev; +} + +static struct pci_dev *pcistub_device_get_pci_dev(struct pciback_device *pdev, + struct pcistub_device *psdev) +{ + struct pci_dev *pci_dev = NULL; + unsigned long flags; + + pcistub_device_get(psdev); + + spin_lock_irqsave(&psdev->lock, flags); + if (!psdev->pdev) { + psdev->pdev = pdev; + pci_dev = psdev->dev; + } + spin_unlock_irqrestore(&psdev->lock, flags); + + if (!pci_dev) + pcistub_device_put(psdev); + + return pci_dev; +} + +struct pci_dev *pcistub_get_pci_dev_by_slot(struct pciback_device *pdev, + int domain, int bus, + int slot, int func) +{ + struct pcistub_device *psdev; + struct pci_dev *found_dev = NULL; + + psdev = pcistub_device_find(domain, bus, slot, func); + if (psdev) { + found_dev = pcistub_device_get_pci_dev(pdev, psdev); + pcistub_device_put(psdev); + } + return found_dev; } @@ -180,7 +198,7 @@ * (so it's ready for the next domain) */ pciback_reset_device(found_psdev->dev); - pciback_config_reset(found_psdev->dev); + pciback_config_reset_dev(found_psdev->dev); spin_lock_irqsave(&found_psdev->lock, flags); found_psdev->pdev = NULL; @@ -230,12 +248,7 @@ dev_dbg(&dev->dev, "initializing...\n"); - /* The PCI backend is not intended to be a module (or to work with - * removable PCI devices (yet). If it were, pciback_config_free() - * would need to be called somewhere to free the memory allocated - * here and then to call kfree(pci_get_drvdata(psdev->dev)). - */ - dev_data = kmalloc(sizeof(*dev_data), GFP_ATOMIC); + dev_data = kzalloc(sizeof(*dev_data), GFP_ATOMIC); if (!dev_data) { err = -ENOMEM; goto out; @@ -243,7 +256,7 @@ pci_set_drvdata(dev, dev_data); dev_dbg(&dev->dev, "initializing config\n"); - err = pciback_config_init(dev); + err = pciback_config_init_dev(dev); if (err) goto out; @@ -268,7 +281,7 @@ return 0; config_release: - pciback_config_free(dev); + pciback_config_free_dev(dev); out: pci_set_drvdata(dev, NULL); @@ -324,38 +337,30 @@ { struct pcistub_device *psdev; unsigned long flags; - int initialize_devices_copy; int err = 0; psdev = pcistub_device_alloc(dev); if (!psdev) return -ENOMEM; - /* initialize_devices has to be accessed under a spin lock. But since - * it can only change from 0 -> 1, if it's already 1, we don't have to - * worry about it changing. That's why we can take a *copy* of - * initialize_devices and wait till we're outside of the lock to - * check if it's 1 (don't ever check if it's 0 outside of the lock) - */ spin_lock_irqsave(&pcistub_devices_lock, flags); - initialize_devices_copy = initialize_devices; - - if (!initialize_devices_copy) { - dev_dbg(&dev->dev, "deferring initialization\n"); - list_add(&psdev->dev_list, &seized_devices); - } - - spin_unlock_irqrestore(&pcistub_devices_lock, flags); - - if (initialize_devices_copy) { + if (initialize_devices) { + spin_unlock_irqrestore(&pcistub_devices_lock, flags); + /* don't want irqs disabled when calling pcistub_init_device */ err = pcistub_init_device(psdev->dev); if (err) goto out; + spin_lock_irqsave(&pcistub_devices_lock, flags); list_add(&psdev->dev_list, &pcistub_devices); - } + } else { + dev_dbg(&dev->dev, "deferring initialization\n"); + list_add(&psdev->dev_list, &seized_devices); + } + + spin_unlock_irqrestore(&pcistub_devices_lock, flags); out: if (err) @@ -595,6 +600,83 @@ } DRIVER_ATTR(slots, S_IRUSR, pcistub_slot_show, NULL); + +static ssize_t permissive_add(struct device_driver *drv, + const char *buf, size_t count) +{ + int domain, bus, slot, func; + int err; + struct pcistub_device *psdev; + struct pciback_dev_data *dev_data; + + err = str_to_slot(buf, &domain, &bus, &slot, &func); + if (err) + goto out; + + psdev = pcistub_device_find(domain, bus, slot, func); + if (!psdev) { + err = -ENODEV; + goto out; + } + if (!psdev->dev) { + err = -ENODEV; + goto release; + } + + dev_data = pci_get_drvdata(psdev->dev); + /* the driver data for a device should never be null at this point */ + if (!dev_data) { + err = -ENXIO; + goto release; + } + + if (!dev_data->permissive) { + dev_data->permissive = 1; + + /* Let user know that what they're doing could be unsafe */ + dev_warn(&psdev->dev->dev, "enabling permissive mode " + "configuration space accesses!\n"); + dev_warn(&psdev->dev->dev, "permissive mode is potentially " + "unsafe!\n"); + } + + release: + pcistub_device_put(psdev); + + out: + if (!err) + err = count; + return err; +} + +static ssize_t permissive_show(struct device_driver *drv, char *buf) +{ + struct pcistub_device *psdev; + struct pciback_dev_data *dev_data; + size_t count = 0; + unsigned long flags; + + spin_lock_irqsave(&pcistub_devices_lock, flags); + list_for_each_entry(psdev, &pcistub_devices, dev_list) { + if (count >= PAGE_SIZE) + break; + + if (!psdev->dev) + continue; + + dev_data = pci_get_drvdata(psdev->dev); + if (!dev_data || !dev_data->permissive) + continue; + + count += scnprintf(buf + count, PAGE_SIZE - count, + "%s\n", pci_name(psdev->dev) ); + } + spin_unlock_irqrestore(&pcistub_devices_lock, flags); + + return count; +} + +DRIVER_ATTR(permissive, S_IRUSR|S_IWUSR, permissive_show, permissive_add); static int __init pcistub_init(void) { @@ -663,9 +745,13 @@ static int __init pciback_init(void) { + int err; + + err = pciback_config_init(); + if (err) + return err; + #ifdef MODULE - int err; - err = pcistub_init(); if (err < 0) return err;