io-unit.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:9k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /* $Id: io-unit.c,v 1.23 2001/02/13 01:16:43 davem Exp $
  2.  * io-unit.c:  IO-UNIT specific routines for memory management.
  3.  *
  4.  * Copyright (C) 1997,1998 Jakub Jelinek    (jj@sunsite.mff.cuni.cz)
  5.  */
  6.  
  7. #include <linux/config.h>
  8. #include <linux/kernel.h>
  9. #include <linux/init.h>
  10. #include <linux/slab.h>
  11. #include <linux/spinlock.h>
  12. #include <asm/scatterlist.h>
  13. #include <asm/pgalloc.h>
  14. #include <asm/pgtable.h>
  15. #include <asm/sbus.h>
  16. #include <asm/io.h>
  17. #include <asm/io-unit.h>
  18. #include <asm/mxcc.h>
  19. #include <asm/bitops.h>
  20. /* #define IOUNIT_DEBUG */
  21. #ifdef IOUNIT_DEBUG
  22. #define IOD(x) printk(x)
  23. #else
  24. #define IOD(x) do { } while (0)
  25. #endif
  26. #define IOPERM        (IOUPTE_CACHE | IOUPTE_WRITE | IOUPTE_VALID)
  27. #define MKIOPTE(phys) __iopte((((phys)>>4) & IOUPTE_PAGE) | IOPERM)
  28. void __init
  29. iounit_init(int sbi_node, int io_node, struct sbus_bus *sbus)
  30. {
  31. iopte_t *xpt, *xptend;
  32. struct iounit_struct *iounit;
  33. struct linux_prom_registers iommu_promregs[PROMREG_MAX];
  34. struct resource r;
  35. iounit = kmalloc(sizeof(struct iounit_struct), GFP_ATOMIC);
  36. memset(iounit, 0, sizeof(*iounit));
  37. iounit->limit[0] = IOUNIT_BMAP1_START;
  38. iounit->limit[1] = IOUNIT_BMAP2_START;
  39. iounit->limit[2] = IOUNIT_BMAPM_START;
  40. iounit->limit[3] = IOUNIT_BMAPM_END;
  41. iounit->rotor[1] = IOUNIT_BMAP2_START;
  42. iounit->rotor[2] = IOUNIT_BMAPM_START;
  43. prom_getproperty(sbi_node, "reg", (void *) iommu_promregs,
  44.  sizeof(iommu_promregs));
  45. prom_apply_generic_ranges(io_node, 0, iommu_promregs, 3);
  46. memset(&r, 0, sizeof(r));
  47. r.flags = iommu_promregs[2].which_io;
  48. r.start = iommu_promregs[2].phys_addr;
  49. xpt = (iopte_t *) sbus_ioremap(&r, 0, PAGE_SIZE * 16, "XPT");
  50. if(!xpt) panic("Cannot map External Page Table.");
  51. sbus->iommu = (struct iommu_struct *)iounit;
  52. iounit->page_table = xpt;
  53. for (xptend = iounit->page_table + (16 * PAGE_SIZE) / sizeof(iopte_t);
  54.      xpt < xptend;)
  55.       *xpt++ = 0;
  56. }
  57. /* One has to hold iounit->lock to call this */
  58. static unsigned long iounit_get_area(struct iounit_struct *iounit, unsigned long vaddr, int size)
  59. {
  60. int i, j, k, npages;
  61. unsigned long rotor, scan, limit;
  62. iopte_t iopte;
  63.         npages = ((vaddr & ~PAGE_MASK) + size + (PAGE_SIZE-1)) >> PAGE_SHIFT;
  64. /* A tiny bit of magic ingredience :) */
  65. switch (npages) {
  66. case 1: i = 0x0231; break;
  67. case 2: i = 0x0132; break;
  68. default: i = 0x0213; break;
  69. }
  70. IOD(("iounit_get_area(%08lx,%d[%d])=", vaddr, size, npages));
  71. next: j = (i & 15);
  72. rotor = iounit->rotor[j - 1];
  73. limit = iounit->limit[j];
  74. scan = rotor;
  75. nexti: scan = find_next_zero_bit(iounit->bmap, limit, scan);
  76. if (scan + npages > limit) {
  77. if (limit != rotor) {
  78. limit = rotor;
  79. scan = iounit->limit[j - 1];
  80. goto nexti;
  81. }
  82. i >>= 4;
  83. if (!(i & 15))
  84. panic("iounit_get_area: Couldn't find free iopte slots for (%08lx,%d)n", vaddr, size);
  85. goto next;
  86. }
  87. for (k = 1, scan++; k < npages; k++)
  88. if (test_bit(scan++, iounit->bmap))
  89. goto nexti;
  90. iounit->rotor[j - 1] = (scan < limit) ? scan : iounit->limit[j - 1];
  91. scan -= npages;
  92. iopte = MKIOPTE(__pa(vaddr & PAGE_MASK));
  93. vaddr = IOUNIT_DMA_BASE + (scan << PAGE_SHIFT) + (vaddr & ~PAGE_MASK);
  94. for (k = 0; k < npages; k++, iopte = __iopte(iopte_val(iopte) + 0x100), scan++) {
  95. set_bit(scan, iounit->bmap);
  96. iounit->page_table[scan] = iopte;
  97. }
  98. IOD(("%08lxn", vaddr));
  99. return vaddr;
  100. }
  101. static __u32 iounit_get_scsi_one(char *vaddr, unsigned long len, struct sbus_bus *sbus)
  102. {
  103. unsigned long ret, flags;
  104. struct iounit_struct *iounit = (struct iounit_struct *)sbus->iommu;
  105. spin_lock_irqsave(&iounit->lock, flags);
  106. ret = iounit_get_area(iounit, (unsigned long)vaddr, len);
  107. spin_unlock_irqrestore(&iounit->lock, flags);
  108. return ret;
  109. }
  110. static void iounit_get_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
  111. {
  112. unsigned long flags;
  113. struct iounit_struct *iounit = (struct iounit_struct *)sbus->iommu;
  114. /* FIXME: Cache some resolved pages - often several sg entries are to the same page */
  115. spin_lock_irqsave(&iounit->lock, flags);
  116. while (sz != 0) {
  117. sz--;
  118. sg[sz].dvma_address = iounit_get_area(iounit, (unsigned long)sg[sz].address, sg[sz].length);
  119. sg[sz].dvma_length = sg[sz].length;
  120. }
  121. spin_unlock_irqrestore(&iounit->lock, flags);
  122. }
  123. static void iounit_release_scsi_one(__u32 vaddr, unsigned long len, struct sbus_bus *sbus)
  124. {
  125. unsigned long flags;
  126. struct iounit_struct *iounit = (struct iounit_struct *)sbus->iommu;
  127. spin_lock_irqsave(&iounit->lock, flags);
  128. len = ((vaddr & ~PAGE_MASK) + len + (PAGE_SIZE-1)) >> PAGE_SHIFT;
  129. vaddr = (vaddr - IOUNIT_DMA_BASE) >> PAGE_SHIFT;
  130. IOD(("iounit_release %08lx-%08lxn", (long)vaddr, (long)len+vaddr));
  131. for (len += vaddr; vaddr < len; vaddr++)
  132. clear_bit(vaddr, iounit->bmap);
  133. spin_unlock_irqrestore(&iounit->lock, flags);
  134. }
  135. static void iounit_release_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
  136. {
  137. unsigned long flags;
  138. unsigned long vaddr, len;
  139. struct iounit_struct *iounit = (struct iounit_struct *)sbus->iommu;
  140. spin_lock_irqsave(&iounit->lock, flags);
  141. while (sz != 0) {
  142. --sz;
  143. len = ((sg[sz].dvma_address & ~PAGE_MASK) + sg[sz].length + (PAGE_SIZE-1)) >> PAGE_SHIFT;
  144. vaddr = (sg[sz].dvma_address - IOUNIT_DMA_BASE) >> PAGE_SHIFT;
  145. IOD(("iounit_release %08lx-%08lxn", (long)vaddr, (long)len+vaddr));
  146. for (len += vaddr; vaddr < len; vaddr++)
  147. clear_bit(vaddr, iounit->bmap);
  148. }
  149. spin_unlock_irqrestore(&iounit->lock, flags);
  150. }
  151. #ifdef CONFIG_SBUS
  152. static void iounit_map_dma_area(unsigned long va, __u32 addr, int len)
  153. {
  154. unsigned long page, end;
  155. pgprot_t dvma_prot;
  156. iopte_t *iopte;
  157. struct sbus_bus *sbus;
  158. dvma_prot = __pgprot(SRMMU_CACHE | SRMMU_ET_PTE | SRMMU_PRIV);
  159. end = PAGE_ALIGN((addr + len));
  160. while(addr < end) {
  161. page = va;
  162. {
  163. pgd_t *pgdp;
  164. pmd_t *pmdp;
  165. pte_t *ptep;
  166. long i;
  167. pgdp = pgd_offset(init_task.mm, addr);
  168. pmdp = pmd_offset(pgdp, addr);
  169. ptep = pte_offset(pmdp, addr);
  170. set_pte(ptep, pte_val(mk_pte(virt_to_page(page), dvma_prot)));
  171. i = ((addr - IOUNIT_DMA_BASE) >> PAGE_SHIFT);
  172. for_each_sbus(sbus) {
  173. struct iounit_struct *iounit = (struct iounit_struct *)sbus->iommu;
  174. iopte = (iopte_t *)(iounit->page_table + i);
  175. *iopte = __iopte(MKIOPTE(__pa(page)));
  176. }
  177. }
  178. addr += PAGE_SIZE;
  179. va += PAGE_SIZE;
  180. }
  181. flush_cache_all();
  182. flush_tlb_all();
  183. }
  184. static void iounit_unmap_dma_area(unsigned long addr, int len)
  185. {
  186. /* XXX Somebody please fill this in */
  187. }
  188. /* XXX We do not pass sbus device here, bad. */
  189. static unsigned long iounit_translate_dvma(unsigned long addr)
  190. {
  191. struct sbus_bus *sbus = sbus_root; /* They are all the same */
  192. struct iounit_struct *iounit = (struct iounit_struct *)sbus->iommu;
  193. int i;
  194. iopte_t *iopte;
  195. i = ((addr - IOUNIT_DMA_BASE) >> PAGE_SHIFT);
  196. iopte = (iopte_t *)(iounit->page_table + i);
  197. return (iopte_val(*iopte) & 0xFFFFFFF0) << 4; /* XXX sun4d guru, help */
  198. }
  199. #endif
  200. static char *iounit_lockarea(char *vaddr, unsigned long len)
  201. {
  202. /* FIXME: Write this */
  203. return vaddr;
  204. }
  205. static void iounit_unlockarea(char *vaddr, unsigned long len)
  206. {
  207. /* FIXME: Write this */
  208. }
  209. void __init ld_mmu_iounit(void)
  210. {
  211. BTFIXUPSET_CALL(mmu_lockarea, iounit_lockarea, BTFIXUPCALL_RETO0);
  212. BTFIXUPSET_CALL(mmu_unlockarea, iounit_unlockarea, BTFIXUPCALL_NOP);
  213. BTFIXUPSET_CALL(mmu_get_scsi_one, iounit_get_scsi_one, BTFIXUPCALL_NORM);
  214. BTFIXUPSET_CALL(mmu_get_scsi_sgl, iounit_get_scsi_sgl, BTFIXUPCALL_NORM);
  215. BTFIXUPSET_CALL(mmu_release_scsi_one, iounit_release_scsi_one, BTFIXUPCALL_NORM);
  216. BTFIXUPSET_CALL(mmu_release_scsi_sgl, iounit_release_scsi_sgl, BTFIXUPCALL_NORM);
  217. #ifdef CONFIG_SBUS
  218. BTFIXUPSET_CALL(mmu_map_dma_area, iounit_map_dma_area, BTFIXUPCALL_NORM);
  219. BTFIXUPSET_CALL(mmu_unmap_dma_area, iounit_unmap_dma_area, BTFIXUPCALL_NORM);
  220. BTFIXUPSET_CALL(mmu_translate_dvma, iounit_translate_dvma, BTFIXUPCALL_NORM);
  221. #endif
  222. }
  223. __u32 iounit_map_dma_init(struct sbus_bus *sbus, int size)
  224. {
  225. int i, j, k, npages;
  226. unsigned long rotor, scan, limit;
  227. unsigned long flags;
  228. __u32 ret;
  229. struct iounit_struct *iounit = (struct iounit_struct *)sbus->iommu;
  230.         npages = (size + (PAGE_SIZE-1)) >> PAGE_SHIFT;
  231. i = 0x0213;
  232. spin_lock_irqsave(&iounit->lock, flags);
  233. next: j = (i & 15);
  234. rotor = iounit->rotor[j - 1];
  235. limit = iounit->limit[j];
  236. scan = rotor;
  237. nexti: scan = find_next_zero_bit(iounit->bmap, limit, scan);
  238. if (scan + npages > limit) {
  239. if (limit != rotor) {
  240. limit = rotor;
  241. scan = iounit->limit[j - 1];
  242. goto nexti;
  243. }
  244. i >>= 4;
  245. if (!(i & 15))
  246. panic("iounit_map_dma_init: Couldn't find free iopte slots for %d bytesn", size);
  247. goto next;
  248. }
  249. for (k = 1, scan++; k < npages; k++)
  250. if (test_bit(scan++, iounit->bmap))
  251. goto nexti;
  252. iounit->rotor[j - 1] = (scan < limit) ? scan : iounit->limit[j - 1];
  253. scan -= npages;
  254. ret = IOUNIT_DMA_BASE + (scan << PAGE_SHIFT);
  255. for (k = 0; k < npages; k++, scan++)
  256. set_bit(scan, iounit->bmap);
  257. spin_unlock_irqrestore(&iounit->lock, flags);
  258. return ret;
  259. }
  260. __u32 iounit_map_dma_page(__u32 vaddr, void *addr, struct sbus_bus *sbus)
  261. {
  262. int scan = (vaddr - IOUNIT_DMA_BASE) >> PAGE_SHIFT;
  263. struct iounit_struct *iounit = (struct iounit_struct *)sbus->iommu;
  264. iounit->page_table[scan] = MKIOPTE(__pa(((unsigned long)addr) & PAGE_MASK));
  265. return vaddr + (((unsigned long)addr) & ~PAGE_MASK);
  266. }