aboutsummaryrefslogtreecommitdiffstats
path: root/arch/ia64
diff options
context:
space:
mode:
authorTony Luck <tony.luck@intel.com>2008-10-17 16:52:22 -0400
committerTony Luck <tony.luck@intel.com>2008-10-17 16:52:22 -0400
commitfe393164c529f72def1952fb66c11732d0984d78 (patch)
tree56e4425988e90cb9608e95844f577cd18009618c /arch/ia64
parent22ca532a4d137545244fdff0b687325fd4e13eae (diff)
parent62fdd7678a26efadd6ac5c2869543caff77d2df0 (diff)
Pull vtd-iommu into release branch
Conflicts: arch/ia64/kernel/acpi.c
Diffstat (limited to 'arch/ia64')
-rw-r--r--arch/ia64/Kconfig17
-rw-r--r--arch/ia64/Makefile1
-rw-r--r--arch/ia64/configs/generic_defconfig2
-rw-r--r--arch/ia64/configs/tiger_defconfig2
-rw-r--r--arch/ia64/dig/Makefile5
-rw-r--r--arch/ia64/dig/dig_vtd_iommu.c59
-rw-r--r--arch/ia64/dig/machvec_vtd.c3
-rw-r--r--arch/ia64/include/asm/cacheflush.h2
-rw-r--r--arch/ia64/include/asm/device.h3
-rw-r--r--arch/ia64/include/asm/dma-mapping.h50
-rw-r--r--arch/ia64/include/asm/iommu.h16
-rw-r--r--arch/ia64/include/asm/machvec.h2
-rw-r--r--arch/ia64/include/asm/machvec_dig_vtd.h38
-rw-r--r--arch/ia64/include/asm/machvec_init.h1
-rw-r--r--arch/ia64/include/asm/pci.h3
-rw-r--r--arch/ia64/include/asm/swiotlb.h56
-rw-r--r--arch/ia64/kernel/Makefile4
-rw-r--r--arch/ia64/kernel/acpi.c17
-rw-r--r--arch/ia64/kernel/msi_ia64.c80
-rw-r--r--arch/ia64/kernel/pci-dma.c129
-rw-r--r--arch/ia64/kernel/pci-swiotlb.c46
-rw-r--r--arch/ia64/kernel/setup.c42
-rw-r--r--arch/ia64/lib/flush.S55
23 files changed, 620 insertions, 13 deletions
diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig
index 239ad6b1c74f..6200a40ff50d 100644
--- a/arch/ia64/Kconfig
+++ b/arch/ia64/Kconfig
@@ -145,6 +145,7 @@ config IA64_GENERIC
145 select NUMA 145 select NUMA
146 select ACPI_NUMA 146 select ACPI_NUMA
147 select SWIOTLB 147 select SWIOTLB
148 select PCI_MSI
148 help 149 help
149 This selects the system type of your hardware. A "generic" kernel 150 This selects the system type of your hardware. A "generic" kernel
150 will run on any supported IA-64 system. However, if you configure 151 will run on any supported IA-64 system. However, if you configure
@@ -152,6 +153,7 @@ config IA64_GENERIC
152 153
153 generic For any supported IA-64 system 154 generic For any supported IA-64 system
154 DIG-compliant For DIG ("Developer's Interface Guide") compliant systems 155 DIG-compliant For DIG ("Developer's Interface Guide") compliant systems
156 DIG+Intel+IOMMU For DIG systems with Intel IOMMU
155 HP-zx1/sx1000 For HP systems 157 HP-zx1/sx1000 For HP systems
156 HP-zx1/sx1000+swiotlb For HP systems with (broken) DMA-constrained devices. 158 HP-zx1/sx1000+swiotlb For HP systems with (broken) DMA-constrained devices.
157 SGI-SN2 For SGI Altix systems 159 SGI-SN2 For SGI Altix systems
@@ -165,6 +167,11 @@ config IA64_DIG
165 bool "DIG-compliant" 167 bool "DIG-compliant"
166 select SWIOTLB 168 select SWIOTLB
167 169
170config IA64_DIG_VTD
171 bool "DIG+Intel+IOMMU"
172 select DMAR
173 select PCI_MSI
174
168config IA64_HP_ZX1 175config IA64_HP_ZX1
169 bool "HP-zx1/sx1000" 176 bool "HP-zx1/sx1000"
170 help 177 help
@@ -614,6 +621,16 @@ source "drivers/pci/hotplug/Kconfig"
614 621
615source "drivers/pcmcia/Kconfig" 622source "drivers/pcmcia/Kconfig"
616 623
624config DMAR
625 bool "Support for DMA Remapping Devices (EXPERIMENTAL)"
626 depends on IA64_GENERIC && ACPI && EXPERIMENTAL
627 help
628 DMA remapping (DMAR) devices support enables independent address
629 translations for Direct Memory Access (DMA) from devices.
630 These DMA remapping devices are reported via ACPI tables
631 and include PCI device scope covered by these DMA
632 remapping devices.
633
617endmenu 634endmenu
618 635
619endif 636endif
diff --git a/arch/ia64/Makefile b/arch/ia64/Makefile
index 40242501bcdd..58a7e46affda 100644
--- a/arch/ia64/Makefile
+++ b/arch/ia64/Makefile
@@ -53,6 +53,7 @@ libs-y += arch/ia64/lib/
53core-y += arch/ia64/kernel/ arch/ia64/mm/ 53core-y += arch/ia64/kernel/ arch/ia64/mm/
54core-$(CONFIG_IA32_SUPPORT) += arch/ia64/ia32/ 54core-$(CONFIG_IA32_SUPPORT) += arch/ia64/ia32/
55core-$(CONFIG_IA64_DIG) += arch/ia64/dig/ 55core-$(CONFIG_IA64_DIG) += arch/ia64/dig/
56core-$(CONFIG_IA64_DIG_VTD) += arch/ia64/dig/
56core-$(CONFIG_IA64_GENERIC) += arch/ia64/dig/ 57core-$(CONFIG_IA64_GENERIC) += arch/ia64/dig/
57core-$(CONFIG_IA64_HP_ZX1) += arch/ia64/dig/ 58core-$(CONFIG_IA64_HP_ZX1) += arch/ia64/dig/
58core-$(CONFIG_IA64_HP_ZX1_SWIOTLB) += arch/ia64/dig/ 59core-$(CONFIG_IA64_HP_ZX1_SWIOTLB) += arch/ia64/dig/
diff --git a/arch/ia64/configs/generic_defconfig b/arch/ia64/configs/generic_defconfig
index 9f483976228f..e05f9e1d3faa 100644
--- a/arch/ia64/configs/generic_defconfig
+++ b/arch/ia64/configs/generic_defconfig
@@ -233,6 +233,8 @@ CONFIG_DMIID=y
233CONFIG_BINFMT_ELF=y 233CONFIG_BINFMT_ELF=y
234CONFIG_BINFMT_MISC=m 234CONFIG_BINFMT_MISC=m
235 235
236# CONFIG_DMAR is not set
237
236# 238#
237# Power management and ACPI 239# Power management and ACPI
238# 240#
diff --git a/arch/ia64/configs/tiger_defconfig b/arch/ia64/configs/tiger_defconfig
index 797acf9066c1..c522edf23c62 100644
--- a/arch/ia64/configs/tiger_defconfig
+++ b/arch/ia64/configs/tiger_defconfig
@@ -172,6 +172,8 @@ CONFIG_DMIID=y
172CONFIG_BINFMT_ELF=y 172CONFIG_BINFMT_ELF=y
173CONFIG_BINFMT_MISC=m 173CONFIG_BINFMT_MISC=m
174 174
175# CONFIG_DMAR is not set
176
175# 177#
176# Power management and ACPI 178# Power management and ACPI
177# 179#
diff --git a/arch/ia64/dig/Makefile b/arch/ia64/dig/Makefile
index 971cd7870dd4..5c0283830bd6 100644
--- a/arch/ia64/dig/Makefile
+++ b/arch/ia64/dig/Makefile
@@ -6,4 +6,9 @@
6# 6#
7 7
8obj-y := setup.o 8obj-y := setup.o
9ifeq ($(CONFIG_DMAR), y)
10obj-$(CONFIG_IA64_GENERIC) += machvec.o machvec_vtd.o dig_vtd_iommu.o
11else
9obj-$(CONFIG_IA64_GENERIC) += machvec.o 12obj-$(CONFIG_IA64_GENERIC) += machvec.o
13endif
14obj-$(CONFIG_IA64_DIG_VTD) += dig_vtd_iommu.o
diff --git a/arch/ia64/dig/dig_vtd_iommu.c b/arch/ia64/dig/dig_vtd_iommu.c
new file mode 100644
index 000000000000..1c8a079017a3
--- /dev/null
+++ b/arch/ia64/dig/dig_vtd_iommu.c
@@ -0,0 +1,59 @@
1#include <linux/types.h>
2#include <linux/kernel.h>
3#include <linux/module.h>
4#include <linux/intel-iommu.h>
5
6void *
7vtd_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
8 gfp_t flags)
9{
10 return intel_alloc_coherent(dev, size, dma_handle, flags);
11}
12EXPORT_SYMBOL_GPL(vtd_alloc_coherent);
13
14void
15vtd_free_coherent(struct device *dev, size_t size, void *vaddr,
16 dma_addr_t dma_handle)
17{
18 intel_free_coherent(dev, size, vaddr, dma_handle);
19}
20EXPORT_SYMBOL_GPL(vtd_free_coherent);
21
22dma_addr_t
23vtd_map_single_attrs(struct device *dev, void *addr, size_t size,
24 int dir, struct dma_attrs *attrs)
25{
26 return intel_map_single(dev, (phys_addr_t)addr, size, dir);
27}
28EXPORT_SYMBOL_GPL(vtd_map_single_attrs);
29
30void
31vtd_unmap_single_attrs(struct device *dev, dma_addr_t iova, size_t size,
32 int dir, struct dma_attrs *attrs)
33{
34 intel_unmap_single(dev, iova, size, dir);
35}
36EXPORT_SYMBOL_GPL(vtd_unmap_single_attrs);
37
38int
39vtd_map_sg_attrs(struct device *dev, struct scatterlist *sglist, int nents,
40 int dir, struct dma_attrs *attrs)
41{
42 return intel_map_sg(dev, sglist, nents, dir);
43}
44EXPORT_SYMBOL_GPL(vtd_map_sg_attrs);
45
46void
47vtd_unmap_sg_attrs(struct device *dev, struct scatterlist *sglist,
48 int nents, int dir, struct dma_attrs *attrs)
49{
50 intel_unmap_sg(dev, sglist, nents, dir);
51}
52EXPORT_SYMBOL_GPL(vtd_unmap_sg_attrs);
53
54int
55vtd_dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
56{
57 return 0;
58}
59EXPORT_SYMBOL_GPL(vtd_dma_mapping_error);
diff --git a/arch/ia64/dig/machvec_vtd.c b/arch/ia64/dig/machvec_vtd.c
new file mode 100644
index 000000000000..7cd3eb471cad
--- /dev/null
+++ b/arch/ia64/dig/machvec_vtd.c
@@ -0,0 +1,3 @@
1#define MACHVEC_PLATFORM_NAME dig_vtd
2#define MACHVEC_PLATFORM_HEADER <asm/machvec_dig_vtd.h>
3#include <asm/machvec_init.h>
diff --git a/arch/ia64/include/asm/cacheflush.h b/arch/ia64/include/asm/cacheflush.h
index afcfbda76e20..c8ce2719fee8 100644
--- a/arch/ia64/include/asm/cacheflush.h
+++ b/arch/ia64/include/asm/cacheflush.h
@@ -34,6 +34,8 @@ do { \
34#define flush_dcache_mmap_unlock(mapping) do { } while (0) 34#define flush_dcache_mmap_unlock(mapping) do { } while (0)
35 35
36extern void flush_icache_range (unsigned long start, unsigned long end); 36extern void flush_icache_range (unsigned long start, unsigned long end);
37extern void clflush_cache_range(void *addr, int size);
38
37 39
38#define flush_icache_user_range(vma, page, user_addr, len) \ 40#define flush_icache_user_range(vma, page, user_addr, len) \
39do { \ 41do { \
diff --git a/arch/ia64/include/asm/device.h b/arch/ia64/include/asm/device.h
index 3db6daf7f251..41ab85d66f33 100644
--- a/arch/ia64/include/asm/device.h
+++ b/arch/ia64/include/asm/device.h
@@ -10,6 +10,9 @@ struct dev_archdata {
10#ifdef CONFIG_ACPI 10#ifdef CONFIG_ACPI
11 void *acpi_handle; 11 void *acpi_handle;
12#endif 12#endif
13#ifdef CONFIG_DMAR
14 void *iommu; /* hook for IOMMU specific extension */
15#endif
13}; 16};
14 17
15#endif /* _ASM_IA64_DEVICE_H */ 18#endif /* _ASM_IA64_DEVICE_H */
diff --git a/arch/ia64/include/asm/dma-mapping.h b/arch/ia64/include/asm/dma-mapping.h
index 06ff1ba21465..bbab7e2b0fc9 100644
--- a/arch/ia64/include/asm/dma-mapping.h
+++ b/arch/ia64/include/asm/dma-mapping.h
@@ -7,6 +7,49 @@
7 */ 7 */
8#include <asm/machvec.h> 8#include <asm/machvec.h>
9#include <linux/scatterlist.h> 9#include <linux/scatterlist.h>
10#include <asm/swiotlb.h>
11
12struct dma_mapping_ops {
13 int (*mapping_error)(struct device *dev,
14 dma_addr_t dma_addr);
15 void* (*alloc_coherent)(struct device *dev, size_t size,
16 dma_addr_t *dma_handle, gfp_t gfp);
17 void (*free_coherent)(struct device *dev, size_t size,
18 void *vaddr, dma_addr_t dma_handle);
19 dma_addr_t (*map_single)(struct device *hwdev, unsigned long ptr,
20 size_t size, int direction);
21 void (*unmap_single)(struct device *dev, dma_addr_t addr,
22 size_t size, int direction);
23 void (*sync_single_for_cpu)(struct device *hwdev,
24 dma_addr_t dma_handle, size_t size,
25 int direction);
26 void (*sync_single_for_device)(struct device *hwdev,
27 dma_addr_t dma_handle, size_t size,
28 int direction);
29 void (*sync_single_range_for_cpu)(struct device *hwdev,
30 dma_addr_t dma_handle, unsigned long offset,
31 size_t size, int direction);
32 void (*sync_single_range_for_device)(struct device *hwdev,
33 dma_addr_t dma_handle, unsigned long offset,
34 size_t size, int direction);
35 void (*sync_sg_for_cpu)(struct device *hwdev,
36 struct scatterlist *sg, int nelems,
37 int direction);
38 void (*sync_sg_for_device)(struct device *hwdev,
39 struct scatterlist *sg, int nelems,
40 int direction);
41 int (*map_sg)(struct device *hwdev, struct scatterlist *sg,
42 int nents, int direction);
43 void (*unmap_sg)(struct device *hwdev,
44 struct scatterlist *sg, int nents,
45 int direction);
46 int (*dma_supported_op)(struct device *hwdev, u64 mask);
47 int is_phys;
48};
49
50extern struct dma_mapping_ops *dma_ops;
51extern struct ia64_machine_vector ia64_mv;
52extern void set_iommu_machvec(void);
10 53
11#define dma_alloc_coherent(dev, size, handle, gfp) \ 54#define dma_alloc_coherent(dev, size, handle, gfp) \
12 platform_dma_alloc_coherent(dev, size, handle, (gfp) | GFP_DMA) 55 platform_dma_alloc_coherent(dev, size, handle, (gfp) | GFP_DMA)
@@ -96,4 +139,11 @@ dma_cache_sync (struct device *dev, void *vaddr, size_t size,
96 139
97#define dma_is_consistent(d, h) (1) /* all we do is coherent memory... */ 140#define dma_is_consistent(d, h) (1) /* all we do is coherent memory... */
98 141
142static inline struct dma_mapping_ops *get_dma_ops(struct device *dev)
143{
144 return dma_ops;
145}
146
147
148
99#endif /* _ASM_IA64_DMA_MAPPING_H */ 149#endif /* _ASM_IA64_DMA_MAPPING_H */
diff --git a/arch/ia64/include/asm/iommu.h b/arch/ia64/include/asm/iommu.h
new file mode 100644
index 000000000000..5fb2bb93de3b
--- /dev/null
+++ b/arch/ia64/include/asm/iommu.h
@@ -0,0 +1,16 @@
1#ifndef _ASM_IA64_IOMMU_H
2#define _ASM_IA64_IOMMU_H 1
3
4#define cpu_has_x2apic 0
5/* 10 seconds */
6#define DMAR_OPERATION_TIMEOUT (((cycles_t) local_cpu_data->itc_freq)*10)
7
8extern void pci_iommu_shutdown(void);
9extern void no_iommu_init(void);
10extern int force_iommu, no_iommu;
11extern int iommu_detected;
12extern void iommu_dma_init(void);
13extern void machvec_init(const char *name);
14extern int forbid_dac;
15
16#endif
diff --git a/arch/ia64/include/asm/machvec.h b/arch/ia64/include/asm/machvec.h
index de99cb2799cf..1ea28bcee33b 100644
--- a/arch/ia64/include/asm/machvec.h
+++ b/arch/ia64/include/asm/machvec.h
@@ -120,6 +120,8 @@ extern void machvec_tlb_migrate_finish (struct mm_struct *);
120# include <asm/machvec_hpsim.h> 120# include <asm/machvec_hpsim.h>
121# elif defined (CONFIG_IA64_DIG) 121# elif defined (CONFIG_IA64_DIG)
122# include <asm/machvec_dig.h> 122# include <asm/machvec_dig.h>
123# elif defined(CONFIG_IA64_DIG_VTD)
124# include <asm/machvec_dig_vtd.h>
123# elif defined (CONFIG_IA64_HP_ZX1) 125# elif defined (CONFIG_IA64_HP_ZX1)
124# include <asm/machvec_hpzx1.h> 126# include <asm/machvec_hpzx1.h>
125# elif defined (CONFIG_IA64_HP_ZX1_SWIOTLB) 127# elif defined (CONFIG_IA64_HP_ZX1_SWIOTLB)
diff --git a/arch/ia64/include/asm/machvec_dig_vtd.h b/arch/ia64/include/asm/machvec_dig_vtd.h
new file mode 100644
index 000000000000..3400b561e711
--- /dev/null
+++ b/arch/ia64/include/asm/machvec_dig_vtd.h
@@ -0,0 +1,38 @@
1#ifndef _ASM_IA64_MACHVEC_DIG_VTD_h
2#define _ASM_IA64_MACHVEC_DIG_VTD_h
3
4extern ia64_mv_setup_t dig_setup;
5extern ia64_mv_dma_alloc_coherent vtd_alloc_coherent;
6extern ia64_mv_dma_free_coherent vtd_free_coherent;
7extern ia64_mv_dma_map_single_attrs vtd_map_single_attrs;
8extern ia64_mv_dma_unmap_single_attrs vtd_unmap_single_attrs;
9extern ia64_mv_dma_map_sg_attrs vtd_map_sg_attrs;
10extern ia64_mv_dma_unmap_sg_attrs vtd_unmap_sg_attrs;
11extern ia64_mv_dma_supported iommu_dma_supported;
12extern ia64_mv_dma_mapping_error vtd_dma_mapping_error;
13extern ia64_mv_dma_init pci_iommu_alloc;
14
15/*
16 * This stuff has dual use!
17 *
18 * For a generic kernel, the macros are used to initialize the
19 * platform's machvec structure. When compiling a non-generic kernel,
20 * the macros are used directly.
21 */
22#define platform_name "dig_vtd"
23#define platform_setup dig_setup
24#define platform_dma_init pci_iommu_alloc
25#define platform_dma_alloc_coherent vtd_alloc_coherent
26#define platform_dma_free_coherent vtd_free_coherent
27#define platform_dma_map_single_attrs vtd_map_single_attrs
28#define platform_dma_unmap_single_attrs vtd_unmap_single_attrs
29#define platform_dma_map_sg_attrs vtd_map_sg_attrs
30#define platform_dma_unmap_sg_attrs vtd_unmap_sg_attrs
31#define platform_dma_sync_single_for_cpu machvec_dma_sync_single
32#define platform_dma_sync_sg_for_cpu machvec_dma_sync_sg
33#define platform_dma_sync_single_for_device machvec_dma_sync_single
34#define platform_dma_sync_sg_for_device machvec_dma_sync_sg
35#define platform_dma_supported iommu_dma_supported
36#define platform_dma_mapping_error vtd_dma_mapping_error
37
38#endif /* _ASM_IA64_MACHVEC_DIG_VTD_h */
diff --git a/arch/ia64/include/asm/machvec_init.h b/arch/ia64/include/asm/machvec_init.h
index 7f21249fba3f..ef964b286842 100644
--- a/arch/ia64/include/asm/machvec_init.h
+++ b/arch/ia64/include/asm/machvec_init.h
@@ -1,3 +1,4 @@
1#include <asm/iommu.h>
1#include <asm/machvec.h> 2#include <asm/machvec.h>
2 3
3extern ia64_mv_send_ipi_t ia64_send_ipi; 4extern ia64_mv_send_ipi_t ia64_send_ipi;
diff --git a/arch/ia64/include/asm/pci.h b/arch/ia64/include/asm/pci.h
index 0149097b736d..645ef06ddaa4 100644
--- a/arch/ia64/include/asm/pci.h
+++ b/arch/ia64/include/asm/pci.h
@@ -164,4 +164,7 @@ static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
164 return channel ? isa_irq_to_vector(15) : isa_irq_to_vector(14); 164 return channel ? isa_irq_to_vector(15) : isa_irq_to_vector(14);
165} 165}
166 166
167#ifdef CONFIG_DMAR
168extern void pci_iommu_alloc(void);
169#endif
167#endif /* _ASM_IA64_PCI_H */ 170#endif /* _ASM_IA64_PCI_H */
diff --git a/arch/ia64/include/asm/swiotlb.h b/arch/ia64/include/asm/swiotlb.h
new file mode 100644
index 000000000000..fb79423834d0
--- /dev/null
+++ b/arch/ia64/include/asm/swiotlb.h
@@ -0,0 +1,56 @@
1#ifndef ASM_IA64__SWIOTLB_H
2#define ASM_IA64__SWIOTLB_H
3
4#include <linux/dma-mapping.h>
5
6/* SWIOTLB interface */
7
8extern dma_addr_t swiotlb_map_single(struct device *hwdev, void *ptr,
9 size_t size, int dir);
10extern void *swiotlb_alloc_coherent(struct device *hwdev, size_t size,
11 dma_addr_t *dma_handle, gfp_t flags);
12extern void swiotlb_unmap_single(struct device *hwdev, dma_addr_t dev_addr,
13 size_t size, int dir);
14extern void swiotlb_sync_single_for_cpu(struct device *hwdev,
15 dma_addr_t dev_addr,
16 size_t size, int dir);
17extern void swiotlb_sync_single_for_device(struct device *hwdev,
18 dma_addr_t dev_addr,
19 size_t size, int dir);
20extern void swiotlb_sync_single_range_for_cpu(struct device *hwdev,
21 dma_addr_t dev_addr,
22 unsigned long offset,
23 size_t size, int dir);
24extern void swiotlb_sync_single_range_for_device(struct device *hwdev,
25 dma_addr_t dev_addr,
26 unsigned long offset,
27 size_t size, int dir);
28extern void swiotlb_sync_sg_for_cpu(struct device *hwdev,
29 struct scatterlist *sg, int nelems,
30 int dir);
31extern void swiotlb_sync_sg_for_device(struct device *hwdev,
32 struct scatterlist *sg, int nelems,
33 int dir);
34extern int swiotlb_map_sg(struct device *hwdev, struct scatterlist *sg,
35 int nents, int direction);
36extern void swiotlb_unmap_sg(struct device *hwdev, struct scatterlist *sg,
37 int nents, int direction);
38extern int swiotlb_dma_mapping_error(struct device *hwdev, dma_addr_t dma_addr);
39extern void swiotlb_free_coherent(struct device *hwdev, size_t size,
40 void *vaddr, dma_addr_t dma_handle);
41extern int swiotlb_dma_supported(struct device *hwdev, u64 mask);
42extern void swiotlb_init(void);
43
44extern int swiotlb_force;
45
46#ifdef CONFIG_SWIOTLB
47extern int swiotlb;
48extern void pci_swiotlb_init(void);
49#else
50#define swiotlb 0
51static inline void pci_swiotlb_init(void)
52{
53}
54#endif
55
56#endif /* ASM_IA64__SWIOTLB_H */
diff --git a/arch/ia64/kernel/Makefile b/arch/ia64/kernel/Makefile
index 55e6ca8eebda..c381ea954892 100644
--- a/arch/ia64/kernel/Makefile
+++ b/arch/ia64/kernel/Makefile
@@ -42,6 +42,10 @@ obj-$(CONFIG_IA64_ESI) += esi.o
42ifneq ($(CONFIG_IA64_ESI),) 42ifneq ($(CONFIG_IA64_ESI),)
43obj-y += esi_stub.o # must be in kernel proper 43obj-y += esi_stub.o # must be in kernel proper
44endif 44endif
45obj-$(CONFIG_DMAR) += pci-dma.o
46ifeq ($(CONFIG_DMAR), y)
47obj-$(CONFIG_SWIOTLB) += pci-swiotlb.o
48endif
45 49
46# The gate DSO image is built using a special linker script. 50# The gate DSO image is built using a special linker script.
47targets += gate.so gate-syms.o 51targets += gate.so gate-syms.o
diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c
index 00936491933e..0635015d0aaa 100644
--- a/arch/ia64/kernel/acpi.c
+++ b/arch/ia64/kernel/acpi.c
@@ -92,6 +92,9 @@ acpi_get_sysname(void)
92 struct acpi_table_rsdp *rsdp; 92 struct acpi_table_rsdp *rsdp;
93 struct acpi_table_xsdt *xsdt; 93 struct acpi_table_xsdt *xsdt;
94 struct acpi_table_header *hdr; 94 struct acpi_table_header *hdr;
95#ifdef CONFIG_DMAR
96 u64 i, nentries;
97#endif
95 98
96 rsdp_phys = acpi_find_rsdp(); 99 rsdp_phys = acpi_find_rsdp();
97 if (!rsdp_phys) { 100 if (!rsdp_phys) {
@@ -126,6 +129,18 @@ acpi_get_sysname(void)
126 return "xen"; 129 return "xen";
127 } 130 }
128 131
132#ifdef CONFIG_DMAR
133 /* Look for Intel IOMMU */
134 nentries = (hdr->length - sizeof(*hdr)) /
135 sizeof(xsdt->table_offset_entry[0]);
136 for (i = 0; i < nentries; i++) {
137 hdr = __va(xsdt->table_offset_entry[i]);
138 if (strncmp(hdr->signature, ACPI_SIG_DMAR,
139 sizeof(ACPI_SIG_DMAR) - 1) == 0)
140 return "dig_vtd";
141 }
142#endif
143
129 return "dig"; 144 return "dig";
130#else 145#else
131# if defined (CONFIG_IA64_HP_SIM) 146# if defined (CONFIG_IA64_HP_SIM)
@@ -142,6 +157,8 @@ acpi_get_sysname(void)
142 return "dig"; 157 return "dig";
143# elif defined (CONFIG_IA64_XEN_GUEST) 158# elif defined (CONFIG_IA64_XEN_GUEST)
144 return "xen"; 159 return "xen";
160# elif defined(CONFIG_IA64_DIG_VTD)
161 return "dig_vtd";
145# else 162# else
146# error Unknown platform. Fix acpi.c. 163# error Unknown platform. Fix acpi.c.
147# endif 164# endif
diff --git a/arch/ia64/kernel/msi_ia64.c b/arch/ia64/kernel/msi_ia64.c
index 60c6ef67ebb2..702a09c13238 100644
--- a/arch/ia64/kernel/msi_ia64.c
+++ b/arch/ia64/kernel/msi_ia64.c
@@ -5,6 +5,7 @@
5#include <linux/pci.h> 5#include <linux/pci.h>
6#include <linux/irq.h> 6#include <linux/irq.h>
7#include <linux/msi.h> 7#include <linux/msi.h>
8#include <linux/dmar.h>
8#include <asm/smp.h> 9#include <asm/smp.h>
9 10
10/* 11/*
@@ -162,3 +163,82 @@ void arch_teardown_msi_irq(unsigned int irq)
162 163
163 return ia64_teardown_msi_irq(irq); 164 return ia64_teardown_msi_irq(irq);
164} 165}
166
167#ifdef CONFIG_DMAR
168#ifdef CONFIG_SMP
169static void dmar_msi_set_affinity(unsigned int irq, cpumask_t mask)
170{
171 struct irq_cfg *cfg = irq_cfg + irq;
172 struct msi_msg msg;
173 int cpu = first_cpu(mask);
174
175
176 if (!cpu_online(cpu))
177 return;
178
179 if (irq_prepare_move(irq, cpu))
180 return;
181
182 dmar_msi_read(irq, &msg);
183
184 msg.data &= ~MSI_DATA_VECTOR_MASK;
185 msg.data |= MSI_DATA_VECTOR(cfg->vector);
186 msg.address_lo &= ~MSI_ADDR_DESTID_MASK;
187 msg.address_lo |= MSI_ADDR_DESTID_CPU(cpu_physical_id(cpu));
188
189 dmar_msi_write(irq, &msg);
190 irq_desc[irq].affinity = mask;
191}
192#endif /* CONFIG_SMP */
193
194struct irq_chip dmar_msi_type = {
195 .name = "DMAR_MSI",
196 .unmask = dmar_msi_unmask,
197 .mask = dmar_msi_mask,
198 .ack = ia64_ack_msi_irq,
199#ifdef CONFIG_SMP
200 .set_affinity = dmar_msi_set_affinity,
201#endif
202 .retrigger = ia64_msi_retrigger_irq,
203};
204
205static int
206msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg)
207{
208 struct irq_cfg *cfg = irq_cfg + irq;
209 unsigned dest;
210 cpumask_t mask;
211
212 cpus_and(mask, irq_to_domain(irq), cpu_online_map);
213 dest = cpu_physical_id(first_cpu(mask));
214
215 msg->address_hi = 0;
216 msg->address_lo =
217 MSI_ADDR_HEADER |
218 MSI_ADDR_DESTMODE_PHYS |
219 MSI_ADDR_REDIRECTION_CPU |
220 MSI_ADDR_DESTID_CPU(dest);
221
222 msg->data =
223 MSI_DATA_TRIGGER_EDGE |
224 MSI_DATA_LEVEL_ASSERT |
225 MSI_DATA_DELIVERY_FIXED |
226 MSI_DATA_VECTOR(cfg->vector);
227 return 0;
228}
229
230int arch_setup_dmar_msi(unsigned int irq)
231{
232 int ret;
233 struct msi_msg msg;
234
235 ret = msi_compose_msg(NULL, irq, &msg);
236 if (ret < 0)
237 return ret;
238 dmar_msi_write(irq, &msg);
239 set_irq_chip_and_handler_name(irq, &dmar_msi_type, handle_edge_irq,
240 "edge");
241 return 0;
242}
243#endif /* CONFIG_DMAR */
244
diff --git a/arch/ia64/kernel/pci-dma.c b/arch/ia64/kernel/pci-dma.c
new file mode 100644
index 000000000000..10a75b557650
--- /dev/null
+++ b/arch/ia64/kernel/pci-dma.c
@@ -0,0 +1,129 @@
1/*
2 * Dynamic DMA mapping support.
3 */
4
5#include <linux/types.h>
6#include <linux/mm.h>
7#include <linux/string.h>
8#include <linux/pci.h>
9#include <linux/module.h>
10#include <linux/dmar.h>
11#include <asm/iommu.h>
12#include <asm/machvec.h>
13#include <linux/dma-mapping.h>
14
15#include <asm/machvec.h>
16#include <asm/system.h>
17
18#ifdef CONFIG_DMAR
19
20#include <linux/kernel.h>
21#include <linux/string.h>
22
23#include <asm/page.h>
24#include <asm/iommu.h>
25
26dma_addr_t bad_dma_address __read_mostly;
27EXPORT_SYMBOL(bad_dma_address);
28
29static int iommu_sac_force __read_mostly;
30
31int no_iommu __read_mostly;
32#ifdef CONFIG_IOMMU_DEBUG
33int force_iommu __read_mostly = 1;
34#else
35int force_iommu __read_mostly;
36#endif
37
38/* Set this to 1 if there is a HW IOMMU in the system */
39int iommu_detected __read_mostly;
40
41/* Dummy device used for NULL arguments (normally ISA). Better would
42 be probably a smaller DMA mask, but this is bug-to-bug compatible
43 to i386. */
44struct device fallback_dev = {
45 .bus_id = "fallback device",
46 .coherent_dma_mask = DMA_32BIT_MASK,
47 .dma_mask = &fallback_dev.coherent_dma_mask,
48};
49
50void __init pci_iommu_alloc(void)
51{
52 /*
53 * The order of these functions is important for
54 * fall-back/fail-over reasons
55 */
56 detect_intel_iommu();
57
58#ifdef CONFIG_SWIOTLB
59 pci_swiotlb_init();
60#endif
61}
62
63static int __init pci_iommu_init(void)
64{
65 if (iommu_detected)
66 intel_iommu_init();
67
68 return 0;
69}
70
71/* Must execute after PCI subsystem */
72fs_initcall(pci_iommu_init);
73
74void pci_iommu_shutdown(void)
75{
76 return;
77}
78
79void __init
80iommu_dma_init(void)
81{
82 return;
83}
84
85struct dma_mapping_ops *dma_ops;
86EXPORT_SYMBOL(dma_ops);
87
88int iommu_dma_supported(struct device *dev, u64 mask)
89{
90 struct dma_mapping_ops *ops = get_dma_ops(dev);
91
92#ifdef CONFIG_PCI
93 if (mask > 0xffffffff && forbid_dac > 0) {
94 dev_info(dev, "Disallowing DAC for device\n");
95 return 0;
96 }
97#endif
98
99 if (ops->dma_supported_op)
100 return ops->dma_supported_op(dev, mask);
101
102 /* Copied from i386. Doesn't make much sense, because it will
103 only work for pci_alloc_coherent.
104 The caller just has to use GFP_DMA in this case. */
105 if (mask < DMA_24BIT_MASK)
106 return 0;
107
108 /* Tell the device to use SAC when IOMMU force is on. This
109 allows the driver to use cheaper accesses in some cases.
110
111 Problem with this is that if we overflow the IOMMU area and
112 return DAC as fallback address the device may not handle it
113 correctly.
114
115 As a special case some controllers have a 39bit address
116 mode that is as efficient as 32bit (aic79xx). Don't force
117 SAC for these. Assume all masks <= 40 bits are of this
118 type. Normally this doesn't make any difference, but gives
119 more gentle handling of IOMMU overflow. */
120 if (iommu_sac_force && (mask >= DMA_40BIT_MASK)) {
121 dev_info(dev, "Force SAC with mask %lx\n", mask);
122 return 0;
123 }
124
125 return 1;
126}
127EXPORT_SYMBOL(iommu_dma_supported);
128
129#endif
diff --git a/arch/ia64/kernel/pci-swiotlb.c b/arch/ia64/kernel/pci-swiotlb.c
new file mode 100644
index 000000000000..16c50516dbc1
--- /dev/null
+++ b/arch/ia64/kernel/pci-swiotlb.c
@@ -0,0 +1,46 @@
1/* Glue code to lib/swiotlb.c */
2
3#include <linux/pci.h>
4#include <linux/cache.h>
5#include <linux/module.h>
6#include <linux/dma-mapping.h>
7
8#include <asm/swiotlb.h>
9#include <asm/dma.h>
10#include <asm/iommu.h>
11#include <asm/machvec.h>
12
13int swiotlb __read_mostly;
14EXPORT_SYMBOL(swiotlb);
15
16struct dma_mapping_ops swiotlb_dma_ops = {
17 .mapping_error = swiotlb_dma_mapping_error,
18 .alloc_coherent = swiotlb_alloc_coherent,
19 .free_coherent = swiotlb_free_coherent,
20 .map_single = swiotlb_map_single,
21 .unmap_single = swiotlb_unmap_single,
22 .sync_single_for_cpu = swiotlb_sync_single_for_cpu,
23 .sync_single_for_device = swiotlb_sync_single_for_device,
24 .sync_single_range_for_cpu = swiotlb_sync_single_range_for_cpu,
25 .sync_single_range_for_device = swiotlb_sync_single_range_for_device,
26 .sync_sg_for_cpu = swiotlb_sync_sg_for_cpu,
27 .sync_sg_for_device = swiotlb_sync_sg_for_device,
28 .map_sg = swiotlb_map_sg,
29 .unmap_sg = swiotlb_unmap_sg,
30 .dma_supported_op = swiotlb_dma_supported,
31};
32
33void __init pci_swiotlb_init(void)
34{
35 if (!iommu_detected) {
36#ifdef CONFIG_IA64_GENERIC
37 swiotlb = 1;
38 printk(KERN_INFO "PCI-DMA: Re-initialize machine vector.\n");
39 machvec_init("dig");
40 swiotlb_init();
41 dma_ops = &swiotlb_dma_ops;
42#else
43 panic("Unable to find Intel IOMMU");
44#endif
45 }
46}
diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c
index de636b215677..2a67a74a48fe 100644
--- a/arch/ia64/kernel/setup.c
+++ b/arch/ia64/kernel/setup.c
@@ -116,6 +116,13 @@ unsigned int num_io_spaces;
116 */ 116 */
117#define I_CACHE_STRIDE_SHIFT 5 /* Safest way to go: 32 bytes by 32 bytes */ 117#define I_CACHE_STRIDE_SHIFT 5 /* Safest way to go: 32 bytes by 32 bytes */
118unsigned long ia64_i_cache_stride_shift = ~0; 118unsigned long ia64_i_cache_stride_shift = ~0;
119/*
120 * "clflush_cache_range()" needs to know what processor dependent stride size to
121 * use when it flushes cache lines including both d-cache and i-cache.
122 */
123/* Safest way to go: 32 bytes by 32 bytes */
124#define CACHE_STRIDE_SHIFT 5
125unsigned long ia64_cache_stride_shift = ~0;
119 126
120/* 127/*
121 * The merge_mask variable needs to be set to (max(iommu_page_size(iommu)) - 1). This 128 * The merge_mask variable needs to be set to (max(iommu_page_size(iommu)) - 1). This
@@ -847,13 +854,14 @@ setup_per_cpu_areas (void)
847} 854}
848 855
849/* 856/*
850 * Calculate the max. cache line size. 857 * Do the following calculations:
851 * 858 *
852 * In addition, the minimum of the i-cache stride sizes is calculated for 859 * 1. the max. cache line size.
853 * "flush_icache_range()". 860 * 2. the minimum of the i-cache stride sizes for "flush_icache_range()".
861 * 3. the minimum of the cache stride sizes for "clflush_cache_range()".
854 */ 862 */
855static void __cpuinit 863static void __cpuinit
856get_max_cacheline_size (void) 864get_cache_info(void)
857{ 865{
858 unsigned long line_size, max = 1; 866 unsigned long line_size, max = 1;
859 u64 l, levels, unique_caches; 867 u64 l, levels, unique_caches;
@@ -867,12 +875,14 @@ get_max_cacheline_size (void)
867 max = SMP_CACHE_BYTES; 875 max = SMP_CACHE_BYTES;
868 /* Safest setup for "flush_icache_range()" */ 876 /* Safest setup for "flush_icache_range()" */
869 ia64_i_cache_stride_shift = I_CACHE_STRIDE_SHIFT; 877 ia64_i_cache_stride_shift = I_CACHE_STRIDE_SHIFT;
878 /* Safest setup for "clflush_cache_range()" */
879 ia64_cache_stride_shift = CACHE_STRIDE_SHIFT;
870 goto out; 880 goto out;
871 } 881 }
872 882
873 for (l = 0; l < levels; ++l) { 883 for (l = 0; l < levels; ++l) {
874 status = ia64_pal_cache_config_info(l, /* cache_type (data_or_unified)= */ 2, 884 /* cache_type (data_or_unified)=2 */
875 &cci); 885 status = ia64_pal_cache_config_info(l, 2, &cci);
876 if (status != 0) { 886 if (status != 0) {
877 printk(KERN_ERR 887 printk(KERN_ERR
878 "%s: ia64_pal_cache_config_info(l=%lu, 2) failed (status=%ld)\n", 888 "%s: ia64_pal_cache_config_info(l=%lu, 2) failed (status=%ld)\n",
@@ -880,15 +890,21 @@ get_max_cacheline_size (void)
880 max = SMP_CACHE_BYTES; 890 max = SMP_CACHE_BYTES;
881 /* The safest setup for "flush_icache_range()" */ 891 /* The safest setup for "flush_icache_range()" */
882 cci.pcci_stride = I_CACHE_STRIDE_SHIFT; 892 cci.pcci_stride = I_CACHE_STRIDE_SHIFT;
893 /* The safest setup for "clflush_cache_range()" */
894 ia64_cache_stride_shift = CACHE_STRIDE_SHIFT;
883 cci.pcci_unified = 1; 895 cci.pcci_unified = 1;
896 } else {
897 if (cci.pcci_stride < ia64_cache_stride_shift)
898 ia64_cache_stride_shift = cci.pcci_stride;
899
900 line_size = 1 << cci.pcci_line_size;
901 if (line_size > max)
902 max = line_size;
884 } 903 }
885 line_size = 1 << cci.pcci_line_size; 904
886 if (line_size > max)
887 max = line_size;
888 if (!cci.pcci_unified) { 905 if (!cci.pcci_unified) {
889 status = ia64_pal_cache_config_info(l, 906 /* cache_type (instruction)=1*/
890 /* cache_type (instruction)= */ 1, 907 status = ia64_pal_cache_config_info(l, 1, &cci);
891 &cci);
892 if (status != 0) { 908 if (status != 0) {
893 printk(KERN_ERR 909 printk(KERN_ERR
894 "%s: ia64_pal_cache_config_info(l=%lu, 1) failed (status=%ld)\n", 910 "%s: ia64_pal_cache_config_info(l=%lu, 1) failed (status=%ld)\n",
@@ -942,7 +958,7 @@ cpu_init (void)
942 } 958 }
943#endif 959#endif
944 960
945 get_max_cacheline_size(); 961 get_cache_info();
946 962
947 /* 963 /*
948 * We can't pass "local_cpu_data" to identify_cpu() because we haven't called 964 * We can't pass "local_cpu_data" to identify_cpu() because we haven't called
diff --git a/arch/ia64/lib/flush.S b/arch/ia64/lib/flush.S
index 2a0d27f2f21b..1d8c88860063 100644
--- a/arch/ia64/lib/flush.S
+++ b/arch/ia64/lib/flush.S
@@ -60,3 +60,58 @@ GLOBAL_ENTRY(flush_icache_range)
60 mov ar.lc=r3 // restore ar.lc 60 mov ar.lc=r3 // restore ar.lc
61 br.ret.sptk.many rp 61 br.ret.sptk.many rp
62END(flush_icache_range) 62END(flush_icache_range)
63
64 /*
65 * clflush_cache_range(start,size)
66 *
67 * Flush cache lines from start to start+size-1.
68 *
69 * Must deal with range from start to start+size-1 but nothing else
70 * (need to be careful not to touch addresses that may be
71 * unmapped).
72 *
73 * Note: "in0" and "in1" are preserved for debugging purposes.
74 */
75 .section .kprobes.text,"ax"
76GLOBAL_ENTRY(clflush_cache_range)
77
78 .prologue
79 alloc r2=ar.pfs,2,0,0,0
80 movl r3=ia64_cache_stride_shift
81 mov r21=1
82 add r22=in1,in0
83 ;;
84 ld8 r20=[r3] // r20: stride shift
85 sub r22=r22,r0,1 // last byte address
86 ;;
87 shr.u r23=in0,r20 // start / (stride size)
88 shr.u r22=r22,r20 // (last byte address) / (stride size)
89 shl r21=r21,r20 // r21: stride size of the i-cache(s)
90 ;;
91 sub r8=r22,r23 // number of strides - 1
92 shl r24=r23,r20 // r24: addresses for "fc" =
93 // "start" rounded down to stride
94 // boundary
95 .save ar.lc,r3
96 mov r3=ar.lc // save ar.lc
97 ;;
98
99 .body
100 mov ar.lc=r8
101 ;;
102 /*
103 * 32 byte aligned loop, even number of (actually 2) bundles
104 */
105.Loop_fc:
106 fc r24 // issuable on M0 only
107 add r24=r21,r24 // we flush "stride size" bytes per iteration
108 nop.i 0
109 br.cloop.sptk.few .Loop_fc
110 ;;
111 sync.i
112 ;;
113 srlz.i
114 ;;
115 mov ar.lc=r3 // restore ar.lc
116 br.ret.sptk.many rp
117END(clflush_cache_range)