diff options
author | Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> | 2012-09-22 20:01:16 -0400 |
---|---|---|
committer | Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> | 2012-09-22 20:01:24 -0400 |
commit | a5f95155709cb854e96aa27969d110668cdbda9d (patch) | |
tree | c9392d6871184838bf81a0b70900e28558e92870 | |
parent | c571898ffc24a1768e1b2dabeac0fc7dd4c14601 (diff) | |
parent | 2a3bce8f6afb9118a7ac3c360a5baf7cdaec87bc (diff) |
Merge branch 'stable/late-swiotlb.v3.3' into stable/for-linus-3.7
* stable/late-swiotlb.v3.3:
xen/swiotlb: Fix compile warnings when using plain integer instead of NULL pointer.
xen/swiotlb: Remove functions not needed anymore.
xen/pcifront: Use Xen-SWIOTLB when initting if required.
xen/swiotlb: For early initialization, return zero on success.
xen/swiotlb: Use the swiotlb_late_init_with_tbl to init Xen-SWIOTLB late when PV PCI is used.
xen/swiotlb: Move the error strings to its own function.
xen/swiotlb: Move the nr_tbl determination in its own function.
swiotlb: add the late swiotlb initialization function with iotlb memory
xen/swiotlb: With more than 4GB on 64-bit, disable the native SWIOTLB.
xen/swiotlb: Simplify the logic.
Conflicts:
arch/x86/xen/pci-swiotlb-xen.c
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 | 47 | ||||
-rw-r--r-- | drivers/pci/xen-pcifront.c | 13 | ||||
-rw-r--r-- | drivers/xen/swiotlb-xen.c | 101 | ||||
-rw-r--r-- | include/linux/swiotlb.h | 1 | ||||
-rw-r--r-- | include/xen/swiotlb-xen.h | 2 | ||||
-rw-r--r-- | lib/swiotlb.c | 33 |
7 files changed, 154 insertions, 45 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 1ab45941502d..969570491c39 100644 --- a/arch/x86/xen/pci-swiotlb-xen.c +++ b/arch/x86/xen/pci-swiotlb-xen.c | |||
@@ -8,7 +8,14 @@ | |||
8 | #include <xen/xen.h> | 8 | #include <xen/xen.h> |
9 | #include <asm/iommu_table.h> | 9 | #include <asm/iommu_table.h> |
10 | 10 | ||
11 | |||
11 | #include <asm/xen/swiotlb-xen.h> | 12 | #include <asm/xen/swiotlb-xen.h> |
13 | #ifdef CONFIG_X86_64 | ||
14 | #include <asm/iommu.h> | ||
15 | #include <asm/dma.h> | ||
16 | #endif | ||
17 | #include <linux/export.h> | ||
18 | |||
12 | int xen_swiotlb __read_mostly; | 19 | int xen_swiotlb __read_mostly; |
13 | 20 | ||
14 | static struct dma_map_ops xen_swiotlb_dma_ops = { | 21 | static struct dma_map_ops xen_swiotlb_dma_ops = { |
@@ -35,33 +42,63 @@ static struct dma_map_ops xen_swiotlb_dma_ops = { | |||
35 | int __init pci_xen_swiotlb_detect(void) | 42 | int __init pci_xen_swiotlb_detect(void) |
36 | { | 43 | { |
37 | 44 | ||
45 | if (!xen_pv_domain()) | ||
46 | return 0; | ||
47 | |||
38 | /* If running as PV guest, either iommu=soft, or swiotlb=force will | 48 | /* If running as PV guest, either iommu=soft, or swiotlb=force will |
39 | * activate this IOMMU. If running as PV privileged, activate it | 49 | * activate this IOMMU. If running as PV privileged, activate it |
40 | * irregardless. | 50 | * irregardless. |
41 | */ | 51 | */ |
42 | if ((xen_initial_domain() || swiotlb || swiotlb_force) && | 52 | if ((xen_initial_domain() || swiotlb || swiotlb_force)) |
43 | (xen_pv_domain())) | ||
44 | xen_swiotlb = 1; | 53 | xen_swiotlb = 1; |
45 | 54 | ||
46 | /* If we are running under Xen, we MUST disable the native SWIOTLB. | 55 | /* If we are running under Xen, we MUST disable the native SWIOTLB. |
47 | * Don't worry about swiotlb_force flag activating the native, as | 56 | * Don't worry about swiotlb_force flag activating the native, as |
48 | * the 'swiotlb' flag is the only one turning it on. */ | 57 | * the 'swiotlb' flag is the only one turning it on. */ |
49 | if (xen_pv_domain()) | 58 | swiotlb = 0; |
50 | swiotlb = 0; | ||
51 | 59 | ||
60 | #ifdef CONFIG_X86_64 | ||
61 | /* pci_swiotlb_detect_4gb turns on native SWIOTLB if no_iommu == 0 | ||
62 | * (so no iommu=X command line over-writes). | ||
63 | * Considering that PV guests do not want the *native SWIOTLB* but | ||
64 | * only Xen SWIOTLB it is not useful to us so set no_iommu=1 here. | ||
65 | */ | ||
66 | if (max_pfn > MAX_DMA32_PFN) | ||
67 | no_iommu = 1; | ||
68 | #endif | ||
52 | return xen_swiotlb; | 69 | return xen_swiotlb; |
53 | } | 70 | } |
54 | 71 | ||
55 | void __init pci_xen_swiotlb_init(void) | 72 | void __init pci_xen_swiotlb_init(void) |
56 | { | 73 | { |
57 | if (xen_swiotlb) { | 74 | if (xen_swiotlb) { |
58 | xen_swiotlb_init(1); | 75 | xen_swiotlb_init(1, true /* early */); |
59 | dma_ops = &xen_swiotlb_dma_ops; | 76 | dma_ops = &xen_swiotlb_dma_ops; |
60 | 77 | ||
61 | /* Make sure ACS will be enabled */ | 78 | /* Make sure ACS will be enabled */ |
62 | pci_request_acs(); | 79 | pci_request_acs(); |
63 | } | 80 | } |
64 | } | 81 | } |
82 | |||
83 | int pci_xen_swiotlb_init_late(void) | ||
84 | { | ||
85 | int rc; | ||
86 | |||
87 | if (xen_swiotlb) | ||
88 | return 0; | ||
89 | |||
90 | rc = xen_swiotlb_init(1, false /* late */); | ||
91 | if (rc) | ||
92 | return rc; | ||
93 | |||
94 | dma_ops = &xen_swiotlb_dma_ops; | ||
95 | /* Make sure ACS will be enabled */ | ||
96 | pci_request_acs(); | ||
97 | |||
98 | return 0; | ||
99 | } | ||
100 | EXPORT_SYMBOL_GPL(pci_xen_swiotlb_init_late); | ||
101 | |||
65 | IOMMU_INIT_FINISH(pci_xen_swiotlb_detect, | 102 | IOMMU_INIT_FINISH(pci_xen_swiotlb_detect, |
66 | NULL, | 103 | NULL, |
67 | pci_xen_swiotlb_init, | 104 | pci_xen_swiotlb_init, |
diff --git a/drivers/pci/xen-pcifront.c b/drivers/pci/xen-pcifront.c index a4d901def8f2..7d6773535b67 100644 --- a/drivers/pci/xen-pcifront.c +++ b/drivers/pci/xen-pcifront.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/bitops.h> | 21 | #include <linux/bitops.h> |
22 | #include <linux/time.h> | 22 | #include <linux/time.h> |
23 | 23 | ||
24 | #include <asm/xen/swiotlb-xen.h> | ||
24 | #define INVALID_GRANT_REF (0) | 25 | #define INVALID_GRANT_REF (0) |
25 | #define INVALID_EVTCHN (-1) | 26 | #define INVALID_EVTCHN (-1) |
26 | 27 | ||
@@ -668,7 +669,7 @@ static irqreturn_t pcifront_handler_aer(int irq, void *dev) | |||
668 | schedule_pcifront_aer_op(pdev); | 669 | schedule_pcifront_aer_op(pdev); |
669 | return IRQ_HANDLED; | 670 | return IRQ_HANDLED; |
670 | } | 671 | } |
671 | static int pcifront_connect(struct pcifront_device *pdev) | 672 | static int pcifront_connect_and_init_dma(struct pcifront_device *pdev) |
672 | { | 673 | { |
673 | int err = 0; | 674 | int err = 0; |
674 | 675 | ||
@@ -681,9 +682,13 @@ static int pcifront_connect(struct pcifront_device *pdev) | |||
681 | dev_err(&pdev->xdev->dev, "PCI frontend already installed!\n"); | 682 | dev_err(&pdev->xdev->dev, "PCI frontend already installed!\n"); |
682 | err = -EEXIST; | 683 | err = -EEXIST; |
683 | } | 684 | } |
684 | |||
685 | spin_unlock(&pcifront_dev_lock); | 685 | spin_unlock(&pcifront_dev_lock); |
686 | 686 | ||
687 | if (!err && !swiotlb_nr_tbl()) { | ||
688 | err = pci_xen_swiotlb_init_late(); | ||
689 | if (err) | ||
690 | dev_err(&pdev->xdev->dev, "Could not setup SWIOTLB!\n"); | ||
691 | } | ||
687 | return err; | 692 | return err; |
688 | } | 693 | } |
689 | 694 | ||
@@ -842,10 +847,10 @@ static int __devinit pcifront_try_connect(struct pcifront_device *pdev) | |||
842 | XenbusStateInitialised) | 847 | XenbusStateInitialised) |
843 | goto out; | 848 | goto out; |
844 | 849 | ||
845 | err = pcifront_connect(pdev); | 850 | err = pcifront_connect_and_init_dma(pdev); |
846 | if (err) { | 851 | if (err) { |
847 | xenbus_dev_fatal(pdev->xdev, err, | 852 | xenbus_dev_fatal(pdev->xdev, err, |
848 | "Error connecting PCI Frontend"); | 853 | "Error setting up PCI Frontend"); |
849 | goto out; | 854 | goto out; |
850 | } | 855 | } |
851 | 856 | ||
diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c index 2e74dba6a04d..58db6df866ef 100644 --- a/drivers/xen/swiotlb-xen.c +++ b/drivers/xen/swiotlb-xen.c | |||
@@ -144,31 +144,72 @@ xen_swiotlb_fixup(void *buf, size_t size, unsigned long nslabs) | |||
144 | } while (i < nslabs); | 144 | } while (i < nslabs); |
145 | return 0; | 145 | return 0; |
146 | } | 146 | } |
147 | static unsigned long xen_set_nslabs(unsigned long nr_tbl) | ||
148 | { | ||
149 | if (!nr_tbl) { | ||
150 | xen_io_tlb_nslabs = (64 * 1024 * 1024 >> IO_TLB_SHIFT); | ||
151 | xen_io_tlb_nslabs = ALIGN(xen_io_tlb_nslabs, IO_TLB_SEGSIZE); | ||
152 | } else | ||
153 | xen_io_tlb_nslabs = nr_tbl; | ||
154 | |||
155 | return xen_io_tlb_nslabs << IO_TLB_SHIFT; | ||
156 | } | ||
157 | |||
158 | enum xen_swiotlb_err { | ||
159 | XEN_SWIOTLB_UNKNOWN = 0, | ||
160 | XEN_SWIOTLB_ENOMEM, | ||
161 | XEN_SWIOTLB_EFIXUP | ||
162 | }; | ||
147 | 163 | ||
148 | void __init xen_swiotlb_init(int verbose) | 164 | static const char *xen_swiotlb_error(enum xen_swiotlb_err err) |
149 | { | 165 | { |
150 | unsigned long bytes; | 166 | switch (err) { |
167 | case XEN_SWIOTLB_ENOMEM: | ||
168 | return "Cannot allocate Xen-SWIOTLB buffer\n"; | ||
169 | case XEN_SWIOTLB_EFIXUP: | ||
170 | return "Failed to get contiguous memory for DMA from Xen!\n"\ | ||
171 | "You either: don't have the permissions, do not have"\ | ||
172 | " enough free memory under 4GB, or the hypervisor memory"\ | ||
173 | " is too fragmented!"; | ||
174 | default: | ||
175 | break; | ||
176 | } | ||
177 | return ""; | ||
178 | } | ||
179 | int __ref xen_swiotlb_init(int verbose, bool early) | ||
180 | { | ||
181 | unsigned long bytes, order; | ||
151 | int rc = -ENOMEM; | 182 | int rc = -ENOMEM; |
152 | unsigned long nr_tbl; | 183 | enum xen_swiotlb_err m_ret = XEN_SWIOTLB_UNKNOWN; |
153 | char *m = NULL; | ||
154 | unsigned int repeat = 3; | 184 | unsigned int repeat = 3; |
155 | 185 | ||
156 | nr_tbl = swiotlb_nr_tbl(); | 186 | xen_io_tlb_nslabs = swiotlb_nr_tbl(); |
157 | if (nr_tbl) | ||
158 | xen_io_tlb_nslabs = nr_tbl; | ||
159 | else { | ||
160 | xen_io_tlb_nslabs = (64 * 1024 * 1024 >> IO_TLB_SHIFT); | ||
161 | xen_io_tlb_nslabs = ALIGN(xen_io_tlb_nslabs, IO_TLB_SEGSIZE); | ||
162 | } | ||
163 | retry: | 187 | retry: |
164 | bytes = xen_io_tlb_nslabs << IO_TLB_SHIFT; | 188 | bytes = xen_set_nslabs(xen_io_tlb_nslabs); |
165 | 189 | order = get_order(xen_io_tlb_nslabs << IO_TLB_SHIFT); | |
166 | /* | 190 | /* |
167 | * Get IO TLB memory from any location. | 191 | * Get IO TLB memory from any location. |
168 | */ | 192 | */ |
169 | 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 | } | ||
170 | if (!xen_io_tlb_start) { | 211 | if (!xen_io_tlb_start) { |
171 | m = "Cannot allocate Xen-SWIOTLB buffer!\n"; | 212 | m_ret = XEN_SWIOTLB_ENOMEM; |
172 | goto error; | 213 | goto error; |
173 | } | 214 | } |
174 | xen_io_tlb_end = xen_io_tlb_start + bytes; | 215 | xen_io_tlb_end = xen_io_tlb_start + bytes; |
@@ -179,17 +220,22 @@ retry: | |||
179 | bytes, | 220 | bytes, |
180 | xen_io_tlb_nslabs); | 221 | xen_io_tlb_nslabs); |
181 | if (rc) { | 222 | if (rc) { |
182 | free_bootmem(__pa(xen_io_tlb_start), PAGE_ALIGN(bytes)); | 223 | if (early) |
183 | m = "Failed to get contiguous memory for DMA from Xen!\n"\ | 224 | free_bootmem(__pa(xen_io_tlb_start), PAGE_ALIGN(bytes)); |
184 | "You either: don't have the permissions, do not have"\ | 225 | else { |
185 | " enough free memory under 4GB, or the hypervisor memory"\ | 226 | free_pages((unsigned long)xen_io_tlb_start, order); |
186 | "is too fragmented!"; | 227 | xen_io_tlb_start = NULL; |
228 | } | ||
229 | m_ret = XEN_SWIOTLB_EFIXUP; | ||
187 | goto error; | 230 | goto error; |
188 | } | 231 | } |
189 | start_dma_addr = xen_virt_to_bus(xen_io_tlb_start); | 232 | start_dma_addr = xen_virt_to_bus(xen_io_tlb_start); |
190 | swiotlb_init_with_tbl(xen_io_tlb_start, xen_io_tlb_nslabs, verbose); | 233 | if (early) { |
191 | 234 | swiotlb_init_with_tbl(xen_io_tlb_start, xen_io_tlb_nslabs, verbose); | |
192 | return; | 235 | rc = 0; |
236 | } else | ||
237 | rc = swiotlb_late_init_with_tbl(xen_io_tlb_start, xen_io_tlb_nslabs); | ||
238 | return rc; | ||
193 | error: | 239 | error: |
194 | if (repeat--) { | 240 | if (repeat--) { |
195 | xen_io_tlb_nslabs = max(1024UL, /* Min is 2MB */ | 241 | xen_io_tlb_nslabs = max(1024UL, /* Min is 2MB */ |
@@ -198,10 +244,13 @@ error: | |||
198 | (xen_io_tlb_nslabs << IO_TLB_SHIFT) >> 20); | 244 | (xen_io_tlb_nslabs << IO_TLB_SHIFT) >> 20); |
199 | goto retry; | 245 | goto retry; |
200 | } | 246 | } |
201 | xen_raw_printk("%s (rc:%d)", m, rc); | 247 | pr_err("%s (rc:%d)", xen_swiotlb_error(m_ret), rc); |
202 | panic("%s (rc:%d)", m, rc); | 248 | if (early) |
249 | panic("%s (rc:%d)", xen_swiotlb_error(m_ret), rc); | ||
250 | else | ||
251 | free_pages((unsigned long)xen_io_tlb_start, order); | ||
252 | return rc; | ||
203 | } | 253 | } |
204 | |||
205 | void * | 254 | void * |
206 | xen_swiotlb_alloc_coherent(struct device *hwdev, size_t size, | 255 | xen_swiotlb_alloc_coherent(struct device *hwdev, size_t size, |
207 | dma_addr_t *dma_handle, gfp_t flags, | 256 | dma_addr_t *dma_handle, gfp_t flags, |
diff --git a/include/linux/swiotlb.h b/include/linux/swiotlb.h index e872526fdc5f..8d08b3ed406d 100644 --- a/include/linux/swiotlb.h +++ b/include/linux/swiotlb.h | |||
@@ -25,6 +25,7 @@ extern int swiotlb_force; | |||
25 | extern void swiotlb_init(int verbose); | 25 | extern void swiotlb_init(int verbose); |
26 | extern void swiotlb_init_with_tbl(char *tlb, unsigned long nslabs, int verbose); | 26 | extern void swiotlb_init_with_tbl(char *tlb, unsigned long nslabs, int verbose); |
27 | extern unsigned long swiotlb_nr_tbl(void); | 27 | extern unsigned long swiotlb_nr_tbl(void); |
28 | extern int swiotlb_late_init_with_tbl(char *tlb, unsigned long nslabs); | ||
28 | 29 | ||
29 | /* | 30 | /* |
30 | * Enumeration for sync targets | 31 | * Enumeration for sync targets |
diff --git a/include/xen/swiotlb-xen.h b/include/xen/swiotlb-xen.h index c050b6b9de38..de8bcc641c49 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, |
diff --git a/lib/swiotlb.c b/lib/swiotlb.c index 45bc1f83a5ad..f114bf6a8e13 100644 --- a/lib/swiotlb.c +++ b/lib/swiotlb.c | |||
@@ -170,7 +170,7 @@ void __init swiotlb_init_with_tbl(char *tlb, unsigned long nslabs, int verbose) | |||
170 | * Statically reserve bounce buffer space and initialize bounce buffer data | 170 | * Statically reserve bounce buffer space and initialize bounce buffer data |
171 | * structures for the software IO TLB used to implement the DMA API. | 171 | * structures for the software IO TLB used to implement the DMA API. |
172 | */ | 172 | */ |
173 | void __init | 173 | static void __init |
174 | swiotlb_init_with_default_size(size_t default_size, int verbose) | 174 | swiotlb_init_with_default_size(size_t default_size, int verbose) |
175 | { | 175 | { |
176 | unsigned long bytes; | 176 | unsigned long bytes; |
@@ -206,8 +206,9 @@ swiotlb_init(int verbose) | |||
206 | int | 206 | int |
207 | swiotlb_late_init_with_default_size(size_t default_size) | 207 | swiotlb_late_init_with_default_size(size_t default_size) |
208 | { | 208 | { |
209 | unsigned long i, bytes, req_nslabs = io_tlb_nslabs; | 209 | unsigned long bytes, req_nslabs = io_tlb_nslabs; |
210 | unsigned int order; | 210 | unsigned int order; |
211 | int rc = 0; | ||
211 | 212 | ||
212 | if (!io_tlb_nslabs) { | 213 | if (!io_tlb_nslabs) { |
213 | io_tlb_nslabs = (default_size >> IO_TLB_SHIFT); | 214 | io_tlb_nslabs = (default_size >> IO_TLB_SHIFT); |
@@ -229,16 +230,32 @@ swiotlb_late_init_with_default_size(size_t default_size) | |||
229 | order--; | 230 | order--; |
230 | } | 231 | } |
231 | 232 | ||
232 | if (!io_tlb_start) | 233 | if (!io_tlb_start) { |
233 | goto cleanup1; | 234 | io_tlb_nslabs = req_nslabs; |
234 | 235 | return -ENOMEM; | |
236 | } | ||
235 | if (order != get_order(bytes)) { | 237 | if (order != get_order(bytes)) { |
236 | printk(KERN_WARNING "Warning: only able to allocate %ld MB " | 238 | printk(KERN_WARNING "Warning: only able to allocate %ld MB " |
237 | "for software IO TLB\n", (PAGE_SIZE << order) >> 20); | 239 | "for software IO TLB\n", (PAGE_SIZE << order) >> 20); |
238 | io_tlb_nslabs = SLABS_PER_PAGE << order; | 240 | io_tlb_nslabs = SLABS_PER_PAGE << order; |
239 | bytes = io_tlb_nslabs << IO_TLB_SHIFT; | ||
240 | } | 241 | } |
242 | rc = swiotlb_late_init_with_tbl(io_tlb_start, io_tlb_nslabs); | ||
243 | if (rc) | ||
244 | free_pages((unsigned long)io_tlb_start, order); | ||
245 | return rc; | ||
246 | } | ||
247 | |||
248 | int | ||
249 | swiotlb_late_init_with_tbl(char *tlb, unsigned long nslabs) | ||
250 | { | ||
251 | unsigned long i, bytes; | ||
252 | |||
253 | bytes = nslabs << IO_TLB_SHIFT; | ||
254 | |||
255 | io_tlb_nslabs = nslabs; | ||
256 | io_tlb_start = tlb; | ||
241 | io_tlb_end = io_tlb_start + bytes; | 257 | io_tlb_end = io_tlb_start + bytes; |
258 | |||
242 | memset(io_tlb_start, 0, bytes); | 259 | memset(io_tlb_start, 0, bytes); |
243 | 260 | ||
244 | /* | 261 | /* |
@@ -288,10 +305,8 @@ cleanup3: | |||
288 | io_tlb_list = NULL; | 305 | io_tlb_list = NULL; |
289 | cleanup2: | 306 | cleanup2: |
290 | io_tlb_end = NULL; | 307 | io_tlb_end = NULL; |
291 | free_pages((unsigned long)io_tlb_start, order); | ||
292 | io_tlb_start = NULL; | 308 | io_tlb_start = NULL; |
293 | cleanup1: | 309 | io_tlb_nslabs = 0; |
294 | io_tlb_nslabs = req_nslabs; | ||
295 | return -ENOMEM; | 310 | return -ENOMEM; |
296 | } | 311 | } |
297 | 312 | ||