linux-ide.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* PATCH 2.6.20 11/14; CRIS architecture update - IDE driver
@ 2007-04-22 19:26 Mikael Starvik
  2007-04-23 12:45 ` Sergei Shtylyov
  0 siblings, 1 reply; 2+ messages in thread
From: Mikael Starvik @ 2007-04-22 19:26 UTC (permalink / raw)
  To: linux-kernel, linux-ide; +Cc: akpm

[-- Attachment #1: Type: text/plain, Size: 144 bytes --]

The attached patch updates the CRIS IDE driver.
 
Signed-off-by: Mikael Starvik <starvik@axis.com <mailto:starvik@axis.com> >
 
/Mikael
 

[-- Attachment #2: cris11_ide.patch --]
[-- Type: application/octet-stream, Size: 13966 bytes --]

diff -urNP --exclude='*.cvsignore' ../linux/drivers/ide/cris/ide-cris.c linux-2.6/drivers/ide/cris/ide-cris.c
--- ../linux/drivers/ide/cris/ide-cris.c	2007-02-04 19:44:54.000000000 +0100
+++ linux-2.6/drivers/ide/cris/ide-cris.c	2006-12-06 14:17:02.000000000 +0100
@@ -1,8 +1,8 @@
-/* $Id: cris-ide-driver.patch,v 1.1 2005/06/29 21:39:07 akpm Exp $
+/* $Id: ide-cris.c,v 1.10 2006/12/06 13:17:02 starvik Exp $
  *
  * Etrax specific IDE functions, like init and PIO-mode setting etc.
  * Almost the entire ide.c is used for the rest of the Etrax ATA driver.
- * Copyright (c) 2000-2005 Axis Communications AB
+ * Copyright (c) 2000-2006 Axis Communications AB
  *
  * Authors:    Bjorn Wesen        (initial version)
  *             Mikael Starvik     (crisv32 port)
@@ -43,8 +43,8 @@
 
 #define IDE_REGISTER_TIMEOUT 300
 
-#define LOWDB(x)
-#define D(x)
+#define LOWDB(x) 
+#define D(x) 
 
 enum /* Transfer types */
 {
@@ -88,12 +88,50 @@
 #define ATA_PIO0_STROBE 39
 #define ATA_PIO0_HOLD    9
 
-int
+/*
+ * On ETRAX FS, an interrupt remains latched and active until ack:ed.
+ * Further, ATA acks are without effect as long as INTRQ is asserted, as the
+ * corresponding ATA interrupt is continuously set to active.  There will be a
+ * clearing ack at the usual cris_ide_ack_intr call, but that serves just to
+ * gracefully handle an actual spurious interrupt or similar situation (which
+ * will cause an early return without further actions, see the ide_intr
+ * function).
+ *
+ * However, the normal case at time of this writing is that nothing has
+ * changed from when INTRQ was asserted until the cris_ide_ack_intr call; no
+ * ATA registers written and no status register read, so INTRQ will *remain*
+ * asserted, thus *another* interrupt will be latched, and will be seen as a
+ * spurious interrupt after the "real" interrupt is serviced.  With lots of
+ * ATA traffic (as in a trivial file-copy between two drives), this will trig
+ * the condition desc->irqs_unhandled > 99900 in
+ * kernel/irq/spurious.c:note_interrupt and the system will halt.
+ *
+ * To actually get rid of the interrupt corresponding to the current INTRQ
+ * assertion, we make a second ack after the next ATA register read or write;
+ * i.e. when INTRQ must be deasserted.  At that time, we don't have the hwif
+ * pointer available, so we need to stash a local copy (safe, because it'll be
+ * set and cleared within the same spin_lock_irqsave region).  The pointer
+ * serves doubly as a boolean flag that an ack is needed.  The caller must
+ * NULL the pointer after the "second ack".
+ */
+
+static ide_hwif_t *hwif_to_ack;
+
+static int
 cris_ide_ack_intr(ide_hwif_t* hwif)
 {
-	reg_ata_rw_ctrl2 ctrl2 = REG_TYPE_CONV(reg_ata_rw_ctrl2,
+	/*
+	 * The interrupt is shared so we need to find the interface bit number
+	 * to ack.  We define the ATA I/O register addresses to have the
+	 * format of ata rw_ctrl2 register contents, conveniently holding this
+	 * number.
+	 */
+	reg_ata_rw_ctrl2 ctrl2 = REG_TYPE_CONV(reg_ata_rw_ctrl2, 
 	                         int, hwif->io_ports[0]);
 	REG_WR_INT(ata, regi_ata, rw_ack_intr, 1 << ctrl2.sel);
+
+	/* Prepare to ack again, see above. */
+	hwif_to_ack = hwif;
 	return 1;
 }
 
@@ -122,8 +160,24 @@
 
 static void
 cris_ide_write_command(unsigned long command)
-{
+{	
 	REG_WR_INT(ata, regi_ata, rw_ctrl2, command); /* write data to the drive's register */
+
+	/*
+	 * Perform a pending ack if needed; see hwif_ack definition.  Perhaps
+	 * we should check closer that this call is really a part of the
+	 * preparation to read the ATA status register or write to the ATA
+	 * command register (causing deassert of INTRQ; see the ATA standard),
+	 * but at time of this writing (and expected to sanely remain so), the
+	 * first ATA register activity after an cris_ide_ack_intr call is
+	 * certain to do exactly that.
+	 */
+	if (hwif_to_ack) {
+		/* The drive may take this long to deassert INTRQ. */
+		ndelay(400);
+		cris_ide_ack_intr(hwif_to_ack);
+		hwif_to_ack = NULL;
+	}
 }
 
 static void
@@ -160,8 +214,8 @@
 {
 	reg_ata_rw_ctrl2 ctrl2 = {0};
 	ctrl2.addr = addr;
-	ctrl2.cs1 = cs1;
-	ctrl2.cs0 = cs0;
+	ctrl2.cs1 = !cs1;
+	ctrl2.cs0 = !cs0;
 	return REG_TYPE_CONV(int, reg_ata_rw_ctrl2, ctrl2);
 }
 
@@ -184,14 +238,14 @@
 
 	intr_mask.bus0 = regk_ata_yes;
 	intr_mask.bus1 = regk_ata_yes;
-	intr_mask.bus2 = regk_ata_yes;
+	intr_mask.bus2 = regk_ata_yes;		
 	intr_mask.bus3 = regk_ata_yes;
 
 	REG_WR(ata, regi_ata, rw_intr_mask, intr_mask);
 
 	crisv32_request_dma(2, "ETRAX FS built-in ATA", DMA_VERBOSE_ON_ERROR, 0, dma_ata);
 	crisv32_request_dma(3, "ETRAX FS built-in ATA", DMA_VERBOSE_ON_ERROR, 0, dma_ata);
-
+        
 	crisv32_pinmux_alloc_fixed(pinmux_ata);
 	crisv32_pinmux_alloc_fixed(pinmux_ata0);
 	crisv32_pinmux_alloc_fixed(pinmux_ata1);
@@ -204,14 +258,15 @@
 	DMA_ENABLE(regi_dma3);
 
 	DMA_WR_CMD (regi_dma2, regk_dma_set_w_size2);
-	DMA_WR_CMD (regi_dma3, regk_dma_set_w_size2);
+	DMA_WR_CMD (regi_dma3, regk_dma_set_w_size2);	
 }
 
 static dma_descr_context mycontext __attribute__ ((__aligned__(32)));
 
 #define cris_dma_descr_type dma_descr_data
-#define cris_pio_read regk_ata_rd
-#define cris_ultra_mask 0x7
+#define cris_pio_read (regk_ata_rd << 24)
+#define cris_ultra_mask 0x0 /* 0x7 for UDMA */
+#define IRQ ATA_INTR_VECT
 #define MAX_DESCR_SIZE 0xffffffffUL
 
 static unsigned long
@@ -226,6 +281,8 @@
 	d->buf = (char*)virt_to_phys(buf);
 	d->after = d->buf + len;
 	d->eol = last;
+	/* assume descriptors are consecutively placed in memory */
+	d->next = last ? 0 : (cris_dma_descr_type*)virt_to_phys(d+1);
 }
 
 static void
@@ -237,8 +294,10 @@
 	mycontext.saved_data = (dma_descr_data*)virt_to_phys(d);
 	mycontext.saved_data_buf = d->buf;
 	/* start the dma channel */
+	if (dir)
+		flush_dma_context(&mycontext); // Cache bug workaround   
 	DMA_START_CONTEXT(dir ? regi_dma3 : regi_dma2, virt_to_phys(&mycontext));
-
+	
 	/* initiate a multi word dma read using PIO handshaking */
 	trf_cnt.cnt = len >> 1;
 	/* Due to a "feature" the transfer count has to be one extra word for UDMA. */
@@ -248,7 +307,7 @@
 
 	ctrl2.rw = dir ? regk_ata_rd : regk_ata_wr;
 	ctrl2.trf_mode = regk_ata_dma;
-	ctrl2.hsh = type == TYPE_PIO ? regk_ata_pio :
+	ctrl2.hsh = type == TYPE_PIO ? regk_ata_pio : 
 	            type == TYPE_DMA ? regk_ata_dma : regk_ata_udma;
 	ctrl2.multi = regk_ata_yes;
 	ctrl2.dma_size = regk_ata_word;
@@ -339,7 +398,7 @@
 #define ATA_PIO0_STROBE 19
 #define ATA_PIO0_HOLD    4
 
-int
+int 
 cris_ide_ack_intr(ide_hwif_t* hwif)
 {
 	return 1;
@@ -348,13 +407,13 @@
 static inline int
 cris_ide_busy(void)
 {
-	return *R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy) ;
+	return *R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy) ; 
 }
 
 static inline int
 cris_ide_ready(void)
 {
-	return *R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, tr_rdy) ;
+	return *R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, tr_rdy) ; 
 }
 
 static inline int
@@ -364,12 +423,12 @@
 	*data = (unsigned short)status;
 	return status & IO_MASK(R_ATA_STATUS_DATA, dav);
 }
-
+	
 static void
 cris_ide_write_command(unsigned long command)
 {
-	*R_ATA_CTRL_DATA = command;
-}
+	*R_ATA_CTRL_DATA = command; 
+}		
 
 static void
 cris_ide_set_speed(int type, int setup, int strobe, int hold)
@@ -406,8 +465,8 @@
 cris_ide_reg_addr(unsigned long addr, int cs0, int cs1)
 {
 	return IO_FIELD(R_ATA_CTRL_DATA, addr, addr) |
-	       IO_FIELD(R_ATA_CTRL_DATA, cs0, cs0) |
-	       IO_FIELD(R_ATA_CTRL_DATA, cs1, cs1);
+	       IO_FIELD(R_ATA_CTRL_DATA, cs0, cs0 ? 0 : 1) |
+	       IO_FIELD(R_ATA_CTRL_DATA, cs1, cs1 ? 0 : 1);
 }
 
 static __init void
@@ -484,6 +543,7 @@
 #define cris_dma_descr_type etrax_dma_descr
 #define cris_pio_read IO_STATE(R_ATA_CTRL_DATA, rw, read)
 #define cris_ultra_mask 0x0
+#define IRQ 4
 #define MAX_DESCR_SIZE 0x10000UL
 
 static unsigned long
@@ -497,8 +557,8 @@
 {
 	d->buf = virt_to_phys(buf);
 	d->sw_len = len == MAX_DESCR_SIZE ? 0 : len;
-	if (last)
-		d->ctrl |= d_eol;
+	d->ctrl = last ? d_eol : 0;
+	d->next = last ? 0 : virt_to_phys(d+1); /* assumes descr's in array */
 }
 
 static void cris_ide_start_dma(ide_drive_t *drive, cris_dma_descr_type *d, int dir, int type, int len)
@@ -521,14 +581,14 @@
 		*R_DMA_CH2_FIRST = virt_to_phys(d);
 		*R_DMA_CH2_CMD   = IO_STATE(R_DMA_CH2_CMD, cmd, start);
 	}
-
+	
 	/* initiate a multi word dma read using DMA handshaking */
 
 	*R_ATA_TRANSFER_CNT =
 		IO_FIELD(R_ATA_TRANSFER_CNT, count, len >> 1);
 
 	cmd = dir ? IO_STATE(R_ATA_CTRL_DATA, rw, read) : IO_STATE(R_ATA_CTRL_DATA, rw, write);
-	cmd |= type == TYPE_PIO ? IO_STATE(R_ATA_CTRL_DATA, handsh, pio) :
+	cmd |= type == TYPE_PIO ? IO_STATE(R_ATA_CTRL_DATA, handsh, pio) : 
 	                          IO_STATE(R_ATA_CTRL_DATA, handsh, dma);
 	*R_ATA_CTRL_DATA =
 		cmd |
@@ -570,7 +630,7 @@
 }
 
 #endif
-
+		
 void
 cris_ide_outw(unsigned short data, unsigned long reg) {
 	int timeleft;
@@ -597,7 +657,7 @@
 	if(!timeleft)
 		printk("ATA timeout reg 0x%lx := 0x%x\n", reg, data);
 
-	cris_ide_write_command(reg|data); /* write data to the drive's register */
+	cris_ide_write_command(reg|data); /* write data to the drive's register */ 
 
 	timeleft = IDE_REGISTER_TIMEOUT;
 	/* wait for transmitter ready */
@@ -684,13 +744,15 @@
 static void cris_atapi_output_bytes(ide_drive_t *drive, void *, unsigned int);
 static int cris_dma_off (ide_drive_t *drive);
 static int cris_dma_on (ide_drive_t *drive);
+static int cris_dma_host_off (ide_drive_t *drive);
+static int cris_dma_host_on (ide_drive_t *drive);
 
 static void tune_cris_ide(ide_drive_t *drive, u8 pio)
 {
 	int setup, strobe, hold;
 
 	switch(pio)
-	{
+	{	
 		case 0:
 			setup = ATA_PIO0_SETUP;
 			strobe = ATA_PIO0_STROBE;
@@ -715,7 +777,7 @@
 			setup = ATA_PIO4_SETUP;
 			strobe = ATA_PIO4_STROBE;
 			hold = ATA_PIO4_HOLD;
-			break;
+			break;    
 		default:
 			return;
 	}
@@ -733,7 +795,7 @@
 	}
 
 	switch(speed)
-	{
+	{	
 		case XFER_UDMA_0:
 			cyc = ATA_UDMA0_CYC;
 			dvs = ATA_UDMA0_DVS;
@@ -765,7 +827,7 @@
 	if (speed >= XFER_UDMA_0)
 		cris_ide_set_speed(TYPE_UDMA, cyc, dvs, 0);
 	else
-		cris_ide_set_speed(TYPE_DMA, 0, strobe, hold);
+		cris_ide_set_speed(TYPE_DMA, 0, strobe, hold);	
 
 	return 0;
 }
@@ -790,11 +852,13 @@
 
 	for(h = 0; h < MAX_HWIFS; h++) {
 		ide_hwif_t *hwif = &ide_hwifs[h];
-		ide_setup_ports(&hw, cris_ide_base_address(h),
+		memset(&hw, 0, sizeof(hw));
+		ide_setup_ports(&hw, cris_ide_base_address(h), 
 		                ide_offsets,
 		                0, 0, cris_ide_ack_intr,
-		                ide_default_irq(0));
+		                IRQ);
 		ide_register_hw(&hw, &hwif);
+		hwif->irq = IRQ;
 		hwif->mmio = 2;
 		hwif->chipset = ide_etrax100;
 		hwif->tuneproc = &tune_cris_ide;
@@ -814,13 +878,15 @@
 		hwif->OUTBSYNC = &cris_ide_outbsync;
 		hwif->INB = &cris_ide_inb;
 		hwif->INW = &cris_ide_inw;
-		hwif->ide_dma_host_off = &cris_dma_off;
-		hwif->ide_dma_host_on = &cris_dma_on;
+		hwif->ide_dma_host_off = &cris_dma_host_off;
+		hwif->ide_dma_host_on = &cris_dma_host_on;
 		hwif->ide_dma_off_quietly = &cris_dma_off;
+		hwif->ide_dma_on = &cris_dma_on;
 		hwif->udma_four = 0;
 		hwif->ultra_mask = cris_ultra_mask;
 		hwif->mwdma_mask = 0x07; /* Multiword DMA 0-2 */
 		hwif->swdma_mask = 0x07; /* Singleword DMA 0-2 */
+		hwif->rqsize = 256;
 	}
 
 	/* Reset pulse */
@@ -835,13 +901,25 @@
 	cris_ide_set_speed(TYPE_UDMA, ATA_UDMA2_CYC, ATA_UDMA2_DVS, 0);
 }
 
+static int cris_dma_host_off (ide_drive_t *drive)
+{
+	return 0;
+}
+
+static int cris_dma_host_on (ide_drive_t *drive)
+{
+	return 0;
+}
+
 static int cris_dma_off (ide_drive_t *drive)
 {
+	drive->using_dma = 0;
 	return 0;
 }
 
 static int cris_dma_on (ide_drive_t *drive)
 {
+	drive->using_dma = 1;
 	return 0;
 }
 
@@ -958,30 +1036,28 @@
 			size += sg_dma_len(sg);
 		}
 
-		/* did we run out of descriptors? */
-
-		if(count >= MAX_DMA_DESCRS) {
-			printk("%s: too few DMA descriptors\n", drive->name);
-			return 1;
-		}
-
-		/* however, this case is more difficult - rw_trf_cnt cannot be more
-		   than 65536 words per transfer, so in that case we need to either
+		/* rw_trf_cnt cannot be more than 131072 words per transfer, 
+		   (- 1 word for UDMA CRC) so in that case we need to either:
 		   1) use a DMA interrupt to re-trigger rw_trf_cnt and continue with
 		      the descriptors, or
 		   2) simply do the request here, and get dma_intr to only ide_end_request on
 		      those blocks that were actually set-up for transfer.
+		      (The ide framework will issue a new request for the remainder)
 		*/
 
-		if(ata_tot_size + size > 131072) {
+		if(ata_tot_size + size > 262140) {
 			printk("too large total ATA DMA request, %d + %d!\n", ata_tot_size, (int)size);
 			return 1;
 		}
 
-		/* If size > MAX_DESCR_SIZE it has to be splitted into new descriptors. Since we
-                   don't handle size > 131072 only one split is necessary */
+		/* If size > MAX_DESCR_SIZE it has to be splitted into new descriptors. */
 
-		if(size > MAX_DESCR_SIZE) {
+		while (size > MAX_DESCR_SIZE) {
+			/* did we run out of descriptors? */
+			if(count >= MAX_DMA_DESCRS) {
+				printk("%s: too few DMA descriptors\n", drive->name);
+				return 1;
+			}
 			cris_ide_fill_descriptor(&ata_descrs[count], (void*)addr, MAX_DESCR_SIZE, 0);
 			count++;
 			ata_tot_size += MAX_DESCR_SIZE;
@@ -989,6 +1065,11 @@
 			addr += MAX_DESCR_SIZE;
 		}
 
+		/* did we run out of descriptors? */
+		if(count >= MAX_DMA_DESCRS) {
+			printk("%s: too few DMA descriptors\n", drive->name);
+			return 1;
+		}
 		cris_ide_fill_descriptor(&ata_descrs[count], (void*)addr, size,i ? 0 : 1);
 		count++;
 		ata_tot_size += size;
@@ -1050,8 +1131,12 @@
 
 	if (id && (id->capability & 1)) {
 		if (ide_use_dma(drive)) {
-			if (cris_config_drive_for_dma(drive))
-				return hwif->ide_dma_on(drive);
+			if (cris_config_drive_for_dma(drive)) {
+				if (hwif->ide_dma_on)
+					return hwif->ide_dma_on(drive);
+				else
+					return 1;
+			}
 		}
 	}
 

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: PATCH 2.6.20 11/14; CRIS architecture update - IDE driver
  2007-04-22 19:26 PATCH 2.6.20 11/14; CRIS architecture update - IDE driver Mikael Starvik
@ 2007-04-23 12:45 ` Sergei Shtylyov
  0 siblings, 0 replies; 2+ messages in thread
From: Sergei Shtylyov @ 2007-04-23 12:45 UTC (permalink / raw)
  To: Mikael Starvik; +Cc: linux-kernel, linux-ide, akpm

Hello.

Mikael Starvik wrote:
> The attached patch updates the CRIS IDE driver.
 
> Signed-off-by: Mikael Starvik <starvik@axis.com <mailto:starvik@axis.com> >

   Please attach the patch as text/plain and clean it from the whitespace noise. :-/
 
> /Mikael
 
MBR, Sergei

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2007-04-23 12:44 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-04-22 19:26 PATCH 2.6.20 11/14; CRIS architecture update - IDE driver Mikael Starvik
2007-04-23 12:45 ` Sergei Shtylyov

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).