aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTejun Heo2007-09-03 12:44:57 +0900
committerJeff Garzik2007-10-12 14:55:39 -0400
commit7a234aff3d83728fd83cf19df32d3df52566d2ac (patch)
treed991844bf7a7882eacd72a57a1465b25dc55e95d
parent05027adccc09401a7e31d5ef51040dc75ab03c22 (diff)
ahci: reimplement port_map handling
Reimplement port_map handling such that 1. Non-zero PORTS_IMPL value is always examined and used if consistent with cap.n_ports. 2. When PI and cat.n_ports are inconsistent, honor cap.n_ports and force port_map to be ((1 << cap.n_ports) - 1). 3. There were two separate places dealing with port_map. Unify them to one. As all newer ahci chips seem to get PI correct and older ones usually have zero PI. Controllers with holes in PI are very unlikely to screw up PI, so #2 makes more sense than following inconsistent PI. Without this change, not setting ATA_FLAG_HONOR_PI when it's needed results in weird detection failure. This changed logic should be able to handle all known cases correctly automatically. Verified on ICH6 (reports 0 PI), ICH8 (with holes in port_map), ICH9, JMB360 and JMB363. Signed-off-by: Tejun Heo <htejun@gmail.com> Signed-off-by: Jeff Garzik <jeff@garzik.org>
-rw-r--r--drivers/ata/ahci.c89
1 files changed, 39 insertions, 50 deletions
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 518c51830357..57cc3e73a7e2 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -77,11 +77,10 @@ enum {
RX_FIS_UNK = 0x60, /* offset of Unknown FIS data */
board_ahci = 0,
- board_ahci_pi = 1,
- board_ahci_vt8251 = 2,
- board_ahci_ign_iferr = 3,
- board_ahci_sb600 = 4,
- board_ahci_mv = 5,
+ board_ahci_vt8251 = 1,
+ board_ahci_ign_iferr = 2,
+ board_ahci_sb600 = 3,
+ board_ahci_mv = 4,
/* global controller registers */
HOST_CAP = 0x00, /* host capabilities */
@@ -170,7 +169,6 @@ enum {
/* ap->flags bits */
AHCI_FLAG_NO_NCQ = (1 << 24),
AHCI_FLAG_IGN_IRQ_IF_ERR = (1 << 25), /* ignore IRQ_IF_ERR */
- AHCI_FLAG_HONOR_PI = (1 << 26), /* honor PORTS_IMPL */
AHCI_FLAG_IGN_SERR_INTERNAL = (1 << 27), /* ignore SERR_INTERNAL */
AHCI_FLAG_32BIT_ONLY = (1 << 28), /* force 32bit */
AHCI_FLAG_MV_PATA = (1 << 29), /* PATA port */
@@ -332,14 +330,6 @@ static const struct ata_port_info ahci_port_info[] = {
.udma_mask = ATA_UDMA6,
.port_ops = &ahci_ops,
},
- /* board_ahci_pi */
- {
- .flags = AHCI_FLAG_COMMON | AHCI_FLAG_HONOR_PI,
- .link_flags = AHCI_LFLAG_COMMON,
- .pio_mask = 0x1f, /* pio0-4 */
- .udma_mask = ATA_UDMA6,
- .port_ops = &ahci_ops,
- },
/* board_ahci_vt8251 */
{
.flags = AHCI_FLAG_COMMON | AHCI_FLAG_NO_NCQ,
@@ -371,8 +361,8 @@ static const struct ata_port_info ahci_port_info[] = {
.sht = &ahci_sht,
.flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
- AHCI_FLAG_HONOR_PI | AHCI_FLAG_NO_NCQ |
- AHCI_FLAG_NO_MSI | AHCI_FLAG_MV_PATA,
+ AHCI_FLAG_NO_NCQ | AHCI_FLAG_NO_MSI |
+ AHCI_FLAG_MV_PATA,
.link_flags = AHCI_LFLAG_COMMON,
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = ATA_UDMA6,
@@ -392,23 +382,23 @@ static const struct pci_device_id ahci_pci_tbl[] = {
{ PCI_VDEVICE(INTEL, 0x2682), board_ahci }, /* ESB2 */
{ PCI_VDEVICE(INTEL, 0x2683), board_ahci }, /* ESB2 */
{ PCI_VDEVICE(INTEL, 0x27c6), board_ahci }, /* ICH7-M DH */
- { PCI_VDEVICE(INTEL, 0x2821), board_ahci_pi }, /* ICH8 */
- { PCI_VDEVICE(INTEL, 0x2822), board_ahci_pi }, /* ICH8 */
- { PCI_VDEVICE(INTEL, 0x2824), board_ahci_pi }, /* ICH8 */
- { PCI_VDEVICE(INTEL, 0x2829), board_ahci_pi }, /* ICH8M */
- { PCI_VDEVICE(INTEL, 0x282a), board_ahci_pi }, /* ICH8M */
- { PCI_VDEVICE(INTEL, 0x2922), board_ahci_pi }, /* ICH9 */
- { PCI_VDEVICE(INTEL, 0x2923), board_ahci_pi }, /* ICH9 */
- { PCI_VDEVICE(INTEL, 0x2924), board_ahci_pi }, /* ICH9 */
- { PCI_VDEVICE(INTEL, 0x2925), board_ahci_pi }, /* ICH9 */
- { PCI_VDEVICE(INTEL, 0x2927), board_ahci_pi }, /* ICH9 */
- { PCI_VDEVICE(INTEL, 0x2929), board_ahci_pi }, /* ICH9M */
- { PCI_VDEVICE(INTEL, 0x292a), board_ahci_pi }, /* ICH9M */
- { PCI_VDEVICE(INTEL, 0x292b), board_ahci_pi }, /* ICH9M */
- { PCI_VDEVICE(INTEL, 0x292c), board_ahci_pi }, /* ICH9M */
- { PCI_VDEVICE(INTEL, 0x292f), board_ahci_pi }, /* ICH9M */
- { PCI_VDEVICE(INTEL, 0x294d), board_ahci_pi }, /* ICH9 */
- { PCI_VDEVICE(INTEL, 0x294e), board_ahci_pi }, /* ICH9M */
+ { PCI_VDEVICE(INTEL, 0x2821), board_ahci }, /* ICH8 */
+ { PCI_VDEVICE(INTEL, 0x2822), board_ahci }, /* ICH8 */
+ { PCI_VDEVICE(INTEL, 0x2824), board_ahci }, /* ICH8 */
+ { PCI_VDEVICE(INTEL, 0x2829), board_ahci }, /* ICH8M */
+ { PCI_VDEVICE(INTEL, 0x282a), board_ahci }, /* ICH8M */
+ { PCI_VDEVICE(INTEL, 0x2922), board_ahci }, /* ICH9 */
+ { PCI_VDEVICE(INTEL, 0x2923), board_ahci }, /* ICH9 */
+ { PCI_VDEVICE(INTEL, 0x2924), board_ahci }, /* ICH9 */
+ { PCI_VDEVICE(INTEL, 0x2925), board_ahci }, /* ICH9 */
+ { PCI_VDEVICE(INTEL, 0x2927), board_ahci }, /* ICH9 */
+ { PCI_VDEVICE(INTEL, 0x2929), board_ahci }, /* ICH9M */
+ { PCI_VDEVICE(INTEL, 0x292a), board_ahci }, /* ICH9M */
+ { PCI_VDEVICE(INTEL, 0x292b), board_ahci }, /* ICH9M */
+ { PCI_VDEVICE(INTEL, 0x292c), board_ahci }, /* ICH9M */
+ { PCI_VDEVICE(INTEL, 0x292f), board_ahci }, /* ICH9M */
+ { PCI_VDEVICE(INTEL, 0x294d), board_ahci }, /* ICH9 */
+ { PCI_VDEVICE(INTEL, 0x294e), board_ahci }, /* ICH9M */
/* JMicron 360/1/3/5/6, match class to avoid IDE function */
{ PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
@@ -562,16 +552,6 @@ static void ahci_save_initial_config(struct pci_dev *pdev,
cap &= ~HOST_CAP_NCQ;
}
- /* fixup zero port_map */
- if (!port_map) {
- port_map = (1 << ahci_nr_ports(cap)) - 1;
- dev_printk(KERN_WARNING, &pdev->dev,
- "PORTS_IMPL is zero, forcing 0x%x\n", port_map);
-
- /* write the fixed up value to the PI register */
- hpriv->saved_port_map = port_map;
- }
-
/*
* Temporary Marvell 6145 hack: PATA port presence
* is asserted through the standard AHCI port
@@ -587,7 +567,7 @@ static void ahci_save_initial_config(struct pci_dev *pdev,
}
/* cross check port_map and cap.n_ports */
- if (pi->flags & AHCI_FLAG_HONOR_PI) {
+ if (port_map) {
u32 tmp_port_map = port_map;
int n_ports = ahci_nr_ports(cap);
@@ -598,17 +578,26 @@ static void ahci_save_initial_config(struct pci_dev *pdev,
}
}
- /* Whine if inconsistent. No need to update cap.
- * port_map is used to determine number of ports.
+ /* If n_ports and port_map are inconsistent, whine and
+ * clear port_map and let it be generated from n_ports.
*/
- if (n_ports || tmp_port_map)
+ if (n_ports || tmp_port_map) {
dev_printk(KERN_WARNING, &pdev->dev,
"nr_ports (%u) and implemented port map "
- "(0x%x) don't match\n",
+ "(0x%x) don't match, using nr_ports\n",
ahci_nr_ports(cap), port_map);
- } else {
- /* fabricate port_map from cap.nr_ports */
+ port_map = 0;
+ }
+ }
+
+ /* fabricate port_map from cap.nr_ports */
+ if (!port_map) {
port_map = (1 << ahci_nr_ports(cap)) - 1;
+ dev_printk(KERN_WARNING, &pdev->dev,
+ "forcing PORTS_IMPL to 0x%x\n", port_map);
+
+ /* write the fixed up value to the PI register */
+ hpriv->saved_port_map = port_map;
}
/* record values to use during operation */