diff options
author | Mark Maule <maule@sgi.com> | 2005-04-25 14:26:03 -0400 |
---|---|---|
committer | Tony Luck <tony.luck@intel.com> | 2005-04-25 14:26:03 -0400 |
commit | e955d82543fea76b02aa243b182e782f71bda82c (patch) | |
tree | 58dc9df5161f47bca69c8dc9c819495f15694352 /arch/ia64/sn/pci | |
parent | 25ee7e3832951cf5896b194f6cd929a44863f419 (diff) |
[IA64-SGI] sn2-pci-dma-abstraction.patch
Provide an abstraction of the altix pci dma runtime layer so that multiple
pci-based bridges can be supported.
Signed-off-by: Mark Maule <maule@sgi.com>
Signed-off-by: Tony Luck <tony.luck@intel.com>
Diffstat (limited to 'arch/ia64/sn/pci')
-rw-r--r-- | arch/ia64/sn/pci/pci_dma.c | 35 | ||||
-rw-r--r-- | arch/ia64/sn/pci/pcibr/pcibr_dma.c | 103 | ||||
-rw-r--r-- | arch/ia64/sn/pci/pcibr/pcibr_provider.c | 20 |
3 files changed, 91 insertions, 67 deletions
diff --git a/arch/ia64/sn/pci/pci_dma.c b/arch/ia64/sn/pci/pci_dma.c index f680824f819d..c2b92b94c563 100644 --- a/arch/ia64/sn/pci/pci_dma.c +++ b/arch/ia64/sn/pci/pci_dma.c | |||
@@ -14,7 +14,6 @@ | |||
14 | #include <asm/sn/sn_sal.h> | 14 | #include <asm/sn/sn_sal.h> |
15 | #include "pci/pcibus_provider_defs.h" | 15 | #include "pci/pcibus_provider_defs.h" |
16 | #include "pci/pcidev.h" | 16 | #include "pci/pcidev.h" |
17 | #include "pci/pcibr_provider.h" | ||
18 | 17 | ||
19 | #define SG_ENT_VIRT_ADDRESS(sg) (page_address((sg)->page) + (sg)->offset) | 18 | #define SG_ENT_VIRT_ADDRESS(sg) (page_address((sg)->page) + (sg)->offset) |
20 | #define SG_ENT_PHYS_ADDRESS(SG) virt_to_phys(SG_ENT_VIRT_ADDRESS(SG)) | 19 | #define SG_ENT_PHYS_ADDRESS(SG) virt_to_phys(SG_ENT_VIRT_ADDRESS(SG)) |
@@ -79,7 +78,8 @@ void *sn_dma_alloc_coherent(struct device *dev, size_t size, | |||
79 | { | 78 | { |
80 | void *cpuaddr; | 79 | void *cpuaddr; |
81 | unsigned long phys_addr; | 80 | unsigned long phys_addr; |
82 | struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(to_pci_dev(dev)); | 81 | struct pci_dev *pdev = to_pci_dev(dev); |
82 | struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev); | ||
83 | 83 | ||
84 | BUG_ON(dev->bus != &pci_bus_type); | 84 | BUG_ON(dev->bus != &pci_bus_type); |
85 | 85 | ||
@@ -102,8 +102,7 @@ void *sn_dma_alloc_coherent(struct device *dev, size_t size, | |||
102 | * resources. | 102 | * resources. |
103 | */ | 103 | */ |
104 | 104 | ||
105 | *dma_handle = pcibr_dma_map(pcidev_info, phys_addr, size, | 105 | *dma_handle = provider->dma_map_consistent(pdev, phys_addr, size); |
106 | SN_PCIDMA_CONSISTENT); | ||
107 | if (!*dma_handle) { | 106 | if (!*dma_handle) { |
108 | printk(KERN_ERR "%s: out of ATEs\n", __FUNCTION__); | 107 | printk(KERN_ERR "%s: out of ATEs\n", __FUNCTION__); |
109 | free_pages((unsigned long)cpuaddr, get_order(size)); | 108 | free_pages((unsigned long)cpuaddr, get_order(size)); |
@@ -127,11 +126,12 @@ EXPORT_SYMBOL(sn_dma_alloc_coherent); | |||
127 | void sn_dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, | 126 | void sn_dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, |
128 | dma_addr_t dma_handle) | 127 | dma_addr_t dma_handle) |
129 | { | 128 | { |
130 | struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(to_pci_dev(dev)); | 129 | struct pci_dev *pdev = to_pci_dev(dev); |
130 | struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev); | ||
131 | 131 | ||
132 | BUG_ON(dev->bus != &pci_bus_type); | 132 | BUG_ON(dev->bus != &pci_bus_type); |
133 | 133 | ||
134 | pcibr_dma_unmap(pcidev_info, dma_handle, 0); | 134 | provider->dma_unmap(pdev, dma_handle, 0); |
135 | free_pages((unsigned long)cpu_addr, get_order(size)); | 135 | free_pages((unsigned long)cpu_addr, get_order(size)); |
136 | } | 136 | } |
137 | EXPORT_SYMBOL(sn_dma_free_coherent); | 137 | EXPORT_SYMBOL(sn_dma_free_coherent); |
@@ -159,12 +159,13 @@ dma_addr_t sn_dma_map_single(struct device *dev, void *cpu_addr, size_t size, | |||
159 | { | 159 | { |
160 | dma_addr_t dma_addr; | 160 | dma_addr_t dma_addr; |
161 | unsigned long phys_addr; | 161 | unsigned long phys_addr; |
162 | struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(to_pci_dev(dev)); | 162 | struct pci_dev *pdev = to_pci_dev(dev); |
163 | struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev); | ||
163 | 164 | ||
164 | BUG_ON(dev->bus != &pci_bus_type); | 165 | BUG_ON(dev->bus != &pci_bus_type); |
165 | 166 | ||
166 | phys_addr = __pa(cpu_addr); | 167 | phys_addr = __pa(cpu_addr); |
167 | dma_addr = pcibr_dma_map(pcidev_info, phys_addr, size, 0); | 168 | dma_addr = provider->dma_map(pdev, phys_addr, size); |
168 | if (!dma_addr) { | 169 | if (!dma_addr) { |
169 | printk(KERN_ERR "%s: out of ATEs\n", __FUNCTION__); | 170 | printk(KERN_ERR "%s: out of ATEs\n", __FUNCTION__); |
170 | return 0; | 171 | return 0; |
@@ -187,10 +188,12 @@ EXPORT_SYMBOL(sn_dma_map_single); | |||
187 | void sn_dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, | 188 | void sn_dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, |
188 | int direction) | 189 | int direction) |
189 | { | 190 | { |
190 | struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(to_pci_dev(dev)); | 191 | struct pci_dev *pdev = to_pci_dev(dev); |
192 | struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev); | ||
191 | 193 | ||
192 | BUG_ON(dev->bus != &pci_bus_type); | 194 | BUG_ON(dev->bus != &pci_bus_type); |
193 | pcibr_dma_unmap(pcidev_info, dma_addr, direction); | 195 | |
196 | provider->dma_unmap(pdev, dma_addr, direction); | ||
194 | } | 197 | } |
195 | EXPORT_SYMBOL(sn_dma_unmap_single); | 198 | EXPORT_SYMBOL(sn_dma_unmap_single); |
196 | 199 | ||
@@ -207,12 +210,13 @@ void sn_dma_unmap_sg(struct device *dev, struct scatterlist *sg, | |||
207 | int nhwentries, int direction) | 210 | int nhwentries, int direction) |
208 | { | 211 | { |
209 | int i; | 212 | int i; |
210 | struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(to_pci_dev(dev)); | 213 | struct pci_dev *pdev = to_pci_dev(dev); |
214 | struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev); | ||
211 | 215 | ||
212 | BUG_ON(dev->bus != &pci_bus_type); | 216 | BUG_ON(dev->bus != &pci_bus_type); |
213 | 217 | ||
214 | for (i = 0; i < nhwentries; i++, sg++) { | 218 | for (i = 0; i < nhwentries; i++, sg++) { |
215 | pcibr_dma_unmap(pcidev_info, sg->dma_address, direction); | 219 | provider->dma_unmap(pdev, sg->dma_address, direction); |
216 | sg->dma_address = (dma_addr_t) NULL; | 220 | sg->dma_address = (dma_addr_t) NULL; |
217 | sg->dma_length = 0; | 221 | sg->dma_length = 0; |
218 | } | 222 | } |
@@ -233,7 +237,8 @@ int sn_dma_map_sg(struct device *dev, struct scatterlist *sg, int nhwentries, | |||
233 | { | 237 | { |
234 | unsigned long phys_addr; | 238 | unsigned long phys_addr; |
235 | struct scatterlist *saved_sg = sg; | 239 | struct scatterlist *saved_sg = sg; |
236 | struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(to_pci_dev(dev)); | 240 | struct pci_dev *pdev = to_pci_dev(dev); |
241 | struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev); | ||
237 | int i; | 242 | int i; |
238 | 243 | ||
239 | BUG_ON(dev->bus != &pci_bus_type); | 244 | BUG_ON(dev->bus != &pci_bus_type); |
@@ -243,8 +248,8 @@ int sn_dma_map_sg(struct device *dev, struct scatterlist *sg, int nhwentries, | |||
243 | */ | 248 | */ |
244 | for (i = 0; i < nhwentries; i++, sg++) { | 249 | for (i = 0; i < nhwentries; i++, sg++) { |
245 | phys_addr = SG_ENT_PHYS_ADDRESS(sg); | 250 | phys_addr = SG_ENT_PHYS_ADDRESS(sg); |
246 | sg->dma_address = pcibr_dma_map(pcidev_info, phys_addr, | 251 | sg->dma_address = provider->dma_map(pdev, |
247 | sg->length, 0); | 252 | phys_addr, sg->length); |
248 | 253 | ||
249 | if (!sg->dma_address) { | 254 | if (!sg->dma_address) { |
250 | printk(KERN_ERR "%s: out of ATEs\n", __FUNCTION__); | 255 | printk(KERN_ERR "%s: out of ATEs\n", __FUNCTION__); |
diff --git a/arch/ia64/sn/pci/pcibr/pcibr_dma.c b/arch/ia64/sn/pci/pcibr/pcibr_dma.c index b1d66ac065c8..3c305f46417f 100644 --- a/arch/ia64/sn/pci/pcibr/pcibr_dma.c +++ b/arch/ia64/sn/pci/pcibr/pcibr_dma.c | |||
@@ -40,7 +40,7 @@ extern int sn_ioif_inited; | |||
40 | * we do not have to allocate entries in the PMU. | 40 | * we do not have to allocate entries in the PMU. |
41 | */ | 41 | */ |
42 | 42 | ||
43 | static uint64_t | 43 | static dma_addr_t |
44 | pcibr_dmamap_ate32(struct pcidev_info *info, | 44 | pcibr_dmamap_ate32(struct pcidev_info *info, |
45 | uint64_t paddr, size_t req_size, uint64_t flags) | 45 | uint64_t paddr, size_t req_size, uint64_t flags) |
46 | { | 46 | { |
@@ -109,7 +109,7 @@ pcibr_dmamap_ate32(struct pcidev_info *info, | |||
109 | return pci_addr; | 109 | return pci_addr; |
110 | } | 110 | } |
111 | 111 | ||
112 | static uint64_t | 112 | static dma_addr_t |
113 | pcibr_dmatrans_direct64(struct pcidev_info * info, uint64_t paddr, | 113 | pcibr_dmatrans_direct64(struct pcidev_info * info, uint64_t paddr, |
114 | uint64_t dma_attributes) | 114 | uint64_t dma_attributes) |
115 | { | 115 | { |
@@ -141,7 +141,7 @@ pcibr_dmatrans_direct64(struct pcidev_info * info, uint64_t paddr, | |||
141 | 141 | ||
142 | } | 142 | } |
143 | 143 | ||
144 | static uint64_t | 144 | static dma_addr_t |
145 | pcibr_dmatrans_direct32(struct pcidev_info * info, | 145 | pcibr_dmatrans_direct32(struct pcidev_info * info, |
146 | uint64_t paddr, size_t req_size, uint64_t flags) | 146 | uint64_t paddr, size_t req_size, uint64_t flags) |
147 | { | 147 | { |
@@ -180,11 +180,11 @@ pcibr_dmatrans_direct32(struct pcidev_info * info, | |||
180 | * DMA mappings for Direct 64 and 32 do not have any DMA maps. | 180 | * DMA mappings for Direct 64 and 32 do not have any DMA maps. |
181 | */ | 181 | */ |
182 | void | 182 | void |
183 | pcibr_dma_unmap(struct pcidev_info *pcidev_info, dma_addr_t dma_handle, | 183 | pcibr_dma_unmap(struct pci_dev *hwdev, dma_addr_t dma_handle, int direction) |
184 | int direction) | ||
185 | { | 184 | { |
186 | struct pcibus_info *pcibus_info = (struct pcibus_info *)pcidev_info-> | 185 | struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(hwdev); |
187 | pdi_pcibus_info; | 186 | struct pcibus_info *pcibus_info = |
187 | (struct pcibus_info *)pcidev_info->pdi_pcibus_info; | ||
188 | 188 | ||
189 | if (IS_PCI32_MAPPED(dma_handle)) { | 189 | if (IS_PCI32_MAPPED(dma_handle)) { |
190 | int ate_index; | 190 | int ate_index; |
@@ -316,64 +316,63 @@ void sn_dma_flush(uint64_t addr) | |||
316 | } | 316 | } |
317 | 317 | ||
318 | /* | 318 | /* |
319 | * Wrapper DMA interface. Called from pci_dma.c routines. | 319 | * DMA interfaces. Called from pci_dma.c routines. |
320 | */ | 320 | */ |
321 | 321 | ||
322 | uint64_t | 322 | dma_addr_t |
323 | pcibr_dma_map(struct pcidev_info * pcidev_info, unsigned long phys_addr, | 323 | pcibr_dma_map(struct pci_dev * hwdev, unsigned long phys_addr, size_t size) |
324 | size_t size, unsigned int flags) | ||
325 | { | 324 | { |
326 | dma_addr_t dma_handle; | 325 | dma_addr_t dma_handle; |
327 | struct pci_dev *pcidev = pcidev_info->pdi_linux_pcidev; | 326 | struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(hwdev); |
328 | |||
329 | if (flags & SN_PCIDMA_CONSISTENT) { | ||
330 | /* sn_pci_alloc_consistent interfaces */ | ||
331 | if (pcidev->dev.coherent_dma_mask == ~0UL) { | ||
332 | dma_handle = | ||
333 | pcibr_dmatrans_direct64(pcidev_info, phys_addr, | ||
334 | PCI64_ATTR_BAR); | ||
335 | } else { | ||
336 | dma_handle = | ||
337 | (dma_addr_t) pcibr_dmamap_ate32(pcidev_info, | ||
338 | phys_addr, size, | ||
339 | PCI32_ATE_BAR); | ||
340 | } | ||
341 | } else { | ||
342 | /* map_sg/map_single interfaces */ | ||
343 | 327 | ||
344 | /* SN cannot support DMA addresses smaller than 32 bits. */ | 328 | /* SN cannot support DMA addresses smaller than 32 bits. */ |
345 | if (pcidev->dma_mask < 0x7fffffff) { | 329 | if (hwdev->dma_mask < 0x7fffffff) { |
346 | return 0; | 330 | return 0; |
347 | } | 331 | } |
348 | 332 | ||
349 | if (pcidev->dma_mask == ~0UL) { | 333 | if (hwdev->dma_mask == ~0UL) { |
334 | /* | ||
335 | * Handle the most common case: 64 bit cards. This | ||
336 | * call should always succeed. | ||
337 | */ | ||
338 | |||
339 | dma_handle = pcibr_dmatrans_direct64(pcidev_info, phys_addr, | ||
340 | PCI64_ATTR_PREF); | ||
341 | } else { | ||
342 | /* Handle 32-63 bit cards via direct mapping */ | ||
343 | dma_handle = pcibr_dmatrans_direct32(pcidev_info, phys_addr, | ||
344 | size, 0); | ||
345 | if (!dma_handle) { | ||
350 | /* | 346 | /* |
351 | * Handle the most common case: 64 bit cards. This | 347 | * It is a 32 bit card and we cannot do direct mapping, |
352 | * call should always succeed. | 348 | * so we use an ATE. |
353 | */ | 349 | */ |
354 | 350 | ||
355 | dma_handle = | 351 | dma_handle = pcibr_dmamap_ate32(pcidev_info, phys_addr, |
356 | pcibr_dmatrans_direct64(pcidev_info, phys_addr, | 352 | size, PCI32_ATE_PREF); |
357 | PCI64_ATTR_PREF); | ||
358 | } else { | ||
359 | /* Handle 32-63 bit cards via direct mapping */ | ||
360 | dma_handle = | ||
361 | pcibr_dmatrans_direct32(pcidev_info, phys_addr, | ||
362 | size, 0); | ||
363 | if (!dma_handle) { | ||
364 | /* | ||
365 | * It is a 32 bit card and we cannot do direct mapping, | ||
366 | * so we use an ATE. | ||
367 | */ | ||
368 | |||
369 | dma_handle = | ||
370 | pcibr_dmamap_ate32(pcidev_info, phys_addr, | ||
371 | size, PCI32_ATE_PREF); | ||
372 | } | ||
373 | } | 353 | } |
374 | } | 354 | } |
375 | 355 | ||
376 | return dma_handle; | 356 | return dma_handle; |
377 | } | 357 | } |
378 | 358 | ||
359 | dma_addr_t | ||
360 | pcibr_dma_map_consistent(struct pci_dev * hwdev, unsigned long phys_addr, | ||
361 | size_t size) | ||
362 | { | ||
363 | dma_addr_t dma_handle; | ||
364 | struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(hwdev); | ||
365 | |||
366 | if (hwdev->dev.coherent_dma_mask == ~0UL) { | ||
367 | dma_handle = pcibr_dmatrans_direct64(pcidev_info, phys_addr, | ||
368 | PCI64_ATTR_BAR); | ||
369 | } else { | ||
370 | dma_handle = (dma_addr_t) pcibr_dmamap_ate32(pcidev_info, | ||
371 | phys_addr, size, | ||
372 | PCI32_ATE_BAR); | ||
373 | } | ||
374 | |||
375 | return dma_handle; | ||
376 | } | ||
377 | |||
379 | EXPORT_SYMBOL(sn_dma_flush); | 378 | EXPORT_SYMBOL(sn_dma_flush); |
diff --git a/arch/ia64/sn/pci/pcibr/pcibr_provider.c b/arch/ia64/sn/pci/pcibr/pcibr_provider.c index 92bd278cf7ff..539ab1fdab21 100644 --- a/arch/ia64/sn/pci/pcibr/pcibr_provider.c +++ b/arch/ia64/sn/pci/pcibr/pcibr_provider.c | |||
@@ -168,3 +168,23 @@ void pcibr_change_devices_irq(struct sn_irq_info *sn_irq_info) | |||
168 | pcibr_force_interrupt(sn_irq_info); | 168 | pcibr_force_interrupt(sn_irq_info); |
169 | } | 169 | } |
170 | } | 170 | } |
171 | |||
172 | /* | ||
173 | * Provider entries for PIC/CP | ||
174 | */ | ||
175 | |||
176 | struct sn_pcibus_provider pcibr_provider = { | ||
177 | .dma_map = pcibr_dma_map, | ||
178 | .dma_map_consistent = pcibr_dma_map_consistent, | ||
179 | .dma_unmap = pcibr_dma_unmap, | ||
180 | .bus_fixup = pcibr_bus_fixup, | ||
181 | }; | ||
182 | |||
183 | int | ||
184 | pcibr_init_provider(void) | ||
185 | { | ||
186 | sn_pci_provider[PCIIO_ASIC_TYPE_PIC] = &pcibr_provider; | ||
187 | sn_pci_provider[PCIIO_ASIC_TYPE_TIOCP] = &pcibr_provider; | ||
188 | |||
189 | return 0; | ||
190 | } | ||