aboutsummaryrefslogtreecommitdiffstats
path: root/arch/ia64
diff options
context:
space:
mode:
authorAlex Williamson <alex.williamson@hp.com>2005-09-06 13:20:49 -0400
committerTony Luck <tony.luck@intel.com>2005-09-14 19:22:11 -0400
commit0b9afede3d9c66fef06f1d5ef5ff15c4b97730fc (patch)
tree95f55e1219eed9c3fd2458ddbf960307c631114e /arch/ia64
parent1619cca2921f6927f4240e03f413d4165c7002fc (diff)
[IA64] more robust zx1/sx1000 machvec support
Machine vector selection has always been a bit of a hack given how early in system boot it needs to be done. Services like ACPI namespace are not available and there are non-trivial problems to moving them to early boot. However, there's no reason we can't change to a different machvec later in boot when the services we need are available. By adding a entry point for later initialization of the swiotlb, we can add an error path for the hpzx1 machevec initialization and fall back to the DIG machine vector if IOMMU hardware isn't found in the system. Since ia64 uses 4GB for zone DMA (no ISA support), it's trivial to allocate a contiguous range from the slab for bounce buffer usage. Signed-off-by: Alex Williamson <alex.williamson@hp.com> Signed-off-by: Tony Luck <tony.luck@intel.com>
Diffstat (limited to 'arch/ia64')
-rw-r--r--arch/ia64/hp/common/hwsw_iommu.c13
-rw-r--r--arch/ia64/hp/common/sba_iommu.c45
-rw-r--r--arch/ia64/lib/swiotlb.c102
3 files changed, 145 insertions, 15 deletions
diff --git a/arch/ia64/hp/common/hwsw_iommu.c b/arch/ia64/hp/common/hwsw_iommu.c
index 80f8ef013939..317c334c5a18 100644
--- a/arch/ia64/hp/common/hwsw_iommu.c
+++ b/arch/ia64/hp/common/hwsw_iommu.c
@@ -17,7 +17,7 @@
17#include <asm/machvec.h> 17#include <asm/machvec.h>
18 18
19/* swiotlb declarations & definitions: */ 19/* swiotlb declarations & definitions: */
20extern void swiotlb_init_with_default_size (size_t size); 20extern int swiotlb_late_init_with_default_size (size_t size);
21extern ia64_mv_dma_alloc_coherent swiotlb_alloc_coherent; 21extern ia64_mv_dma_alloc_coherent swiotlb_alloc_coherent;
22extern ia64_mv_dma_free_coherent swiotlb_free_coherent; 22extern ia64_mv_dma_free_coherent swiotlb_free_coherent;
23extern ia64_mv_dma_map_single swiotlb_map_single; 23extern ia64_mv_dma_map_single swiotlb_map_single;
@@ -67,7 +67,16 @@ void
67hwsw_init (void) 67hwsw_init (void)
68{ 68{
69 /* default to a smallish 2MB sw I/O TLB */ 69 /* default to a smallish 2MB sw I/O TLB */
70 swiotlb_init_with_default_size (2 * (1<<20)); 70 if (swiotlb_late_init_with_default_size (2 * (1<<20)) != 0) {
71#ifdef CONFIG_IA64_GENERIC
72 /* Better to have normal DMA than panic */
73 printk(KERN_WARNING "%s: Failed to initialize software I/O TLB,"
74 " reverting to hpzx1 platform vector\n", __FUNCTION__);
75 machvec_init("hpzx1");
76#else
77 panic("Unable to initialize software I/O TLB services");
78#endif
79 }
71} 80}
72 81
73void * 82void *
diff --git a/arch/ia64/hp/common/sba_iommu.c b/arch/ia64/hp/common/sba_iommu.c
index 11957598a8b9..e64ca04ace89 100644
--- a/arch/ia64/hp/common/sba_iommu.c
+++ b/arch/ia64/hp/common/sba_iommu.c
@@ -2028,9 +2028,40 @@ static struct acpi_driver acpi_sba_ioc_driver = {
2028static int __init 2028static int __init
2029sba_init(void) 2029sba_init(void)
2030{ 2030{
2031 if (!ia64_platform_is("hpzx1") && !ia64_platform_is("hpzx1_swiotlb"))
2032 return 0;
2033
2031 acpi_bus_register_driver(&acpi_sba_ioc_driver); 2034 acpi_bus_register_driver(&acpi_sba_ioc_driver);
2032 if (!ioc_list) 2035 if (!ioc_list) {
2036#ifdef CONFIG_IA64_GENERIC
2037 extern int swiotlb_late_init_with_default_size (size_t size);
2038
2039 /*
2040 * If we didn't find something sba_iommu can claim, we
2041 * need to setup the swiotlb and switch to the dig machvec.
2042 */
2043 if (swiotlb_late_init_with_default_size(64 * (1<<20)) != 0)
2044 panic("Unable to find SBA IOMMU or initialize "
2045 "software I/O TLB: Try machvec=dig boot option");
2046 machvec_init("dig");
2047#else
2048 panic("Unable to find SBA IOMMU: Try a generic or DIG kernel");
2049#endif
2033 return 0; 2050 return 0;
2051 }
2052
2053#if defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_HP_ZX1_SWIOTLB)
2054 /*
2055 * hpzx1_swiotlb needs to have a fairly small swiotlb bounce
2056 * buffer setup to support devices with smaller DMA masks than
2057 * sba_iommu can handle.
2058 */
2059 if (ia64_platform_is("hpzx1_swiotlb")) {
2060 extern void hwsw_init(void);
2061
2062 hwsw_init();
2063 }
2064#endif
2034 2065
2035#ifdef CONFIG_PCI 2066#ifdef CONFIG_PCI
2036 { 2067 {
@@ -2048,18 +2079,6 @@ sba_init(void)
2048 2079
2049subsys_initcall(sba_init); /* must be initialized after ACPI etc., but before any drivers... */ 2080subsys_initcall(sba_init); /* must be initialized after ACPI etc., but before any drivers... */
2050 2081
2051extern void dig_setup(char**);
2052/*
2053 * MAX_DMA_ADDRESS needs to be setup prior to paging_init to do any good,
2054 * so we use the platform_setup hook to fix it up.
2055 */
2056void __init
2057sba_setup(char **cmdline_p)
2058{
2059 MAX_DMA_ADDRESS = ~0UL;
2060 dig_setup(cmdline_p);
2061}
2062
2063static int __init 2082static int __init
2064nosbagart(char *str) 2083nosbagart(char *str)
2065{ 2084{
diff --git a/arch/ia64/lib/swiotlb.c b/arch/ia64/lib/swiotlb.c
index dbc0b3e449c5..875b0c16250c 100644
--- a/arch/ia64/lib/swiotlb.c
+++ b/arch/ia64/lib/swiotlb.c
@@ -49,6 +49,15 @@
49 */ 49 */
50#define IO_TLB_SHIFT 11 50#define IO_TLB_SHIFT 11
51 51
52#define SLABS_PER_PAGE (1 << (PAGE_SHIFT - IO_TLB_SHIFT))
53
54/*
55 * Minimum IO TLB size to bother booting with. Systems with mainly
56 * 64bit capable cards will only lightly use the swiotlb. If we can't
57 * allocate a contiguous 1MB, we're probably in trouble anyway.
58 */
59#define IO_TLB_MIN_SLABS ((1<<20) >> IO_TLB_SHIFT)
60
52int swiotlb_force; 61int swiotlb_force;
53 62
54/* 63/*
@@ -154,6 +163,99 @@ swiotlb_init (void)
154 swiotlb_init_with_default_size(64 * (1<<20)); /* default to 64MB */ 163 swiotlb_init_with_default_size(64 * (1<<20)); /* default to 64MB */
155} 164}
156 165
166/*
167 * Systems with larger DMA zones (those that don't support ISA) can
168 * initialize the swiotlb later using the slab allocator if needed.
169 * This should be just like above, but with some error catching.
170 */
171int
172swiotlb_late_init_with_default_size (size_t default_size)
173{
174 unsigned long i, req_nslabs = io_tlb_nslabs;
175 unsigned int order;
176
177 if (!io_tlb_nslabs) {
178 io_tlb_nslabs = (default_size >> IO_TLB_SHIFT);
179 io_tlb_nslabs = ALIGN(io_tlb_nslabs, IO_TLB_SEGSIZE);
180 }
181
182 /*
183 * Get IO TLB memory from the low pages
184 */
185 order = get_order(io_tlb_nslabs * (1 << IO_TLB_SHIFT));
186 io_tlb_nslabs = SLABS_PER_PAGE << order;
187
188 while ((SLABS_PER_PAGE << order) > IO_TLB_MIN_SLABS) {
189 io_tlb_start = (char *)__get_free_pages(GFP_DMA | __GFP_NOWARN,
190 order);
191 if (io_tlb_start)
192 break;
193 order--;
194 }
195
196 if (!io_tlb_start)
197 goto cleanup1;
198
199 if (order != get_order(io_tlb_nslabs * (1 << IO_TLB_SHIFT))) {
200 printk(KERN_WARNING "Warning: only able to allocate %ld MB "
201 "for software IO TLB\n", (PAGE_SIZE << order) >> 20);
202 io_tlb_nslabs = SLABS_PER_PAGE << order;
203 }
204 io_tlb_end = io_tlb_start + io_tlb_nslabs * (1 << IO_TLB_SHIFT);
205 memset(io_tlb_start, 0, io_tlb_nslabs * (1 << IO_TLB_SHIFT));
206
207 /*
208 * Allocate and initialize the free list array. This array is used
209 * to find contiguous free memory regions of size up to IO_TLB_SEGSIZE
210 * between io_tlb_start and io_tlb_end.
211 */
212 io_tlb_list = (unsigned int *)__get_free_pages(GFP_KERNEL,
213 get_order(io_tlb_nslabs * sizeof(int)));
214 if (!io_tlb_list)
215 goto cleanup2;
216
217 for (i = 0; i < io_tlb_nslabs; i++)
218 io_tlb_list[i] = IO_TLB_SEGSIZE - OFFSET(i, IO_TLB_SEGSIZE);
219 io_tlb_index = 0;
220
221 io_tlb_orig_addr = (unsigned char **)__get_free_pages(GFP_KERNEL,
222 get_order(io_tlb_nslabs * sizeof(char *)));
223 if (!io_tlb_orig_addr)
224 goto cleanup3;
225
226 memset(io_tlb_orig_addr, 0, io_tlb_nslabs * sizeof(char *));
227
228 /*
229 * Get the overflow emergency buffer
230 */
231 io_tlb_overflow_buffer = (void *)__get_free_pages(GFP_DMA,
232 get_order(io_tlb_overflow));
233 if (!io_tlb_overflow_buffer)
234 goto cleanup4;
235
236 printk(KERN_INFO "Placing %ldMB software IO TLB between 0x%lx - "
237 "0x%lx\n", (io_tlb_nslabs * (1 << IO_TLB_SHIFT)) >> 20,
238 virt_to_phys(io_tlb_start), virt_to_phys(io_tlb_end));
239
240 return 0;
241
242cleanup4:
243 free_pages((unsigned long)io_tlb_orig_addr, get_order(io_tlb_nslabs *
244 sizeof(char *)));
245 io_tlb_orig_addr = NULL;
246cleanup3:
247 free_pages((unsigned long)io_tlb_list, get_order(io_tlb_nslabs *
248 sizeof(int)));
249 io_tlb_list = NULL;
250 io_tlb_end = NULL;
251cleanup2:
252 free_pages((unsigned long)io_tlb_start, order);
253 io_tlb_start = NULL;
254cleanup1:
255 io_tlb_nslabs = req_nslabs;
256 return -ENOMEM;
257}
258
157static inline int 259static inline int
158address_needs_mapping(struct device *hwdev, dma_addr_t addr) 260address_needs_mapping(struct device *hwdev, dma_addr_t addr)
159{ 261{