|
|
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.