diff options
author | Bjorn Helgaas <bhelgaas@google.com> | 2018-04-04 14:28:50 -0400 |
---|---|---|
committer | Bjorn Helgaas <helgaas@kernel.org> | 2018-04-04 14:28:50 -0400 |
commit | 84d4d6f882175e02ab630fd444987e1e1b12e90a (patch) | |
tree | 2714371e6e49a1dbc97ac3fe0bbe9154e9522693 | |
parent | 74716ff7abb483111eb44104b05799226e69b4b3 (diff) | |
parent | 948373b3ed1bcf05a237c24675b84804315aff14 (diff) |
Merge branch 'lorenzo/pci/hv'
* lorenzo/pci/hv:
PCI: hv: Only queue new work items in hv_pci_devices_present() if necessary
PCI: hv: Remove the bogus test in hv_eject_device_work()
PCI: hv: Fix a comment typo in _hv_pcifront_read_config()
PCI: hv: Fix 2 hang issues in hv_compose_msi_msg()
PCI: hv: Serialize the present and eject work items
-rw-r--r-- | drivers/pci/host/pci-hyperv.c | 112 |
1 files changed, 87 insertions, 25 deletions
diff --git a/drivers/pci/host/pci-hyperv.c b/drivers/pci/host/pci-hyperv.c index 2faf38eab785..50cdefe3f6d3 100644 --- a/drivers/pci/host/pci-hyperv.c +++ b/drivers/pci/host/pci-hyperv.c | |||
@@ -447,7 +447,6 @@ struct hv_pcibus_device { | |||
447 | spinlock_t device_list_lock; /* Protect lists below */ | 447 | spinlock_t device_list_lock; /* Protect lists below */ |
448 | void __iomem *cfg_addr; | 448 | void __iomem *cfg_addr; |
449 | 449 | ||
450 | struct semaphore enum_sem; | ||
451 | struct list_head resources_for_children; | 450 | struct list_head resources_for_children; |
452 | 451 | ||
453 | struct list_head children; | 452 | struct list_head children; |
@@ -461,6 +460,8 @@ struct hv_pcibus_device { | |||
461 | struct retarget_msi_interrupt retarget_msi_interrupt_params; | 460 | struct retarget_msi_interrupt retarget_msi_interrupt_params; |
462 | 461 | ||
463 | spinlock_t retarget_msi_interrupt_lock; | 462 | spinlock_t retarget_msi_interrupt_lock; |
463 | |||
464 | struct workqueue_struct *wq; | ||
464 | }; | 465 | }; |
465 | 466 | ||
466 | /* | 467 | /* |
@@ -520,6 +521,8 @@ struct hv_pci_compl { | |||
520 | s32 completion_status; | 521 | s32 completion_status; |
521 | }; | 522 | }; |
522 | 523 | ||
524 | static void hv_pci_onchannelcallback(void *context); | ||
525 | |||
523 | /** | 526 | /** |
524 | * hv_pci_generic_compl() - Invoked for a completion packet | 527 | * hv_pci_generic_compl() - Invoked for a completion packet |
525 | * @context: Set up by the sender of the packet. | 528 | * @context: Set up by the sender of the packet. |
@@ -653,7 +656,7 @@ static void _hv_pcifront_read_config(struct hv_pci_dev *hpdev, int where, | |||
653 | break; | 656 | break; |
654 | } | 657 | } |
655 | /* | 658 | /* |
656 | * Make sure the write was done before we release the spinlock | 659 | * Make sure the read was done before we release the spinlock |
657 | * allowing consecutive reads/writes. | 660 | * allowing consecutive reads/writes. |
658 | */ | 661 | */ |
659 | mb(); | 662 | mb(); |
@@ -664,6 +667,31 @@ static void _hv_pcifront_read_config(struct hv_pci_dev *hpdev, int where, | |||
664 | } | 667 | } |
665 | } | 668 | } |
666 | 669 | ||
670 | static u16 hv_pcifront_get_vendor_id(struct hv_pci_dev *hpdev) | ||
671 | { | ||
672 | u16 ret; | ||
673 | unsigned long flags; | ||
674 | void __iomem *addr = hpdev->hbus->cfg_addr + CFG_PAGE_OFFSET + | ||
675 | PCI_VENDOR_ID; | ||
676 | |||
677 | spin_lock_irqsave(&hpdev->hbus->config_lock, flags); | ||
678 | |||
679 | /* Choose the function to be read. (See comment above) */ | ||
680 | writel(hpdev->desc.win_slot.slot, hpdev->hbus->cfg_addr); | ||
681 | /* Make sure the function was chosen before we start reading. */ | ||
682 | mb(); | ||
683 | /* Read from that function's config space. */ | ||
684 | ret = readw(addr); | ||
685 | /* | ||
686 | * mb() is not required here, because the spin_unlock_irqrestore() | ||
687 | * is a barrier. | ||
688 | */ | ||
689 | |||
690 | spin_unlock_irqrestore(&hpdev->hbus->config_lock, flags); | ||
691 | |||
692 | return ret; | ||
693 | } | ||
694 | |||
667 | /** | 695 | /** |
668 | * _hv_pcifront_write_config() - Internal PCI config write | 696 | * _hv_pcifront_write_config() - Internal PCI config write |
669 | * @hpdev: The PCI driver's representation of the device | 697 | * @hpdev: The PCI driver's representation of the device |
@@ -1106,8 +1134,37 @@ static void hv_compose_msi_msg(struct irq_data *data, struct msi_msg *msg) | |||
1106 | * Since this function is called with IRQ locks held, can't | 1134 | * Since this function is called with IRQ locks held, can't |
1107 | * do normal wait for completion; instead poll. | 1135 | * do normal wait for completion; instead poll. |
1108 | */ | 1136 | */ |
1109 | while (!try_wait_for_completion(&comp.comp_pkt.host_event)) | 1137 | while (!try_wait_for_completion(&comp.comp_pkt.host_event)) { |
1138 | /* 0xFFFF means an invalid PCI VENDOR ID. */ | ||
1139 | if (hv_pcifront_get_vendor_id(hpdev) == 0xFFFF) { | ||
1140 | dev_err_once(&hbus->hdev->device, | ||
1141 | "the device has gone\n"); | ||
1142 | goto free_int_desc; | ||
1143 | } | ||
1144 | |||
1145 | /* | ||
1146 | * When the higher level interrupt code calls us with | ||
1147 | * interrupt disabled, we must poll the channel by calling | ||
1148 | * the channel callback directly when channel->target_cpu is | ||
1149 | * the current CPU. When the higher level interrupt code | ||
1150 | * calls us with interrupt enabled, let's add the | ||
1151 | * local_bh_disable()/enable() to avoid race. | ||
1152 | */ | ||
1153 | local_bh_disable(); | ||
1154 | |||
1155 | if (hbus->hdev->channel->target_cpu == smp_processor_id()) | ||
1156 | hv_pci_onchannelcallback(hbus); | ||
1157 | |||
1158 | local_bh_enable(); | ||
1159 | |||
1160 | if (hpdev->state == hv_pcichild_ejecting) { | ||
1161 | dev_err_once(&hbus->hdev->device, | ||
1162 | "the device is being ejected\n"); | ||
1163 | goto free_int_desc; | ||
1164 | } | ||
1165 | |||
1110 | udelay(100); | 1166 | udelay(100); |
1167 | } | ||
1111 | 1168 | ||
1112 | if (comp.comp_pkt.completion_status < 0) { | 1169 | if (comp.comp_pkt.completion_status < 0) { |
1113 | dev_err(&hbus->hdev->device, | 1170 | dev_err(&hbus->hdev->device, |
@@ -1590,12 +1647,8 @@ static struct hv_pci_dev *get_pcichild_wslot(struct hv_pcibus_device *hbus, | |||
1590 | * It must also treat the omission of a previously observed device as | 1647 | * It must also treat the omission of a previously observed device as |
1591 | * notification that the device no longer exists. | 1648 | * notification that the device no longer exists. |
1592 | * | 1649 | * |
1593 | * Note that this function is a work item, and it may not be | 1650 | * Note that this function is serialized with hv_eject_device_work(), |
1594 | * invoked in the order that it was queued. Back to back | 1651 | * because both are pushed to the ordered workqueue hbus->wq. |
1595 | * updates of the list of present devices may involve queuing | ||
1596 | * multiple work items, and this one may run before ones that | ||
1597 | * were sent later. As such, this function only does something | ||
1598 | * if is the last one in the queue. | ||
1599 | */ | 1652 | */ |
1600 | static void pci_devices_present_work(struct work_struct *work) | 1653 | static void pci_devices_present_work(struct work_struct *work) |
1601 | { | 1654 | { |
@@ -1616,11 +1669,6 @@ static void pci_devices_present_work(struct work_struct *work) | |||
1616 | 1669 | ||
1617 | INIT_LIST_HEAD(&removed); | 1670 | INIT_LIST_HEAD(&removed); |
1618 | 1671 | ||
1619 | if (down_interruptible(&hbus->enum_sem)) { | ||
1620 | put_hvpcibus(hbus); | ||
1621 | return; | ||
1622 | } | ||
1623 | |||
1624 | /* Pull this off the queue and process it if it was the last one. */ | 1672 | /* Pull this off the queue and process it if it was the last one. */ |
1625 | spin_lock_irqsave(&hbus->device_list_lock, flags); | 1673 | spin_lock_irqsave(&hbus->device_list_lock, flags); |
1626 | while (!list_empty(&hbus->dr_list)) { | 1674 | while (!list_empty(&hbus->dr_list)) { |
@@ -1637,7 +1685,6 @@ static void pci_devices_present_work(struct work_struct *work) | |||
1637 | spin_unlock_irqrestore(&hbus->device_list_lock, flags); | 1685 | spin_unlock_irqrestore(&hbus->device_list_lock, flags); |
1638 | 1686 | ||
1639 | if (!dr) { | 1687 | if (!dr) { |
1640 | up(&hbus->enum_sem); | ||
1641 | put_hvpcibus(hbus); | 1688 | put_hvpcibus(hbus); |
1642 | return; | 1689 | return; |
1643 | } | 1690 | } |
@@ -1724,7 +1771,6 @@ static void pci_devices_present_work(struct work_struct *work) | |||
1724 | break; | 1771 | break; |
1725 | } | 1772 | } |
1726 | 1773 | ||
1727 | up(&hbus->enum_sem); | ||
1728 | put_hvpcibus(hbus); | 1774 | put_hvpcibus(hbus); |
1729 | kfree(dr); | 1775 | kfree(dr); |
1730 | } | 1776 | } |
@@ -1743,6 +1789,7 @@ static void hv_pci_devices_present(struct hv_pcibus_device *hbus, | |||
1743 | struct hv_dr_state *dr; | 1789 | struct hv_dr_state *dr; |
1744 | struct hv_dr_work *dr_wrk; | 1790 | struct hv_dr_work *dr_wrk; |
1745 | unsigned long flags; | 1791 | unsigned long flags; |
1792 | bool pending_dr; | ||
1746 | 1793 | ||
1747 | dr_wrk = kzalloc(sizeof(*dr_wrk), GFP_NOWAIT); | 1794 | dr_wrk = kzalloc(sizeof(*dr_wrk), GFP_NOWAIT); |
1748 | if (!dr_wrk) | 1795 | if (!dr_wrk) |
@@ -1766,11 +1813,21 @@ static void hv_pci_devices_present(struct hv_pcibus_device *hbus, | |||
1766 | } | 1813 | } |
1767 | 1814 | ||
1768 | spin_lock_irqsave(&hbus->device_list_lock, flags); | 1815 | spin_lock_irqsave(&hbus->device_list_lock, flags); |
1816 | /* | ||
1817 | * If pending_dr is true, we have already queued a work, | ||
1818 | * which will see the new dr. Otherwise, we need to | ||
1819 | * queue a new work. | ||
1820 | */ | ||
1821 | pending_dr = !list_empty(&hbus->dr_list); | ||
1769 | list_add_tail(&dr->list_entry, &hbus->dr_list); | 1822 | list_add_tail(&dr->list_entry, &hbus->dr_list); |
1770 | spin_unlock_irqrestore(&hbus->device_list_lock, flags); | 1823 | spin_unlock_irqrestore(&hbus->device_list_lock, flags); |
1771 | 1824 | ||
1772 | get_hvpcibus(hbus); | 1825 | if (pending_dr) { |
1773 | schedule_work(&dr_wrk->wrk); | 1826 | kfree(dr_wrk); |
1827 | } else { | ||
1828 | get_hvpcibus(hbus); | ||
1829 | queue_work(hbus->wq, &dr_wrk->wrk); | ||
1830 | } | ||
1774 | } | 1831 | } |
1775 | 1832 | ||
1776 | /** | 1833 | /** |
@@ -1796,10 +1853,7 @@ static void hv_eject_device_work(struct work_struct *work) | |||
1796 | 1853 | ||
1797 | hpdev = container_of(work, struct hv_pci_dev, wrk); | 1854 | hpdev = container_of(work, struct hv_pci_dev, wrk); |
1798 | 1855 | ||
1799 | if (hpdev->state != hv_pcichild_ejecting) { | 1856 | WARN_ON(hpdev->state != hv_pcichild_ejecting); |
1800 | put_pcichild(hpdev, hv_pcidev_ref_pnp); | ||
1801 | return; | ||
1802 | } | ||
1803 | 1857 | ||
1804 | /* | 1858 | /* |
1805 | * Ejection can come before or after the PCI bus has been set up, so | 1859 | * Ejection can come before or after the PCI bus has been set up, so |
@@ -1848,7 +1902,7 @@ static void hv_pci_eject_device(struct hv_pci_dev *hpdev) | |||
1848 | get_pcichild(hpdev, hv_pcidev_ref_pnp); | 1902 | get_pcichild(hpdev, hv_pcidev_ref_pnp); |
1849 | INIT_WORK(&hpdev->wrk, hv_eject_device_work); | 1903 | INIT_WORK(&hpdev->wrk, hv_eject_device_work); |
1850 | get_hvpcibus(hpdev->hbus); | 1904 | get_hvpcibus(hpdev->hbus); |
1851 | schedule_work(&hpdev->wrk); | 1905 | queue_work(hpdev->hbus->wq, &hpdev->wrk); |
1852 | } | 1906 | } |
1853 | 1907 | ||
1854 | /** | 1908 | /** |
@@ -2461,13 +2515,18 @@ static int hv_pci_probe(struct hv_device *hdev, | |||
2461 | spin_lock_init(&hbus->config_lock); | 2515 | spin_lock_init(&hbus->config_lock); |
2462 | spin_lock_init(&hbus->device_list_lock); | 2516 | spin_lock_init(&hbus->device_list_lock); |
2463 | spin_lock_init(&hbus->retarget_msi_interrupt_lock); | 2517 | spin_lock_init(&hbus->retarget_msi_interrupt_lock); |
2464 | sema_init(&hbus->enum_sem, 1); | ||
2465 | init_completion(&hbus->remove_event); | 2518 | init_completion(&hbus->remove_event); |
2519 | hbus->wq = alloc_ordered_workqueue("hv_pci_%x", 0, | ||
2520 | hbus->sysdata.domain); | ||
2521 | if (!hbus->wq) { | ||
2522 | ret = -ENOMEM; | ||
2523 | goto free_bus; | ||
2524 | } | ||
2466 | 2525 | ||
2467 | ret = vmbus_open(hdev->channel, pci_ring_size, pci_ring_size, NULL, 0, | 2526 | ret = vmbus_open(hdev->channel, pci_ring_size, pci_ring_size, NULL, 0, |
2468 | hv_pci_onchannelcallback, hbus); | 2527 | hv_pci_onchannelcallback, hbus); |
2469 | if (ret) | 2528 | if (ret) |
2470 | goto free_bus; | 2529 | goto destroy_wq; |
2471 | 2530 | ||
2472 | hv_set_drvdata(hdev, hbus); | 2531 | hv_set_drvdata(hdev, hbus); |
2473 | 2532 | ||
@@ -2536,6 +2595,8 @@ free_config: | |||
2536 | hv_free_config_window(hbus); | 2595 | hv_free_config_window(hbus); |
2537 | close: | 2596 | close: |
2538 | vmbus_close(hdev->channel); | 2597 | vmbus_close(hdev->channel); |
2598 | destroy_wq: | ||
2599 | destroy_workqueue(hbus->wq); | ||
2539 | free_bus: | 2600 | free_bus: |
2540 | free_page((unsigned long)hbus); | 2601 | free_page((unsigned long)hbus); |
2541 | return ret; | 2602 | return ret; |
@@ -2615,6 +2676,7 @@ static int hv_pci_remove(struct hv_device *hdev) | |||
2615 | irq_domain_free_fwnode(hbus->sysdata.fwnode); | 2676 | irq_domain_free_fwnode(hbus->sysdata.fwnode); |
2616 | put_hvpcibus(hbus); | 2677 | put_hvpcibus(hbus); |
2617 | wait_for_completion(&hbus->remove_event); | 2678 | wait_for_completion(&hbus->remove_event); |
2679 | destroy_workqueue(hbus->wq); | ||
2618 | free_page((unsigned long)hbus); | 2680 | free_page((unsigned long)hbus); |
2619 | return 0; | 2681 | return 0; |
2620 | } | 2682 | } |