dma.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. #include "u.h"
  2. #include "../port/lib.h"
  3. #include "mem.h"
  4. #include "dat.h"
  5. #include "fns.h"
  6. #include "io.h"
  7. typedef struct DMAport DMAport;
  8. typedef struct DMA DMA;
  9. typedef struct DMAxfer DMAxfer;
  10. /*
  11. * state of a dma transfer
  12. */
  13. struct DMAxfer
  14. {
  15. ulong bpa; /* bounce buffer physical address */
  16. void* bva; /* bounce buffer virtual address */
  17. int blen; /* bounce buffer length */
  18. void* va; /* virtual address destination/src */
  19. long len; /* bytes to be transferred */
  20. int isread;
  21. };
  22. /*
  23. * the dma controllers. the first half of this structure specifies
  24. * the I/O ports used by the DMA controllers.
  25. */
  26. struct DMAport
  27. {
  28. uchar addr[4]; /* current address (4 channels) */
  29. uchar count[4]; /* current count (4 channels) */
  30. uchar page[4]; /* page registers (4 channels) */
  31. uchar cmd; /* command status register */
  32. uchar req; /* request registers */
  33. uchar sbm; /* single bit mask register */
  34. uchar mode; /* mode register */
  35. uchar cbp; /* clear byte pointer */
  36. uchar mc; /* master clear */
  37. uchar cmask; /* clear mask register */
  38. uchar wam; /* write all mask register bit */
  39. };
  40. struct DMA
  41. {
  42. DMAport;
  43. int shift;
  44. Lock;
  45. DMAxfer x[4];
  46. };
  47. DMA dma[2] = {
  48. { 0x00, 0x02, 0x04, 0x06,
  49. 0x01, 0x03, 0x05, 0x07,
  50. 0x87, 0x83, 0x81, 0x82,
  51. 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
  52. 0 },
  53. { 0xc0, 0xc4, 0xc8, 0xcc,
  54. 0xc2, 0xc6, 0xca, 0xce,
  55. 0x8f, 0x8b, 0x89, 0x8a,
  56. 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde,
  57. 1 },
  58. };
  59. static void
  60. dmastatus(DMA *dp, int chan, char c)
  61. {
  62. int a, l, s;
  63. ilock(dp);
  64. outb(dp->cbp, 0);
  65. a = inb(dp->addr[chan]);
  66. a |= inb(dp->addr[chan])<<8;
  67. a |= inb(dp->page[chan])<<16;
  68. a |= inb(0x400|dp->page[chan])<<24;
  69. outb(dp->cbp, 0);
  70. l = inb(dp->count[chan]);
  71. l |= inb(dp->count[chan])<<8;
  72. s = inb(dp->cmd);
  73. iunlock(dp);
  74. print("%c: addr %uX len %uX stat %uX\n", c, a, l, s);
  75. }
  76. /*
  77. * DMA must be in the first 16MB. This gets called early by the
  78. * initialisation routines of any devices which require DMA to ensure
  79. * the allocated bounce buffers are below the 16MB limit.
  80. */
  81. int
  82. dmainit(int chan, int maxtransfer)
  83. {
  84. DMA *dp;
  85. DMAxfer *xp;
  86. static int once;
  87. if(once == 0){
  88. if(ioalloc(0x00, 0x10, 0, "dma") < 0
  89. || ioalloc(0x80, 0x10, 0, "dma") < 0
  90. || ioalloc(0xd0, 0x10, 0, "dma") < 0)
  91. panic("dmainit");
  92. outb(dma[0].mc, 0);
  93. outb(dma[1].mc, 0);
  94. outb(dma[0].cmask, 0);
  95. outb(dma[1].cmask, 0);
  96. outb(dma[1].mode, 0xC0);
  97. once = 1;
  98. }
  99. if(maxtransfer > 64*1024)
  100. maxtransfer = 64*1024;
  101. dp = &dma[(chan>>2)&1];
  102. chan = chan & 3;
  103. xp = &dp->x[chan];
  104. if(xp->bva != nil){
  105. if(xp->blen < maxtransfer)
  106. return 1;
  107. return 0;
  108. }
  109. //dmastatus(dp, chan, 'I');
  110. xp->bva = xspanalloc(maxtransfer, BY2PG, 64*1024);
  111. if(xp->bva == nil)
  112. return 1;
  113. xp->bpa = PADDR(xp->bva);
  114. if(xp->bpa >= 16*MB){
  115. /*
  116. * This will panic with the current
  117. * implementation of xspanalloc().
  118. xfree(xp->bva);
  119. */
  120. xp->bva = nil;
  121. return 1;
  122. }
  123. xp->blen = maxtransfer;
  124. xp->len = 0;
  125. xp->isread = 0;
  126. return 0;
  127. }
  128. void
  129. xdmastatus(int chan)
  130. {
  131. DMA *dp;
  132. dp = &dma[(chan>>2)&1];
  133. chan = chan & 3;
  134. dmastatus(dp, chan, 'X');
  135. }
  136. /*
  137. * setup a dma transfer. if the destination is not in kernel
  138. * memory, allocate a page for the transfer.
  139. *
  140. * we assume BIOS has set up the command register before we
  141. * are booted.
  142. *
  143. * return the updated transfer length (we can't transfer across 64k
  144. * boundaries)
  145. */
  146. long
  147. dmasetup(int chan, void *va, long len, int isread)
  148. {
  149. DMA *dp;
  150. ulong pa;
  151. uchar mode;
  152. DMAxfer *xp;
  153. dp = &dma[(chan>>2)&1];
  154. chan = chan & 3;
  155. xp = &dp->x[chan];
  156. //print("va%lux+", va);
  157. #define tryPCI
  158. #ifndef PCIWADDR
  159. #define PCIWADDR(va) PADDR(va)
  160. #endif /* PCIWADDR */
  161. #ifdef notdef
  162. /*
  163. * if this isn't kernel memory or crossing 64k boundary or above 16 meg
  164. * use the bounce buffer.
  165. */
  166. pa = PADDR(va);
  167. if((((ulong)va)&0xF0000000) != KZERO
  168. || (pa&0xFFFF0000) != ((pa+len)&0xFFFF0000)
  169. || pa >= 16*MB) {
  170. if(xp->bva == nil)
  171. return -1;
  172. if(len > xp->blen)
  173. len = xp->blen;
  174. if(!isread)
  175. memmove(xp->bva, va, len);
  176. xp->va = va;
  177. xp->len = len;
  178. xp->isread = isread;
  179. pa = xp->bpa;
  180. }
  181. else
  182. xp->len = 0;
  183. #endif /* notdef */
  184. #ifdef tryISA
  185. pa = ISAWADDR(va);
  186. #endif /* tryISA */
  187. #ifdef tryPCI
  188. pa = PCIWADDR(va);
  189. if((((ulong)va)&0xF0000000) != KZERO){
  190. if(xp->bva == nil)
  191. return -1;
  192. if(len > xp->blen)
  193. len = xp->blen;
  194. if(!isread)
  195. memmove(xp->bva, va, len);
  196. xp->va = va;
  197. xp->len = len;
  198. xp->isread = isread;
  199. pa = PCIWADDR(xp->bva);
  200. }
  201. else
  202. xp->len = 0;
  203. #endif /* tryPCI */
  204. /*
  205. * this setup must be atomic
  206. */
  207. mode = (isread ? 0x44 : 0x48) | chan;
  208. ilock(dp);
  209. outb(dp->cbp, 0); /* set count & address to their first byte */
  210. outb(dp->mode, mode); /* single mode dma (give CPU a chance at mem) */
  211. outb(dp->addr[chan], pa>>dp->shift); /* set address */
  212. outb(dp->addr[chan], pa>>(8+dp->shift));
  213. outb(dp->page[chan], pa>>16);
  214. #ifdef tryPCI
  215. outb(0x400|dp->page[chan], pa>>24);
  216. #endif /* tryPCI */
  217. outb(dp->cbp, 0); /* set count & address to their first byte */
  218. outb(dp->count[chan], (len>>dp->shift)-1); /* set count */
  219. outb(dp->count[chan], ((len>>dp->shift)-1)>>8);
  220. outb(dp->sbm, chan); /* enable the channel */
  221. iunlock(dp);
  222. //dmastatus(dp, chan, 'S');
  223. return len;
  224. }
  225. int
  226. dmadone(int chan)
  227. {
  228. DMA *dp;
  229. dp = &dma[(chan>>2)&1];
  230. chan = chan & 3;
  231. return inb(dp->cmd) & (1<<chan);
  232. }
  233. /*
  234. * this must be called after a dma has been completed.
  235. *
  236. * if a page has been allocated for the dma,
  237. * copy the data into the actual destination
  238. * and free the page.
  239. */
  240. void
  241. dmaend(int chan)
  242. {
  243. DMA *dp;
  244. DMAxfer *xp;
  245. dp = &dma[(chan>>2)&1];
  246. chan = chan & 3;
  247. //dmastatus(dp, chan, 'E');
  248. /*
  249. * disable the channel
  250. */
  251. ilock(dp);
  252. outb(dp->sbm, 4|chan);
  253. iunlock(dp);
  254. xp = &dp->x[chan];
  255. if(xp->len == 0 || !xp->isread)
  256. return;
  257. /*
  258. * copy out of temporary page
  259. */
  260. memmove(xp->va, xp->bva, xp->len);
  261. xp->len = 0;
  262. }
  263. /*
  264. int
  265. dmacount(int chan)
  266. {
  267. int retval;
  268. DMA *dp;
  269. dp = &dma[(chan>>2)&1];
  270. outb(dp->cbp, 0);
  271. retval = inb(dp->count[chan]);
  272. retval |= inb(dp->count[chan]) << 8;
  273. return((retval<<dp->shift)+1);
  274. }
  275. */