diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-12-11 21:15:33 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-12-11 21:15:33 -0500 |
commit | 9d050966e2eb37a643ac15904b6a8fda7fcfabe9 (patch) | |
tree | f3a6f9cc93f6dde2e0cd6f4114b8258afb596bc1 /drivers/xen | |
parent | c0222ac086669a631814bbf857f8c8023452a4d7 (diff) | |
parent | 4ef8e3f3504808621e594f01852476a1d4e7ef93 (diff) |
Merge tag 'stable/for-linus-3.19-rc0-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip
Pull xen features and fixes from David Vrabel:
- Fully support non-coherent devices on ARM by introducing the
mechanisms to request the hypervisor to perform the required cache
maintainance operations.
- A number of pciback bug fixes and cleanups. Notably a deadlock fix
if a PCI device was manually uunbound and a fix for incorrectly
restoring state after a function reset.
- In x86 PVHVM guests, use the APIC for interrupts if this has been
virtualized by the hardware. This reduces the number of interrupt-
related VM exits on such hardware.
* tag 'stable/for-linus-3.19-rc0-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip: (26 commits)
Revert "swiotlb-xen: pass dev_addr to swiotlb_tbl_unmap_single"
xen/pci: Use APIC directly when APIC virtualization hardware is available
xen/pci: Defer initialization of MSI ops on HVM guests
xen-pciback: drop SR-IOV VFs when PF driver unloads
xen/pciback: Restore configuration space when detaching from a guest.
PCI: Expose pci_load_saved_state for public consumption.
xen/pciback: Remove tons of dereferences
xen/pciback: Print out the domain owning the device.
xen/pciback: Include the domain id if removing the device whilst still in use
driver core: Provide an wrapper around the mutex to do lockdep warnings
xen/pciback: Don't deadlock when unbinding.
swiotlb-xen: pass dev_addr to swiotlb_tbl_unmap_single
swiotlb-xen: call xen_dma_sync_single_for_device when appropriate
swiotlb-xen: remove BUG_ON in xen_bus_to_phys
swiotlb-xen: pass dev_addr to xen_dma_unmap_page and xen_dma_sync_single_for_cpu
xen/arm: introduce GNTTABOP_cache_flush
xen/arm/arm64: introduce xen_arch_need_swiotlb
xen/arm/arm64: merge xen/mm32.c into xen/mm.c
xen/arm: use hypercall to flush caches in map_page
xen: add a dma_addr_t dev_addr argument to xen_dma_map_page
...
Diffstat (limited to 'drivers/xen')
-rw-r--r-- | drivers/xen/swiotlb-xen.c | 19 | ||||
-rw-r--r-- | drivers/xen/xen-pciback/passthrough.c | 14 | ||||
-rw-r--r-- | drivers/xen/xen-pciback/pci_stub.c | 112 | ||||
-rw-r--r-- | drivers/xen/xen-pciback/pciback.h | 7 | ||||
-rw-r--r-- | drivers/xen/xen-pciback/vpci.c | 14 | ||||
-rw-r--r-- | drivers/xen/xen-pciback/xenbus.c | 4 |
6 files changed, 130 insertions, 40 deletions
diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c index ebd8f218a788..810ad419e34c 100644 --- a/drivers/xen/swiotlb-xen.c +++ b/drivers/xen/swiotlb-xen.c | |||
@@ -96,8 +96,6 @@ static inline phys_addr_t xen_bus_to_phys(dma_addr_t baddr) | |||
96 | dma_addr_t dma = (dma_addr_t)pfn << PAGE_SHIFT; | 96 | dma_addr_t dma = (dma_addr_t)pfn << PAGE_SHIFT; |
97 | phys_addr_t paddr = dma; | 97 | phys_addr_t paddr = dma; |
98 | 98 | ||
99 | BUG_ON(paddr != dma); /* truncation has occurred, should never happen */ | ||
100 | |||
101 | paddr |= baddr & ~PAGE_MASK; | 99 | paddr |= baddr & ~PAGE_MASK; |
102 | 100 | ||
103 | return paddr; | 101 | return paddr; |
@@ -399,11 +397,13 @@ dma_addr_t xen_swiotlb_map_page(struct device *dev, struct page *page, | |||
399 | * buffering it. | 397 | * buffering it. |
400 | */ | 398 | */ |
401 | if (dma_capable(dev, dev_addr, size) && | 399 | if (dma_capable(dev, dev_addr, size) && |
402 | !range_straddles_page_boundary(phys, size) && !swiotlb_force) { | 400 | !range_straddles_page_boundary(phys, size) && |
401 | !xen_arch_need_swiotlb(dev, PFN_DOWN(phys), PFN_DOWN(dev_addr)) && | ||
402 | !swiotlb_force) { | ||
403 | /* we are not interested in the dma_addr returned by | 403 | /* we are not interested in the dma_addr returned by |
404 | * xen_dma_map_page, only in the potential cache flushes executed | 404 | * xen_dma_map_page, only in the potential cache flushes executed |
405 | * by the function. */ | 405 | * by the function. */ |
406 | xen_dma_map_page(dev, page, offset, size, dir, attrs); | 406 | xen_dma_map_page(dev, page, dev_addr, offset, size, dir, attrs); |
407 | return dev_addr; | 407 | return dev_addr; |
408 | } | 408 | } |
409 | 409 | ||
@@ -417,7 +417,7 @@ dma_addr_t xen_swiotlb_map_page(struct device *dev, struct page *page, | |||
417 | return DMA_ERROR_CODE; | 417 | return DMA_ERROR_CODE; |
418 | 418 | ||
419 | xen_dma_map_page(dev, pfn_to_page(map >> PAGE_SHIFT), | 419 | xen_dma_map_page(dev, pfn_to_page(map >> PAGE_SHIFT), |
420 | map & ~PAGE_MASK, size, dir, attrs); | 420 | dev_addr, map & ~PAGE_MASK, size, dir, attrs); |
421 | dev_addr = xen_phys_to_bus(map); | 421 | dev_addr = xen_phys_to_bus(map); |
422 | 422 | ||
423 | /* | 423 | /* |
@@ -447,7 +447,7 @@ static void xen_unmap_single(struct device *hwdev, dma_addr_t dev_addr, | |||
447 | 447 | ||
448 | BUG_ON(dir == DMA_NONE); | 448 | BUG_ON(dir == DMA_NONE); |
449 | 449 | ||
450 | xen_dma_unmap_page(hwdev, paddr, size, dir, attrs); | 450 | xen_dma_unmap_page(hwdev, dev_addr, size, dir, attrs); |
451 | 451 | ||
452 | /* NOTE: We use dev_addr here, not paddr! */ | 452 | /* NOTE: We use dev_addr here, not paddr! */ |
453 | if (is_xen_swiotlb_buffer(dev_addr)) { | 453 | if (is_xen_swiotlb_buffer(dev_addr)) { |
@@ -495,14 +495,14 @@ xen_swiotlb_sync_single(struct device *hwdev, dma_addr_t dev_addr, | |||
495 | BUG_ON(dir == DMA_NONE); | 495 | BUG_ON(dir == DMA_NONE); |
496 | 496 | ||
497 | if (target == SYNC_FOR_CPU) | 497 | if (target == SYNC_FOR_CPU) |
498 | xen_dma_sync_single_for_cpu(hwdev, paddr, size, dir); | 498 | xen_dma_sync_single_for_cpu(hwdev, dev_addr, size, dir); |
499 | 499 | ||
500 | /* NOTE: We use dev_addr here, not paddr! */ | 500 | /* NOTE: We use dev_addr here, not paddr! */ |
501 | if (is_xen_swiotlb_buffer(dev_addr)) | 501 | if (is_xen_swiotlb_buffer(dev_addr)) |
502 | swiotlb_tbl_sync_single(hwdev, paddr, size, dir, target); | 502 | swiotlb_tbl_sync_single(hwdev, paddr, size, dir, target); |
503 | 503 | ||
504 | if (target == SYNC_FOR_DEVICE) | 504 | if (target == SYNC_FOR_DEVICE) |
505 | xen_dma_sync_single_for_cpu(hwdev, paddr, size, dir); | 505 | xen_dma_sync_single_for_device(hwdev, dev_addr, size, dir); |
506 | 506 | ||
507 | if (dir != DMA_FROM_DEVICE) | 507 | if (dir != DMA_FROM_DEVICE) |
508 | return; | 508 | return; |
@@ -557,6 +557,7 @@ xen_swiotlb_map_sg_attrs(struct device *hwdev, struct scatterlist *sgl, | |||
557 | dma_addr_t dev_addr = xen_phys_to_bus(paddr); | 557 | dma_addr_t dev_addr = xen_phys_to_bus(paddr); |
558 | 558 | ||
559 | if (swiotlb_force || | 559 | if (swiotlb_force || |
560 | xen_arch_need_swiotlb(hwdev, PFN_DOWN(paddr), PFN_DOWN(dev_addr)) || | ||
560 | !dma_capable(hwdev, dev_addr, sg->length) || | 561 | !dma_capable(hwdev, dev_addr, sg->length) || |
561 | range_straddles_page_boundary(paddr, sg->length)) { | 562 | range_straddles_page_boundary(paddr, sg->length)) { |
562 | phys_addr_t map = swiotlb_tbl_map_single(hwdev, | 563 | phys_addr_t map = swiotlb_tbl_map_single(hwdev, |
@@ -574,6 +575,7 @@ xen_swiotlb_map_sg_attrs(struct device *hwdev, struct scatterlist *sgl, | |||
574 | return 0; | 575 | return 0; |
575 | } | 576 | } |
576 | xen_dma_map_page(hwdev, pfn_to_page(map >> PAGE_SHIFT), | 577 | xen_dma_map_page(hwdev, pfn_to_page(map >> PAGE_SHIFT), |
578 | dev_addr, | ||
577 | map & ~PAGE_MASK, | 579 | map & ~PAGE_MASK, |
578 | sg->length, | 580 | sg->length, |
579 | dir, | 581 | dir, |
@@ -584,6 +586,7 @@ xen_swiotlb_map_sg_attrs(struct device *hwdev, struct scatterlist *sgl, | |||
584 | * xen_dma_map_page, only in the potential cache flushes executed | 586 | * xen_dma_map_page, only in the potential cache flushes executed |
585 | * by the function. */ | 587 | * by the function. */ |
586 | xen_dma_map_page(hwdev, pfn_to_page(paddr >> PAGE_SHIFT), | 588 | xen_dma_map_page(hwdev, pfn_to_page(paddr >> PAGE_SHIFT), |
589 | dev_addr, | ||
587 | paddr & ~PAGE_MASK, | 590 | paddr & ~PAGE_MASK, |
588 | sg->length, | 591 | sg->length, |
589 | dir, | 592 | dir, |
diff --git a/drivers/xen/xen-pciback/passthrough.c b/drivers/xen/xen-pciback/passthrough.c index 828dddc360df..f16a30e2a110 100644 --- a/drivers/xen/xen-pciback/passthrough.c +++ b/drivers/xen/xen-pciback/passthrough.c | |||
@@ -69,7 +69,7 @@ static int __xen_pcibk_add_pci_dev(struct xen_pcibk_device *pdev, | |||
69 | } | 69 | } |
70 | 70 | ||
71 | static void __xen_pcibk_release_pci_dev(struct xen_pcibk_device *pdev, | 71 | static void __xen_pcibk_release_pci_dev(struct xen_pcibk_device *pdev, |
72 | struct pci_dev *dev) | 72 | struct pci_dev *dev, bool lock) |
73 | { | 73 | { |
74 | struct passthrough_dev_data *dev_data = pdev->pci_dev_data; | 74 | struct passthrough_dev_data *dev_data = pdev->pci_dev_data; |
75 | struct pci_dev_entry *dev_entry, *t; | 75 | struct pci_dev_entry *dev_entry, *t; |
@@ -87,8 +87,13 @@ static void __xen_pcibk_release_pci_dev(struct xen_pcibk_device *pdev, | |||
87 | 87 | ||
88 | mutex_unlock(&dev_data->lock); | 88 | mutex_unlock(&dev_data->lock); |
89 | 89 | ||
90 | if (found_dev) | 90 | if (found_dev) { |
91 | if (lock) | ||
92 | device_lock(&found_dev->dev); | ||
91 | pcistub_put_pci_dev(found_dev); | 93 | pcistub_put_pci_dev(found_dev); |
94 | if (lock) | ||
95 | device_unlock(&found_dev->dev); | ||
96 | } | ||
92 | } | 97 | } |
93 | 98 | ||
94 | static int __xen_pcibk_init_devices(struct xen_pcibk_device *pdev) | 99 | static int __xen_pcibk_init_devices(struct xen_pcibk_device *pdev) |
@@ -156,8 +161,11 @@ static void __xen_pcibk_release_devices(struct xen_pcibk_device *pdev) | |||
156 | struct pci_dev_entry *dev_entry, *t; | 161 | struct pci_dev_entry *dev_entry, *t; |
157 | 162 | ||
158 | list_for_each_entry_safe(dev_entry, t, &dev_data->dev_list, list) { | 163 | list_for_each_entry_safe(dev_entry, t, &dev_data->dev_list, list) { |
164 | struct pci_dev *dev = dev_entry->dev; | ||
159 | list_del(&dev_entry->list); | 165 | list_del(&dev_entry->list); |
160 | pcistub_put_pci_dev(dev_entry->dev); | 166 | device_lock(&dev->dev); |
167 | pcistub_put_pci_dev(dev); | ||
168 | device_unlock(&dev->dev); | ||
161 | kfree(dev_entry); | 169 | kfree(dev_entry); |
162 | } | 170 | } |
163 | 171 | ||
diff --git a/drivers/xen/xen-pciback/pci_stub.c b/drivers/xen/xen-pciback/pci_stub.c index 017069a455d4..cc3cbb4435f8 100644 --- a/drivers/xen/xen-pciback/pci_stub.c +++ b/drivers/xen/xen-pciback/pci_stub.c | |||
@@ -105,7 +105,7 @@ static void pcistub_device_release(struct kref *kref) | |||
105 | */ | 105 | */ |
106 | __pci_reset_function_locked(dev); | 106 | __pci_reset_function_locked(dev); |
107 | if (pci_load_and_free_saved_state(dev, &dev_data->pci_saved_state)) | 107 | if (pci_load_and_free_saved_state(dev, &dev_data->pci_saved_state)) |
108 | dev_dbg(&dev->dev, "Could not reload PCI state\n"); | 108 | dev_info(&dev->dev, "Could not reload PCI state\n"); |
109 | else | 109 | else |
110 | pci_restore_state(dev); | 110 | pci_restore_state(dev); |
111 | 111 | ||
@@ -250,11 +250,15 @@ struct pci_dev *pcistub_get_pci_dev(struct xen_pcibk_device *pdev, | |||
250 | * - 'echo BDF > unbind' with a guest still using it. See pcistub_remove | 250 | * - 'echo BDF > unbind' with a guest still using it. See pcistub_remove |
251 | * | 251 | * |
252 | * As such we have to be careful. | 252 | * As such we have to be careful. |
253 | * | ||
254 | * To make this easier, the caller has to hold the device lock. | ||
253 | */ | 255 | */ |
254 | void pcistub_put_pci_dev(struct pci_dev *dev) | 256 | void pcistub_put_pci_dev(struct pci_dev *dev) |
255 | { | 257 | { |
256 | struct pcistub_device *psdev, *found_psdev = NULL; | 258 | struct pcistub_device *psdev, *found_psdev = NULL; |
257 | unsigned long flags; | 259 | unsigned long flags; |
260 | struct xen_pcibk_dev_data *dev_data; | ||
261 | int ret; | ||
258 | 262 | ||
259 | spin_lock_irqsave(&pcistub_devices_lock, flags); | 263 | spin_lock_irqsave(&pcistub_devices_lock, flags); |
260 | 264 | ||
@@ -276,13 +280,20 @@ void pcistub_put_pci_dev(struct pci_dev *dev) | |||
276 | /* Cleanup our device | 280 | /* Cleanup our device |
277 | * (so it's ready for the next domain) | 281 | * (so it's ready for the next domain) |
278 | */ | 282 | */ |
283 | device_lock_assert(&dev->dev); | ||
284 | __pci_reset_function_locked(dev); | ||
279 | 285 | ||
280 | /* This is OK - we are running from workqueue context | 286 | dev_data = pci_get_drvdata(dev); |
281 | * and want to inhibit the user from fiddling with 'reset' | 287 | ret = pci_load_saved_state(dev, dev_data->pci_saved_state); |
282 | */ | 288 | if (!ret) { |
283 | pci_reset_function(dev); | 289 | /* |
284 | pci_restore_state(dev); | 290 | * The usual sequence is pci_save_state & pci_restore_state |
285 | 291 | * but the guest might have messed the configuration space up. | |
292 | * Use the initial version (when device was bound to us). | ||
293 | */ | ||
294 | pci_restore_state(dev); | ||
295 | } else | ||
296 | dev_info(&dev->dev, "Could not reload PCI state\n"); | ||
286 | /* This disables the device. */ | 297 | /* This disables the device. */ |
287 | xen_pcibk_reset_device(dev); | 298 | xen_pcibk_reset_device(dev); |
288 | 299 | ||
@@ -554,12 +565,14 @@ static void pcistub_remove(struct pci_dev *dev) | |||
554 | spin_unlock_irqrestore(&pcistub_devices_lock, flags); | 565 | spin_unlock_irqrestore(&pcistub_devices_lock, flags); |
555 | 566 | ||
556 | if (found_psdev) { | 567 | if (found_psdev) { |
557 | dev_dbg(&dev->dev, "found device to remove - in use? %p\n", | 568 | dev_dbg(&dev->dev, "found device to remove %s\n", |
558 | found_psdev->pdev); | 569 | found_psdev->pdev ? "- in-use" : ""); |
559 | 570 | ||
560 | if (found_psdev->pdev) { | 571 | if (found_psdev->pdev) { |
561 | pr_warn("****** removing device %s while still in-use! ******\n", | 572 | int domid = xen_find_device_domain_owner(dev); |
562 | pci_name(found_psdev->dev)); | 573 | |
574 | pr_warn("****** removing device %s while still in-use by domain %d! ******\n", | ||
575 | pci_name(found_psdev->dev), domid); | ||
563 | pr_warn("****** driver domain may still access this device's i/o resources!\n"); | 576 | pr_warn("****** driver domain may still access this device's i/o resources!\n"); |
564 | pr_warn("****** shutdown driver domain before binding device\n"); | 577 | pr_warn("****** shutdown driver domain before binding device\n"); |
565 | pr_warn("****** to other drivers or domains\n"); | 578 | pr_warn("****** to other drivers or domains\n"); |
@@ -567,7 +580,8 @@ static void pcistub_remove(struct pci_dev *dev) | |||
567 | /* N.B. This ends up calling pcistub_put_pci_dev which ends up | 580 | /* N.B. This ends up calling pcistub_put_pci_dev which ends up |
568 | * doing the FLR. */ | 581 | * doing the FLR. */ |
569 | xen_pcibk_release_pci_dev(found_psdev->pdev, | 582 | xen_pcibk_release_pci_dev(found_psdev->pdev, |
570 | found_psdev->dev); | 583 | found_psdev->dev, |
584 | false /* caller holds the lock. */); | ||
571 | } | 585 | } |
572 | 586 | ||
573 | spin_lock_irqsave(&pcistub_devices_lock, flags); | 587 | spin_lock_irqsave(&pcistub_devices_lock, flags); |
@@ -629,10 +643,12 @@ static pci_ers_result_t common_process(struct pcistub_device *psdev, | |||
629 | { | 643 | { |
630 | pci_ers_result_t res = result; | 644 | pci_ers_result_t res = result; |
631 | struct xen_pcie_aer_op *aer_op; | 645 | struct xen_pcie_aer_op *aer_op; |
646 | struct xen_pcibk_device *pdev = psdev->pdev; | ||
647 | struct xen_pci_sharedinfo *sh_info = pdev->sh_info; | ||
632 | int ret; | 648 | int ret; |
633 | 649 | ||
634 | /*with PV AER drivers*/ | 650 | /*with PV AER drivers*/ |
635 | aer_op = &(psdev->pdev->sh_info->aer_op); | 651 | aer_op = &(sh_info->aer_op); |
636 | aer_op->cmd = aer_cmd ; | 652 | aer_op->cmd = aer_cmd ; |
637 | /*useful for error_detected callback*/ | 653 | /*useful for error_detected callback*/ |
638 | aer_op->err = state; | 654 | aer_op->err = state; |
@@ -653,36 +669,36 @@ static pci_ers_result_t common_process(struct pcistub_device *psdev, | |||
653 | * this flag to judge whether we need to check pci-front give aer | 669 | * this flag to judge whether we need to check pci-front give aer |
654 | * service ack signal | 670 | * service ack signal |
655 | */ | 671 | */ |
656 | set_bit(_PCIB_op_pending, (unsigned long *)&psdev->pdev->flags); | 672 | set_bit(_PCIB_op_pending, (unsigned long *)&pdev->flags); |
657 | 673 | ||
658 | /*It is possible that a pcifront conf_read_write ops request invokes | 674 | /*It is possible that a pcifront conf_read_write ops request invokes |
659 | * the callback which cause the spurious execution of wake_up. | 675 | * the callback which cause the spurious execution of wake_up. |
660 | * Yet it is harmless and better than a spinlock here | 676 | * Yet it is harmless and better than a spinlock here |
661 | */ | 677 | */ |
662 | set_bit(_XEN_PCIB_active, | 678 | set_bit(_XEN_PCIB_active, |
663 | (unsigned long *)&psdev->pdev->sh_info->flags); | 679 | (unsigned long *)&sh_info->flags); |
664 | wmb(); | 680 | wmb(); |
665 | notify_remote_via_irq(psdev->pdev->evtchn_irq); | 681 | notify_remote_via_irq(pdev->evtchn_irq); |
666 | 682 | ||
667 | ret = wait_event_timeout(xen_pcibk_aer_wait_queue, | 683 | ret = wait_event_timeout(xen_pcibk_aer_wait_queue, |
668 | !(test_bit(_XEN_PCIB_active, (unsigned long *) | 684 | !(test_bit(_XEN_PCIB_active, (unsigned long *) |
669 | &psdev->pdev->sh_info->flags)), 300*HZ); | 685 | &sh_info->flags)), 300*HZ); |
670 | 686 | ||
671 | if (!ret) { | 687 | if (!ret) { |
672 | if (test_bit(_XEN_PCIB_active, | 688 | if (test_bit(_XEN_PCIB_active, |
673 | (unsigned long *)&psdev->pdev->sh_info->flags)) { | 689 | (unsigned long *)&sh_info->flags)) { |
674 | dev_err(&psdev->dev->dev, | 690 | dev_err(&psdev->dev->dev, |
675 | "pcifront aer process not responding!\n"); | 691 | "pcifront aer process not responding!\n"); |
676 | clear_bit(_XEN_PCIB_active, | 692 | clear_bit(_XEN_PCIB_active, |
677 | (unsigned long *)&psdev->pdev->sh_info->flags); | 693 | (unsigned long *)&sh_info->flags); |
678 | aer_op->err = PCI_ERS_RESULT_NONE; | 694 | aer_op->err = PCI_ERS_RESULT_NONE; |
679 | return res; | 695 | return res; |
680 | } | 696 | } |
681 | } | 697 | } |
682 | clear_bit(_PCIB_op_pending, (unsigned long *)&psdev->pdev->flags); | 698 | clear_bit(_PCIB_op_pending, (unsigned long *)&pdev->flags); |
683 | 699 | ||
684 | if (test_bit(_XEN_PCIF_active, | 700 | if (test_bit(_XEN_PCIF_active, |
685 | (unsigned long *)&psdev->pdev->sh_info->flags)) { | 701 | (unsigned long *)&sh_info->flags)) { |
686 | dev_dbg(&psdev->dev->dev, | 702 | dev_dbg(&psdev->dev->dev, |
687 | "schedule pci_conf service in " DRV_NAME "\n"); | 703 | "schedule pci_conf service in " DRV_NAME "\n"); |
688 | xen_pcibk_test_and_schedule_op(psdev->pdev); | 704 | xen_pcibk_test_and_schedule_op(psdev->pdev); |
@@ -1502,6 +1518,53 @@ parse_error: | |||
1502 | fs_initcall(pcistub_init); | 1518 | fs_initcall(pcistub_init); |
1503 | #endif | 1519 | #endif |
1504 | 1520 | ||
1521 | #ifdef CONFIG_PCI_IOV | ||
1522 | static struct pcistub_device *find_vfs(const struct pci_dev *pdev) | ||
1523 | { | ||
1524 | struct pcistub_device *psdev = NULL; | ||
1525 | unsigned long flags; | ||
1526 | bool found = false; | ||
1527 | |||
1528 | spin_lock_irqsave(&pcistub_devices_lock, flags); | ||
1529 | list_for_each_entry(psdev, &pcistub_devices, dev_list) { | ||
1530 | if (!psdev->pdev && psdev->dev != pdev | ||
1531 | && pci_physfn(psdev->dev) == pdev) { | ||
1532 | found = true; | ||
1533 | break; | ||
1534 | } | ||
1535 | } | ||
1536 | spin_unlock_irqrestore(&pcistub_devices_lock, flags); | ||
1537 | if (found) | ||
1538 | return psdev; | ||
1539 | return NULL; | ||
1540 | } | ||
1541 | |||
1542 | static int pci_stub_notifier(struct notifier_block *nb, | ||
1543 | unsigned long action, void *data) | ||
1544 | { | ||
1545 | struct device *dev = data; | ||
1546 | const struct pci_dev *pdev = to_pci_dev(dev); | ||
1547 | |||
1548 | if (action != BUS_NOTIFY_UNBIND_DRIVER) | ||
1549 | return NOTIFY_DONE; | ||
1550 | |||
1551 | if (!pdev->is_physfn) | ||
1552 | return NOTIFY_DONE; | ||
1553 | |||
1554 | for (;;) { | ||
1555 | struct pcistub_device *psdev = find_vfs(pdev); | ||
1556 | if (!psdev) | ||
1557 | break; | ||
1558 | device_release_driver(&psdev->dev->dev); | ||
1559 | } | ||
1560 | return NOTIFY_DONE; | ||
1561 | } | ||
1562 | |||
1563 | static struct notifier_block pci_stub_nb = { | ||
1564 | .notifier_call = pci_stub_notifier, | ||
1565 | }; | ||
1566 | #endif | ||
1567 | |||
1505 | static int __init xen_pcibk_init(void) | 1568 | static int __init xen_pcibk_init(void) |
1506 | { | 1569 | { |
1507 | int err; | 1570 | int err; |
@@ -1523,12 +1586,19 @@ static int __init xen_pcibk_init(void) | |||
1523 | err = xen_pcibk_xenbus_register(); | 1586 | err = xen_pcibk_xenbus_register(); |
1524 | if (err) | 1587 | if (err) |
1525 | pcistub_exit(); | 1588 | pcistub_exit(); |
1589 | #ifdef CONFIG_PCI_IOV | ||
1590 | else | ||
1591 | bus_register_notifier(&pci_bus_type, &pci_stub_nb); | ||
1592 | #endif | ||
1526 | 1593 | ||
1527 | return err; | 1594 | return err; |
1528 | } | 1595 | } |
1529 | 1596 | ||
1530 | static void __exit xen_pcibk_cleanup(void) | 1597 | static void __exit xen_pcibk_cleanup(void) |
1531 | { | 1598 | { |
1599 | #ifdef CONFIG_PCI_IOV | ||
1600 | bus_unregister_notifier(&pci_bus_type, &pci_stub_nb); | ||
1601 | #endif | ||
1532 | xen_pcibk_xenbus_unregister(); | 1602 | xen_pcibk_xenbus_unregister(); |
1533 | pcistub_exit(); | 1603 | pcistub_exit(); |
1534 | } | 1604 | } |
diff --git a/drivers/xen/xen-pciback/pciback.h b/drivers/xen/xen-pciback/pciback.h index f72af87640e0..58e38d586f52 100644 --- a/drivers/xen/xen-pciback/pciback.h +++ b/drivers/xen/xen-pciback/pciback.h | |||
@@ -99,7 +99,8 @@ struct xen_pcibk_backend { | |||
99 | unsigned int *domain, unsigned int *bus, | 99 | unsigned int *domain, unsigned int *bus, |
100 | unsigned int *devfn); | 100 | unsigned int *devfn); |
101 | int (*publish)(struct xen_pcibk_device *pdev, publish_pci_root_cb cb); | 101 | int (*publish)(struct xen_pcibk_device *pdev, publish_pci_root_cb cb); |
102 | void (*release)(struct xen_pcibk_device *pdev, struct pci_dev *dev); | 102 | void (*release)(struct xen_pcibk_device *pdev, struct pci_dev *dev, |
103 | bool lock); | ||
103 | int (*add)(struct xen_pcibk_device *pdev, struct pci_dev *dev, | 104 | int (*add)(struct xen_pcibk_device *pdev, struct pci_dev *dev, |
104 | int devid, publish_pci_dev_cb publish_cb); | 105 | int devid, publish_pci_dev_cb publish_cb); |
105 | struct pci_dev *(*get)(struct xen_pcibk_device *pdev, | 106 | struct pci_dev *(*get)(struct xen_pcibk_device *pdev, |
@@ -122,10 +123,10 @@ static inline int xen_pcibk_add_pci_dev(struct xen_pcibk_device *pdev, | |||
122 | } | 123 | } |
123 | 124 | ||
124 | static inline void xen_pcibk_release_pci_dev(struct xen_pcibk_device *pdev, | 125 | static inline void xen_pcibk_release_pci_dev(struct xen_pcibk_device *pdev, |
125 | struct pci_dev *dev) | 126 | struct pci_dev *dev, bool lock) |
126 | { | 127 | { |
127 | if (xen_pcibk_backend && xen_pcibk_backend->release) | 128 | if (xen_pcibk_backend && xen_pcibk_backend->release) |
128 | return xen_pcibk_backend->release(pdev, dev); | 129 | return xen_pcibk_backend->release(pdev, dev, lock); |
129 | } | 130 | } |
130 | 131 | ||
131 | static inline struct pci_dev * | 132 | static inline struct pci_dev * |
diff --git a/drivers/xen/xen-pciback/vpci.c b/drivers/xen/xen-pciback/vpci.c index 51afff96c515..c99f8bb1c56c 100644 --- a/drivers/xen/xen-pciback/vpci.c +++ b/drivers/xen/xen-pciback/vpci.c | |||
@@ -145,7 +145,7 @@ out: | |||
145 | } | 145 | } |
146 | 146 | ||
147 | static void __xen_pcibk_release_pci_dev(struct xen_pcibk_device *pdev, | 147 | static void __xen_pcibk_release_pci_dev(struct xen_pcibk_device *pdev, |
148 | struct pci_dev *dev) | 148 | struct pci_dev *dev, bool lock) |
149 | { | 149 | { |
150 | int slot; | 150 | int slot; |
151 | struct vpci_dev_data *vpci_dev = pdev->pci_dev_data; | 151 | struct vpci_dev_data *vpci_dev = pdev->pci_dev_data; |
@@ -169,8 +169,13 @@ static void __xen_pcibk_release_pci_dev(struct xen_pcibk_device *pdev, | |||
169 | out: | 169 | out: |
170 | mutex_unlock(&vpci_dev->lock); | 170 | mutex_unlock(&vpci_dev->lock); |
171 | 171 | ||
172 | if (found_dev) | 172 | if (found_dev) { |
173 | if (lock) | ||
174 | device_lock(&found_dev->dev); | ||
173 | pcistub_put_pci_dev(found_dev); | 175 | pcistub_put_pci_dev(found_dev); |
176 | if (lock) | ||
177 | device_unlock(&found_dev->dev); | ||
178 | } | ||
174 | } | 179 | } |
175 | 180 | ||
176 | static int __xen_pcibk_init_devices(struct xen_pcibk_device *pdev) | 181 | static int __xen_pcibk_init_devices(struct xen_pcibk_device *pdev) |
@@ -208,8 +213,11 @@ static void __xen_pcibk_release_devices(struct xen_pcibk_device *pdev) | |||
208 | struct pci_dev_entry *e, *tmp; | 213 | struct pci_dev_entry *e, *tmp; |
209 | list_for_each_entry_safe(e, tmp, &vpci_dev->dev_list[slot], | 214 | list_for_each_entry_safe(e, tmp, &vpci_dev->dev_list[slot], |
210 | list) { | 215 | list) { |
216 | struct pci_dev *dev = e->dev; | ||
211 | list_del(&e->list); | 217 | list_del(&e->list); |
212 | pcistub_put_pci_dev(e->dev); | 218 | device_lock(&dev->dev); |
219 | pcistub_put_pci_dev(dev); | ||
220 | device_unlock(&dev->dev); | ||
213 | kfree(e); | 221 | kfree(e); |
214 | } | 222 | } |
215 | } | 223 | } |
diff --git a/drivers/xen/xen-pciback/xenbus.c b/drivers/xen/xen-pciback/xenbus.c index ad8d30c088fe..fe17c80ff4b7 100644 --- a/drivers/xen/xen-pciback/xenbus.c +++ b/drivers/xen/xen-pciback/xenbus.c | |||
@@ -247,7 +247,7 @@ static int xen_pcibk_export_device(struct xen_pcibk_device *pdev, | |||
247 | if (err) | 247 | if (err) |
248 | goto out; | 248 | goto out; |
249 | 249 | ||
250 | dev_dbg(&dev->dev, "registering for %d\n", pdev->xdev->otherend_id); | 250 | dev_info(&dev->dev, "registering for %d\n", pdev->xdev->otherend_id); |
251 | if (xen_register_device_domain_owner(dev, | 251 | if (xen_register_device_domain_owner(dev, |
252 | pdev->xdev->otherend_id) != 0) { | 252 | pdev->xdev->otherend_id) != 0) { |
253 | dev_err(&dev->dev, "Stealing ownership from dom%d.\n", | 253 | dev_err(&dev->dev, "Stealing ownership from dom%d.\n", |
@@ -291,7 +291,7 @@ static int xen_pcibk_remove_device(struct xen_pcibk_device *pdev, | |||
291 | 291 | ||
292 | /* N.B. This ends up calling pcistub_put_pci_dev which ends up | 292 | /* N.B. This ends up calling pcistub_put_pci_dev which ends up |
293 | * doing the FLR. */ | 293 | * doing the FLR. */ |
294 | xen_pcibk_release_pci_dev(pdev, dev); | 294 | xen_pcibk_release_pci_dev(pdev, dev, true /* use the lock. */); |
295 | 295 | ||
296 | out: | 296 | out: |
297 | return err; | 297 | return err; |