* 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).