aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFenghua Yu <fenghua.yu@intel.com>2008-10-17 15:14:13 -0400
committerTony Luck <tony.luck@intel.com>2008-10-17 15:14:13 -0400
commit62fdd7678a26efadd6ac5c2869543caff77d2df0 (patch)
tree0dd67208590c4540ff6a4476579a55bcac0d1fce
parent6bb7a935489dab20802dde6c2cb7d8582f4849bf (diff)
[IA64] Add Variable Page Size and IA64 Support in Intel IOMMU
The patch contains Intel IOMMU IA64 specific code. It defines new machvec dig_vtd, hooks for IOMMU, DMAR table detection, cache line flush function, etc. For a generic kernel with CONFIG_DMAR=y, if Intel IOMMU is detected, dig_vtd is used for machinve vector. Otherwise, kernel falls back to dig machine vector. Kernel parameter "machvec=dig" or "intel_iommu=off" can be used to force kernel to boot dig machine vector. Signed-off-by: Fenghua Yu <fenghua.yu@intel.com> Signed-off-by: Tony Luck <tony.luck@intel.com>
-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 3b7aa38254a8..a924a84df325 100644
--- a/arch/ia64/Kconfig
+++ b/arch/ia64/Kconfig
@@ -117,6 +117,7 @@ config IA64_GENERIC
117 select NUMA 117 select NUMA
118 select ACPI_NUMA 118 select ACPI_NUMA
119 select SWIOTLB 119 select SWIOTLB
120 select PCI_MSI
120 help 121 help
121 This selects the system type of your hardware. A "generic" kernel 122 This selects the system type of your hardware. A "generic" kernel
122 will run on any supported IA-64 system. However, if you configure 123 will run on any supported IA-64 system. However, if you configure
@@ -124,6 +125,7 @@ config IA64_GENERIC
124 125
125 generic For any supported IA-64 system 126 generic For any supported IA-64 system
126 DIG-compliant For DIG ("Developer's Interface Guide") compliant systems 127 DIG-compliant For DIG ("Developer's Interface Guide") compliant systems
128 DIG+Intel+IOMMU For DIG systems with Intel IOMMU
127 HP-zx1/sx1000 For HP systems 129 HP-zx1/sx1000 For HP systems
128 HP-zx1/sx1000+swiotlb For HP systems with (broken) DMA-constrained devices. 130 HP-zx1/sx1000+swiotlb For HP systems with (broken) DMA-constrained devices.
129 SGI-SN2 For SGI Altix systems 131 SGI-SN2 For SGI Altix systems
@@ -136,6 +138,11 @@ config IA64_DIG
136 bool "DIG-compliant" 138 bool "DIG-compliant"
137 select SWIOTLB 139 select SWIOTLB
138 140
141config IA64_DIG_VTD
142 bool "DIG+Intel+IOMMU"
143 select DMAR
144 select PCI_MSI
145
139config IA64_HP_ZX1 146config IA64_HP_ZX1
140 bool "HP-zx1/sx1000" 147 bool "HP-zx1/sx1000"
141 help 148 help
@@ -581,6 +588,16 @@ source "drivers/pci/hotplug/Kconfig"
581 588
582source "drivers/pcmcia/Kconfig" 589source "drivers/pcmcia/Kconfig"
583 590
591config DMAR
592 bool "Support for DMA Remapping Devices (EXPERIMENTAL)"
593 depends on IA64_GENERIC && ACPI && EXPERIMENTAL
594 help
595 DMA remapping (DMAR) devices support enables independent address
596 translations for Direct Memory Access (DMA) from devices.
597 These DMA remapping devices are reported via ACPI tables
598 and include PCI device scope covered by these DMA
599 remapping devices.
600
584endmenu 601endmenu
585 602
586endif 603endif
diff --git a/arch/ia64/Makefile b/arch/ia64/Makefile
index 905d25b13d5a..04cecee1ed1b 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 2b850ccafef5..ce9b1d05083a 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 87fea11aecb7..af0e750705e3 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 5d1eb7ee2bf6..8cc2f8a610c4 100644
--- a/arch/ia64/kernel/acpi.c
+++ b/arch/ia64/kernel/acpi.c
@@ -91,6 +91,9 @@ acpi_get_sysname(void)
91 struct acpi_table_rsdp *rsdp; 91 struct acpi_table_rsdp *rsdp;
92 struct acpi_table_xsdt *xsdt; 92 struct acpi_table_xsdt *xsdt;
93 struct acpi_table_header *hdr; 93 struct acpi_table_header *hdr;
94#ifdef CONFIG_DMAR
95 u64 i, nentries;
96#endif
94 97
95 rsdp_phys = acpi_find_rsdp(); 98 rsdp_phys = acpi_find_rsdp();
96 if (!rsdp_phys) { 99 if (!rsdp_phys) {
@@ -123,6 +126,18 @@ acpi_get_sysname(void)
123 return "sn2"; 126 return "sn2";
124 } 127 }
125 128
129#ifdef CONFIG_DMAR
130 /* Look for Intel IOMMU */
131 nentries = (hdr->length - sizeof(*hdr)) /
132 sizeof(xsdt->table_offset_entry[0]);
133 for (i = 0; i < nentries; i++) {
134 hdr = __va(xsdt->table_offset_entry[i]);
135 if (strncmp(hdr->signature, ACPI_SIG_DMAR,
136 sizeof(ACPI_SIG_DMAR) - 1) == 0)
137 return "dig_vtd";
138 }
139#endif
140
126 return "dig"; 141 return "dig";
127#else 142#else
128# if defined (CONFIG_IA64_HP_SIM) 143# if defined (CONFIG_IA64_HP_SIM)
@@ -137,6 +152,8 @@ acpi_get_sysname(void)
137 return "uv"; 152 return "uv";
138# elif defined (CONFIG_IA64_DIG) 153# elif defined (CONFIG_IA64_DIG)
139 return "dig"; 154 return "dig";
155# elif defined(CONFIG_IA64_DIG_VTD)
156 return "dig_vtd";
140# else 157# else
141# error Unknown platform. Fix acpi.c. 158# error Unknown platform. Fix acpi.c.
142# endif 159# 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)