diff options
Diffstat (limited to 'arch/sparc64/kernel/psycho_common.c')
-rw-r--r-- | arch/sparc64/kernel/psycho_common.c | 93 |
1 files changed, 93 insertions, 0 deletions
diff --git a/arch/sparc64/kernel/psycho_common.c b/arch/sparc64/kernel/psycho_common.c new file mode 100644 index 000000000000..07acc13637b3 --- /dev/null +++ b/arch/sparc64/kernel/psycho_common.c | |||
@@ -0,0 +1,93 @@ | |||
1 | /* psycho_common.c: Code common to PSYCHO and derivative PCI controllers. | ||
2 | * | ||
3 | * Copyright (C) 2008 David S. Miller <davem@davemloft.net> | ||
4 | */ | ||
5 | #include <linux/kernel.h> | ||
6 | |||
7 | #include <asm/upa.h> | ||
8 | |||
9 | #include "pci_impl.h" | ||
10 | #include "psycho_common.h" | ||
11 | |||
12 | #define PSYCHO_IOMMU_TAG 0xa580UL | ||
13 | #define PSYCHO_IOMMU_DATA 0xa600UL | ||
14 | |||
15 | static void psycho_iommu_flush(struct pci_pbm_info *pbm) | ||
16 | { | ||
17 | int i; | ||
18 | |||
19 | for (i = 0; i < 16; i++) { | ||
20 | unsigned long off = i * 8; | ||
21 | |||
22 | upa_writeq(0, pbm->controller_regs + PSYCHO_IOMMU_TAG + off); | ||
23 | upa_writeq(0, pbm->controller_regs + PSYCHO_IOMMU_DATA + off); | ||
24 | } | ||
25 | } | ||
26 | |||
27 | #define PSYCHO_IOMMU_CONTROL 0x0200UL | ||
28 | #define PSYCHO_IOMMU_CTRL_TSBSZ 0x0000000000070000UL | ||
29 | #define PSYCHO_IOMMU_TSBSZ_1K 0x0000000000000000UL | ||
30 | #define PSYCHO_IOMMU_TSBSZ_2K 0x0000000000010000UL | ||
31 | #define PSYCHO_IOMMU_TSBSZ_4K 0x0000000000020000UL | ||
32 | #define PSYCHO_IOMMU_TSBSZ_8K 0x0000000000030000UL | ||
33 | #define PSYCHO_IOMMU_TSBSZ_16K 0x0000000000040000UL | ||
34 | #define PSYCHO_IOMMU_TSBSZ_32K 0x0000000000050000UL | ||
35 | #define PSYCHO_IOMMU_TSBSZ_64K 0x0000000000060000UL | ||
36 | #define PSYCHO_IOMMU_TSBSZ_128K 0x0000000000070000UL | ||
37 | #define PSYCHO_IOMMU_CTRL_TBWSZ 0x0000000000000004UL | ||
38 | #define PSYCHO_IOMMU_CTRL_DENAB 0x0000000000000002UL | ||
39 | #define PSYCHO_IOMMU_CTRL_ENAB 0x0000000000000001UL | ||
40 | #define PSYCHO_IOMMU_FLUSH 0x0210UL | ||
41 | #define PSYCHO_IOMMU_TSBBASE 0x0208UL | ||
42 | |||
43 | int psycho_iommu_init(struct pci_pbm_info *pbm, int tsbsize, | ||
44 | u32 dvma_offset, u32 dma_mask, | ||
45 | unsigned long write_complete_offset) | ||
46 | { | ||
47 | struct iommu *iommu = pbm->iommu; | ||
48 | u64 control; | ||
49 | int err; | ||
50 | |||
51 | iommu->iommu_control = pbm->controller_regs + PSYCHO_IOMMU_CONTROL; | ||
52 | iommu->iommu_tsbbase = pbm->controller_regs + PSYCHO_IOMMU_TSBBASE; | ||
53 | iommu->iommu_flush = pbm->controller_regs + PSYCHO_IOMMU_FLUSH; | ||
54 | iommu->iommu_tags = pbm->controller_regs + PSYCHO_IOMMU_TAG; | ||
55 | iommu->write_complete_reg = (pbm->controller_regs + | ||
56 | write_complete_offset); | ||
57 | |||
58 | iommu->iommu_ctxflush = 0; | ||
59 | |||
60 | control = upa_readq(iommu->iommu_control); | ||
61 | control |= PSYCHO_IOMMU_CTRL_DENAB; | ||
62 | upa_writeq(control, iommu->iommu_control); | ||
63 | |||
64 | psycho_iommu_flush(pbm); | ||
65 | |||
66 | /* Leave diag mode enabled for full-flushing done in pci_iommu.c */ | ||
67 | err = iommu_table_init(iommu, tsbsize * 1024 * 8, | ||
68 | dvma_offset, dma_mask, pbm->numa_node); | ||
69 | if (err) | ||
70 | return err; | ||
71 | |||
72 | upa_writeq(__pa(iommu->page_table), iommu->iommu_tsbbase); | ||
73 | |||
74 | control = upa_readq(iommu->iommu_control); | ||
75 | control &= ~(PSYCHO_IOMMU_CTRL_TSBSZ | PSYCHO_IOMMU_CTRL_TBWSZ); | ||
76 | control |= PSYCHO_IOMMU_CTRL_ENAB; | ||
77 | |||
78 | switch (tsbsize) { | ||
79 | case 64: | ||
80 | control |= PSYCHO_IOMMU_TSBSZ_64K; | ||
81 | break; | ||
82 | case 128: | ||
83 | control |= PSYCHO_IOMMU_TSBSZ_128K; | ||
84 | break; | ||
85 | default: | ||
86 | return -EINVAL; | ||
87 | } | ||
88 | |||
89 | upa_writeq(control, iommu->iommu_control); | ||
90 | |||
91 | return 0; | ||
92 | |||
93 | } | ||