home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #18 / NN_1992_18.iso / spool / comp / unix / bsd / 4364 < prev    next >
Encoding:
Internet Message Format  |  1992-08-18  |  8.7 KB

  1. Path: sparky!uunet!sun-barr!cs.utexas.edu!zaphod.mps.ohio-state.edu!uwm.edu!bionet!ucselx!crash!fpm
  2. From: fpm@crash.cts.com (Frank Maclachlan)
  3. Newsgroups: comp.unix.bsd
  4. Subject: Bugs in DMA code (w/ patch)
  5. Summary: Bugs in DMA code fixed
  6. Keywords: DMA, patch
  7. Message-ID: <1992Aug18.142737.16819@crash>
  8. Date: 18 Aug 92 21:27:36 GMT
  9. Followup-To: comp.unix.bsd
  10. Organization: CTS Network Services (crash, ctsnet), El Cajon, CA
  11. Lines: 298
  12.  
  13. I found a few problems in '/usr/src/sys.386bsd/i386/isa/isa.c'.
  14.  
  15. At line 389 in isa_dmarangecheck(), the automatic variable priorpage
  16. is used without being initially set to 0.  This causes the function
  17. to flag special handling for virtually all DMA transfer requests.
  18. Also, no check is made for DMA requests crossing DMA page boundaries
  19. (64k for DMA chans 0..3, 128k for DMA chans 4..7).  This problem is
  20. masked by priorpage not being initialized - almost all DMA is done
  21. to/from safe 'bounce' buffers which don't cross DMA page boundaries
  22. and the data are block moved from/to the user's buffer.
  23.  
  24. In line 359, nbytes is doubled by shifting it left 1 bit; it
  25. should instead be divided by 2 by shifting right 1 bit position.
  26. This occurs when any of the word mode DMA channels (4..7) is used.
  27.  
  28. The following patch fixes the above problems and makes some cosmetic
  29. changes to isa_dmacascade() and isa_dmastart():
  30.  
  31.  
  32. *** isa.c.ORIG    Tue Jul 14 12:25:24 1992
  33. --- isa.c    Tue Aug 18 14:12:49 1992
  34. ***************
  35. *** 39,44 ****
  36. --- 39,50 ----
  37.   
  38.   /*
  39.    * code to manage AT bus
  40. +  *
  41. +  * 92/08/18  Frank P. MacLachlan (fpm@crash.cts.com):
  42. +  * Fixed uninitialized variable problem and added code to deal
  43. +  * with DMA page boundaries in isa_dmarangecheck().  Fixed word
  44. +  * mode DMA count compution and reorganized DMA setup code in
  45. +  * isa_dmastart()
  46.    */
  47.   
  48.   #include "param.h"
  49. ***************
  50. *** 58,63 ****
  51. --- 64,85 ----
  52.   #include "i386/isa/ic/i8237.h"
  53.   #include "i386/isa/ic/i8042.h"
  54.   
  55. + /*
  56. + **  Register definitions for DMA controller 1 (channels 0..3):
  57. + */
  58. + #define    DMA1_CHN(c)    (IO_DMA1 + 1*(2*(c)))    /* addr reg for channel c */
  59. + #define    DMA1_SMSK    (IO_DMA1 + 1*10)    /* single mask register */
  60. + #define    DMA1_MODE    (IO_DMA1 + 1*11)    /* mode register */
  61. + #define    DMA1_FFC    (IO_DMA1 + 1*12)    /* clear first/last FF */
  62. + /*
  63. + **  Register definitions for DMA controller 2 (channels 4..7):
  64. + */
  65. + #define    DMA2_CHN(c)    (IO_DMA1 + 2*(2*(c)))    /* addr reg for channel c */
  66. + #define    DMA2_SMSK    (IO_DMA2 + 2*10)    /* single mask register */
  67. + #define    DMA2_MODE    (IO_DMA2 + 2*11)    /* mode register */
  68. + #define    DMA2_FFC    (IO_DMA2 + 2*12)    /* clear first/last FF */
  69.   int config_isadev(struct isa_device *, u_short *);
  70.   #ifdef notyet
  71.   struct rlist *isa_iomem;
  72. ***************
  73. *** 278,298 ****
  74.    * external dma control by a board.
  75.    */
  76.   void isa_dmacascade(unsigned chan)
  77. ! {    int modeport;
  78.       if (chan > 7)
  79.           panic("isa_dmacascade: impossible request"); 
  80.   
  81.       /* set dma channel mode, and set dma channel mode */
  82. !     if ((chan & 4) == 0)
  83. !         modeport = IO_DMA1 + 0xb;
  84. !     else
  85. !         modeport = IO_DMA2 + 0x16;
  86. !     outb(modeport, DMA37MD_CASCADE | (chan & 3));
  87. !     if ((chan & 4) == 0)
  88. !         outb(modeport - 1, chan & 3);
  89. !     else
  90. !         outb(modeport - 2, chan & 3);
  91.   }
  92.   
  93.   /*
  94. --- 300,317 ----
  95.    * external dma control by a board.
  96.    */
  97.   void isa_dmacascade(unsigned chan)
  98. ! {
  99.       if (chan > 7)
  100.           panic("isa_dmacascade: impossible request"); 
  101.   
  102.       /* set dma channel mode, and set dma channel mode */
  103. !     if ((chan & 4) == 0) {
  104. !         outb(DMA1_MODE, DMA37MD_CASCADE | chan);
  105. !         outb(DMA1_SMSK, chan);
  106. !     } else {
  107. !         outb(DMA2_MODE, DMA37MD_CASCADE | (chan & 3));
  108. !         outb(DMA2_SMSK, chan & 3);
  109. !     }
  110.   }
  111.   
  112.   /*
  113. ***************
  114. *** 301,313 ****
  115.    */
  116.   void isa_dmastart(int flags, caddr_t addr, unsigned nbytes, unsigned chan)
  117.   {    vm_offset_t phys;
  118. !     int modeport, waport, mskport;
  119.       caddr_t newaddr;
  120.   
  121. !     if (chan > 7 || nbytes > (1<<16))
  122.           panic("isa_dmastart: impossible request"); 
  123.   
  124. !     if (isa_dmarangecheck(addr, nbytes)) {
  125.           if (dma_bounce[chan] == 0)
  126.               dma_bounce[chan] =
  127.                   /*(caddr_t)malloc(MAXDMASZ, M_TEMP, M_WAITOK);*/
  128. --- 320,334 ----
  129.    */
  130.   void isa_dmastart(int flags, caddr_t addr, unsigned nbytes, unsigned chan)
  131.   {    vm_offset_t phys;
  132. !     int waport;
  133.       caddr_t newaddr;
  134.   
  135. !     if (    chan > 7
  136. !         || (chan < 4 && nbytes > (1<<16))
  137. !         || (chan >= 4 && (nbytes > (1<<17) || (u_int)addr & 1)))
  138.           panic("isa_dmastart: impossible request"); 
  139.   
  140. !     if (isa_dmarangecheck(addr, nbytes, chan)) {
  141.           if (dma_bounce[chan] == 0)
  142.               dma_bounce[chan] =
  143.                   /*(caddr_t)malloc(MAXDMASZ, M_TEMP, M_WAITOK);*/
  144. ***************
  145. *** 325,372 ****
  146.       /* translate to physical */
  147.       phys = pmap_extract(pmap_kernel(), (vm_offset_t)addr);
  148.   
  149. -     /* set dma channel mode, and reset address ff */
  150. -     if ((chan & 4) == 0)
  151. -         modeport = IO_DMA1 + 0xb;
  152. -     else
  153. -         modeport = IO_DMA2 + 0x16;
  154. -     if (flags & B_READ)
  155. -         outb(modeport, DMA37MD_SINGLE|DMA37MD_WRITE|(chan&3));
  156. -     else
  157. -         outb(modeport, DMA37MD_SINGLE|DMA37MD_READ|(chan&3));
  158. -     if ((chan & 4) == 0)
  159. -         outb(modeport + 1, 0);
  160. -     else
  161. -         outb(modeport + 2, 0);
  162. -     /* send start address */
  163.       if ((chan & 4) == 0) {
  164. !         waport =  IO_DMA1 + (chan<<1);
  165.           outb(waport, phys);
  166.           outb(waport, phys>>8);
  167. !     } else {
  168. !         waport =  IO_DMA2 + ((chan - 4)<<2);
  169. !         outb(waport, phys>>1);
  170. !         outb(waport, phys>>9);
  171. !     }
  172. !     outb(dmapageport[chan], phys>>16);
  173.   
  174. !     /* send count */
  175. !     if ((chan & 4) == 0) {
  176.           outb(waport + 1, --nbytes);
  177.           outb(waport + 1, nbytes>>8);
  178.       } else {
  179. !         nbytes <<= 1;
  180.           outb(waport + 2, --nbytes);
  181.           outb(waport + 2, nbytes>>8);
  182. -     }
  183.   
  184. !     /* unmask channel */
  185. !     if ((chan & 4) == 0)
  186. !         mskport =  IO_DMA1 + 0x0a;
  187. !     else
  188. !         mskport =  IO_DMA2 + 0x14;
  189. !     outb(mskport, chan & 3);
  190.   }
  191.   
  192.   void isa_dmadone(int flags, caddr_t addr, int nbytes, int chan)
  193. --- 346,401 ----
  194.       /* translate to physical */
  195.       phys = pmap_extract(pmap_kernel(), (vm_offset_t)addr);
  196.   
  197.       if ((chan & 4) == 0) {
  198. !         /*
  199. !          * Program one of DMA channels 0..3.  These are
  200. !          * byte mode channels.
  201. !          */
  202. !         /* set dma channel mode, and reset address ff */
  203. !         if (flags & B_READ)
  204. !             outb(DMA1_MODE, DMA37MD_SINGLE|DMA37MD_WRITE|chan);
  205. !         else
  206. !             outb(DMA1_MODE, DMA37MD_SINGLE|DMA37MD_READ|chan);
  207. !         outb(DMA1_FFC, 0);
  208. !         /* send start address */
  209. !         waport =  DMA1_CHN(chan);
  210.           outb(waport, phys);
  211.           outb(waport, phys>>8);
  212. !         outb(dmapageport[chan], phys>>16);
  213.   
  214. !         /* send count */
  215.           outb(waport + 1, --nbytes);
  216.           outb(waport + 1, nbytes>>8);
  217. +         /* unmask channel */
  218. +         outb(DMA1_SMSK, chan);
  219.       } else {
  220. !         /*
  221. !          * Program one of DMA channels 4..7.  These are
  222. !          * word mode channels.
  223. !          */
  224. !         /* set dma channel mode, and reset address ff */
  225. !         if (flags & B_READ)
  226. !             outb(DMA2_MODE, DMA37MD_SINGLE|DMA37MD_WRITE|(chan&3));
  227. !         else
  228. !             outb(DMA2_MODE, DMA37MD_SINGLE|DMA37MD_READ|(chan&3));
  229. !         outb(DMA2_FFC, 0);
  230. !         /* send start address */
  231. !         waport = DMA2_CHN(chan - 4);
  232. !         outb(waport, phys>>1);
  233. !         outb(waport, phys>>9);
  234. !         outb(dmapageport[chan], phys>>16);
  235. !         /* send count */
  236. !         nbytes >>= 1;
  237.           outb(waport + 2, --nbytes);
  238.           outb(waport + 2, nbytes>>8);
  239.   
  240. !         /* unmask channel */
  241. !         outb(DMA2_SMSK, chan & 3);
  242. !     }
  243.   }
  244.   
  245.   void isa_dmadone(int flags, caddr_t addr, int nbytes, int chan)
  246. ***************
  247. *** 382,393 ****
  248.   
  249.   /*
  250.    * Check for problems with the address range of a DMA transfer
  251. !  * (non-contiguous physical pages, outside of bus address space).
  252.    * Return true if special handling needed.
  253.    */
  254.   
  255. ! isa_dmarangecheck(caddr_t va, unsigned length) {
  256. !     vm_offset_t phys, priorpage, endva;
  257.   
  258.       endva = (vm_offset_t)round_page(va + length);
  259.       for (; va < (caddr_t) endva ; va += NBPG) {
  260. --- 411,424 ----
  261.   
  262.   /*
  263.    * Check for problems with the address range of a DMA transfer
  264. !  * (non-contiguous physical pages, outside of bus address space,
  265. !  * crossing DMA page boundaries).
  266.    * Return true if special handling needed.
  267.    */
  268.   
  269. ! isa_dmarangecheck(caddr_t va, unsigned length, unsigned chan) {
  270. !     vm_offset_t phys, priorpage = 0, endva;
  271. !     u_int dma_pgmsk = (chan & 4) ?  ~(128*1024-1) : ~(64*1024-1);
  272.   
  273.       endva = (vm_offset_t)round_page(va + length);
  274.       for (; va < (caddr_t) endva ; va += NBPG) {
  275. ***************
  276. *** 397,404 ****
  277.               panic("isa_dmacheck: no physical page present");
  278.           if (phys > ISARAM_END) 
  279.               return (1);
  280. !         if (priorpage && priorpage + NBPG != phys)
  281. !             return (1);
  282.           priorpage = phys;
  283.       }
  284.       return (0);
  285. --- 428,440 ----
  286.               panic("isa_dmacheck: no physical page present");
  287.           if (phys > ISARAM_END) 
  288.               return (1);
  289. !         if (priorpage) {
  290. !             if (priorpage + NBPG != phys)
  291. !                 return (1);
  292. !             /* check if crossing a DMA page boundary */
  293. !             if (((u_int)priorpage ^ (u_int)phys) & dma_pgmsk)
  294. !                 return (1);
  295. !         }
  296.           priorpage = phys;
  297.       }
  298.       return (0);
  299. --
  300. UUCP: {hplabs!hp-sdd ucsd nosc}!crash!fpm
  301. ARPA: crash!fpm@nosc.mil
  302. INET: fpm@crash.cts.com
  303.