diff options
author | Tejun Heo <htejun@gmail.com> | 2007-09-02 23:44:57 -0400 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2007-10-12 14:55:39 -0400 |
commit | 7a234aff3d83728fd83cf19df32d3df52566d2ac (patch) | |
tree | d991844bf7a7882eacd72a57a1465b25dc55e95d | |
parent | 05027adccc09401a7e31d5ef51040dc75ab03c22 (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.c | 89 |
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 { | |||
77 | RX_FIS_UNK = 0x60, /* offset of Unknown FIS data */ | 77 | RX_FIS_UNK = 0x60, /* offset of Unknown FIS data */ |
78 | 78 | ||
79 | board_ahci = 0, | 79 | board_ahci = 0, |
80 | board_ahci_pi = 1, | 80 | board_ahci_vt8251 = 1, |
81 | board_ahci_vt8251 = 2, | 81 | board_ahci_ign_iferr = 2, |
82 | board_ahci_ign_iferr = 3, | 82 | board_ahci_sb600 = 3, |
83 | board_ahci_sb600 = 4, | 83 | board_ahci_mv = 4, |
84 | board_ahci_mv = 5, | ||
85 | 84 | ||
86 | /* global controller registers */ | 85 | /* global controller registers */ |
87 | HOST_CAP = 0x00, /* host capabilities */ | 86 | HOST_CAP = 0x00, /* host capabilities */ |
@@ -170,7 +169,6 @@ enum { | |||
170 | /* ap->flags bits */ | 169 | /* ap->flags bits */ |
171 | AHCI_FLAG_NO_NCQ = (1 << 24), | 170 | AHCI_FLAG_NO_NCQ = (1 << 24), |
172 | AHCI_FLAG_IGN_IRQ_IF_ERR = (1 << 25), /* ignore IRQ_IF_ERR */ | 171 | AHCI_FLAG_IGN_IRQ_IF_ERR = (1 << 25), /* ignore IRQ_IF_ERR */ |
173 | AHCI_FLAG_HONOR_PI = (1 << 26), /* honor PORTS_IMPL */ | ||
174 | AHCI_FLAG_IGN_SERR_INTERNAL = (1 << 27), /* ignore SERR_INTERNAL */ | 172 | AHCI_FLAG_IGN_SERR_INTERNAL = (1 << 27), /* ignore SERR_INTERNAL */ |
175 | AHCI_FLAG_32BIT_ONLY = (1 << 28), /* force 32bit */ | 173 | AHCI_FLAG_32BIT_ONLY = (1 << 28), /* force 32bit */ |
176 | AHCI_FLAG_MV_PATA = (1 << 29), /* PATA port */ | 174 | AHCI_FLAG_MV_PATA = (1 << 29), /* PATA port */ |
@@ -332,14 +330,6 @@ static const struct ata_port_info ahci_port_info[] = { | |||
332 | .udma_mask = ATA_UDMA6, | 330 | .udma_mask = ATA_UDMA6, |
333 | .port_ops = &ahci_ops, | 331 | .port_ops = &ahci_ops, |
334 | }, | 332 | }, |
335 | /* board_ahci_pi */ | ||
336 | { | ||
337 | .flags = AHCI_FLAG_COMMON | AHCI_FLAG_HONOR_PI, | ||
338 | .link_flags = AHCI_LFLAG_COMMON, | ||
339 | .pio_mask = 0x1f, /* pio0-4 */ | ||
340 | .udma_mask = ATA_UDMA6, | ||
341 | .port_ops = &ahci_ops, | ||
342 | }, | ||
343 | /* board_ahci_vt8251 */ | 333 | /* board_ahci_vt8251 */ |
344 | { | 334 | { |
345 | .flags = AHCI_FLAG_COMMON | AHCI_FLAG_NO_NCQ, | 335 | .flags = AHCI_FLAG_COMMON | AHCI_FLAG_NO_NCQ, |
@@ -371,8 +361,8 @@ static const struct ata_port_info ahci_port_info[] = { | |||
371 | .sht = &ahci_sht, | 361 | .sht = &ahci_sht, |
372 | .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | | 362 | .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | |
373 | ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | | 363 | ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | |
374 | AHCI_FLAG_HONOR_PI | AHCI_FLAG_NO_NCQ | | 364 | AHCI_FLAG_NO_NCQ | AHCI_FLAG_NO_MSI | |
375 | AHCI_FLAG_NO_MSI | AHCI_FLAG_MV_PATA, | 365 | AHCI_FLAG_MV_PATA, |
376 | .link_flags = AHCI_LFLAG_COMMON, | 366 | .link_flags = AHCI_LFLAG_COMMON, |
377 | .pio_mask = 0x1f, /* pio0-4 */ | 367 | .pio_mask = 0x1f, /* pio0-4 */ |
378 | .udma_mask = ATA_UDMA6, | 368 | .udma_mask = ATA_UDMA6, |
@@ -392,23 +382,23 @@ static const struct pci_device_id ahci_pci_tbl[] = { | |||
392 | { PCI_VDEVICE(INTEL, 0x2682), board_ahci }, /* ESB2 */ | 382 | { PCI_VDEVICE(INTEL, 0x2682), board_ahci }, /* ESB2 */ |
393 | { PCI_VDEVICE(INTEL, 0x2683), board_ahci }, /* ESB2 */ | 383 | { PCI_VDEVICE(INTEL, 0x2683), board_ahci }, /* ESB2 */ |
394 | { PCI_VDEVICE(INTEL, 0x27c6), board_ahci }, /* ICH7-M DH */ | 384 | { PCI_VDEVICE(INTEL, 0x27c6), board_ahci }, /* ICH7-M DH */ |
395 | { PCI_VDEVICE(INTEL, 0x2821), board_ahci_pi }, /* ICH8 */ | 385 | { PCI_VDEVICE(INTEL, 0x2821), board_ahci }, /* ICH8 */ |
396 | { PCI_VDEVICE(INTEL, 0x2822), board_ahci_pi }, /* ICH8 */ | 386 | { PCI_VDEVICE(INTEL, 0x2822), board_ahci }, /* ICH8 */ |
397 | { PCI_VDEVICE(INTEL, 0x2824), board_ahci_pi }, /* ICH8 */ | 387 | { PCI_VDEVICE(INTEL, 0x2824), board_ahci }, /* ICH8 */ |
398 | { PCI_VDEVICE(INTEL, 0x2829), board_ahci_pi }, /* ICH8M */ | 388 | { PCI_VDEVICE(INTEL, 0x2829), board_ahci }, /* ICH8M */ |
399 | { PCI_VDEVICE(INTEL, 0x282a), board_ahci_pi }, /* ICH8M */ | 389 | { PCI_VDEVICE(INTEL, 0x282a), board_ahci }, /* ICH8M */ |
400 | { PCI_VDEVICE(INTEL, 0x2922), board_ahci_pi }, /* ICH9 */ | 390 | { PCI_VDEVICE(INTEL, 0x2922), board_ahci }, /* ICH9 */ |
401 | { PCI_VDEVICE(INTEL, 0x2923), board_ahci_pi }, /* ICH9 */ | 391 | { PCI_VDEVICE(INTEL, 0x2923), board_ahci }, /* ICH9 */ |
402 | { PCI_VDEVICE(INTEL, 0x2924), board_ahci_pi }, /* ICH9 */ | 392 | { PCI_VDEVICE(INTEL, 0x2924), board_ahci }, /* ICH9 */ |
403 | { PCI_VDEVICE(INTEL, 0x2925), board_ahci_pi }, /* ICH9 */ | 393 | { PCI_VDEVICE(INTEL, 0x2925), board_ahci }, /* ICH9 */ |
404 | { PCI_VDEVICE(INTEL, 0x2927), board_ahci_pi }, /* ICH9 */ | 394 | { PCI_VDEVICE(INTEL, 0x2927), board_ahci }, /* ICH9 */ |
405 | { PCI_VDEVICE(INTEL, 0x2929), board_ahci_pi }, /* ICH9M */ | 395 | { PCI_VDEVICE(INTEL, 0x2929), board_ahci }, /* ICH9M */ |
406 | { PCI_VDEVICE(INTEL, 0x292a), board_ahci_pi }, /* ICH9M */ | 396 | { PCI_VDEVICE(INTEL, 0x292a), board_ahci }, /* ICH9M */ |
407 | { PCI_VDEVICE(INTEL, 0x292b), board_ahci_pi }, /* ICH9M */ | 397 | { PCI_VDEVICE(INTEL, 0x292b), board_ahci }, /* ICH9M */ |
408 | { PCI_VDEVICE(INTEL, 0x292c), board_ahci_pi }, /* ICH9M */ | 398 | { PCI_VDEVICE(INTEL, 0x292c), board_ahci }, /* ICH9M */ |
409 | { PCI_VDEVICE(INTEL, 0x292f), board_ahci_pi }, /* ICH9M */ | 399 | { PCI_VDEVICE(INTEL, 0x292f), board_ahci }, /* ICH9M */ |
410 | { PCI_VDEVICE(INTEL, 0x294d), board_ahci_pi }, /* ICH9 */ | 400 | { PCI_VDEVICE(INTEL, 0x294d), board_ahci }, /* ICH9 */ |
411 | { PCI_VDEVICE(INTEL, 0x294e), board_ahci_pi }, /* ICH9M */ | 401 | { PCI_VDEVICE(INTEL, 0x294e), board_ahci }, /* ICH9M */ |
412 | 402 | ||
413 | /* JMicron 360/1/3/5/6, match class to avoid IDE function */ | 403 | /* JMicron 360/1/3/5/6, match class to avoid IDE function */ |
414 | { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, | 404 | { 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, | |||
562 | cap &= ~HOST_CAP_NCQ; | 552 | cap &= ~HOST_CAP_NCQ; |
563 | } | 553 | } |
564 | 554 | ||
565 | /* fixup zero port_map */ | ||
566 | if (!port_map) { | ||
567 | port_map = (1 << ahci_nr_ports(cap)) - 1; | ||
568 | dev_printk(KERN_WARNING, &pdev->dev, | ||
569 | "PORTS_IMPL is zero, forcing 0x%x\n", port_map); | ||
570 | |||
571 | /* write the fixed up value to the PI register */ | ||
572 | hpriv->saved_port_map = port_map; | ||
573 | } | ||
574 | |||
575 | /* | 555 | /* |
576 | * Temporary Marvell 6145 hack: PATA port presence | 556 | * Temporary Marvell 6145 hack: PATA port presence |
577 | * is asserted through the standard AHCI port | 557 | * is asserted through the standard AHCI port |
@@ -587,7 +567,7 @@ static void ahci_save_initial_config(struct pci_dev *pdev, | |||
587 | } | 567 | } |
588 | 568 | ||
589 | /* cross check port_map and cap.n_ports */ | 569 | /* cross check port_map and cap.n_ports */ |
590 | if (pi->flags & AHCI_FLAG_HONOR_PI) { | 570 | if (port_map) { |
591 | u32 tmp_port_map = port_map; | 571 | u32 tmp_port_map = port_map; |
592 | int n_ports = ahci_nr_ports(cap); | 572 | int n_ports = ahci_nr_ports(cap); |
593 | 573 | ||
@@ -598,17 +578,26 @@ static void ahci_save_initial_config(struct pci_dev *pdev, | |||
598 | } | 578 | } |
599 | } | 579 | } |
600 | 580 | ||
601 | /* Whine if inconsistent. No need to update cap. | 581 | /* If n_ports and port_map are inconsistent, whine and |
602 | * port_map is used to determine number of ports. | 582 | * clear port_map and let it be generated from n_ports. |
603 | */ | 583 | */ |
604 | if (n_ports || tmp_port_map) | 584 | if (n_ports || tmp_port_map) { |
605 | dev_printk(KERN_WARNING, &pdev->dev, | 585 | dev_printk(KERN_WARNING, &pdev->dev, |
606 | "nr_ports (%u) and implemented port map " | 586 | "nr_ports (%u) and implemented port map " |
607 | "(0x%x) don't match\n", | 587 | "(0x%x) don't match, using nr_ports\n", |
608 | ahci_nr_ports(cap), port_map); | 588 | ahci_nr_ports(cap), port_map); |
609 | } else { | 589 | port_map = 0; |
610 | /* fabricate port_map from cap.nr_ports */ | 590 | } |
591 | } | ||
592 | |||
593 | /* fabricate port_map from cap.nr_ports */ | ||
594 | if (!port_map) { | ||
611 | port_map = (1 << ahci_nr_ports(cap)) - 1; | 595 | port_map = (1 << ahci_nr_ports(cap)) - 1; |
596 | dev_printk(KERN_WARNING, &pdev->dev, | ||
597 | "forcing PORTS_IMPL to 0x%x\n", port_map); | ||
598 | |||
599 | /* write the fixed up value to the PI register */ | ||
600 | hpriv->saved_port_map = port_map; | ||
612 | } | 601 | } |
613 | 602 | ||
614 | /* record values to use during operation */ | 603 | /* record values to use during operation */ |