|
|
1.1 root 1: /**
2: ** Proll (PROM replacement)
3: ** iommu.c: Functions for DVMA management.
4: ** Copyright 1999 Pete Zaitcev
5: ** This code is licensed under GNU General Public License.
6: **/
7: #include "config.h"
8: #include "libopenbios/bindings.h"
9: #include "drivers/drivers.h"
10: #include "iommu.h"
11: #include "libopenbios/ofmem.h"
12:
13: #ifdef CONFIG_DEBUG_IOMMU
14: #define DPRINTF(fmt, args...) \
15: do { printk(fmt , ##args); } while (0)
16: #else
17: #define DPRINTF(fmt, args...)
18: #endif
19:
20: /*
21: * IOMMU parameters
22: */
23: struct iommu {
24: struct iommu_regs *regs;
25: unsigned int *page_table;
26: unsigned long plow; /* Base bus address */
27: };
28:
29: static struct iommu ciommu;
30:
31: static void
32: iommu_invalidate(struct iommu_regs *iregs)
33: {
34: iregs->tlbflush = 0;
35: }
36:
37: /*
38: * XXX This is a problematic interface. We alloc _memory_ which is uncached.
39: * So if we ever reuse allocations somebody is going to get uncached pages.
40: * Returned address is always aligned by page.
41: * BTW, we were not going to give away anonymous storage, were we not?
42: */
43: void *
44: dvma_alloc(int size, unsigned int *pphys)
45: {
46: void *va;
47: unsigned int pa, ba;
48: unsigned int npages;
49: unsigned int mva, mpa;
50: unsigned int i;
51: unsigned int *iopte;
52: struct iommu *t = &ciommu;
53: int ret;
54:
55: npages = (size + (PAGE_SIZE-1)) / PAGE_SIZE;
56: ret = ofmem_posix_memalign(&va, npages * PAGE_SIZE, PAGE_SIZE);
57: if (ret != 0)
58: return NULL;
59:
60: ba = (unsigned int)mem_alloc(&cdvmem, npages * PAGE_SIZE, PAGE_SIZE);
61: if (ba == 0)
62: return NULL;
63:
64: pa = (unsigned int)va2pa((unsigned long)va);
65:
66: /*
67: * Change page attributes in MMU to uncached.
68: */
69: mva = (unsigned int) va;
70: mpa = (unsigned int) pa;
71: ofmem_arch_early_map_pages(mpa, mva, npages * PAGE_SIZE, ofmem_arch_io_translation_mode(mpa));
72:
73: /*
74: * Map into IOMMU page table.
75: */
76: mpa = (unsigned int) pa;
77: iopte = &t->page_table[(ba - t->plow) / PAGE_SIZE];
78: for (i = 0; i < npages; i++) {
79: *iopte++ = MKIOPTE(mpa);
80: mpa += PAGE_SIZE;
81: }
82:
83: *pphys = ba;
84:
85: return va;
86: }
87:
88: /*
89: * Initialize IOMMU
90: * This looks like initialization of CPU MMU but
91: * the routine is higher in food chain.
92: */
93: static struct iommu_regs *
94: iommu_init(struct iommu *t, uint64_t base)
95: {
96: unsigned int *ptab;
97: int ptsize;
98: #ifdef CONFIG_DEBUG_IOMMU
99: unsigned int impl, vers;
100: #endif
101: unsigned int tmp;
102: struct iommu_regs *regs;
103: int ret;
104: unsigned long vasize;
105:
106: regs = (struct iommu_regs *)ofmem_map_io(base, IOMMU_REGS);
107: if (regs == NULL) {
108: DPRINTF("Cannot map IOMMU\n");
109: for (;;) { }
110: }
111: t->regs = regs;
112: #ifdef CONFIG_DEBUG_IOMMU
113: impl = (regs->control & IOMMU_CTRL_IMPL) >> 28;
114: vers = (regs->control & IOMMU_CTRL_VERS) >> 24;
115: #endif
116:
117: tmp = regs->control;
118: tmp &= ~(IOMMU_CTRL_RNGE);
119:
120: tmp |= (IOMMU_RNGE_32MB | IOMMU_CTRL_ENAB);
121: t->plow = 0xfe000000; /* End - 32 MB */
122: /* Size of VA region that we manage */
123: vasize = 0x2000000; /* 32 MB */
124:
125: regs->control = tmp;
126: iommu_invalidate(regs);
127:
128: /* Allocate IOMMU page table */
129: /* Tremendous alignment causes great waste... */
130: ptsize = (vasize / PAGE_SIZE) * sizeof(int);
131: ret = ofmem_posix_memalign((void *)&ptab, ptsize, ptsize);
132: if (ret != 0) {
133: DPRINTF("Cannot allocate IOMMU table [0x%x]\n", ptsize);
134: for (;;) { }
135: }
136: t->page_table = ptab;
137:
138: /* flush_cache_all(); */
139: /** flush_tlb_all(); **/
140: tmp = (unsigned int)va2pa((unsigned long)ptab);
141: regs->base = tmp >> 4;
142: iommu_invalidate(regs);
143:
144: DPRINTF("IOMMU: impl %d vers %d page table at 0x%p (pa 0x%x) of size %d bytes\n",
145: impl, vers, t->page_table, tmp, ptsize);
146:
147: mem_init(&cdvmem, (char*)t->plow, (char *)0xfffff000);
148: return regs;
149: }
150:
151: void
152: ob_init_iommu(uint64_t base)
153: {
154: struct iommu_regs *regs;
155:
156: regs = iommu_init(&ciommu, base);
157:
158: push_str("/iommu");
159: fword("find-device");
160: PUSH((unsigned long)regs);
161: fword("encode-int");
162: push_str("address");
163: fword("property");
164:
165: PUSH(base >> 32);
166: fword("encode-int");
167: PUSH(base & 0xffffffff);
168: fword("encode-int");
169: fword("encode+");
170: PUSH(IOMMU_REGS);
171: fword("encode-int");
172: fword("encode+");
173: push_str("reg");
174: fword("property");
175: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.