diff options
Diffstat (limited to 'drivers/pci/host/pci-hyperv.c')
-rw-r--r-- | drivers/pci/host/pci-hyperv.c | 46 |
1 files changed, 35 insertions, 11 deletions
diff --git a/drivers/pci/host/pci-hyperv.c b/drivers/pci/host/pci-hyperv.c index ada98569b78e..84936383e269 100644 --- a/drivers/pci/host/pci-hyperv.c +++ b/drivers/pci/host/pci-hyperv.c | |||
@@ -56,6 +56,7 @@ | |||
56 | #include <asm/apic.h> | 56 | #include <asm/apic.h> |
57 | #include <linux/msi.h> | 57 | #include <linux/msi.h> |
58 | #include <linux/hyperv.h> | 58 | #include <linux/hyperv.h> |
59 | #include <linux/refcount.h> | ||
59 | #include <asm/mshyperv.h> | 60 | #include <asm/mshyperv.h> |
60 | 61 | ||
61 | /* | 62 | /* |
@@ -72,6 +73,7 @@ enum { | |||
72 | PCI_PROTOCOL_VERSION_CURRENT = PCI_PROTOCOL_VERSION_1_1 | 73 | PCI_PROTOCOL_VERSION_CURRENT = PCI_PROTOCOL_VERSION_1_1 |
73 | }; | 74 | }; |
74 | 75 | ||
76 | #define CPU_AFFINITY_ALL -1ULL | ||
75 | #define PCI_CONFIG_MMIO_LENGTH 0x2000 | 77 | #define PCI_CONFIG_MMIO_LENGTH 0x2000 |
76 | #define CFG_PAGE_OFFSET 0x1000 | 78 | #define CFG_PAGE_OFFSET 0x1000 |
77 | #define CFG_PAGE_SIZE (PCI_CONFIG_MMIO_LENGTH - CFG_PAGE_OFFSET) | 79 | #define CFG_PAGE_SIZE (PCI_CONFIG_MMIO_LENGTH - CFG_PAGE_OFFSET) |
@@ -350,6 +352,7 @@ enum hv_pcibus_state { | |||
350 | hv_pcibus_init = 0, | 352 | hv_pcibus_init = 0, |
351 | hv_pcibus_probed, | 353 | hv_pcibus_probed, |
352 | hv_pcibus_installed, | 354 | hv_pcibus_installed, |
355 | hv_pcibus_removed, | ||
353 | hv_pcibus_maximum | 356 | hv_pcibus_maximum |
354 | }; | 357 | }; |
355 | 358 | ||
@@ -421,7 +424,7 @@ enum hv_pcidev_ref_reason { | |||
421 | struct hv_pci_dev { | 424 | struct hv_pci_dev { |
422 | /* List protected by pci_rescan_remove_lock */ | 425 | /* List protected by pci_rescan_remove_lock */ |
423 | struct list_head list_entry; | 426 | struct list_head list_entry; |
424 | atomic_t refs; | 427 | refcount_t refs; |
425 | enum hv_pcichild_state state; | 428 | enum hv_pcichild_state state; |
426 | struct pci_function_description desc; | 429 | struct pci_function_description desc; |
427 | bool reported_missing; | 430 | bool reported_missing; |
@@ -876,7 +879,7 @@ static void hv_compose_msi_msg(struct irq_data *data, struct msi_msg *msg) | |||
876 | hv_int_desc_free(hpdev, int_desc); | 879 | hv_int_desc_free(hpdev, int_desc); |
877 | } | 880 | } |
878 | 881 | ||
879 | int_desc = kzalloc(sizeof(*int_desc), GFP_KERNEL); | 882 | int_desc = kzalloc(sizeof(*int_desc), GFP_ATOMIC); |
880 | if (!int_desc) | 883 | if (!int_desc) |
881 | goto drop_reference; | 884 | goto drop_reference; |
882 | 885 | ||
@@ -897,9 +900,13 @@ static void hv_compose_msi_msg(struct irq_data *data, struct msi_msg *msg) | |||
897 | * processors because Hyper-V only supports 64 in a guest. | 900 | * processors because Hyper-V only supports 64 in a guest. |
898 | */ | 901 | */ |
899 | affinity = irq_data_get_affinity_mask(data); | 902 | affinity = irq_data_get_affinity_mask(data); |
900 | for_each_cpu_and(cpu, affinity, cpu_online_mask) { | 903 | if (cpumask_weight(affinity) >= 32) { |
901 | int_pkt->int_desc.cpu_mask |= | 904 | int_pkt->int_desc.cpu_mask = CPU_AFFINITY_ALL; |
902 | (1ULL << vmbus_cpu_number_to_vp_number(cpu)); | 905 | } else { |
906 | for_each_cpu_and(cpu, affinity, cpu_online_mask) { | ||
907 | int_pkt->int_desc.cpu_mask |= | ||
908 | (1ULL << vmbus_cpu_number_to_vp_number(cpu)); | ||
909 | } | ||
903 | } | 910 | } |
904 | 911 | ||
905 | ret = vmbus_sendpacket(hpdev->hbus->hdev->channel, int_pkt, | 912 | ret = vmbus_sendpacket(hpdev->hbus->hdev->channel, int_pkt, |
@@ -1208,9 +1215,11 @@ static int create_root_hv_pci_bus(struct hv_pcibus_device *hbus) | |||
1208 | hbus->pci_bus->msi = &hbus->msi_chip; | 1215 | hbus->pci_bus->msi = &hbus->msi_chip; |
1209 | hbus->pci_bus->msi->dev = &hbus->hdev->device; | 1216 | hbus->pci_bus->msi->dev = &hbus->hdev->device; |
1210 | 1217 | ||
1218 | pci_lock_rescan_remove(); | ||
1211 | pci_scan_child_bus(hbus->pci_bus); | 1219 | pci_scan_child_bus(hbus->pci_bus); |
1212 | pci_bus_assign_resources(hbus->pci_bus); | 1220 | pci_bus_assign_resources(hbus->pci_bus); |
1213 | pci_bus_add_devices(hbus->pci_bus); | 1221 | pci_bus_add_devices(hbus->pci_bus); |
1222 | pci_unlock_rescan_remove(); | ||
1214 | hbus->state = hv_pcibus_installed; | 1223 | hbus->state = hv_pcibus_installed; |
1215 | return 0; | 1224 | return 0; |
1216 | } | 1225 | } |
@@ -1254,13 +1263,13 @@ static void q_resource_requirements(void *context, struct pci_response *resp, | |||
1254 | static void get_pcichild(struct hv_pci_dev *hpdev, | 1263 | static void get_pcichild(struct hv_pci_dev *hpdev, |
1255 | enum hv_pcidev_ref_reason reason) | 1264 | enum hv_pcidev_ref_reason reason) |
1256 | { | 1265 | { |
1257 | atomic_inc(&hpdev->refs); | 1266 | refcount_inc(&hpdev->refs); |
1258 | } | 1267 | } |
1259 | 1268 | ||
1260 | static void put_pcichild(struct hv_pci_dev *hpdev, | 1269 | static void put_pcichild(struct hv_pci_dev *hpdev, |
1261 | enum hv_pcidev_ref_reason reason) | 1270 | enum hv_pcidev_ref_reason reason) |
1262 | { | 1271 | { |
1263 | if (atomic_dec_and_test(&hpdev->refs)) | 1272 | if (refcount_dec_and_test(&hpdev->refs)) |
1264 | kfree(hpdev); | 1273 | kfree(hpdev); |
1265 | } | 1274 | } |
1266 | 1275 | ||
@@ -1314,7 +1323,7 @@ static struct hv_pci_dev *new_pcichild_device(struct hv_pcibus_device *hbus, | |||
1314 | wait_for_completion(&comp_pkt.host_event); | 1323 | wait_for_completion(&comp_pkt.host_event); |
1315 | 1324 | ||
1316 | hpdev->desc = *desc; | 1325 | hpdev->desc = *desc; |
1317 | get_pcichild(hpdev, hv_pcidev_ref_initial); | 1326 | refcount_set(&hpdev->refs, 1); |
1318 | get_pcichild(hpdev, hv_pcidev_ref_childlist); | 1327 | get_pcichild(hpdev, hv_pcidev_ref_childlist); |
1319 | spin_lock_irqsave(&hbus->device_list_lock, flags); | 1328 | spin_lock_irqsave(&hbus->device_list_lock, flags); |
1320 | 1329 | ||
@@ -1504,13 +1513,24 @@ static void pci_devices_present_work(struct work_struct *work) | |||
1504 | put_pcichild(hpdev, hv_pcidev_ref_initial); | 1513 | put_pcichild(hpdev, hv_pcidev_ref_initial); |
1505 | } | 1514 | } |
1506 | 1515 | ||
1507 | /* Tell the core to rescan bus because there may have been changes. */ | 1516 | switch(hbus->state) { |
1508 | if (hbus->state == hv_pcibus_installed) { | 1517 | case hv_pcibus_installed: |
1518 | /* | ||
1519 | * Tell the core to rescan bus | ||
1520 | * because there may have been changes. | ||
1521 | */ | ||
1509 | pci_lock_rescan_remove(); | 1522 | pci_lock_rescan_remove(); |
1510 | pci_scan_child_bus(hbus->pci_bus); | 1523 | pci_scan_child_bus(hbus->pci_bus); |
1511 | pci_unlock_rescan_remove(); | 1524 | pci_unlock_rescan_remove(); |
1512 | } else { | 1525 | break; |
1526 | |||
1527 | case hv_pcibus_init: | ||
1528 | case hv_pcibus_probed: | ||
1513 | survey_child_resources(hbus); | 1529 | survey_child_resources(hbus); |
1530 | break; | ||
1531 | |||
1532 | default: | ||
1533 | break; | ||
1514 | } | 1534 | } |
1515 | 1535 | ||
1516 | up(&hbus->enum_sem); | 1536 | up(&hbus->enum_sem); |
@@ -1600,8 +1620,10 @@ static void hv_eject_device_work(struct work_struct *work) | |||
1600 | pdev = pci_get_domain_bus_and_slot(hpdev->hbus->sysdata.domain, 0, | 1620 | pdev = pci_get_domain_bus_and_slot(hpdev->hbus->sysdata.domain, 0, |
1601 | wslot); | 1621 | wslot); |
1602 | if (pdev) { | 1622 | if (pdev) { |
1623 | pci_lock_rescan_remove(); | ||
1603 | pci_stop_and_remove_bus_device(pdev); | 1624 | pci_stop_and_remove_bus_device(pdev); |
1604 | pci_dev_put(pdev); | 1625 | pci_dev_put(pdev); |
1626 | pci_unlock_rescan_remove(); | ||
1605 | } | 1627 | } |
1606 | 1628 | ||
1607 | spin_lock_irqsave(&hpdev->hbus->device_list_lock, flags); | 1629 | spin_lock_irqsave(&hpdev->hbus->device_list_lock, flags); |
@@ -2185,6 +2207,7 @@ static int hv_pci_probe(struct hv_device *hdev, | |||
2185 | hbus = kzalloc(sizeof(*hbus), GFP_KERNEL); | 2207 | hbus = kzalloc(sizeof(*hbus), GFP_KERNEL); |
2186 | if (!hbus) | 2208 | if (!hbus) |
2187 | return -ENOMEM; | 2209 | return -ENOMEM; |
2210 | hbus->state = hv_pcibus_init; | ||
2188 | 2211 | ||
2189 | /* | 2212 | /* |
2190 | * The PCI bus "domain" is what is called "segment" in ACPI and | 2213 | * The PCI bus "domain" is what is called "segment" in ACPI and |
@@ -2348,6 +2371,7 @@ static int hv_pci_remove(struct hv_device *hdev) | |||
2348 | pci_stop_root_bus(hbus->pci_bus); | 2371 | pci_stop_root_bus(hbus->pci_bus); |
2349 | pci_remove_root_bus(hbus->pci_bus); | 2372 | pci_remove_root_bus(hbus->pci_bus); |
2350 | pci_unlock_rescan_remove(); | 2373 | pci_unlock_rescan_remove(); |
2374 | hbus->state = hv_pcibus_removed; | ||
2351 | } | 2375 | } |
2352 | 2376 | ||
2353 | hv_pci_bus_exit(hdev); | 2377 | hv_pci_bus_exit(hdev); |