work on Silicon Image 3114 4-port support
PATCH 1/1 work on Silicon Image 3114 4-port support
The Silicon Image 3114 is the four-port counterpart to the 3112. It has a magic "make all four ports work" bit that must be set, in order to receive interrupts from all four ports. This bit, annoyingly, was placed in a register that software has traditionally chosen to unconditionally zero. Doh.
The attached patch sets/clears only the bits we care about, which deviates from legacy software, but is arguably better behavior.
The patch shuffles, but does not add, IOs in the dma-start path. And it adds one IO, a read, to the dma-stop path. This affects everybody, so testing of this patch on -any- libata-supported hardware would be appreciated.
Jeff
===== drivers/scsi/libata-core.c 1.26 vs edited =====
drivers/scsi/libata-core.c +16 -10
@@ -2263,9 +2263,12 @@mb ();/* make sure PRD table writes are visible to controller */ writel (ap->prd_dma, mmio +ATA_DMA_TABLE_OFS ); -/* specify data direction */ -/* FIXME: redundant to later start-dma command? */ -writeb (rw ?0 :ATA_DMA_WR , mmio +ATA_DMA_CMD ); +/* specify data direction, triple-check start bit is clear */ + dmactl =readb (mmio +ATA_DMA_CMD ); + dmactl &= ~(ATA_DMA_WR |ATA_DMA_START ); +if (!rw) + dmactl |=ATA_DMA_WR ; +writeb (dmactl, mmio +ATA_DMA_CMD );/* clear interrupt, error bits */ host_stat =readb (mmio +ATA_DMA_STATUS );
@@ -2275,7 +2278,6 @@ ap->ops->exec_command (ap, &qc->tf);/* start host DMA transaction */ - dmactl =readb (mmio +ATA_DMA_CMD );writeb (dmactl |ATA_DMA_START , mmio +ATA_DMA_CMD );/* Strictly, one may wish to issue a readb() here, to
@@ -2308,9 +2310,12 @@/* load PRD table addr. */ outl (ap->prd_dma, ap->ioaddr.bmdma_addr +ATA_DMA_TABLE_OFS ); -/* specify data direction */ -/* FIXME: redundant to later start-dma command? */ -outb (rw ?0 :ATA_DMA_WR , ap->ioaddr.bmdma_addr +ATA_DMA_CMD ); +/* specify data direction, triple-check start bit is clear */ + dmactl =inb (ap->ioaddr.bmdma_addr +ATA_DMA_CMD ); + dmactl &= ~(ATA_DMA_WR |ATA_DMA_START ); +if (!rw) + dmactl |=ATA_DMA_WR ; +outb (dmactl, ap->ioaddr.bmdma_addr +ATA_DMA_CMD );/* clear interrupt, error bits */ host_stat =inb (ap->ioaddr.bmdma_addr +ATA_DMA_STATUS );
@@ -2321,7 +2326,6 @@ ap->ops->exec_command (ap, &qc->tf);/* start host DMA transaction */ - dmactl =inb (ap->ioaddr.bmdma_addr +ATA_DMA_CMD );outb (dmactl |ATA_DMA_START , ap->ioaddr.bmdma_addr +ATA_DMA_CMD ); }
@@ -2344,14 +2348,16 @@void *mmio = (void *) ap->ioaddr.bmdma_addr;/* clear start/stop bit */ -writeb (0 , mmio +ATA_DMA_CMD ); +writeb (readb (mmio +ATA_DMA_CMD ) & ~ATA_DMA_START , + mmio +ATA_DMA_CMD );/* ack intr, err bits */ writeb (host_stat |ATA_DMA_INTR |ATA_DMA_ERR , mmio +ATA_DMA_STATUS ); }else {/* clear start/stop bit */ -outb (0 , ap->ioaddr.bmdma_addr +ATA_DMA_CMD ); +outb (inb (ap->ioaddr.bmdma_addr +ATA_DMA_CMD ) & ~ATA_DMA_START , + ap->ioaddr.bmdma_addr +ATA_DMA_CMD );/* ack intr, err bits */ outb(host_stat | ATA_DMA_INTR | ATA_DMA_ERR,