diff options
| -rw-r--r-- | arch/x86/include/asm/xen/swiotlb-xen.h | 2 | ||||
| -rw-r--r-- | arch/x86/xen/enlighten.c | 8 | ||||
| -rw-r--r-- | arch/x86/xen/pci-swiotlb-xen.c | 47 | ||||
| -rw-r--r-- | arch/x86/xen/vga.c | 7 | ||||
| -rw-r--r-- | drivers/net/xen-netback/netback.c | 11 | ||||
| -rw-r--r-- | drivers/pci/xen-pcifront.c | 13 | ||||
| -rw-r--r-- | drivers/xen/grant-table.c | 53 | ||||
| -rw-r--r-- | drivers/xen/swiotlb-xen.c | 101 | ||||
| -rw-r--r-- | drivers/xen/xen-pciback/pci_stub.c | 136 | ||||
| -rw-r--r-- | drivers/xen/xenbus/xenbus_client.c | 6 | ||||
| -rw-r--r-- | include/linux/swiotlb.h | 1 | ||||
| -rw-r--r-- | include/xen/grant_table.h | 12 | ||||
| -rw-r--r-- | include/xen/interface/platform.h | 3 | ||||
| -rw-r--r-- | include/xen/interface/xen.h | 1 | ||||
| -rw-r--r-- | include/xen/swiotlb-xen.h | 2 | ||||
| -rw-r--r-- | lib/swiotlb.c | 33 |
16 files changed, 349 insertions, 87 deletions
diff --git a/arch/x86/include/asm/xen/swiotlb-xen.h b/arch/x86/include/asm/xen/swiotlb-xen.h index 1be1ab7d6a41..ee52fcac6f72 100644 --- a/arch/x86/include/asm/xen/swiotlb-xen.h +++ b/arch/x86/include/asm/xen/swiotlb-xen.h | |||
| @@ -5,10 +5,12 @@ | |||
| 5 | extern int xen_swiotlb; | 5 | extern int xen_swiotlb; |
| 6 | extern int __init pci_xen_swiotlb_detect(void); | 6 | extern int __init pci_xen_swiotlb_detect(void); |
| 7 | extern void __init pci_xen_swiotlb_init(void); | 7 | extern void __init pci_xen_swiotlb_init(void); |
| 8 | extern int pci_xen_swiotlb_init_late(void); | ||
| 8 | #else | 9 | #else |
| 9 | #define xen_swiotlb (0) | 10 | #define xen_swiotlb (0) |
| 10 | static inline int __init pci_xen_swiotlb_detect(void) { return 0; } | 11 | static inline int __init pci_xen_swiotlb_detect(void) { return 0; } |
| 11 | static inline void __init pci_xen_swiotlb_init(void) { } | 12 | static inline void __init pci_xen_swiotlb_init(void) { } |
| 13 | static inline int pci_xen_swiotlb_init_late(void) { return -ENXIO; } | ||
| 12 | #endif | 14 | #endif |
| 13 | 15 | ||
| 14 | #endif /* _ASM_X86_SWIOTLB_XEN_H */ | 16 | #endif /* _ASM_X86_SWIOTLB_XEN_H */ |
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index 689a4c9da866..70f140447a28 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c | |||
| @@ -1441,11 +1441,19 @@ asmlinkage void __init xen_start_kernel(void) | |||
| 1441 | const struct dom0_vga_console_info *info = | 1441 | const struct dom0_vga_console_info *info = |
| 1442 | (void *)((char *)xen_start_info + | 1442 | (void *)((char *)xen_start_info + |
| 1443 | xen_start_info->console.dom0.info_off); | 1443 | xen_start_info->console.dom0.info_off); |
| 1444 | struct xen_platform_op op = { | ||
| 1445 | .cmd = XENPF_firmware_info, | ||
| 1446 | .interface_version = XENPF_INTERFACE_VERSION, | ||
| 1447 | .u.firmware_info.type = XEN_FW_KBD_SHIFT_FLAGS, | ||
| 1448 | }; | ||
| 1444 | 1449 | ||
| 1445 | xen_init_vga(info, xen_start_info->console.dom0.info_size); | 1450 | xen_init_vga(info, xen_start_info->console.dom0.info_size); |
| 1446 | xen_start_info->console.domU.mfn = 0; | 1451 | xen_start_info->console.domU.mfn = 0; |
| 1447 | xen_start_info->console.domU.evtchn = 0; | 1452 | xen_start_info->console.domU.evtchn = 0; |
| 1448 | 1453 | ||
| 1454 | if (HYPERVISOR_dom0_op(&op) == 0) | ||
| 1455 | boot_params.kbd_status = op.u.firmware_info.u.kbd_shift_flags; | ||
| 1456 | |||
| 1449 | xen_init_apic(); | 1457 | xen_init_apic(); |
| 1450 | 1458 | ||
| 1451 | /* Make sure ACS will be enabled */ | 1459 | /* Make sure ACS will be enabled */ |
diff --git a/arch/x86/xen/pci-swiotlb-xen.c b/arch/x86/xen/pci-swiotlb-xen.c index 1ab45941502d..969570491c39 100644 --- a/arch/x86/xen/pci-swiotlb-xen.c +++ b/arch/x86/xen/pci-swiotlb-xen.c | |||
| @@ -8,7 +8,14 @@ | |||
| 8 | #include <xen/xen.h> | 8 | #include <xen/xen.h> |
| 9 | #include <asm/iommu_table.h> | 9 | #include <asm/iommu_table.h> |
| 10 | 10 | ||
| 11 | |||
| 11 | #include <asm/xen/swiotlb-xen.h> | 12 | #include <asm/xen/swiotlb-xen.h> |
| 13 | #ifdef CONFIG_X86_64 | ||
| 14 | #include <asm/iommu.h> | ||
| 15 | #include <asm/dma.h> | ||
| 16 | #endif | ||
| 17 | #include <linux/export.h> | ||
| 18 | |||
| 12 | int xen_swiotlb __read_mostly; | 19 | int xen_swiotlb __read_mostly; |
| 13 | 20 | ||
| 14 | static struct dma_map_ops xen_swiotlb_dma_ops = { | 21 | static struct dma_map_ops xen_swiotlb_dma_ops = { |
| @@ -35,33 +42,63 @@ static struct dma_map_ops xen_swiotlb_dma_ops = { | |||
| 35 | int __init pci_xen_swiotlb_detect(void) | 42 | int __init pci_xen_swiotlb_detect(void) |
| 36 | { | 43 | { |
| 37 | 44 | ||
| 45 | if (!xen_pv_domain()) | ||
| 46 | return 0; | ||
| 47 | |||
| 38 | /* If running as PV guest, either iommu=soft, or swiotlb=force will | 48 | /* If running as PV guest, either iommu=soft, or swiotlb=force will |
| 39 | * activate this IOMMU. If running as PV privileged, activate it | 49 | * activate this IOMMU. If running as PV privileged, activate it |
| 40 | * irregardless. | 50 | * irregardless. |
| 41 | */ | 51 | */ |
| 42 | if ((xen_initial_domain() || swiotlb || swiotlb_force) && | 52 | if ((xen_initial_domain() || swiotlb || swiotlb_force)) |
| 43 | (xen_pv_domain())) | ||
| 44 | xen_swiotlb = 1; | 53 | xen_swiotlb = 1; |
| 45 | 54 | ||
| 46 | /* If we are running under Xen, we MUST disable the native SWIOTLB. | 55 | /* If we are running under Xen, we MUST disable the native SWIOTLB. |
| 47 | * Don't worry about swiotlb_force flag activating the native, as | 56 | * Don't worry about swiotlb_force flag activating the native, as |
| 48 | * the 'swiotlb' flag is the only one turning it on. */ | 57 | * the 'swiotlb' flag is the only one turning it on. */ |
| 49 | if (xen_pv_domain()) | 58 | swiotlb = 0; |
| 50 | swiotlb = 0; | ||
| 51 | 59 | ||
| 60 | #ifdef CONFIG_X86_64 | ||
| 61 | /* pci_swiotlb_detect_4gb turns on native SWIOTLB if no_iommu == 0 | ||
| 62 | * (so no iommu=X command line over-writes). | ||
| 63 | * Considering that PV guests do not want the *native SWIOTLB* but | ||
| 64 | * only Xen SWIOTLB it is not useful to us so set no_iommu=1 here. | ||
| 65 | */ | ||
| 66 | if (max_pfn > MAX_DMA32_PFN) | ||
| 67 | no_iommu = 1; | ||
| 68 | #endif | ||
| 52 | return xen_swiotlb; | 69 | return xen_swiotlb; |
| 53 | } | 70 | } |
| 54 | 71 | ||
| 55 | void __init pci_xen_swiotlb_init(void) | 72 | void __init pci_xen_swiotlb_init(void) |
| 56 | { | 73 | { |
| 57 | if (xen_swiotlb) { | 74 | if (xen_swiotlb) { |
| 58 | xen_swiotlb_init(1); | 75 | xen_swiotlb_init(1, true /* early */); |
| 59 | dma_ops = &xen_swiotlb_dma_ops; | 76 | dma_ops = &xen_swiotlb_dma_ops; |
| 60 | 77 | ||
| 61 | /* Make sure ACS will be enabled */ | 78 | /* Make sure ACS will be enabled */ |
| 62 | pci_request_acs(); | 79 | pci_request_acs(); |
| 63 | } | 80 | } |
| 64 | } | 81 | } |
| 82 | |||
| 83 | int pci_xen_swiotlb_init_late(void) | ||
| 84 | { | ||
| 85 | int rc; | ||
| 86 | |||
| 87 | if (xen_swiotlb) | ||
| 88 | return 0; | ||
| 89 | |||
| 90 | rc = xen_swiotlb_init(1, false /* late */); | ||
| 91 | if (rc) | ||
| 92 | return rc; | ||
| 93 | |||
| 94 | dma_ops = &xen_swiotlb_dma_ops; | ||
| 95 | /* Make sure ACS will be enabled */ | ||
| 96 | pci_request_acs(); | ||
| 97 | |||
| 98 | return 0; | ||
| 99 | } | ||
| 100 | EXPORT_SYMBOL_GPL(pci_xen_swiotlb_init_late); | ||
| 101 | |||
| 65 | IOMMU_INIT_FINISH(pci_xen_swiotlb_detect, | 102 | IOMMU_INIT_FINISH(pci_xen_swiotlb_detect, |
| 66 | NULL, | 103 | NULL, |
| 67 | pci_xen_swiotlb_init, | 104 | pci_xen_swiotlb_init, |
diff --git a/arch/x86/xen/vga.c b/arch/x86/xen/vga.c index 1cd7f4d11e29..6722e3733f02 100644 --- a/arch/x86/xen/vga.c +++ b/arch/x86/xen/vga.c | |||
| @@ -35,6 +35,7 @@ void __init xen_init_vga(const struct dom0_vga_console_info *info, size_t size) | |||
| 35 | info->u.text_mode_3.font_height; | 35 | info->u.text_mode_3.font_height; |
| 36 | break; | 36 | break; |
| 37 | 37 | ||
| 38 | case XEN_VGATYPE_EFI_LFB: | ||
| 38 | case XEN_VGATYPE_VESA_LFB: | 39 | case XEN_VGATYPE_VESA_LFB: |
| 39 | if (size < offsetof(struct dom0_vga_console_info, | 40 | if (size < offsetof(struct dom0_vga_console_info, |
| 40 | u.vesa_lfb.gbl_caps)) | 41 | u.vesa_lfb.gbl_caps)) |
| @@ -54,6 +55,12 @@ void __init xen_init_vga(const struct dom0_vga_console_info *info, size_t size) | |||
| 54 | screen_info->blue_pos = info->u.vesa_lfb.blue_pos; | 55 | screen_info->blue_pos = info->u.vesa_lfb.blue_pos; |
| 55 | screen_info->rsvd_size = info->u.vesa_lfb.rsvd_size; | 56 | screen_info->rsvd_size = info->u.vesa_lfb.rsvd_size; |
| 56 | screen_info->rsvd_pos = info->u.vesa_lfb.rsvd_pos; | 57 | screen_info->rsvd_pos = info->u.vesa_lfb.rsvd_pos; |
| 58 | |||
| 59 | if (info->video_type == XEN_VGATYPE_EFI_LFB) { | ||
| 60 | screen_info->orig_video_isVGA = VIDEO_TYPE_EFI; | ||
| 61 | break; | ||
| 62 | } | ||
| 63 | |||
| 57 | if (size >= offsetof(struct dom0_vga_console_info, | 64 | if (size >= offsetof(struct dom0_vga_console_info, |
| 58 | u.vesa_lfb.gbl_caps) | 65 | u.vesa_lfb.gbl_caps) |
| 59 | + sizeof(info->u.vesa_lfb.gbl_caps)) | 66 | + sizeof(info->u.vesa_lfb.gbl_caps)) |
diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index 1c0a30240d97..4ebfcf3d8a3b 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c | |||
| @@ -636,9 +636,7 @@ static void xen_netbk_rx_action(struct xen_netbk *netbk) | |||
| 636 | return; | 636 | return; |
| 637 | 637 | ||
| 638 | BUG_ON(npo.copy_prod > ARRAY_SIZE(netbk->grant_copy_op)); | 638 | BUG_ON(npo.copy_prod > ARRAY_SIZE(netbk->grant_copy_op)); |
| 639 | ret = HYPERVISOR_grant_table_op(GNTTABOP_copy, &netbk->grant_copy_op, | 639 | gnttab_batch_copy(netbk->grant_copy_op, npo.copy_prod); |
| 640 | npo.copy_prod); | ||
| 641 | BUG_ON(ret != 0); | ||
| 642 | 640 | ||
| 643 | while ((skb = __skb_dequeue(&rxq)) != NULL) { | 641 | while ((skb = __skb_dequeue(&rxq)) != NULL) { |
| 644 | sco = (struct skb_cb_overlay *)skb->cb; | 642 | sco = (struct skb_cb_overlay *)skb->cb; |
| @@ -1461,18 +1459,15 @@ static void xen_netbk_tx_submit(struct xen_netbk *netbk) | |||
| 1461 | static void xen_netbk_tx_action(struct xen_netbk *netbk) | 1459 | static void xen_netbk_tx_action(struct xen_netbk *netbk) |
| 1462 | { | 1460 | { |
| 1463 | unsigned nr_gops; | 1461 | unsigned nr_gops; |
| 1464 | int ret; | ||
| 1465 | 1462 | ||
| 1466 | nr_gops = xen_netbk_tx_build_gops(netbk); | 1463 | nr_gops = xen_netbk_tx_build_gops(netbk); |
| 1467 | 1464 | ||
| 1468 | if (nr_gops == 0) | 1465 | if (nr_gops == 0) |
| 1469 | return; | 1466 | return; |
| 1470 | ret = HYPERVISOR_grant_table_op(GNTTABOP_copy, | ||
| 1471 | netbk->tx_copy_ops, nr_gops); | ||
| 1472 | BUG_ON(ret); | ||
| 1473 | 1467 | ||
| 1474 | xen_netbk_tx_submit(netbk); | 1468 | gnttab_batch_copy(netbk->tx_copy_ops, nr_gops); |
| 1475 | 1469 | ||
| 1470 | xen_netbk_tx_submit(netbk); | ||
| 1476 | } | 1471 | } |
| 1477 | 1472 | ||
| 1478 | static void xen_netbk_idx_release(struct xen_netbk *netbk, u16 pending_idx) | 1473 | static void xen_netbk_idx_release(struct xen_netbk *netbk, u16 pending_idx) |
diff --git a/drivers/pci/xen-pcifront.c b/drivers/pci/xen-pcifront.c index a4d901def8f2..7d6773535b67 100644 --- a/drivers/pci/xen-pcifront.c +++ b/drivers/pci/xen-pcifront.c | |||
| @@ -21,6 +21,7 @@ | |||
| 21 | #include <linux/bitops.h> | 21 | #include <linux/bitops.h> |
| 22 | #include <linux/time.h> | 22 | #include <linux/time.h> |
| 23 | 23 | ||
| 24 | #include <asm/xen/swiotlb-xen.h> | ||
| 24 | #define INVALID_GRANT_REF (0) | 25 | #define INVALID_GRANT_REF (0) |
| 25 | #define INVALID_EVTCHN (-1) | 26 | #define INVALID_EVTCHN (-1) |
| 26 | 27 | ||
| @@ -668,7 +669,7 @@ static irqreturn_t pcifront_handler_aer(int irq, void *dev) | |||
| 668 | schedule_pcifront_aer_op(pdev); | 669 | schedule_pcifront_aer_op(pdev); |
| 669 | return IRQ_HANDLED; | 670 | return IRQ_HANDLED; |
| 670 | } | 671 | } |
| 671 | static int pcifront_connect(struct pcifront_device *pdev) | 672 | static int pcifront_connect_and_init_dma(struct pcifront_device *pdev) |
| 672 | { | 673 | { |
| 673 | int err = 0; | 674 | int err = 0; |
| 674 | 675 | ||
| @@ -681,9 +682,13 @@ static int pcifront_connect(struct pcifront_device *pdev) | |||
| 681 | dev_err(&pdev->xdev->dev, "PCI frontend already installed!\n"); | 682 | dev_err(&pdev->xdev->dev, "PCI frontend already installed!\n"); |
| 682 | err = -EEXIST; | 683 | err = -EEXIST; |
| 683 | } | 684 | } |
| 684 | |||
| 685 | spin_unlock(&pcifront_dev_lock); | 685 | spin_unlock(&pcifront_dev_lock); |
| 686 | 686 | ||
| 687 | if (!err && !swiotlb_nr_tbl()) { | ||
| 688 | err = pci_xen_swiotlb_init_late(); | ||
| 689 | if (err) | ||
| 690 | dev_err(&pdev->xdev->dev, "Could not setup SWIOTLB!\n"); | ||
| 691 | } | ||
| 687 | return err; | 692 | return err; |
| 688 | } | 693 | } |
| 689 | 694 | ||
| @@ -842,10 +847,10 @@ static int __devinit pcifront_try_connect(struct pcifront_device *pdev) | |||
| 842 | XenbusStateInitialised) | 847 | XenbusStateInitialised) |
| 843 | goto out; | 848 | goto out; |
| 844 | 849 | ||
| 845 | err = pcifront_connect(pdev); | 850 | err = pcifront_connect_and_init_dma(pdev); |
| 846 | if (err) { | 851 | if (err) { |
| 847 | xenbus_dev_fatal(pdev->xdev, err, | 852 | xenbus_dev_fatal(pdev->xdev, err, |
| 848 | "Error connecting PCI Frontend"); | 853 | "Error setting up PCI Frontend"); |
| 849 | goto out; | 854 | goto out; |
| 850 | } | 855 | } |
| 851 | 856 | ||
diff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c index eea81cf8a2a5..3a567b15600b 100644 --- a/drivers/xen/grant-table.c +++ b/drivers/xen/grant-table.c | |||
| @@ -38,6 +38,7 @@ | |||
| 38 | #include <linux/vmalloc.h> | 38 | #include <linux/vmalloc.h> |
| 39 | #include <linux/uaccess.h> | 39 | #include <linux/uaccess.h> |
| 40 | #include <linux/io.h> | 40 | #include <linux/io.h> |
| 41 | #include <linux/delay.h> | ||
| 41 | #include <linux/hardirq.h> | 42 | #include <linux/hardirq.h> |
| 42 | 43 | ||
| 43 | #include <xen/xen.h> | 44 | #include <xen/xen.h> |
| @@ -823,6 +824,52 @@ unsigned int gnttab_max_grant_frames(void) | |||
| 823 | } | 824 | } |
| 824 | EXPORT_SYMBOL_GPL(gnttab_max_grant_frames); | 825 | EXPORT_SYMBOL_GPL(gnttab_max_grant_frames); |
| 825 | 826 | ||
| 827 | /* Handling of paged out grant targets (GNTST_eagain) */ | ||
| 828 | #define MAX_DELAY 256 | ||
| 829 | static inline void | ||
| 830 | gnttab_retry_eagain_gop(unsigned int cmd, void *gop, int16_t *status, | ||
| 831 | const char *func) | ||
| 832 | { | ||
| 833 | unsigned delay = 1; | ||
| 834 | |||
| 835 | do { | ||
| 836 | BUG_ON(HYPERVISOR_grant_table_op(cmd, gop, 1)); | ||
| 837 | if (*status == GNTST_eagain) | ||
| 838 | msleep(delay++); | ||
| 839 | } while ((*status == GNTST_eagain) && (delay < MAX_DELAY)); | ||
| 840 | |||
| 841 | if (delay >= MAX_DELAY) { | ||
| 842 | printk(KERN_ERR "%s: %s eagain grant\n", func, current->comm); | ||
| 843 | *status = GNTST_bad_page; | ||
| 844 | } | ||
| 845 | } | ||
| 846 | |||
| 847 | void gnttab_batch_map(struct gnttab_map_grant_ref *batch, unsigned count) | ||
| 848 | { | ||
| 849 | struct gnttab_map_grant_ref *op; | ||
| 850 | |||
| 851 | if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, batch, count)) | ||
| 852 | BUG(); | ||
| 853 | for (op = batch; op < batch + count; op++) | ||
| 854 | if (op->status == GNTST_eagain) | ||
| 855 | gnttab_retry_eagain_gop(GNTTABOP_map_grant_ref, op, | ||
| 856 | &op->status, __func__); | ||
| 857 | } | ||
| 858 | EXPORT_SYMBOL_GPL(gnttab_batch_map); | ||
| 859 | |||
| 860 | void gnttab_batch_copy(struct gnttab_copy *batch, unsigned count) | ||
| 861 | { | ||
| 862 | struct gnttab_copy *op; | ||
| 863 | |||
| 864 | if (HYPERVISOR_grant_table_op(GNTTABOP_copy, batch, count)) | ||
| 865 | BUG(); | ||
| 866 | for (op = batch; op < batch + count; op++) | ||
| 867 | if (op->status == GNTST_eagain) | ||
| 868 | gnttab_retry_eagain_gop(GNTTABOP_copy, op, | ||
| 869 | &op->status, __func__); | ||
| 870 | } | ||
| 871 | EXPORT_SYMBOL_GPL(gnttab_batch_copy); | ||
| 872 | |||
| 826 | int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops, | 873 | int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops, |
| 827 | struct gnttab_map_grant_ref *kmap_ops, | 874 | struct gnttab_map_grant_ref *kmap_ops, |
| 828 | struct page **pages, unsigned int count) | 875 | struct page **pages, unsigned int count) |
| @@ -836,6 +883,12 @@ int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops, | |||
| 836 | if (ret) | 883 | if (ret) |
| 837 | return ret; | 884 | return ret; |
| 838 | 885 | ||
| 886 | /* Retry eagain maps */ | ||
| 887 | for (i = 0; i < count; i++) | ||
| 888 | if (map_ops[i].status == GNTST_eagain) | ||
| 889 | gnttab_retry_eagain_gop(GNTTABOP_map_grant_ref, map_ops + i, | ||
| 890 | &map_ops[i].status, __func__); | ||
| 891 | |||
| 839 | if (xen_feature(XENFEAT_auto_translated_physmap)) | 892 | if (xen_feature(XENFEAT_auto_translated_physmap)) |
| 840 | return ret; | 893 | return ret; |
| 841 | 894 | ||
diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c index 2e74dba6a04d..58db6df866ef 100644 --- a/drivers/xen/swiotlb-xen.c +++ b/drivers/xen/swiotlb-xen.c | |||
| @@ -144,31 +144,72 @@ xen_swiotlb_fixup(void *buf, size_t size, unsigned long nslabs) | |||
| 144 | } while (i < nslabs); | 144 | } while (i < nslabs); |
| 145 | return 0; | 145 | return 0; |
| 146 | } | 146 | } |
| 147 | static unsigned long xen_set_nslabs(unsigned long nr_tbl) | ||
| 148 | { | ||
| 149 | if (!nr_tbl) { | ||
| 150 | xen_io_tlb_nslabs = (64 * 1024 * 1024 >> IO_TLB_SHIFT); | ||
| 151 | xen_io_tlb_nslabs = ALIGN(xen_io_tlb_nslabs, IO_TLB_SEGSIZE); | ||
| 152 | } else | ||
| 153 | xen_io_tlb_nslabs = nr_tbl; | ||
| 154 | |||
| 155 | return xen_io_tlb_nslabs << IO_TLB_SHIFT; | ||
| 156 | } | ||
| 157 | |||
| 158 | enum xen_swiotlb_err { | ||
| 159 | XEN_SWIOTLB_UNKNOWN = 0, | ||
| 160 | XEN_SWIOTLB_ENOMEM, | ||
| 161 | XEN_SWIOTLB_EFIXUP | ||
| 162 | }; | ||
| 147 | 163 | ||
| 148 | void __init xen_swiotlb_init(int verbose) | 164 | static const char *xen_swiotlb_error(enum xen_swiotlb_err err) |
| 149 | { | 165 | { |
| 150 | unsigned long bytes; | 166 | switch (err) { |
| 167 | case XEN_SWIOTLB_ENOMEM: | ||
| 168 | return "Cannot allocate Xen-SWIOTLB buffer\n"; | ||
| 169 | case XEN_SWIOTLB_EFIXUP: | ||
| 170 | return "Failed to get contiguous memory for DMA from Xen!\n"\ | ||
| 171 | "You either: don't have the permissions, do not have"\ | ||
| 172 | " enough free memory under 4GB, or the hypervisor memory"\ | ||
| 173 | " is too fragmented!"; | ||
| 174 | default: | ||
| 175 | break; | ||
| 176 | } | ||
| 177 | return ""; | ||
| 178 | } | ||
| 179 | int __ref xen_swiotlb_init(int verbose, bool early) | ||
| 180 | { | ||
| 181 | unsigned long bytes, order; | ||
| 151 | int rc = -ENOMEM; | 182 | int rc = -ENOMEM; |
| 152 | unsigned long nr_tbl; | 183 | enum xen_swiotlb_err m_ret = XEN_SWIOTLB_UNKNOWN; |
| 153 | char *m = NULL; | ||
| 154 | unsigned int repeat = 3; | 184 | unsigned int repeat = 3; |
| 155 | 185 | ||
| 156 | nr_tbl = swiotlb_nr_tbl(); | 186 | xen_io_tlb_nslabs = swiotlb_nr_tbl(); |
| 157 | if (nr_tbl) | ||
| 158 | xen_io_tlb_nslabs = nr_tbl; | ||
| 159 | else { | ||
| 160 | xen_io_tlb_nslabs = (64 * 1024 * 1024 >> IO_TLB_SHIFT); | ||
| 161 | xen_io_tlb_nslabs = ALIGN(xen_io_tlb_nslabs, IO_TLB_SEGSIZE); | ||
| 162 | } | ||
| 163 | retry: | 187 | retry: |
| 164 | bytes = xen_io_tlb_nslabs << IO_TLB_SHIFT; | 188 | bytes = xen_set_nslabs(xen_io_tlb_nslabs); |
| 165 | 189 | order = get_order(xen_io_tlb_nslabs << IO_TLB_SHIFT); | |
| 166 | /* | 190 | /* |
| 167 | * Get IO TLB memory from any location. | 191 | * Get IO TLB memory from any location. |
| 168 | */ | 192 | */ |
| 169 | xen_io_tlb_start = alloc_bootmem_pages(PAGE_ALIGN(bytes)); | 193 | if (early) |
| 194 | xen_io_tlb_start = alloc_bootmem_pages(PAGE_ALIGN(bytes)); | ||
| 195 | else { | ||
| 196 | #define SLABS_PER_PAGE (1 << (PAGE_SHIFT - IO_TLB_SHIFT)) | ||
| 197 | #define IO_TLB_MIN_SLABS ((1<<20) >> IO_TLB_SHIFT) | ||
| 198 | while ((SLABS_PER_PAGE << order) > IO_TLB_MIN_SLABS) { | ||
| 199 | xen_io_tlb_start = (void *)__get_free_pages(__GFP_NOWARN, order); | ||
| 200 | if (xen_io_tlb_start) | ||
| 201 | break; | ||
| 202 | order--; | ||
| 203 | } | ||
| 204 | if (order != get_order(bytes)) { | ||
| 205 | pr_warn("Warning: only able to allocate %ld MB " | ||
| 206 | "for software IO TLB\n", (PAGE_SIZE << order) >> 20); | ||
| 207 | xen_io_tlb_nslabs = SLABS_PER_PAGE << order; | ||
| 208 | bytes = xen_io_tlb_nslabs << IO_TLB_SHIFT; | ||
| 209 | } | ||
| 210 | } | ||
| 170 | if (!xen_io_tlb_start) { | 211 | if (!xen_io_tlb_start) { |
| 171 | m = "Cannot allocate Xen-SWIOTLB buffer!\n"; | 212 | m_ret = XEN_SWIOTLB_ENOMEM; |
| 172 | goto error; | 213 | goto error; |
| 173 | } | 214 | } |
| 174 | xen_io_tlb_end = xen_io_tlb_start + bytes; | 215 | xen_io_tlb_end = xen_io_tlb_start + bytes; |
| @@ -179,17 +220,22 @@ retry: | |||
| 179 | bytes, | 220 | bytes, |
| 180 | xen_io_tlb_nslabs); | 221 | xen_io_tlb_nslabs); |
| 181 | if (rc) { | 222 | if (rc) { |
| 182 | free_bootmem(__pa(xen_io_tlb_start), PAGE_ALIGN(bytes)); | 223 | if (early) |
| 183 | m = "Failed to get contiguous memory for DMA from Xen!\n"\ | 224 | free_bootmem(__pa(xen_io_tlb_start), PAGE_ALIGN(bytes)); |
| 184 | "You either: don't have the permissions, do not have"\ | 225 | else { |
| 185 | " enough free memory under 4GB, or the hypervisor memory"\ | 226 | free_pages((unsigned long)xen_io_tlb_start, order); |
| 186 | "is too fragmented!"; | 227 | xen_io_tlb_start = NULL; |
| 228 | } | ||
| 229 | m_ret = XEN_SWIOTLB_EFIXUP; | ||
| 187 | goto error; | 230 | goto error; |
| 188 | } | 231 | } |
| 189 | start_dma_addr = xen_virt_to_bus(xen_io_tlb_start); | 232 | start_dma_addr = xen_virt_to_bus(xen_io_tlb_start); |
| 190 | swiotlb_init_with_tbl(xen_io_tlb_start, xen_io_tlb_nslabs, verbose); | 233 | if (early) { |
| 191 | 234 | swiotlb_init_with_tbl(xen_io_tlb_start, xen_io_tlb_nslabs, verbose); | |
| 192 | return; | 235 | rc = 0; |
| 236 | } else | ||
| 237 | rc = swiotlb_late_init_with_tbl(xen_io_tlb_start, xen_io_tlb_nslabs); | ||
| 238 | return rc; | ||
| 193 | error: | 239 | error: |
| 194 | if (repeat--) { | 240 | if (repeat--) { |
| 195 | xen_io_tlb_nslabs = max(1024UL, /* Min is 2MB */ | 241 | xen_io_tlb_nslabs = max(1024UL, /* Min is 2MB */ |
| @@ -198,10 +244,13 @@ error: | |||
| 198 | (xen_io_tlb_nslabs << IO_TLB_SHIFT) >> 20); | 244 | (xen_io_tlb_nslabs << IO_TLB_SHIFT) >> 20); |
| 199 | goto retry; | 245 | goto retry; |
| 200 | } | 246 | } |
| 201 | xen_raw_printk("%s (rc:%d)", m, rc); | 247 | pr_err("%s (rc:%d)", xen_swiotlb_error(m_ret), rc); |
| 202 | panic("%s (rc:%d)", m, rc); | 248 | if (early) |
| 249 | panic("%s (rc:%d)", xen_swiotlb_error(m_ret), rc); | ||
| 250 | else | ||
| 251 | free_pages((unsigned long)xen_io_tlb_start, order); | ||
| 252 | return rc; | ||
| 203 | } | 253 | } |
| 204 | |||
| 205 | void * | 254 | void * |
| 206 | xen_swiotlb_alloc_coherent(struct device *hwdev, size_t size, | 255 | xen_swiotlb_alloc_coherent(struct device *hwdev, size_t size, |
| 207 | dma_addr_t *dma_handle, gfp_t flags, | 256 | dma_addr_t *dma_handle, gfp_t flags, |
diff --git a/drivers/xen/xen-pciback/pci_stub.c b/drivers/xen/xen-pciback/pci_stub.c index 03342728bf23..e5a0c13e2ad4 100644 --- a/drivers/xen/xen-pciback/pci_stub.c +++ b/drivers/xen/xen-pciback/pci_stub.c | |||
| @@ -362,6 +362,7 @@ static int __devinit pcistub_init_device(struct pci_dev *dev) | |||
| 362 | else { | 362 | else { |
| 363 | dev_dbg(&dev->dev, "reseting (FLR, D3, etc) the device\n"); | 363 | dev_dbg(&dev->dev, "reseting (FLR, D3, etc) the device\n"); |
| 364 | __pci_reset_function_locked(dev); | 364 | __pci_reset_function_locked(dev); |
| 365 | pci_restore_state(dev); | ||
| 365 | } | 366 | } |
| 366 | /* Now disable the device (this also ensures some private device | 367 | /* Now disable the device (this also ensures some private device |
| 367 | * data is setup before we export) | 368 | * data is setup before we export) |
| @@ -681,14 +682,14 @@ static pci_ers_result_t xen_pcibk_slot_reset(struct pci_dev *dev) | |||
| 681 | dev_err(&dev->dev, DRV_NAME " device is not connected or owned" | 682 | dev_err(&dev->dev, DRV_NAME " device is not connected or owned" |
| 682 | " by HVM, kill it\n"); | 683 | " by HVM, kill it\n"); |
| 683 | kill_domain_by_device(psdev); | 684 | kill_domain_by_device(psdev); |
| 684 | goto release; | 685 | goto end; |
| 685 | } | 686 | } |
| 686 | 687 | ||
| 687 | if (!test_bit(_XEN_PCIB_AERHANDLER, | 688 | if (!test_bit(_XEN_PCIB_AERHANDLER, |
| 688 | (unsigned long *)&psdev->pdev->sh_info->flags)) { | 689 | (unsigned long *)&psdev->pdev->sh_info->flags)) { |
| 689 | dev_err(&dev->dev, | 690 | dev_err(&dev->dev, |
| 690 | "guest with no AER driver should have been killed\n"); | 691 | "guest with no AER driver should have been killed\n"); |
| 691 | goto release; | 692 | goto end; |
| 692 | } | 693 | } |
| 693 | result = common_process(psdev, 1, XEN_PCI_OP_aer_slotreset, result); | 694 | result = common_process(psdev, 1, XEN_PCI_OP_aer_slotreset, result); |
| 694 | 695 | ||
| @@ -698,9 +699,9 @@ static pci_ers_result_t xen_pcibk_slot_reset(struct pci_dev *dev) | |||
| 698 | "No AER slot_reset service or disconnected!\n"); | 699 | "No AER slot_reset service or disconnected!\n"); |
| 699 | kill_domain_by_device(psdev); | 700 | kill_domain_by_device(psdev); |
| 700 | } | 701 | } |
| 701 | release: | ||
| 702 | pcistub_device_put(psdev); | ||
| 703 | end: | 702 | end: |
| 703 | if (psdev) | ||
| 704 | pcistub_device_put(psdev); | ||
| 704 | up_write(&pcistub_sem); | 705 | up_write(&pcistub_sem); |
| 705 | return result; | 706 | return result; |
| 706 | 707 | ||
| @@ -739,14 +740,14 @@ static pci_ers_result_t xen_pcibk_mmio_enabled(struct pci_dev *dev) | |||
| 739 | dev_err(&dev->dev, DRV_NAME " device is not connected or owned" | 740 | dev_err(&dev->dev, DRV_NAME " device is not connected or owned" |
| 740 | " by HVM, kill it\n"); | 741 | " by HVM, kill it\n"); |
| 741 | kill_domain_by_device(psdev); | 742 | kill_domain_by_device(psdev); |
| 742 | goto release; | 743 | goto end; |
| 743 | } | 744 | } |
| 744 | 745 | ||
| 745 | if (!test_bit(_XEN_PCIB_AERHANDLER, | 746 | if (!test_bit(_XEN_PCIB_AERHANDLER, |
| 746 | (unsigned long *)&psdev->pdev->sh_info->flags)) { | 747 | (unsigned long *)&psdev->pdev->sh_info->flags)) { |
| 747 | dev_err(&dev->dev, | 748 | dev_err(&dev->dev, |
| 748 | "guest with no AER driver should have been killed\n"); | 749 | "guest with no AER driver should have been killed\n"); |
| 749 | goto release; | 750 | goto end; |
| 750 | } | 751 | } |
| 751 | result = common_process(psdev, 1, XEN_PCI_OP_aer_mmio, result); | 752 | result = common_process(psdev, 1, XEN_PCI_OP_aer_mmio, result); |
| 752 | 753 | ||
| @@ -756,9 +757,9 @@ static pci_ers_result_t xen_pcibk_mmio_enabled(struct pci_dev *dev) | |||
| 756 | "No AER mmio_enabled service or disconnected!\n"); | 757 | "No AER mmio_enabled service or disconnected!\n"); |
| 757 | kill_domain_by_device(psdev); | 758 | kill_domain_by_device(psdev); |
| 758 | } | 759 | } |
| 759 | release: | ||
| 760 | pcistub_device_put(psdev); | ||
| 761 | end: | 760 | end: |
| 761 | if (psdev) | ||
| 762 | pcistub_device_put(psdev); | ||
| 762 | up_write(&pcistub_sem); | 763 | up_write(&pcistub_sem); |
| 763 | return result; | 764 | return result; |
| 764 | } | 765 | } |
| @@ -797,7 +798,7 @@ static pci_ers_result_t xen_pcibk_error_detected(struct pci_dev *dev, | |||
| 797 | dev_err(&dev->dev, DRV_NAME " device is not connected or owned" | 798 | dev_err(&dev->dev, DRV_NAME " device is not connected or owned" |
| 798 | " by HVM, kill it\n"); | 799 | " by HVM, kill it\n"); |
| 799 | kill_domain_by_device(psdev); | 800 | kill_domain_by_device(psdev); |
| 800 | goto release; | 801 | goto end; |
| 801 | } | 802 | } |
| 802 | 803 | ||
| 803 | /*Guest owns the device yet no aer handler regiested, kill guest*/ | 804 | /*Guest owns the device yet no aer handler regiested, kill guest*/ |
| @@ -805,7 +806,7 @@ static pci_ers_result_t xen_pcibk_error_detected(struct pci_dev *dev, | |||
| 805 | (unsigned long *)&psdev->pdev->sh_info->flags)) { | 806 | (unsigned long *)&psdev->pdev->sh_info->flags)) { |
| 806 | dev_dbg(&dev->dev, "guest may have no aer driver, kill it\n"); | 807 | dev_dbg(&dev->dev, "guest may have no aer driver, kill it\n"); |
| 807 | kill_domain_by_device(psdev); | 808 | kill_domain_by_device(psdev); |
| 808 | goto release; | 809 | goto end; |
| 809 | } | 810 | } |
| 810 | result = common_process(psdev, error, XEN_PCI_OP_aer_detected, result); | 811 | result = common_process(psdev, error, XEN_PCI_OP_aer_detected, result); |
| 811 | 812 | ||
| @@ -815,9 +816,9 @@ static pci_ers_result_t xen_pcibk_error_detected(struct pci_dev *dev, | |||
| 815 | "No AER error_detected service or disconnected!\n"); | 816 | "No AER error_detected service or disconnected!\n"); |
| 816 | kill_domain_by_device(psdev); | 817 | kill_domain_by_device(psdev); |
| 817 | } | 818 | } |
| 818 | release: | ||
| 819 | pcistub_device_put(psdev); | ||
| 820 | end: | 819 | end: |
| 820 | if (psdev) | ||
| 821 | pcistub_device_put(psdev); | ||
| 821 | up_write(&pcistub_sem); | 822 | up_write(&pcistub_sem); |
| 822 | return result; | 823 | return result; |
| 823 | } | 824 | } |
| @@ -851,7 +852,7 @@ static void xen_pcibk_error_resume(struct pci_dev *dev) | |||
| 851 | dev_err(&dev->dev, DRV_NAME " device is not connected or owned" | 852 | dev_err(&dev->dev, DRV_NAME " device is not connected or owned" |
| 852 | " by HVM, kill it\n"); | 853 | " by HVM, kill it\n"); |
| 853 | kill_domain_by_device(psdev); | 854 | kill_domain_by_device(psdev); |
| 854 | goto release; | 855 | goto end; |
| 855 | } | 856 | } |
| 856 | 857 | ||
| 857 | if (!test_bit(_XEN_PCIB_AERHANDLER, | 858 | if (!test_bit(_XEN_PCIB_AERHANDLER, |
| @@ -859,13 +860,13 @@ static void xen_pcibk_error_resume(struct pci_dev *dev) | |||
| 859 | dev_err(&dev->dev, | 860 | dev_err(&dev->dev, |
| 860 | "guest with no AER driver should have been killed\n"); | 861 | "guest with no AER driver should have been killed\n"); |
| 861 | kill_domain_by_device(psdev); | 862 | kill_domain_by_device(psdev); |
| 862 | goto release; | 863 | goto end; |
| 863 | } | 864 | } |
| 864 | common_process(psdev, 1, XEN_PCI_OP_aer_resume, | 865 | common_process(psdev, 1, XEN_PCI_OP_aer_resume, |
| 865 | PCI_ERS_RESULT_RECOVERED); | 866 | PCI_ERS_RESULT_RECOVERED); |
| 866 | release: | ||
| 867 | pcistub_device_put(psdev); | ||
| 868 | end: | 867 | end: |
| 868 | if (psdev) | ||
| 869 | pcistub_device_put(psdev); | ||
| 869 | up_write(&pcistub_sem); | 870 | up_write(&pcistub_sem); |
| 870 | return; | 871 | return; |
| 871 | } | 872 | } |
| @@ -897,17 +898,41 @@ static inline int str_to_slot(const char *buf, int *domain, int *bus, | |||
| 897 | int *slot, int *func) | 898 | int *slot, int *func) |
| 898 | { | 899 | { |
| 899 | int err; | 900 | int err; |
| 901 | char wc = '*'; | ||
| 900 | 902 | ||
| 901 | err = sscanf(buf, " %x:%x:%x.%x", domain, bus, slot, func); | 903 | err = sscanf(buf, " %x:%x:%x.%x", domain, bus, slot, func); |
| 902 | if (err == 4) | 904 | switch (err) { |
| 905 | case 3: | ||
| 906 | *func = -1; | ||
| 907 | err = sscanf(buf, " %x:%x:%x.%c", domain, bus, slot, &wc); | ||
| 908 | break; | ||
| 909 | case 2: | ||
| 910 | *slot = *func = -1; | ||
| 911 | err = sscanf(buf, " %x:%x:*.%c", domain, bus, &wc); | ||
| 912 | if (err >= 2) | ||
| 913 | ++err; | ||
| 914 | break; | ||
| 915 | } | ||
| 916 | if (err == 4 && wc == '*') | ||
| 903 | return 0; | 917 | return 0; |
| 904 | else if (err < 0) | 918 | else if (err < 0) |
| 905 | return -EINVAL; | 919 | return -EINVAL; |
| 906 | 920 | ||
| 907 | /* try again without domain */ | 921 | /* try again without domain */ |
| 908 | *domain = 0; | 922 | *domain = 0; |
| 923 | wc = '*'; | ||
| 909 | err = sscanf(buf, " %x:%x.%x", bus, slot, func); | 924 | err = sscanf(buf, " %x:%x.%x", bus, slot, func); |
| 910 | if (err == 3) | 925 | switch (err) { |
| 926 | case 2: | ||
| 927 | *func = -1; | ||
| 928 | err = sscanf(buf, " %x:%x.%c", bus, slot, &wc); | ||
| 929 | break; | ||
| 930 | case 1: | ||
| 931 | *slot = *func = -1; | ||
| 932 | err = sscanf(buf, " %x:*.%c", bus, &wc) + 1; | ||
| 933 | break; | ||
| 934 | } | ||
| 935 | if (err == 3 && wc == '*') | ||
| 911 | return 0; | 936 | return 0; |
| 912 | 937 | ||
| 913 | return -EINVAL; | 938 | return -EINVAL; |
| @@ -930,6 +955,19 @@ static int pcistub_device_id_add(int domain, int bus, int slot, int func) | |||
| 930 | { | 955 | { |
| 931 | struct pcistub_device_id *pci_dev_id; | 956 | struct pcistub_device_id *pci_dev_id; |
| 932 | unsigned long flags; | 957 | unsigned long flags; |
| 958 | int rc = 0; | ||
| 959 | |||
| 960 | if (slot < 0) { | ||
| 961 | for (slot = 0; !rc && slot < 32; ++slot) | ||
| 962 | rc = pcistub_device_id_add(domain, bus, slot, func); | ||
| 963 | return rc; | ||
| 964 | } | ||
| 965 | |||
| 966 | if (func < 0) { | ||
| 967 | for (func = 0; !rc && func < 8; ++func) | ||
| 968 | rc = pcistub_device_id_add(domain, bus, slot, func); | ||
| 969 | return rc; | ||
| 970 | } | ||
| 933 | 971 | ||
| 934 | pci_dev_id = kmalloc(sizeof(*pci_dev_id), GFP_KERNEL); | 972 | pci_dev_id = kmalloc(sizeof(*pci_dev_id), GFP_KERNEL); |
| 935 | if (!pci_dev_id) | 973 | if (!pci_dev_id) |
| @@ -952,15 +990,15 @@ static int pcistub_device_id_add(int domain, int bus, int slot, int func) | |||
| 952 | static int pcistub_device_id_remove(int domain, int bus, int slot, int func) | 990 | static int pcistub_device_id_remove(int domain, int bus, int slot, int func) |
| 953 | { | 991 | { |
| 954 | struct pcistub_device_id *pci_dev_id, *t; | 992 | struct pcistub_device_id *pci_dev_id, *t; |
| 955 | int devfn = PCI_DEVFN(slot, func); | ||
| 956 | int err = -ENOENT; | 993 | int err = -ENOENT; |
| 957 | unsigned long flags; | 994 | unsigned long flags; |
| 958 | 995 | ||
| 959 | spin_lock_irqsave(&device_ids_lock, flags); | 996 | spin_lock_irqsave(&device_ids_lock, flags); |
| 960 | list_for_each_entry_safe(pci_dev_id, t, &pcistub_device_ids, | 997 | list_for_each_entry_safe(pci_dev_id, t, &pcistub_device_ids, |
| 961 | slot_list) { | 998 | slot_list) { |
| 962 | if (pci_dev_id->domain == domain | 999 | if (pci_dev_id->domain == domain && pci_dev_id->bus == bus |
| 963 | && pci_dev_id->bus == bus && pci_dev_id->devfn == devfn) { | 1000 | && (slot < 0 || PCI_SLOT(pci_dev_id->devfn) == slot) |
| 1001 | && (func < 0 || PCI_FUNC(pci_dev_id->devfn) == func)) { | ||
| 964 | /* Don't break; here because it's possible the same | 1002 | /* Don't break; here because it's possible the same |
| 965 | * slot could be in the list more than once | 1003 | * slot could be in the list more than once |
| 966 | */ | 1004 | */ |
| @@ -987,7 +1025,7 @@ static int pcistub_reg_add(int domain, int bus, int slot, int func, int reg, | |||
| 987 | struct config_field *field; | 1025 | struct config_field *field; |
| 988 | 1026 | ||
| 989 | psdev = pcistub_device_find(domain, bus, slot, func); | 1027 | psdev = pcistub_device_find(domain, bus, slot, func); |
| 990 | if (!psdev || !psdev->dev) { | 1028 | if (!psdev) { |
| 991 | err = -ENODEV; | 1029 | err = -ENODEV; |
| 992 | goto out; | 1030 | goto out; |
| 993 | } | 1031 | } |
| @@ -1011,6 +1049,8 @@ static int pcistub_reg_add(int domain, int bus, int slot, int func, int reg, | |||
| 1011 | if (err) | 1049 | if (err) |
| 1012 | kfree(field); | 1050 | kfree(field); |
| 1013 | out: | 1051 | out: |
| 1052 | if (psdev) | ||
| 1053 | pcistub_device_put(psdev); | ||
| 1014 | return err; | 1054 | return err; |
| 1015 | } | 1055 | } |
| 1016 | 1056 | ||
| @@ -1115,10 +1155,9 @@ static ssize_t pcistub_irq_handler_switch(struct device_driver *drv, | |||
| 1115 | 1155 | ||
| 1116 | err = str_to_slot(buf, &domain, &bus, &slot, &func); | 1156 | err = str_to_slot(buf, &domain, &bus, &slot, &func); |
| 1117 | if (err) | 1157 | if (err) |
| 1118 | goto out; | 1158 | return err; |
| 1119 | 1159 | ||
| 1120 | psdev = pcistub_device_find(domain, bus, slot, func); | 1160 | psdev = pcistub_device_find(domain, bus, slot, func); |
| 1121 | |||
| 1122 | if (!psdev) | 1161 | if (!psdev) |
| 1123 | goto out; | 1162 | goto out; |
| 1124 | 1163 | ||
| @@ -1134,6 +1173,8 @@ static ssize_t pcistub_irq_handler_switch(struct device_driver *drv, | |||
| 1134 | if (dev_data->isr_on) | 1173 | if (dev_data->isr_on) |
| 1135 | dev_data->ack_intr = 1; | 1174 | dev_data->ack_intr = 1; |
| 1136 | out: | 1175 | out: |
| 1176 | if (psdev) | ||
| 1177 | pcistub_device_put(psdev); | ||
| 1137 | if (!err) | 1178 | if (!err) |
| 1138 | err = count; | 1179 | err = count; |
| 1139 | return err; | 1180 | return err; |
| @@ -1216,15 +1257,16 @@ static ssize_t permissive_add(struct device_driver *drv, const char *buf, | |||
| 1216 | err = str_to_slot(buf, &domain, &bus, &slot, &func); | 1257 | err = str_to_slot(buf, &domain, &bus, &slot, &func); |
| 1217 | if (err) | 1258 | if (err) |
| 1218 | goto out; | 1259 | goto out; |
| 1260 | if (slot < 0 || func < 0) { | ||
| 1261 | err = -EINVAL; | ||
| 1262 | goto out; | ||
| 1263 | } | ||
| 1219 | psdev = pcistub_device_find(domain, bus, slot, func); | 1264 | psdev = pcistub_device_find(domain, bus, slot, func); |
| 1220 | if (!psdev) { | 1265 | if (!psdev) { |
| 1221 | err = -ENODEV; | 1266 | err = -ENODEV; |
| 1222 | goto out; | 1267 | goto out; |
| 1223 | } | 1268 | } |
| 1224 | if (!psdev->dev) { | 1269 | |
| 1225 | err = -ENODEV; | ||
| 1226 | goto release; | ||
| 1227 | } | ||
| 1228 | dev_data = pci_get_drvdata(psdev->dev); | 1270 | dev_data = pci_get_drvdata(psdev->dev); |
| 1229 | /* the driver data for a device should never be null at this point */ | 1271 | /* the driver data for a device should never be null at this point */ |
| 1230 | if (!dev_data) { | 1272 | if (!dev_data) { |
| @@ -1297,17 +1339,51 @@ static int __init pcistub_init(void) | |||
| 1297 | 1339 | ||
| 1298 | if (pci_devs_to_hide && *pci_devs_to_hide) { | 1340 | if (pci_devs_to_hide && *pci_devs_to_hide) { |
| 1299 | do { | 1341 | do { |
| 1342 | char wc = '*'; | ||
| 1343 | |||
| 1300 | parsed = 0; | 1344 | parsed = 0; |
| 1301 | 1345 | ||
| 1302 | err = sscanf(pci_devs_to_hide + pos, | 1346 | err = sscanf(pci_devs_to_hide + pos, |
| 1303 | " (%x:%x:%x.%x) %n", | 1347 | " (%x:%x:%x.%x) %n", |
| 1304 | &domain, &bus, &slot, &func, &parsed); | 1348 | &domain, &bus, &slot, &func, &parsed); |
| 1305 | if (err != 4) { | 1349 | switch (err) { |
| 1350 | case 3: | ||
| 1351 | func = -1; | ||
| 1352 | err = sscanf(pci_devs_to_hide + pos, | ||
| 1353 | " (%x:%x:%x.%c) %n", | ||
| 1354 | &domain, &bus, &slot, &wc, | ||
| 1355 | &parsed); | ||
| 1356 | break; | ||
| 1357 | case 2: | ||
| 1358 | slot = func = -1; | ||
| 1359 | err = sscanf(pci_devs_to_hide + pos, | ||
| 1360 | " (%x:%x:*.%c) %n", | ||
| 1361 | &domain, &bus, &wc, &parsed) + 1; | ||
| 1362 | break; | ||
| 1363 | } | ||
| 1364 | |||
| 1365 | if (err != 4 || wc != '*') { | ||
| 1306 | domain = 0; | 1366 | domain = 0; |
| 1367 | wc = '*'; | ||
| 1307 | err = sscanf(pci_devs_to_hide + pos, | 1368 | err = sscanf(pci_devs_to_hide + pos, |
| 1308 | " (%x:%x.%x) %n", | 1369 | " (%x:%x.%x) %n", |
| 1309 | &bus, &slot, &func, &parsed); | 1370 | &bus, &slot, &func, &parsed); |
| 1310 | if (err != 3) | 1371 | switch (err) { |
| 1372 | case 2: | ||
| 1373 | func = -1; | ||
| 1374 | err = sscanf(pci_devs_to_hide + pos, | ||
| 1375 | " (%x:%x.%c) %n", | ||
| 1376 | &bus, &slot, &wc, | ||
| 1377 | &parsed); | ||
| 1378 | break; | ||
| 1379 | case 1: | ||
| 1380 | slot = func = -1; | ||
| 1381 | err = sscanf(pci_devs_to_hide + pos, | ||
| 1382 | " (%x:*.%c) %n", | ||
| 1383 | &bus, &wc, &parsed) + 1; | ||
| 1384 | break; | ||
| 1385 | } | ||
| 1386 | if (err != 3 || wc != '*') | ||
| 1311 | goto parse_error; | 1387 | goto parse_error; |
| 1312 | } | 1388 | } |
| 1313 | 1389 | ||
diff --git a/drivers/xen/xenbus/xenbus_client.c b/drivers/xen/xenbus/xenbus_client.c index b3e146edb51d..bcf3ba4a6ec1 100644 --- a/drivers/xen/xenbus/xenbus_client.c +++ b/drivers/xen/xenbus/xenbus_client.c | |||
| @@ -490,8 +490,7 @@ static int xenbus_map_ring_valloc_pv(struct xenbus_device *dev, | |||
| 490 | 490 | ||
| 491 | op.host_addr = arbitrary_virt_to_machine(pte).maddr; | 491 | op.host_addr = arbitrary_virt_to_machine(pte).maddr; |
| 492 | 492 | ||
| 493 | if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1)) | 493 | gnttab_batch_map(&op, 1); |
| 494 | BUG(); | ||
| 495 | 494 | ||
| 496 | if (op.status != GNTST_okay) { | 495 | if (op.status != GNTST_okay) { |
| 497 | free_vm_area(area); | 496 | free_vm_area(area); |
| @@ -572,8 +571,7 @@ int xenbus_map_ring(struct xenbus_device *dev, int gnt_ref, | |||
| 572 | gnttab_set_map_op(&op, (unsigned long)vaddr, GNTMAP_host_map, gnt_ref, | 571 | gnttab_set_map_op(&op, (unsigned long)vaddr, GNTMAP_host_map, gnt_ref, |
| 573 | dev->otherend_id); | 572 | dev->otherend_id); |
| 574 | 573 | ||
| 575 | if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1)) | 574 | gnttab_batch_map(&op, 1); |
| 576 | BUG(); | ||
| 577 | 575 | ||
| 578 | if (op.status != GNTST_okay) { | 576 | if (op.status != GNTST_okay) { |
| 579 | xenbus_dev_fatal(dev, op.status, | 577 | xenbus_dev_fatal(dev, op.status, |
diff --git a/include/linux/swiotlb.h b/include/linux/swiotlb.h index e872526fdc5f..8d08b3ed406d 100644 --- a/include/linux/swiotlb.h +++ b/include/linux/swiotlb.h | |||
| @@ -25,6 +25,7 @@ extern int swiotlb_force; | |||
| 25 | extern void swiotlb_init(int verbose); | 25 | extern void swiotlb_init(int verbose); |
| 26 | extern void swiotlb_init_with_tbl(char *tlb, unsigned long nslabs, int verbose); | 26 | extern void swiotlb_init_with_tbl(char *tlb, unsigned long nslabs, int verbose); |
| 27 | extern unsigned long swiotlb_nr_tbl(void); | 27 | extern unsigned long swiotlb_nr_tbl(void); |
| 28 | extern int swiotlb_late_init_with_tbl(char *tlb, unsigned long nslabs); | ||
| 28 | 29 | ||
| 29 | /* | 30 | /* |
| 30 | * Enumeration for sync targets | 31 | * Enumeration for sync targets |
diff --git a/include/xen/grant_table.h b/include/xen/grant_table.h index 11e27c3af3cb..ba0d77529a29 100644 --- a/include/xen/grant_table.h +++ b/include/xen/grant_table.h | |||
| @@ -189,4 +189,16 @@ int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops, | |||
| 189 | int gnttab_unmap_refs(struct gnttab_unmap_grant_ref *unmap_ops, | 189 | int gnttab_unmap_refs(struct gnttab_unmap_grant_ref *unmap_ops, |
| 190 | struct page **pages, unsigned int count, bool clear_pte); | 190 | struct page **pages, unsigned int count, bool clear_pte); |
| 191 | 191 | ||
| 192 | /* Perform a batch of grant map/copy operations. Retry every batch slot | ||
| 193 | * for which the hypervisor returns GNTST_eagain. This is typically due | ||
| 194 | * to paged out target frames. | ||
| 195 | * | ||
| 196 | * Will retry for 1, 2, ... 255 ms, i.e. 256 times during 32 seconds. | ||
| 197 | * | ||
| 198 | * Return value in each iand every status field of the batch guaranteed | ||
| 199 | * to not be GNTST_eagain. | ||
| 200 | */ | ||
| 201 | void gnttab_batch_map(struct gnttab_map_grant_ref *batch, unsigned count); | ||
| 202 | void gnttab_batch_copy(struct gnttab_copy *batch, unsigned count); | ||
| 203 | |||
| 192 | #endif /* __ASM_GNTTAB_H__ */ | 204 | #endif /* __ASM_GNTTAB_H__ */ |
diff --git a/include/xen/interface/platform.h b/include/xen/interface/platform.h index a3275a850e54..54ad6f9e4725 100644 --- a/include/xen/interface/platform.h +++ b/include/xen/interface/platform.h | |||
| @@ -112,6 +112,7 @@ DEFINE_GUEST_HANDLE_STRUCT(xenpf_platform_quirk_t); | |||
| 112 | #define XEN_FW_DISK_INFO 1 /* from int 13 AH=08/41/48 */ | 112 | #define XEN_FW_DISK_INFO 1 /* from int 13 AH=08/41/48 */ |
| 113 | #define XEN_FW_DISK_MBR_SIGNATURE 2 /* from MBR offset 0x1b8 */ | 113 | #define XEN_FW_DISK_MBR_SIGNATURE 2 /* from MBR offset 0x1b8 */ |
| 114 | #define XEN_FW_VBEDDC_INFO 3 /* from int 10 AX=4f15 */ | 114 | #define XEN_FW_VBEDDC_INFO 3 /* from int 10 AX=4f15 */ |
| 115 | #define XEN_FW_KBD_SHIFT_FLAGS 5 /* Int16, Fn02: Get keyboard shift flags. */ | ||
| 115 | struct xenpf_firmware_info { | 116 | struct xenpf_firmware_info { |
| 116 | /* IN variables. */ | 117 | /* IN variables. */ |
| 117 | uint32_t type; | 118 | uint32_t type; |
| @@ -142,6 +143,8 @@ struct xenpf_firmware_info { | |||
| 142 | /* must refer to 128-byte buffer */ | 143 | /* must refer to 128-byte buffer */ |
| 143 | GUEST_HANDLE(uchar) edid; | 144 | GUEST_HANDLE(uchar) edid; |
| 144 | } vbeddc_info; /* XEN_FW_VBEDDC_INFO */ | 145 | } vbeddc_info; /* XEN_FW_VBEDDC_INFO */ |
| 146 | |||
| 147 | uint8_t kbd_shift_flags; /* XEN_FW_KBD_SHIFT_FLAGS */ | ||
| 145 | } u; | 148 | } u; |
| 146 | }; | 149 | }; |
| 147 | DEFINE_GUEST_HANDLE_STRUCT(xenpf_firmware_info_t); | 150 | DEFINE_GUEST_HANDLE_STRUCT(xenpf_firmware_info_t); |
diff --git a/include/xen/interface/xen.h b/include/xen/interface/xen.h index 1e0df6b7d3b3..886a5d80a18f 100644 --- a/include/xen/interface/xen.h +++ b/include/xen/interface/xen.h | |||
| @@ -454,6 +454,7 @@ struct dom0_vga_console_info { | |||
| 454 | uint8_t video_type; | 454 | uint8_t video_type; |
| 455 | #define XEN_VGATYPE_TEXT_MODE_3 0x03 | 455 | #define XEN_VGATYPE_TEXT_MODE_3 0x03 |
| 456 | #define XEN_VGATYPE_VESA_LFB 0x23 | 456 | #define XEN_VGATYPE_VESA_LFB 0x23 |
| 457 | #define XEN_VGATYPE_EFI_LFB 0x70 | ||
| 457 | 458 | ||
| 458 | union { | 459 | union { |
| 459 | struct { | 460 | struct { |
diff --git a/include/xen/swiotlb-xen.h b/include/xen/swiotlb-xen.h index c050b6b9de38..de8bcc641c49 100644 --- a/include/xen/swiotlb-xen.h +++ b/include/xen/swiotlb-xen.h | |||
| @@ -3,7 +3,7 @@ | |||
| 3 | 3 | ||
| 4 | #include <linux/swiotlb.h> | 4 | #include <linux/swiotlb.h> |
| 5 | 5 | ||
| 6 | extern void xen_swiotlb_init(int verbose); | 6 | extern int xen_swiotlb_init(int verbose, bool early); |
| 7 | 7 | ||
| 8 | extern void | 8 | extern void |
| 9 | *xen_swiotlb_alloc_coherent(struct device *hwdev, size_t size, | 9 | *xen_swiotlb_alloc_coherent(struct device *hwdev, size_t size, |
diff --git a/lib/swiotlb.c b/lib/swiotlb.c index 45bc1f83a5ad..f114bf6a8e13 100644 --- a/lib/swiotlb.c +++ b/lib/swiotlb.c | |||
| @@ -170,7 +170,7 @@ void __init swiotlb_init_with_tbl(char *tlb, unsigned long nslabs, int verbose) | |||
| 170 | * Statically reserve bounce buffer space and initialize bounce buffer data | 170 | * Statically reserve bounce buffer space and initialize bounce buffer data |
| 171 | * structures for the software IO TLB used to implement the DMA API. | 171 | * structures for the software IO TLB used to implement the DMA API. |
| 172 | */ | 172 | */ |
| 173 | void __init | 173 | static void __init |
| 174 | swiotlb_init_with_default_size(size_t default_size, int verbose) | 174 | swiotlb_init_with_default_size(size_t default_size, int verbose) |
| 175 | { | 175 | { |
| 176 | unsigned long bytes; | 176 | unsigned long bytes; |
| @@ -206,8 +206,9 @@ swiotlb_init(int verbose) | |||
| 206 | int | 206 | int |
| 207 | swiotlb_late_init_with_default_size(size_t default_size) | 207 | swiotlb_late_init_with_default_size(size_t default_size) |
| 208 | { | 208 | { |
| 209 | unsigned long i, bytes, req_nslabs = io_tlb_nslabs; | 209 | unsigned long bytes, req_nslabs = io_tlb_nslabs; |
| 210 | unsigned int order; | 210 | unsigned int order; |
| 211 | int rc = 0; | ||
| 211 | 212 | ||
| 212 | if (!io_tlb_nslabs) { | 213 | if (!io_tlb_nslabs) { |
| 213 | io_tlb_nslabs = (default_size >> IO_TLB_SHIFT); | 214 | io_tlb_nslabs = (default_size >> IO_TLB_SHIFT); |
| @@ -229,16 +230,32 @@ swiotlb_late_init_with_default_size(size_t default_size) | |||
| 229 | order--; | 230 | order--; |
| 230 | } | 231 | } |
| 231 | 232 | ||
| 232 | if (!io_tlb_start) | 233 | if (!io_tlb_start) { |
| 233 | goto cleanup1; | 234 | io_tlb_nslabs = req_nslabs; |
| 234 | 235 | return -ENOMEM; | |
| 236 | } | ||
| 235 | if (order != get_order(bytes)) { | 237 | if (order != get_order(bytes)) { |
| 236 | printk(KERN_WARNING "Warning: only able to allocate %ld MB " | 238 | printk(KERN_WARNING "Warning: only able to allocate %ld MB " |
| 237 | "for software IO TLB\n", (PAGE_SIZE << order) >> 20); | 239 | "for software IO TLB\n", (PAGE_SIZE << order) >> 20); |
| 238 | io_tlb_nslabs = SLABS_PER_PAGE << order; | 240 | io_tlb_nslabs = SLABS_PER_PAGE << order; |
| 239 | bytes = io_tlb_nslabs << IO_TLB_SHIFT; | ||
| 240 | } | 241 | } |
| 242 | rc = swiotlb_late_init_with_tbl(io_tlb_start, io_tlb_nslabs); | ||
| 243 | if (rc) | ||
| 244 | free_pages((unsigned long)io_tlb_start, order); | ||
| 245 | return rc; | ||
| 246 | } | ||
| 247 | |||
| 248 | int | ||
| 249 | swiotlb_late_init_with_tbl(char *tlb, unsigned long nslabs) | ||
| 250 | { | ||
| 251 | unsigned long i, bytes; | ||
| 252 | |||
| 253 | bytes = nslabs << IO_TLB_SHIFT; | ||
| 254 | |||
| 255 | io_tlb_nslabs = nslabs; | ||
| 256 | io_tlb_start = tlb; | ||
| 241 | io_tlb_end = io_tlb_start + bytes; | 257 | io_tlb_end = io_tlb_start + bytes; |
| 258 | |||
| 242 | memset(io_tlb_start, 0, bytes); | 259 | memset(io_tlb_start, 0, bytes); |
| 243 | 260 | ||
| 244 | /* | 261 | /* |
| @@ -288,10 +305,8 @@ cleanup3: | |||
| 288 | io_tlb_list = NULL; | 305 | io_tlb_list = NULL; |
| 289 | cleanup2: | 306 | cleanup2: |
| 290 | io_tlb_end = NULL; | 307 | io_tlb_end = NULL; |
| 291 | free_pages((unsigned long)io_tlb_start, order); | ||
| 292 | io_tlb_start = NULL; | 308 | io_tlb_start = NULL; |
| 293 | cleanup1: | 309 | io_tlb_nslabs = 0; |
| 294 | io_tlb_nslabs = req_nslabs; | ||
| 295 | return -ENOMEM; | 310 | return -ENOMEM; |
| 296 | } | 311 | } |
| 297 | 312 | ||
