atari_dma_emul.c 11 KB

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