Commit e4e10e3e authored by Tejun Heo's avatar Tejun Heo Committed by Jeff Garzik

[PATCH] sata_sil: implement R_ERR on DMA activate FIS errata fix

Silicon Image has disclosed a new sil3114/3152 errata and workaround
which causes the controller to return R_ERR on DMA activate FIS if the
FIS is received while the next PRD is being fetched.  This patch
implements the workaround.

This errata results in lock up and doesn't trigger if m15w workaround
is in effect.  We stopped applying m15w to 3512 and 3114 in 2.6.14-rc1
which makes 3512/3114 lock up with some drives on all kernel versions
since 2.6.14-rc1 upto now (2.6.16-rc4).  This patch should fix the
regression.
Signed-off-by: default avatarTejun Heo <htejun@gmail.com>
Signed-off-by: default avatarJeff Garzik <jeff@garzik.org>
parent 0ee304d5
...@@ -49,6 +49,7 @@ ...@@ -49,6 +49,7 @@
#define DRV_VERSION "0.9" #define DRV_VERSION "0.9"
enum { enum {
SIL_FLAG_RERR_ON_DMA_ACT = (1 << 29),
SIL_FLAG_MOD15WRITE = (1 << 30), SIL_FLAG_MOD15WRITE = (1 << 30),
sil_3112 = 0, sil_3112 = 0,
...@@ -202,7 +203,8 @@ static const struct ata_port_info sil_port_info[] = { ...@@ -202,7 +203,8 @@ static const struct ata_port_info sil_port_info[] = {
{ {
.sht = &sil_sht, .sht = &sil_sht,
.host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
ATA_FLAG_SRST | ATA_FLAG_MMIO, ATA_FLAG_SRST | ATA_FLAG_MMIO |
SIL_FLAG_RERR_ON_DMA_ACT,
.pio_mask = 0x1f, /* pio0-4 */ .pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */ .mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = 0x3f, /* udma0-5 */ .udma_mask = 0x3f, /* udma0-5 */
...@@ -212,7 +214,8 @@ static const struct ata_port_info sil_port_info[] = { ...@@ -212,7 +214,8 @@ static const struct ata_port_info sil_port_info[] = {
{ {
.sht = &sil_sht, .sht = &sil_sht,
.host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
ATA_FLAG_SRST | ATA_FLAG_MMIO, ATA_FLAG_SRST | ATA_FLAG_MMIO |
SIL_FLAG_RERR_ON_DMA_ACT,
.pio_mask = 0x1f, /* pio0-4 */ .pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */ .mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = 0x3f, /* udma0-5 */ .udma_mask = 0x3f, /* udma0-5 */
...@@ -229,12 +232,13 @@ static const struct { ...@@ -229,12 +232,13 @@ static const struct {
unsigned long scr; /* SATA control register block */ unsigned long scr; /* SATA control register block */
unsigned long sien; /* SATA Interrupt Enable register */ unsigned long sien; /* SATA Interrupt Enable register */
unsigned long xfer_mode;/* data transfer mode register */ unsigned long xfer_mode;/* data transfer mode register */
unsigned long sfis_cfg; /* SATA FIS reception config register */
} sil_port[] = { } sil_port[] = {
/* port 0 ... */ /* port 0 ... */
{ 0x80, 0x8A, 0x00, 0x100, 0x148, 0xb4 }, { 0x80, 0x8A, 0x00, 0x100, 0x148, 0xb4, 0x14c },
{ 0xC0, 0xCA, 0x08, 0x180, 0x1c8, 0xf4 }, { 0xC0, 0xCA, 0x08, 0x180, 0x1c8, 0xf4, 0x1cc },
{ 0x280, 0x28A, 0x200, 0x300, 0x348, 0x2b4 }, { 0x280, 0x28A, 0x200, 0x300, 0x348, 0x2b4, 0x34c },
{ 0x2C0, 0x2CA, 0x208, 0x380, 0x3c8, 0x2f4 }, { 0x2C0, 0x2CA, 0x208, 0x380, 0x3c8, 0x2f4, 0x3cc },
/* ... port 3 */ /* ... port 3 */
}; };
...@@ -484,6 +488,23 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -484,6 +488,23 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
dev_printk(KERN_WARNING, &pdev->dev, dev_printk(KERN_WARNING, &pdev->dev,
"cache line size not set. Driver may not function\n"); "cache line size not set. Driver may not function\n");
/* Apply R_ERR on DMA activate FIS errata workaround */
if (probe_ent->host_flags & SIL_FLAG_RERR_ON_DMA_ACT) {
int cnt;
for (i = 0, cnt = 0; i < probe_ent->n_ports; i++) {
tmp = readl(mmio_base + sil_port[i].sfis_cfg);
if ((tmp & 0x3) != 0x01)
continue;
if (!cnt)
dev_printk(KERN_INFO, &pdev->dev,
"Applying R_ERR on DMA activate "
"FIS errata fix\n");
writel(tmp & ~0x3, mmio_base + sil_port[i].sfis_cfg);
cnt++;
}
}
if (ent->driver_data == sil_3114) { if (ent->driver_data == sil_3114) {
irq_mask = SIL_MASK_4PORT; irq_mask = SIL_MASK_4PORT;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment