Date: Wed, 5 Aug 1998 17:13:37 -0500
From: Chris Lawrence <quango@ix.netcom.com>
To: Linux/m68k Mailing List <linux-m68k@lists.linux-m68k.org>
Subject: L68K: Chip RAM support for A2091 DMA
Mail-Followup-To: Linux/m68k Mailing List <linux-m68k@lists.linux-m68k.org>
Organization: Kathie Lee's Sweatshops
X-Operating-System: Linux/m68k 2.1.108
Sender: owner-linux-m68k@phil.uni-sb.de

The following patch adds support for DMA to Chip RAM on the A2091 (and
A590); it's similar to the support that's already in the GVP Series II
driver.

It's relative to 2.1.106, but it applies cleanly to 2.1.108.

The main other changes are (a) I got rid of all the #if 0 scatter/gather
bits, and (b) it always uses the values in SCpnt, instead of doing an if()
test, since the wd33c93 driver fills in SCpnt whether or not it actually
uses scatter/gather.  I also changed the VTOP()s to virt_to_phys()s to
de-m68k-ify it somewhat.

It's tested somewhat and seems to work (but Zorro II DMA and my system don't
get along at all, so the testing is limited).


Chris
-- 
=============================================================================
|         Chris Lawrence        |               My home page:               |
|      <lawrencc@clark.net>     |    http://www.clark.net/pub/lawrencc/     |
|                               |                                           |
|    Amiga A4000 (060/PPC) &    |       Visit the Amiga Web Directory       |
|       Linux/m68k 2.1.108      |      http://www.cucug.org/amiga.html      |
=============================================================================

--- clean-linux-2.1.106/drivers/scsi/a2091.c	Sat May 30 21:31:51 1998
+++ linux-2.1.106/drivers/scsi/a2091.c	Thu Jun 25 23:21:06 1998
@@ -13,13 +13,14 @@
 #include <linux/zorro.h>
 #include <asm/irq.h>
 #include <asm/spinlock.h>
+#include <asm/io.h>
 
 #include "scsi.h"
 #include "hosts.h"
 #include "wd33c93.h"
 #include "a2091.h"
 
-#include<linux/stat.h>
+#include <linux/stat.h>
 
 struct proc_dir_entry proc_scsi_a2091 = {
     PROC_SCSI_A2091, 5, "A2091",
@@ -57,7 +58,7 @@
 static int dma_setup (Scsi_Cmnd *cmd, int dir_in)
 {
     unsigned short cntr = CNTR_PDMD | CNTR_INTEN;
-    unsigned long addr = VTOP(cmd->SCp.ptr);
+    unsigned long addr = virt_to_phys(cmd->SCp.ptr);
     struct Scsi_Host *instance = cmd->host;
 
     /* don't allow DMA if the physical address is bad */
@@ -68,39 +69,58 @@
 	    & ~0x1ff;
 	HDATA(instance)->dma_bounce_buffer =
 	    scsi_malloc (HDATA(instance)->dma_bounce_len);
+	HDATA(cmd->host)->dma_buffer_pool = BUF_SCSI_ALLOCED;
 	
-	/* can't allocate memory; use PIO */
 	if (!HDATA(instance)->dma_bounce_buffer) {
-	    HDATA(instance)->dma_bounce_len = 0;
-	    return 1;
+	    /* Fall back to chip RAM */
+	    HDATA(cmd->host)->dma_bounce_buffer =
+		amiga_chip_alloc(HDATA(cmd->host)->dma_bounce_len);
+
+	    if(!HDATA(cmd->host)->dma_bounce_buffer) {
+		/* can't allocate memory; use PIO */
+		HDATA(cmd->host)->dma_bounce_len = 0;
+		return 1;
+	    }
+
+	    HDATA(cmd->host)->dma_buffer_pool = BUF_CHIP_ALLOCED;
 	}
 
 	/* get the physical address of the bounce buffer */
-	addr = VTOP(HDATA(instance)->dma_bounce_buffer);
+	addr = virt_to_phys(HDATA(instance)->dma_bounce_buffer);
 
 	/* the bounce buffer may not be in the first 16M of physmem */
 	if (addr & A2091_XFER_MASK) {
-	    /* we could use chipmem... maybe later */
-	    scsi_free (HDATA(instance)->dma_bounce_buffer,
-		       HDATA(instance)->dma_bounce_len);
-	    HDATA(instance)->dma_bounce_buffer = NULL;
-	    HDATA(instance)->dma_bounce_len = 0;
-	    return 1;
+	    /* fall back to Chip RAM if address out of range */
+	    if( HDATA(cmd->host)->dma_buffer_pool == BUF_SCSI_ALLOCED)
+	    {
+		scsi_free (HDATA(cmd->host)->dma_bounce_buffer,
+			   HDATA(cmd->host)->dma_bounce_len);
+	    } else {
+		/* It was already in Chip RAM; we lose
+		 * Note that this is logically impossible...
+		 */
+		amiga_chip_free(HDATA(cmd->host)->dma_bounce_buffer);
+		HDATA(cmd->host)->dma_bounce_buffer = NULL;
+		HDATA(cmd->host)->dma_bounce_len = 0;
+		return 1;
+	    }
+	    
+	    HDATA(cmd->host)->dma_bounce_buffer =
+		amiga_chip_alloc(HDATA(cmd->host)->dma_bounce_len);
+
+	    if(!HDATA(cmd->host)->dma_bounce_buffer) {
+		HDATA(cmd->host)->dma_bounce_len = 0;
+		return 1;
+	    }
+
+	    addr = virt_to_phys(HDATA(cmd->host)->dma_bounce_buffer);
+	    HDATA(cmd->host)->dma_buffer_pool = BUF_CHIP_ALLOCED;
 	}
 
 	if (!dir_in) {
 	    /* copy to bounce buffer for a write */
-	    if (cmd->use_sg)
-#if 0
-		panic ("scsi%ddma: incomplete s/g support",
-		       instance->host_no);
-#else
-		memcpy (HDATA(instance)->dma_bounce_buffer,
-			cmd->SCp.ptr, cmd->SCp.this_residual);
-#endif
-	    else
-		memcpy (HDATA(instance)->dma_bounce_buffer,
-			cmd->request_buffer, cmd->request_bufflen);
+	    memcpy (HDATA(instance)->dma_bounce_buffer,
+		    cmd->SCp.ptr, cmd->SCp.this_residual);
 	}
     }
 
@@ -116,13 +136,13 @@
     /* setup DMA *physical* address */
     DMA(cmd->host)->ACR = addr;
 
-    if (dir_in){
+    if (dir_in) {
 	/* invalidate any cache */
 	cache_clear (addr, cmd->SCp.this_residual);
-    }else{
+    } else {
 	/* push any dirty cache */
 	cache_push (addr, cmd->SCp.this_residual);
-      }
+    }
     /* start DMA */
     DMA(cmd->host)->ST_DMA = 1;
 
@@ -160,32 +180,23 @@
 
     /* copy from a bounce buffer, if necessary */
     if (status && HDATA(instance)->dma_bounce_buffer) {
-	if (SCpnt && SCpnt->use_sg) {
-#if 0
-	    panic ("scsi%d: incomplete s/g support",
-		   instance->host_no);
-#else
-	    if( HDATA(instance)->dma_dir )
-		memcpy (SCpnt->SCp.ptr, 
-			HDATA(instance)->dma_bounce_buffer,
-			SCpnt->SCp.this_residual);
-	    scsi_free (HDATA(instance)->dma_bounce_buffer,
-		       HDATA(instance)->dma_bounce_len);
-	    HDATA(instance)->dma_bounce_buffer = NULL;
-	    HDATA(instance)->dma_bounce_len = 0;
-	    
-#endif
-	} else {
-	    if (HDATA(instance)->dma_dir && SCpnt)
-		memcpy (SCpnt->request_buffer,
-			HDATA(instance)->dma_bounce_buffer,
-			SCpnt->request_bufflen);
-
+	if( HDATA(instance)->dma_dir && SCpnt ) {
+	    /* Clear cache again, for good measure */
+	    cache_clear( virt_to_phys(HDATA(instance)->dma_bounce_buffer),
+			 SCpnt->SCp.this_residual);
+	    memcpy (SCpnt->SCp.ptr, 
+		    HDATA(instance)->dma_bounce_buffer,
+		    SCpnt->SCp.this_residual);
+	}
+	
+	if (HDATA(instance)->dma_buffer_pool == BUF_SCSI_ALLOCED)
 	    scsi_free (HDATA(instance)->dma_bounce_buffer,
 		       HDATA(instance)->dma_bounce_len);
-	    HDATA(instance)->dma_bounce_buffer = NULL;
-	    HDATA(instance)->dma_bounce_len = 0;
-	}
+	else
+	    amiga_chip_free(HDATA(instance)->dma_bounce_buffer);
+	
+	HDATA(instance)->dma_bounce_buffer = NULL;
+	HDATA(instance)->dma_bounce_len = 0;
     }
 }
 
