xref: /openbmc/linux/arch/m68k/sun3x/dvma.c (revision 8f246087)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * Virtual DMA allocation
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  * (C) 1999 Thomas Bogendoerfer (tsbogend@alpha.franken.de)
61da177e4SLinus Torvalds  *
71da177e4SLinus Torvalds  * 11/26/2000 -- disabled the existing code because it didn't work for
81da177e4SLinus Torvalds  * me in 2.4.  Replaced with a significantly more primitive version
91da177e4SLinus Torvalds  * similar to the sun3 code.  the old functionality was probably more
101da177e4SLinus Torvalds  * desirable, but....   -- Sam Creasey (sammy@oh.verio.com)
111da177e4SLinus Torvalds  *
121da177e4SLinus Torvalds  */
131da177e4SLinus Torvalds 
141da177e4SLinus Torvalds #include <linux/kernel.h>
151da177e4SLinus Torvalds #include <linux/init.h>
161da177e4SLinus Torvalds #include <linux/bitops.h>
171da177e4SLinus Torvalds #include <linux/mm.h>
1857c8a661SMike Rapoport #include <linux/memblock.h>
191da177e4SLinus Torvalds #include <linux/vmalloc.h>
201da177e4SLinus Torvalds 
211da177e4SLinus Torvalds #include <asm/sun3x.h>
221da177e4SLinus Torvalds #include <asm/dvma.h>
231da177e4SLinus Torvalds #include <asm/io.h>
241da177e4SLinus Torvalds #include <asm/page.h>
25ca15ca40SMike Rapoport #include <asm/tlbflush.h>
261da177e4SLinus Torvalds 
271da177e4SLinus Torvalds /* IOMMU support */
281da177e4SLinus Torvalds 
291da177e4SLinus Torvalds #define IOMMU_ADDR_MASK            0x03ffe000
301da177e4SLinus Torvalds #define IOMMU_CACHE_INHIBIT        0x00000040
311da177e4SLinus Torvalds #define IOMMU_FULL_BLOCK           0x00000020
321da177e4SLinus Torvalds #define IOMMU_MODIFIED             0x00000010
331da177e4SLinus Torvalds #define IOMMU_USED                 0x00000008
341da177e4SLinus Torvalds #define IOMMU_WRITE_PROTECT        0x00000004
351da177e4SLinus Torvalds #define IOMMU_DT_MASK              0x00000003
361da177e4SLinus Torvalds #define IOMMU_DT_INVALID           0x00000000
371da177e4SLinus Torvalds #define IOMMU_DT_VALID             0x00000001
381da177e4SLinus Torvalds #define IOMMU_DT_BAD               0x00000002
391da177e4SLinus Torvalds 
401da177e4SLinus Torvalds 
411da177e4SLinus Torvalds static volatile unsigned long *iommu_pte = (unsigned long *)SUN3X_IOMMU;
421da177e4SLinus Torvalds 
431da177e4SLinus Torvalds 
441da177e4SLinus Torvalds #define dvma_entry_paddr(index)		(iommu_pte[index] & IOMMU_ADDR_MASK)
451da177e4SLinus Torvalds #define dvma_entry_vaddr(index,paddr)	((index << DVMA_PAGE_SHIFT) |  \
461da177e4SLinus Torvalds 					 (paddr & (DVMA_PAGE_SIZE-1)))
471da177e4SLinus Torvalds #if 0
481da177e4SLinus Torvalds #define dvma_entry_set(index,addr)	(iommu_pte[index] =            \
491da177e4SLinus Torvalds 					    (addr & IOMMU_ADDR_MASK) | \
501da177e4SLinus Torvalds 				             IOMMU_DT_VALID | IOMMU_CACHE_INHIBIT)
511da177e4SLinus Torvalds #else
521da177e4SLinus Torvalds #define dvma_entry_set(index,addr)	(iommu_pte[index] =            \
531da177e4SLinus Torvalds 					    (addr & IOMMU_ADDR_MASK) | \
541da177e4SLinus Torvalds 				             IOMMU_DT_VALID)
551da177e4SLinus Torvalds #endif
561da177e4SLinus Torvalds #define dvma_entry_clr(index)		(iommu_pte[index] = IOMMU_DT_INVALID)
571da177e4SLinus Torvalds #define dvma_entry_hash(addr)		((addr >> DVMA_PAGE_SHIFT) ^ \
581da177e4SLinus Torvalds 					 ((addr & 0x03c00000) >>     \
591da177e4SLinus Torvalds 						(DVMA_PAGE_SHIFT+4)))
601da177e4SLinus Torvalds 
611da177e4SLinus Torvalds #ifdef DEBUG
621da177e4SLinus Torvalds /* code to print out a dvma mapping for debugging purposes */
dvma_print(unsigned long dvma_addr)631da177e4SLinus Torvalds void dvma_print (unsigned long dvma_addr)
641da177e4SLinus Torvalds {
651da177e4SLinus Torvalds 
661da177e4SLinus Torvalds 	unsigned long index;
671da177e4SLinus Torvalds 
681da177e4SLinus Torvalds 	index = dvma_addr >> DVMA_PAGE_SHIFT;
691da177e4SLinus Torvalds 
704eee1e72SGeert Uytterhoeven 	pr_info("idx %lx dvma_addr %08lx paddr %08lx\n", index, dvma_addr,
711da177e4SLinus Torvalds 		dvma_entry_paddr(index));
721da177e4SLinus Torvalds }
731da177e4SLinus Torvalds #endif
741da177e4SLinus Torvalds 
751da177e4SLinus Torvalds 
761da177e4SLinus Torvalds /* create a virtual mapping for a page assigned within the IOMMU
771da177e4SLinus Torvalds    so that the cpu can reach it easily */
dvma_map_cpu(unsigned long kaddr,unsigned long vaddr,int len)781da177e4SLinus Torvalds inline int dvma_map_cpu(unsigned long kaddr,
791da177e4SLinus Torvalds 			       unsigned long vaddr, int len)
801da177e4SLinus Torvalds {
811da177e4SLinus Torvalds 	pgd_t *pgd;
8260e50f34SMike Rapoport 	p4d_t *p4d;
8360e50f34SMike Rapoport 	pud_t *pud;
841da177e4SLinus Torvalds 	unsigned long end;
851da177e4SLinus Torvalds 	int ret = 0;
861da177e4SLinus Torvalds 
871da177e4SLinus Torvalds 	kaddr &= PAGE_MASK;
881da177e4SLinus Torvalds 	vaddr &= PAGE_MASK;
891da177e4SLinus Torvalds 
901da177e4SLinus Torvalds 	end = PAGE_ALIGN(vaddr + len);
911da177e4SLinus Torvalds 
924eee1e72SGeert Uytterhoeven 	pr_debug("dvma: mapping kern %08lx to virt %08lx\n", kaddr, vaddr);
931da177e4SLinus Torvalds 	pgd = pgd_offset_k(vaddr);
9460e50f34SMike Rapoport 	p4d = p4d_offset(pgd, vaddr);
9560e50f34SMike Rapoport 	pud = pud_offset(p4d, vaddr);
961da177e4SLinus Torvalds 
971da177e4SLinus Torvalds 	do {
981da177e4SLinus Torvalds 		pmd_t *pmd;
991da177e4SLinus Torvalds 		unsigned long end2;
1001da177e4SLinus Torvalds 
10160e50f34SMike Rapoport 		if((pmd = pmd_alloc(&init_mm, pud, vaddr)) == NULL) {
1021da177e4SLinus Torvalds 			ret = -ENOMEM;
1031da177e4SLinus Torvalds 			goto out;
1041da177e4SLinus Torvalds 		}
1051da177e4SLinus Torvalds 
1061da177e4SLinus Torvalds 		if((end & PGDIR_MASK) > (vaddr & PGDIR_MASK))
1071da177e4SLinus Torvalds 			end2 = (vaddr + (PGDIR_SIZE-1)) & PGDIR_MASK;
1081da177e4SLinus Torvalds 		else
1091da177e4SLinus Torvalds 			end2 = end;
1101da177e4SLinus Torvalds 
1111da177e4SLinus Torvalds 		do {
1121da177e4SLinus Torvalds 			pte_t *pte;
1131da177e4SLinus Torvalds 			unsigned long end3;
1141da177e4SLinus Torvalds 
115872fec16SHugh Dickins 			if((pte = pte_alloc_kernel(pmd, vaddr)) == NULL) {
1161da177e4SLinus Torvalds 				ret = -ENOMEM;
1171da177e4SLinus Torvalds 				goto out;
1181da177e4SLinus Torvalds 			}
1191da177e4SLinus Torvalds 
1201da177e4SLinus Torvalds 			if((end2 & PMD_MASK) > (vaddr & PMD_MASK))
1211da177e4SLinus Torvalds 				end3 = (vaddr + (PMD_SIZE-1)) & PMD_MASK;
1221da177e4SLinus Torvalds 			else
1231da177e4SLinus Torvalds 				end3 = end2;
1241da177e4SLinus Torvalds 
1251da177e4SLinus Torvalds 			do {
1264eee1e72SGeert Uytterhoeven 				pr_debug("mapping %08lx phys to %08lx\n",
1271da177e4SLinus Torvalds 					 __pa(kaddr), vaddr);
128*8f246087SLinus Walleij 				set_pte(pte, pfn_pte(virt_to_pfn((void *)kaddr),
1291da177e4SLinus Torvalds 						     PAGE_KERNEL));
1301da177e4SLinus Torvalds 				pte++;
1311da177e4SLinus Torvalds 				kaddr += PAGE_SIZE;
1321da177e4SLinus Torvalds 				vaddr += PAGE_SIZE;
1331da177e4SLinus Torvalds 			} while(vaddr < end3);
1341da177e4SLinus Torvalds 
1351da177e4SLinus Torvalds 		} while(vaddr < end2);
1361da177e4SLinus Torvalds 
1371da177e4SLinus Torvalds 	} while(vaddr < end);
1381da177e4SLinus Torvalds 
1391da177e4SLinus Torvalds 	flush_tlb_all();
1401da177e4SLinus Torvalds 
1411da177e4SLinus Torvalds  out:
1421da177e4SLinus Torvalds 	return ret;
1431da177e4SLinus Torvalds }
1441da177e4SLinus Torvalds 
1451da177e4SLinus Torvalds 
dvma_map_iommu(unsigned long kaddr,unsigned long baddr,int len)1461da177e4SLinus Torvalds inline int dvma_map_iommu(unsigned long kaddr, unsigned long baddr,
1471da177e4SLinus Torvalds 				 int len)
1481da177e4SLinus Torvalds {
1491da177e4SLinus Torvalds 	unsigned long end, index;
1501da177e4SLinus Torvalds 
1511da177e4SLinus Torvalds 	index = baddr >> DVMA_PAGE_SHIFT;
1521da177e4SLinus Torvalds 	end = ((baddr+len) >> DVMA_PAGE_SHIFT);
1531da177e4SLinus Torvalds 
1541da177e4SLinus Torvalds 	if(len & ~DVMA_PAGE_MASK)
1551da177e4SLinus Torvalds 		end++;
1561da177e4SLinus Torvalds 
1571da177e4SLinus Torvalds 	for(; index < end ; index++) {
1581da177e4SLinus Torvalds //		if(dvma_entry_use(index))
1591da177e4SLinus Torvalds //			BUG();
1604eee1e72SGeert Uytterhoeven //		pr_info("mapping pa %lx to ba %lx\n", __pa(kaddr),
1614eee1e72SGeert Uytterhoeven //			index << DVMA_PAGE_SHIFT);
1621da177e4SLinus Torvalds 
1631da177e4SLinus Torvalds 		dvma_entry_set(index, __pa(kaddr));
1641da177e4SLinus Torvalds 
1651da177e4SLinus Torvalds 		iommu_pte[index] |= IOMMU_FULL_BLOCK;
1661da177e4SLinus Torvalds //		dvma_entry_inc(index);
1671da177e4SLinus Torvalds 
1681da177e4SLinus Torvalds 		kaddr += DVMA_PAGE_SIZE;
1691da177e4SLinus Torvalds 	}
1701da177e4SLinus Torvalds 
1711da177e4SLinus Torvalds #ifdef DEBUG
1721da177e4SLinus Torvalds 	for(index = (baddr >> DVMA_PAGE_SHIFT); index < end; index++)
1731da177e4SLinus Torvalds 		dvma_print(index << DVMA_PAGE_SHIFT);
1741da177e4SLinus Torvalds #endif
1751da177e4SLinus Torvalds 	return 0;
1761da177e4SLinus Torvalds 
1771da177e4SLinus Torvalds }
1781da177e4SLinus Torvalds 
dvma_unmap_iommu(unsigned long baddr,int len)1791da177e4SLinus Torvalds void dvma_unmap_iommu(unsigned long baddr, int len)
1801da177e4SLinus Torvalds {
1811da177e4SLinus Torvalds 
1821da177e4SLinus Torvalds 	int index, end;
1831da177e4SLinus Torvalds 
1841da177e4SLinus Torvalds 
1851da177e4SLinus Torvalds 	index = baddr >> DVMA_PAGE_SHIFT;
1861da177e4SLinus Torvalds 	end = (DVMA_PAGE_ALIGN(baddr+len) >> DVMA_PAGE_SHIFT);
1871da177e4SLinus Torvalds 
1881da177e4SLinus Torvalds 	for(; index < end ; index++) {
1894eee1e72SGeert Uytterhoeven 		pr_debug("freeing bus mapping %08x\n",
1904eee1e72SGeert Uytterhoeven 			 index << DVMA_PAGE_SHIFT);
1911da177e4SLinus Torvalds #if 0
1921da177e4SLinus Torvalds 		if(!dvma_entry_use(index))
1934eee1e72SGeert Uytterhoeven 			pr_info("dvma_unmap freeing unused entry %04x\n",
1941da177e4SLinus Torvalds 				index);
1951da177e4SLinus Torvalds 		else
1961da177e4SLinus Torvalds 			dvma_entry_dec(index);
1971da177e4SLinus Torvalds #endif
1981da177e4SLinus Torvalds 		dvma_entry_clr(index);
1991da177e4SLinus Torvalds 	}
2001da177e4SLinus Torvalds 
2011da177e4SLinus Torvalds }
202