aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>2012-08-23 14:36:15 -0400
committerKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>2012-09-17 12:58:16 -0400
commitb82776005369899c1c7ca2e4b2414bb64b538d2c (patch)
treeb07bb5fc8cd2b335f46a43791f0fc7505a57d4ac
parent5bab7864b1167f9a72d375f6854027db436a1cc1 (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.h2
-rw-r--r--arch/x86/xen/pci-swiotlb-xen.c24
-rw-r--r--drivers/xen/swiotlb-xen.c48
-rw-r--r--include/xen/swiotlb-xen.h2
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 @@
5extern int xen_swiotlb; 5extern int xen_swiotlb;
6extern int __init pci_xen_swiotlb_detect(void); 6extern int __init pci_xen_swiotlb_detect(void);
7extern void __init pci_xen_swiotlb_init(void); 7extern void __init pci_xen_swiotlb_init(void);
8extern int pci_xen_swiotlb_init_late(void);
8#else 9#else
9#define xen_swiotlb (0) 10#define xen_swiotlb (0)
10static inline int __init pci_xen_swiotlb_detect(void) { return 0; } 11static inline int __init pci_xen_swiotlb_detect(void) { return 0; }
11static inline void __init pci_xen_swiotlb_init(void) { } 12static inline void __init pci_xen_swiotlb_init(void) { }
13static 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>
16int xen_swiotlb __read_mostly; 16int xen_swiotlb __read_mostly;
17 17
18static struct dma_map_ops xen_swiotlb_dma_ops = { 18static struct dma_map_ops xen_swiotlb_dma_ops = {
@@ -69,13 +69,33 @@ int __init pci_xen_swiotlb_detect(void)
69void __init pci_xen_swiotlb_init(void) 69void __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
80int 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}
97EXPORT_SYMBOL_GPL(pci_xen_swiotlb_init_late);
98
79IOMMU_INIT_FINISH(pci_xen_swiotlb_detect, 99IOMMU_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}
179void __init xen_swiotlb_init(int verbose) 179int __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();
187retry: 187retry:
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;
213error: 238error:
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
225void * 253void *
226xen_swiotlb_alloc_coherent(struct device *hwdev, size_t size, 254xen_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
6extern void xen_swiotlb_init(int verbose); 6extern int xen_swiotlb_init(int verbose, bool early);
7 7
8extern void 8extern void
9*xen_swiotlb_alloc_coherent(struct device *hwdev, size_t size, 9*xen_swiotlb_alloc_coherent(struct device *hwdev, size_t size,