• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6/arch/m68k/sun3x/
1/*
2 * Virtual DMA allocation
3 *
4 * (C) 1999 Thomas Bogendoerfer (tsbogend@alpha.franken.de)
5 *
6 * 11/26/2000 -- disabled the existing code because it didn't work for
7 * me in 2.4.  Replaced with a significantly more primitive version
8 * similar to the sun3 code.  the old functionality was probably more
9 * desirable, but....   -- Sam Creasey (sammy@oh.verio.com)
10 *
11 */
12
13#include <linux/kernel.h>
14#include <linux/init.h>
15#include <linux/bitops.h>
16#include <linux/mm.h>
17#include <linux/bootmem.h>
18#include <linux/vmalloc.h>
19
20#include <asm/sun3x.h>
21#include <asm/dvma.h>
22#include <asm/io.h>
23#include <asm/page.h>
24#include <asm/pgtable.h>
25#include <asm/pgalloc.h>
26
27/* IOMMU support */
28
29#define IOMMU_ADDR_MASK            0x03ffe000
30#define IOMMU_CACHE_INHIBIT        0x00000040
31#define IOMMU_FULL_BLOCK           0x00000020
32#define IOMMU_MODIFIED             0x00000010
33#define IOMMU_USED                 0x00000008
34#define IOMMU_WRITE_PROTECT        0x00000004
35#define IOMMU_DT_MASK              0x00000003
36#define IOMMU_DT_INVALID           0x00000000
37#define IOMMU_DT_VALID             0x00000001
38#define IOMMU_DT_BAD               0x00000002
39
40
41static volatile unsigned long *iommu_pte = (unsigned long *)SUN3X_IOMMU;
42
43
44#define dvma_entry_paddr(index)		(iommu_pte[index] & IOMMU_ADDR_MASK)
45#define dvma_entry_vaddr(index,paddr)	((index << DVMA_PAGE_SHIFT) |  \
46					 (paddr & (DVMA_PAGE_SIZE-1)))
47#define dvma_entry_set(index,addr)	(iommu_pte[index] =            \
48					    (addr & IOMMU_ADDR_MASK) | \
49				             IOMMU_DT_VALID)
50#define dvma_entry_clr(index)		(iommu_pte[index] = IOMMU_DT_INVALID)
51#define dvma_entry_hash(addr)		((addr >> DVMA_PAGE_SHIFT) ^ \
52					 ((addr & 0x03c00000) >>     \
53						(DVMA_PAGE_SHIFT+4)))
54
55#undef DEBUG
56
57#ifdef DEBUG
58/* code to print out a dvma mapping for debugging purposes */
59void dvma_print (unsigned long dvma_addr)
60{
61
62        unsigned long index;
63
64        index = dvma_addr >> DVMA_PAGE_SHIFT;
65
66        printk("idx %lx dvma_addr %08lx paddr %08lx\n", index, dvma_addr,
67               dvma_entry_paddr(index));
68
69
70}
71#endif
72
73
74/* create a virtual mapping for a page assigned within the IOMMU
75   so that the cpu can reach it easily */
76inline int dvma_map_cpu(unsigned long kaddr,
77			       unsigned long vaddr, int len)
78{
79	pgd_t *pgd;
80	unsigned long end;
81	int ret = 0;
82
83	kaddr &= PAGE_MASK;
84	vaddr &= PAGE_MASK;
85
86	end = PAGE_ALIGN(vaddr + len);
87
88#ifdef DEBUG
89	printk("dvma: mapping kern %08lx to virt %08lx\n",
90	       kaddr, vaddr);
91#endif
92	pgd = pgd_offset_k(vaddr);
93
94	do {
95		pmd_t *pmd;
96		unsigned long end2;
97
98		if((pmd = pmd_alloc(&init_mm, pgd, vaddr)) == NULL) {
99			ret = -ENOMEM;
100			goto out;
101		}
102
103		if((end & PGDIR_MASK) > (vaddr & PGDIR_MASK))
104			end2 = (vaddr + (PGDIR_SIZE-1)) & PGDIR_MASK;
105		else
106			end2 = end;
107
108		do {
109			pte_t *pte;
110			unsigned long end3;
111
112			if((pte = pte_alloc_kernel(pmd, vaddr)) == NULL) {
113				ret = -ENOMEM;
114				goto out;
115			}
116
117			if((end2 & PMD_MASK) > (vaddr & PMD_MASK))
118				end3 = (vaddr + (PMD_SIZE-1)) & PMD_MASK;
119			else
120				end3 = end2;
121
122			do {
123#ifdef DEBUG
124				printk("mapping %08lx phys to %08lx\n",
125				       __pa(kaddr), vaddr);
126#endif
127				set_pte(pte, pfn_pte(virt_to_pfn(kaddr),
128						     PAGE_KERNEL));
129				pte++;
130				kaddr += PAGE_SIZE;
131				vaddr += PAGE_SIZE;
132			} while(vaddr < end3);
133
134		} while(vaddr < end2);
135
136	} while(vaddr < end);
137
138	flush_tlb_all();
139
140 out:
141	return ret;
142}
143
144
145inline int dvma_map_iommu(unsigned long kaddr, unsigned long baddr,
146				 int len)
147{
148	unsigned long end, index;
149
150	index = baddr >> DVMA_PAGE_SHIFT;
151	end = ((baddr+len) >> DVMA_PAGE_SHIFT);
152
153	if(len & ~DVMA_PAGE_MASK)
154		end++;
155
156	for(; index < end ; index++) {
157//		if(dvma_entry_use(index))
158//			BUG();
159//		printk("mapping pa %lx to ba %lx\n", __pa(kaddr), index << DVMA_PAGE_SHIFT);
160
161		dvma_entry_set(index, __pa(kaddr));
162
163		iommu_pte[index] |= IOMMU_FULL_BLOCK;
164//		dvma_entry_inc(index);
165
166		kaddr += DVMA_PAGE_SIZE;
167	}
168
169#ifdef DEBUG
170	for(index = (baddr >> DVMA_PAGE_SHIFT); index < end; index++)
171		dvma_print(index << DVMA_PAGE_SHIFT);
172#endif
173	return 0;
174
175}
176
177void dvma_unmap_iommu(unsigned long baddr, int len)
178{
179
180	int index, end;
181
182
183	index = baddr >> DVMA_PAGE_SHIFT;
184	end = (DVMA_PAGE_ALIGN(baddr+len) >> DVMA_PAGE_SHIFT);
185
186	for(; index < end ; index++) {
187#ifdef DEBUG
188		printk("freeing bus mapping %08x\n", index << DVMA_PAGE_SHIFT);
189#endif
190		dvma_entry_clr(index);
191	}
192
193}
194