atari_dma_emul.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466
  1. /*
  2. * atari_dma_emul.c -- TT SCSI DMA emulator for the Hades.
  3. *
  4. * Copyright 1997 Wout Klaren <W.Klaren@inter.nl.net>
  5. *
  6. * This file is subject to the terms and conditions of the GNU General Public
  7. * License. See the file COPYING in the main directory of this archive
  8. * for more details.
  9. *
  10. * This code was written using the Hades TOS source code as a
  11. * reference. This source code can be found on the home page
  12. * of Medusa Computer Systems.
  13. *
  14. * Version 0.1, 1997-09-24.
  15. *
  16. * This code should be considered experimental. It has only been
  17. * tested on a Hades with a 68060. It might not work on a Hades
  18. * with a 68040. Make backups of your hard drives before using
  19. * this code.
  20. */
  21. #include <asm/uaccess.h>
  22. #define hades_dma_ctrl (*(unsigned char *) 0xffff8717)
  23. #define hades_psdm_reg (*(unsigned char *) 0xffff8741)
  24. #define TRANSFER_SIZE 16
  25. struct m68040_frame {
  26. unsigned long effaddr; /* effective address */
  27. unsigned short ssw; /* special status word */
  28. unsigned short wb3s; /* write back 3 status */
  29. unsigned short wb2s; /* write back 2 status */
  30. unsigned short wb1s; /* write back 1 status */
  31. unsigned long faddr; /* fault address */
  32. unsigned long wb3a; /* write back 3 address */
  33. unsigned long wb3d; /* write back 3 data */
  34. unsigned long wb2a; /* write back 2 address */
  35. unsigned long wb2d; /* write back 2 data */
  36. unsigned long wb1a; /* write back 1 address */
  37. unsigned long wb1dpd0; /* write back 1 data/push data 0*/
  38. unsigned long pd1; /* push data 1*/
  39. unsigned long pd2; /* push data 2*/
  40. unsigned long pd3; /* push data 3*/
  41. };
  42. static void writeback (unsigned short wbs, unsigned long wba,
  43. unsigned long wbd, void *old_buserr)
  44. {
  45. mm_segment_t fs = get_fs();
  46. static void *save_buserr;
  47. __asm__ __volatile__ ("movec.l %%vbr,%%a0\n\t"
  48. "move.l %0,8(%%a0)\n\t"
  49. :
  50. : "r" (&&bus_error)
  51. : "a0" );
  52. save_buserr = old_buserr;
  53. set_fs (MAKE_MM_SEG(wbs & WBTM_040));
  54. switch (wbs & WBSIZ_040) {
  55. case BA_SIZE_BYTE:
  56. put_user (wbd & 0xff, (char *)wba);
  57. break;
  58. case BA_SIZE_WORD:
  59. put_user (wbd & 0xffff, (short *)wba);
  60. break;
  61. case BA_SIZE_LONG:
  62. put_user (wbd, (int *)wba);
  63. break;
  64. }
  65. set_fs (fs);
  66. return;
  67. bus_error:
  68. __asm__ __volatile__ ("cmp.l %0,2(%%sp)\n\t"
  69. "bcs.s .jump_old\n\t"
  70. "cmp.l %1,2(%%sp)\n\t"
  71. "bls.s .restore_old\n"
  72. ".jump_old:\n\t"
  73. "move.l %2,-(%%sp)\n\t"
  74. "rts\n"
  75. ".restore_old:\n\t"
  76. "move.l %%a0,-(%%sp)\n\t"
  77. "movec.l %%vbr,%%a0\n\t"
  78. "move.l %2,8(%%a0)\n\t"
  79. "move.l (%%sp)+,%%a0\n\t"
  80. "rte\n\t"
  81. :
  82. : "i" (writeback), "i" (&&bus_error),
  83. "m" (save_buserr) );
  84. }
  85. /*
  86. * static inline void set_restdata_reg(unsigned char *cur_addr)
  87. *
  88. * Set the rest data register if necessary.
  89. */
  90. static inline void set_restdata_reg(unsigned char *cur_addr)
  91. {
  92. if (((long) cur_addr & ~3) != 0)
  93. tt_scsi_dma.dma_restdata =
  94. *((unsigned long *) ((long) cur_addr & ~3));
  95. }
  96. /*
  97. * void hades_dma_emulator(int irq, void *dummy, struct pt_regs *fp)
  98. *
  99. * This code emulates TT SCSI DMA on the Hades.
  100. *
  101. * Note the following:
  102. *
  103. * 1. When there is no byte available to read from the SCSI bus, or
  104. * when a byte cannot yet bet written to the SCSI bus, a bus
  105. * error occurs when reading or writing the pseudo DMA data
  106. * register (hades_psdm_reg). We have to catch this bus error
  107. * and try again to read or write the byte. If after several tries
  108. * we still get a bus error, the interrupt handler is left. When
  109. * the byte can be read or written, the interrupt handler is
  110. * called again.
  111. *
  112. * 2. The SCSI interrupt must be disabled in this interrupt handler.
  113. *
  114. * 3. If we set the EOP signal, the SCSI controller still expects one
  115. * byte to be read or written. Therefore the last byte is transferred
  116. * separately, after setting the EOP signal.
  117. *
  118. * 4. When this function is left, the address pointer (start_addr) is
  119. * converted to a physical address. Because it points one byte
  120. * further than the last transferred byte, it can point outside the
  121. * current page. If virt_to_phys() is called with this address we
  122. * might get an access error. Therefore virt_to_phys() is called with
  123. * start_addr - 1 if the count has reached zero. The result is
  124. * increased with one.
  125. */
  126. static irqreturn_t hades_dma_emulator(int irq, void *dummy, struct pt_regs *fp)
  127. {
  128. unsigned long dma_base;
  129. register unsigned long dma_cnt asm ("d3");
  130. static long save_buserr;
  131. register unsigned long save_sp asm ("d4");
  132. register int tries asm ("d5");
  133. register unsigned char *start_addr asm ("a3"), *end_addr asm ("a4");
  134. register unsigned char *eff_addr;
  135. register unsigned char *psdm_reg;
  136. unsigned long rem;
  137. atari_disable_irq(IRQ_TT_MFP_SCSI);
  138. /*
  139. * Read the dma address and count registers.
  140. */
  141. dma_base = SCSI_DMA_READ_P(dma_addr);
  142. dma_cnt = SCSI_DMA_READ_P(dma_cnt);
  143. /*
  144. * Check if DMA is still enabled.
  145. */
  146. if ((tt_scsi_dma.dma_ctrl & 2) == 0)
  147. {
  148. atari_enable_irq(IRQ_TT_MFP_SCSI);
  149. return IRQ_HANDLED;
  150. }
  151. if (dma_cnt == 0)
  152. {
  153. printk(KERN_NOTICE "DMA emulation: count is zero.\n");
  154. tt_scsi_dma.dma_ctrl &= 0xfd; /* DMA ready. */
  155. atari_enable_irq(IRQ_TT_MFP_SCSI);
  156. return IRQ_HANDLED;
  157. }
  158. /*
  159. * Install new bus error routine.
  160. */
  161. __asm__ __volatile__ ("movec.l %%vbr,%%a0\n\t"
  162. "move.l 8(%%a0),%0\n\t"
  163. "move.l %1,8(%%a0)\n\t"
  164. : "=&r" (save_buserr)
  165. : "r" (&&scsi_bus_error)
  166. : "a0" );
  167. hades_dma_ctrl &= 0xfc; /* Bus error and EOP off. */
  168. /*
  169. * Save the stack pointer.
  170. */
  171. __asm__ __volatile__ ("move.l %%sp,%0\n\t"
  172. : "=&r" (save_sp) );
  173. tries = 100; /* Maximum number of bus errors. */
  174. start_addr = phys_to_virt(dma_base);
  175. end_addr = start_addr + dma_cnt;
  176. scsi_loop:
  177. dma_cnt--;
  178. rem = dma_cnt & (TRANSFER_SIZE - 1);
  179. dma_cnt &= ~(TRANSFER_SIZE - 1);
  180. psdm_reg = &hades_psdm_reg;
  181. if (tt_scsi_dma.dma_ctrl & 1) /* Read or write? */
  182. {
  183. /*
  184. * SCSI write. Abort when count is zero.
  185. */
  186. switch (rem)
  187. {
  188. case 0:
  189. while (dma_cnt > 0)
  190. {
  191. dma_cnt -= TRANSFER_SIZE;
  192. *psdm_reg = *start_addr++;
  193. case 15:
  194. *psdm_reg = *start_addr++;
  195. case 14:
  196. *psdm_reg = *start_addr++;
  197. case 13:
  198. *psdm_reg = *start_addr++;
  199. case 12:
  200. *psdm_reg = *start_addr++;
  201. case 11:
  202. *psdm_reg = *start_addr++;
  203. case 10:
  204. *psdm_reg = *start_addr++;
  205. case 9:
  206. *psdm_reg = *start_addr++;
  207. case 8:
  208. *psdm_reg = *start_addr++;
  209. case 7:
  210. *psdm_reg = *start_addr++;
  211. case 6:
  212. *psdm_reg = *start_addr++;
  213. case 5:
  214. *psdm_reg = *start_addr++;
  215. case 4:
  216. *psdm_reg = *start_addr++;
  217. case 3:
  218. *psdm_reg = *start_addr++;
  219. case 2:
  220. *psdm_reg = *start_addr++;
  221. case 1:
  222. *psdm_reg = *start_addr++;
  223. }
  224. }
  225. hades_dma_ctrl |= 1; /* Set EOP. */
  226. udelay(10);
  227. *psdm_reg = *start_addr++; /* Dummy byte. */
  228. tt_scsi_dma.dma_ctrl &= 0xfd; /* DMA ready. */
  229. }
  230. else
  231. {
  232. /*
  233. * SCSI read. Abort when count is zero.
  234. */
  235. switch (rem)
  236. {
  237. case 0:
  238. while (dma_cnt > 0)
  239. {
  240. dma_cnt -= TRANSFER_SIZE;
  241. *start_addr++ = *psdm_reg;
  242. case 15:
  243. *start_addr++ = *psdm_reg;
  244. case 14:
  245. *start_addr++ = *psdm_reg;
  246. case 13:
  247. *start_addr++ = *psdm_reg;
  248. case 12:
  249. *start_addr++ = *psdm_reg;
  250. case 11:
  251. *start_addr++ = *psdm_reg;
  252. case 10:
  253. *start_addr++ = *psdm_reg;
  254. case 9:
  255. *start_addr++ = *psdm_reg;
  256. case 8:
  257. *start_addr++ = *psdm_reg;
  258. case 7:
  259. *start_addr++ = *psdm_reg;
  260. case 6:
  261. *start_addr++ = *psdm_reg;
  262. case 5:
  263. *start_addr++ = *psdm_reg;
  264. case 4:
  265. *start_addr++ = *psdm_reg;
  266. case 3:
  267. *start_addr++ = *psdm_reg;
  268. case 2:
  269. *start_addr++ = *psdm_reg;
  270. case 1:
  271. *start_addr++ = *psdm_reg;
  272. }
  273. }
  274. hades_dma_ctrl |= 1; /* Set EOP. */
  275. udelay(10);
  276. *start_addr++ = *psdm_reg;
  277. tt_scsi_dma.dma_ctrl &= 0xfd; /* DMA ready. */
  278. set_restdata_reg(start_addr);
  279. }
  280. if (start_addr != end_addr)
  281. printk(KERN_CRIT "DMA emulation: FATAL: Count is not zero at end of transfer.\n");
  282. dma_cnt = end_addr - start_addr;
  283. scsi_end:
  284. dma_base = (dma_cnt == 0) ? virt_to_phys(start_addr - 1) + 1 :
  285. virt_to_phys(start_addr);
  286. SCSI_DMA_WRITE_P(dma_addr, dma_base);
  287. SCSI_DMA_WRITE_P(dma_cnt, dma_cnt);
  288. /*
  289. * Restore old bus error routine.
  290. */
  291. __asm__ __volatile__ ("movec.l %%vbr,%%a0\n\t"
  292. "move.l %0,8(%%a0)\n\t"
  293. :
  294. : "r" (save_buserr)
  295. : "a0" );
  296. atari_enable_irq(IRQ_TT_MFP_SCSI);
  297. return IRQ_HANDLED;
  298. scsi_bus_error:
  299. /*
  300. * First check if the bus error is caused by our code.
  301. * If not, call the original handler.
  302. */
  303. __asm__ __volatile__ ("cmp.l %0,2(%%sp)\n\t"
  304. "bcs.s .old_vector\n\t"
  305. "cmp.l %1,2(%%sp)\n\t"
  306. "bls.s .scsi_buserr\n"
  307. ".old_vector:\n\t"
  308. "move.l %2,-(%%sp)\n\t"
  309. "rts\n"
  310. ".scsi_buserr:\n\t"
  311. :
  312. : "i" (&&scsi_loop), "i" (&&scsi_end),
  313. "m" (save_buserr) );
  314. if (CPU_IS_060)
  315. {
  316. /*
  317. * Get effective address and restore the stack.
  318. */
  319. __asm__ __volatile__ ("move.l 8(%%sp),%0\n\t"
  320. "move.l %1,%%sp\n\t"
  321. : "=a&" (eff_addr)
  322. : "r" (save_sp) );
  323. }
  324. else
  325. {
  326. register struct m68040_frame *frame;
  327. __asm__ __volatile__ ("lea 8(%%sp),%0\n\t"
  328. : "=a&" (frame) );
  329. if (tt_scsi_dma.dma_ctrl & 1)
  330. {
  331. /*
  332. * Bus error while writing.
  333. */
  334. if (frame->wb3s & WBV_040)
  335. {
  336. if (frame->wb3a == (long) &hades_psdm_reg)
  337. start_addr--;
  338. else
  339. writeback(frame->wb3s, frame->wb3a,
  340. frame->wb3d, &&scsi_bus_error);
  341. }
  342. if (frame->wb2s & WBV_040)
  343. {
  344. if (frame->wb2a == (long) &hades_psdm_reg)
  345. start_addr--;
  346. else
  347. writeback(frame->wb2s, frame->wb2a,
  348. frame->wb2d, &&scsi_bus_error);
  349. }
  350. if (frame->wb1s & WBV_040)
  351. {
  352. if (frame->wb1a == (long) &hades_psdm_reg)
  353. start_addr--;
  354. }
  355. }
  356. else
  357. {
  358. /*
  359. * Bus error while reading.
  360. */
  361. if (frame->wb3s & WBV_040)
  362. writeback(frame->wb3s, frame->wb3a,
  363. frame->wb3d, &&scsi_bus_error);
  364. }
  365. eff_addr = (unsigned char *) frame->faddr;
  366. __asm__ __volatile__ ("move.l %0,%%sp\n\t"
  367. :
  368. : "r" (save_sp) );
  369. }
  370. dma_cnt = end_addr - start_addr;
  371. if (eff_addr == &hades_psdm_reg)
  372. {
  373. /*
  374. * Bus error occurred while reading the pseudo
  375. * DMA register. Time out.
  376. */
  377. tries--;
  378. if (tries <= 0)
  379. {
  380. if ((tt_scsi_dma.dma_ctrl & 1) == 0) /* Read or write? */
  381. set_restdata_reg(start_addr);
  382. if (dma_cnt <= 1)
  383. printk(KERN_CRIT "DMA emulation: Fatal "
  384. "error while %s the last byte.\n",
  385. (tt_scsi_dma.dma_ctrl & 1)
  386. ? "writing" : "reading");
  387. goto scsi_end;
  388. }
  389. else
  390. goto scsi_loop;
  391. }
  392. else
  393. {
  394. /*
  395. * Bus error during pseudo DMA transfer.
  396. * Terminate the DMA transfer.
  397. */
  398. hades_dma_ctrl |= 3; /* Set EOP and bus error. */
  399. if ((tt_scsi_dma.dma_ctrl & 1) == 0) /* Read or write? */
  400. set_restdata_reg(start_addr);
  401. goto scsi_end;
  402. }
  403. }