diff options
Diffstat (limited to 'drivers/xen/swiotlb-xen.c')
-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, |