diff options
| -rw-r--r-- | arch/x86/include/asm/xen/swiotlb-xen.h | 2 | ||||
| -rw-r--r-- | arch/x86/xen/pci-swiotlb-xen.c | 24 | ||||
| -rw-r--r-- | drivers/xen/swiotlb-xen.c | 48 | ||||
| -rw-r--r-- | include/xen/swiotlb-xen.h | 2 |
4 files changed, 63 insertions, 13 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/pci-swiotlb-xen.c b/arch/x86/xen/pci-swiotlb-xen.c index 1c1722761eec..b152640d8388 100644 --- a/arch/x86/xen/pci-swiotlb-xen.c +++ b/arch/x86/xen/pci-swiotlb-xen.c | |||
| @@ -12,7 +12,7 @@ | |||
| 12 | #include <asm/iommu.h> | 12 | #include <asm/iommu.h> |
| 13 | #include <asm/dma.h> | 13 | #include <asm/dma.h> |
| 14 | #endif | 14 | #endif |
| 15 | 15 | #include <linux/export.h> | |
| 16 | int xen_swiotlb __read_mostly; | 16 | int xen_swiotlb __read_mostly; |
| 17 | 17 | ||
| 18 | static struct dma_map_ops xen_swiotlb_dma_ops = { | 18 | static struct dma_map_ops xen_swiotlb_dma_ops = { |
| @@ -69,13 +69,33 @@ int __init pci_xen_swiotlb_detect(void) | |||
| 69 | void __init pci_xen_swiotlb_init(void) | 69 | void __init pci_xen_swiotlb_init(void) |
| 70 | { | 70 | { |
| 71 | if (xen_swiotlb) { | 71 | if (xen_swiotlb) { |
| 72 | xen_swiotlb_init(1); | 72 | xen_swiotlb_init(1, true /* early */); |
| 73 | dma_ops = &xen_swiotlb_dma_ops; | 73 | dma_ops = &xen_swiotlb_dma_ops; |
| 74 | 74 | ||
| 75 | /* Make sure ACS will be enabled */ | 75 | /* Make sure ACS will be enabled */ |
| 76 | pci_request_acs(); | 76 | pci_request_acs(); |
| 77 | } | 77 | } |
| 78 | } | 78 | } |
| 79 | |||
| 80 | int pci_xen_swiotlb_init_late(void) | ||
| 81 | { | ||
| 82 | int rc; | ||
| 83 | |||
| 84 | if (xen_swiotlb) | ||
| 85 | return 0; | ||
| 86 | |||
| 87 | rc = xen_swiotlb_init(1, false /* late */); | ||
| 88 | if (rc) | ||
| 89 | return rc; | ||
| 90 | |||
| 91 | dma_ops = &xen_swiotlb_dma_ops; | ||
| 92 | /* Make sure ACS will be enabled */ | ||
| 93 | pci_request_acs(); | ||
| 94 | |||
| 95 | return 0; | ||
| 96 | } | ||
| 97 | EXPORT_SYMBOL_GPL(pci_xen_swiotlb_init_late); | ||
| 98 | |||
| 79 | IOMMU_INIT_FINISH(pci_xen_swiotlb_detect, | 99 | IOMMU_INIT_FINISH(pci_xen_swiotlb_detect, |
| 80 | 0, | 100 | 0, |
| 81 | pci_xen_swiotlb_init, | 101 | pci_xen_swiotlb_init, |
diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c index 701b1035fa6f..7461edb5118e 100644 --- a/drivers/xen/swiotlb-xen.c +++ b/drivers/xen/swiotlb-xen.c | |||
| @@ -176,9 +176,9 @@ static const char *xen_swiotlb_error(enum xen_swiotlb_err err) | |||
| 176 | } | 176 | } |
| 177 | return ""; | 177 | return ""; |
| 178 | } | 178 | } |
| 179 | void __init xen_swiotlb_init(int verbose) | 179 | int __ref xen_swiotlb_init(int verbose, bool early) |
| 180 | { | 180 | { |
| 181 | unsigned long bytes; | 181 | unsigned long bytes, order; |
| 182 | int rc = -ENOMEM; | 182 | int rc = -ENOMEM; |
| 183 | enum xen_swiotlb_err m_ret = XEN_SWIOTLB_UNKNOWN; | 183 | enum xen_swiotlb_err m_ret = XEN_SWIOTLB_UNKNOWN; |
| 184 | unsigned int repeat = 3; | 184 | unsigned int repeat = 3; |
| @@ -186,10 +186,28 @@ void __init xen_swiotlb_init(int verbose) | |||
| 186 | xen_io_tlb_nslabs = swiotlb_nr_tbl(); | 186 | xen_io_tlb_nslabs = swiotlb_nr_tbl(); |
| 187 | retry: | 187 | retry: |
| 188 | bytes = xen_set_nslabs(xen_io_tlb_nslabs); | 188 | bytes = xen_set_nslabs(xen_io_tlb_nslabs); |
| 189 | order = get_order(xen_io_tlb_nslabs << IO_TLB_SHIFT); | ||
| 189 | /* | 190 | /* |
| 190 | * Get IO TLB memory from any location. | 191 | * Get IO TLB memory from any location. |
| 191 | */ | 192 | */ |
| 192 | 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 | } | ||
| 193 | if (!xen_io_tlb_start) { | 211 | if (!xen_io_tlb_start) { |
| 194 | m_ret = XEN_SWIOTLB_ENOMEM; | 212 | m_ret = XEN_SWIOTLB_ENOMEM; |
| 195 | goto error; | 213 | goto error; |
| @@ -202,14 +220,21 @@ retry: | |||
| 202 | bytes, | 220 | bytes, |
| 203 | xen_io_tlb_nslabs); | 221 | xen_io_tlb_nslabs); |
| 204 | if (rc) { | 222 | if (rc) { |
| 205 | free_bootmem(__pa(xen_io_tlb_start), PAGE_ALIGN(bytes)); | 223 | if (early) |
| 224 | free_bootmem(__pa(xen_io_tlb_start), PAGE_ALIGN(bytes)); | ||
| 225 | else { | ||
| 226 | free_pages((unsigned long)xen_io_tlb_start, order); | ||
| 227 | xen_io_tlb_start = NULL; | ||
| 228 | } | ||
| 206 | m_ret = XEN_SWIOTLB_EFIXUP; | 229 | m_ret = XEN_SWIOTLB_EFIXUP; |
| 207 | goto error; | 230 | goto error; |
| 208 | } | 231 | } |
| 209 | start_dma_addr = xen_virt_to_bus(xen_io_tlb_start); | 232 | start_dma_addr = xen_virt_to_bus(xen_io_tlb_start); |
| 210 | swiotlb_init_with_tbl(xen_io_tlb_start, xen_io_tlb_nslabs, verbose); | 233 | if (early) |
| 211 | 234 | swiotlb_init_with_tbl(xen_io_tlb_start, xen_io_tlb_nslabs, verbose); | |
| 212 | return; | 235 | else |
| 236 | rc = swiotlb_late_init_with_tbl(xen_io_tlb_start, xen_io_tlb_nslabs); | ||
| 237 | return rc; | ||
| 213 | error: | 238 | error: |
| 214 | if (repeat--) { | 239 | if (repeat--) { |
| 215 | xen_io_tlb_nslabs = max(1024UL, /* Min is 2MB */ | 240 | xen_io_tlb_nslabs = max(1024UL, /* Min is 2MB */ |
| @@ -218,10 +243,13 @@ error: | |||
| 218 | (xen_io_tlb_nslabs << IO_TLB_SHIFT) >> 20); | 243 | (xen_io_tlb_nslabs << IO_TLB_SHIFT) >> 20); |
| 219 | goto retry; | 244 | goto retry; |
| 220 | } | 245 | } |
| 221 | xen_raw_printk("%s (rc:%d)", xen_swiotlb_error(m_ret), rc); | 246 | pr_err("%s (rc:%d)", xen_swiotlb_error(m_ret), rc); |
| 222 | panic("%s (rc:%d)", xen_swiotlb_error(m_ret), rc); | 247 | if (early) |
| 248 | panic("%s (rc:%d)", xen_swiotlb_error(m_ret), rc); | ||
| 249 | else | ||
| 250 | free_pages((unsigned long)xen_io_tlb_start, order); | ||
| 251 | return rc; | ||
| 223 | } | 252 | } |
| 224 | |||
| 225 | void * | 253 | void * |
| 226 | xen_swiotlb_alloc_coherent(struct device *hwdev, size_t size, | 254 | xen_swiotlb_alloc_coherent(struct device *hwdev, size_t size, |
| 227 | dma_addr_t *dma_handle, gfp_t flags, | 255 | dma_addr_t *dma_handle, gfp_t flags, |
diff --git a/include/xen/swiotlb-xen.h b/include/xen/swiotlb-xen.h index 4f4d449f00f6..289ee509bda9 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, |
