static int xen_pcibk_remove_device(struct xen_pcibk_device *pdev, int domain, int bus, int slot, int func) { int err = 0; struct pci_dev *dev; dev_dbg(&pdev->xdev->dev, "removing dom %x bus %x slot %x func %x\n", domain, bus, slot, func); dev = xen_pcibk_get_pci_dev(pdev, domain, bus, PCI_DEVFN(slot, func)); if (!dev) { err = -EINVAL; dev_dbg(&pdev->xdev->dev, "Couldn't locate PCI device " "(%04x:%02x:%02x.%01x)! not owned by this domain\n", domain, bus, slot, func); goto out; } dev_dbg(&dev->dev, "unregistering for %d\n", pdev->xdev->otherend_id); dev->dev_flags &= ~PCI_DEV_FLAGS_ASSIGNED; xen_unregister_device_domain_owner(dev); xen_pcibk_release_pci_dev(pdev, dev); out: return err; }
static int xen_pcibk_remove_device(struct xen_pcibk_device *pdev, int domain, int bus, int slot, int func) { int err = 0; struct pci_dev *dev; dev_dbg(&pdev->xdev->dev, "removing dom %x bus %x slot %x func %x\n", domain, bus, slot, func); dev = xen_pcibk_get_pci_dev(pdev, domain, bus, PCI_DEVFN(slot, func)); if (!dev) { err = -EINVAL; dev_dbg(&pdev->xdev->dev, "Couldn't locate PCI device " "(%04x:%02x:%02x.%d)! not owned by this domain\n", domain, bus, slot, func); goto out; } dev_dbg(&dev->dev, "unregistering for %d\n", pdev->xdev->otherend_id); xen_unregister_device_domain_owner(dev); /* N.B. This ends up calling pcistub_put_pci_dev which ends up * doing the FLR. */ xen_pcibk_release_pci_dev(pdev, dev, true /* use the lock. */); out: return err; }
void xen_pcibk_do_op(struct work_struct *data) { struct xen_pcibk_device *pdev = container_of(data, struct xen_pcibk_device, op_work); struct pci_dev *dev; struct xen_pcibk_dev_data *dev_data = NULL; struct xen_pci_op *op = &pdev->op; int test_intx = 0; #ifdef CONFIG_PCI_MSI unsigned int nr = 0; #endif *op = pdev->sh_info->op; barrier(); dev = xen_pcibk_get_pci_dev(pdev, op->domain, op->bus, op->devfn); if (dev == NULL) op->err = XEN_PCI_ERR_dev_not_found; else { dev_data = pci_get_drvdata(dev); if (dev_data) test_intx = dev_data->enable_intx; switch (op->cmd) { case XEN_PCI_OP_conf_read: op->err = xen_pcibk_config_read(dev, op->offset, op->size, &op->value); break; case XEN_PCI_OP_conf_write: op->err = xen_pcibk_config_write(dev, op->offset, op->size, op->value); break; #ifdef CONFIG_PCI_MSI case XEN_PCI_OP_enable_msi: op->err = xen_pcibk_enable_msi(pdev, dev, op); break; case XEN_PCI_OP_disable_msi: op->err = xen_pcibk_disable_msi(pdev, dev, op); break; case XEN_PCI_OP_enable_msix: nr = op->value; op->err = xen_pcibk_enable_msix(pdev, dev, op); break; case XEN_PCI_OP_disable_msix: op->err = xen_pcibk_disable_msix(pdev, dev, op); break; #endif default: op->err = XEN_PCI_ERR_not_implemented; break; } } if (!op->err && dev && dev_data) { /* Transition detected */ if ((dev_data->enable_intx != test_intx)) xen_pcibk_control_isr(dev, 0 /* no reset */); } pdev->sh_info->op.err = op->err; pdev->sh_info->op.value = op->value; #ifdef CONFIG_PCI_MSI if (op->cmd == XEN_PCI_OP_enable_msix && op->err == 0) { unsigned int i; for (i = 0; i < nr; i++) pdev->sh_info->op.msix_entries[i].vector = op->msix_entries[i].vector; } #endif /* Tell the driver domain that we're done. */ wmb(); clear_bit(_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags); notify_remote_via_irq(pdev->evtchn_irq); /* Mark that we're done. */ smp_mb__before_clear_bit(); /* /after/ clearing PCIF_active */ clear_bit(_PDEVF_op_active, &pdev->flags); smp_mb__after_clear_bit(); /* /before/ final check for work */ /* Check to see if the driver domain tried to start another request in * between clearing _XEN_PCIF_active and clearing _PDEVF_op_active. */ xen_pcibk_test_and_schedule_op(pdev); }