diff options
author | Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> | 2012-08-23 14:36:15 -0400 |
---|---|---|
committer | Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> | 2012-09-17 12:58:16 -0400 |
commit | b82776005369899c1c7ca2e4b2414bb64b538d2c (patch) | |
tree | b07bb5fc8cd2b335f46a43791f0fc7505a57d4ac | |
parent | 5bab7864b1167f9a72d375f6854027db436a1cc1 (diff) |
xen/swiotlb: Use the swiotlb_late_init_with_tbl to init Xen-SWIOTLB late when PV PCI is used.
With this patch we provide the functionality to initialize the
Xen-SWIOTLB late in the bootup cycle - specifically for
Xen PCI-frontend. We still will work if the user had
supplied 'iommu=soft' on the Linux command line.
Note: We cannot depend on after_bootmem to automatically
determine whether this is early or not. This is because
when PCI IOMMUs are initialized it is after after_bootmem but
before a lot of "other" subsystems are initialized.
CC: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
[v1: Fix smatch warnings]
[v2: Added check for xen_swiotlb]
[v3: Rebased with new xen-swiotlb changes]
[v4: squashed xen/swiotlb: Depending on after_bootmem is not correct in]
Reviewed-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
-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, |