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 /drivers | |
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>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/xen/swiotlb-xen.c | 48 |
1 files changed, 38 insertions, 10 deletions
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, |