SATA_SIL on IXP425 workaround

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



I'm trying to add a workaround for IXP4xx CPUs to SATA SIL driver. The
problem is that IXP4xx CPUs (Intel's XScale (ARM) network-oriented
processors) are unable to perform 8 and 16-bit read from PCI MMIO, they
can only do a full 32-bit readl(); SIL chips respond to that with PCI
abort. The workaround is to use 8 and 16-bit regular IO reads (inb/inw)
instead (MMIO write is not a problem).

For SIL3x12 the workaround is simple (attached) and it works on my 3512.
I'm not sure about 3114 (the 4-port chip) - the PIO BARs have TF, CTL
and BWDMA registers which are common to channels 0 and 2, and (the other
set) to channels 1 and 3. Channel selection is done with bit 4 of
device/head TF register, this is similar (same?) as PATA master/slave.
Does that mean that I can simply treat channel 0 as PRI master, ch#2 as
PRI slave, ch#1 as SEC master and ch#3 as SEC slave, and the SFF code
will select the right device correctly? Does it need additional code?
I don't have anything based on 3114.

Note: the large PRD is not a problem here, the transfer can be started
by MMIO write. Only reads are an issue.

--- a/drivers/ata/sata_sil.c
+++ b/drivers/ata/sata_sil.c
@@ -757,7 +757,12 @@ static int sil_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 	if (rc)
 		return rc;
 
+#ifdef CONFIG_ARCH_IXP4XX
+	/* We need all 6 regions on IXP4xx */
+	rc = pcim_iomap_regions(pdev, 0x3F, DRV_NAME);
+#else
 	rc = pcim_iomap_regions(pdev, 1 << SIL_MMIO_BAR, DRV_NAME);
+#endif
 	if (rc == -EBUSY)
 		pcim_pin_device(pdev);
 	if (rc)
@@ -777,10 +782,18 @@ static int sil_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 		struct ata_port *ap = host->ports[i];
 		struct ata_ioports *ioaddr = &ap->ioaddr;
 
+#ifdef CONFIG_ARCH_IXP4XX
+		/* IXP4xx CPUs can't perform 8 and 16-bit MMIO reads,
+		   use normal IO from/to regions 0-5 instead */
+		ioaddr->cmd_addr = host->iomap[i * 2];
+		ioaddr->altstatus_addr = host->iomap[1 + i * 2] + 2;
+		ioaddr->bmdma_addr = host->iomap[4] + sil_port[i].bmdma;
+#else
 		ioaddr->cmd_addr = mmio_base + sil_port[i].tf;
-		ioaddr->altstatus_addr =
-		ioaddr->ctl_addr = mmio_base + sil_port[i].ctl;
+		ioaddr->altstatus_addr = mmio_base + sil_port[i].ctl;
 		ioaddr->bmdma_addr = mmio_base + sil_port[i].bmdma;
+#endif
+		ioaddr->ctl_addr = mmio_base + sil_port[i].ctl;
 		ioaddr->scr_addr = mmio_base + sil_port[i].scr;
 		ata_sff_std_ports(ioaddr);
 

-- 
Krzysztof Halasa
--
To unsubscribe from this list: send the line "unsubscribe linux-ide" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Filesystems]     [Linux SCSI]     [Linux RAID]     [Git]     [Kernel Newbies]     [Linux Newbie]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Samba]     [Device Mapper]

  Powered by Linux