Commit 7a234aff authored by Tejun Heo's avatar Tejun Heo Committed by Jeff Garzik

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: default avatarTejun Heo <htejun@gmail.com>
Signed-off-by: default avatarJeff Garzik <jeff@garzik.org>
parent 05027adc
...@@ -77,11 +77,10 @@ enum { ...@@ -77,11 +77,10 @@ enum {
RX_FIS_UNK = 0x60, /* offset of Unknown FIS data */ RX_FIS_UNK = 0x60, /* offset of Unknown FIS data */
board_ahci = 0, board_ahci = 0,
board_ahci_pi = 1, board_ahci_vt8251 = 1,
board_ahci_vt8251 = 2, board_ahci_ign_iferr = 2,
board_ahci_ign_iferr = 3, board_ahci_sb600 = 3,
board_ahci_sb600 = 4, board_ahci_mv = 4,
board_ahci_mv = 5,
/* global controller registers */ /* global controller registers */
HOST_CAP = 0x00, /* host capabilities */ HOST_CAP = 0x00, /* host capabilities */
...@@ -170,7 +169,6 @@ enum { ...@@ -170,7 +169,6 @@ enum {
/* ap->flags bits */ /* ap->flags bits */
AHCI_FLAG_NO_NCQ = (1 << 24), AHCI_FLAG_NO_NCQ = (1 << 24),
AHCI_FLAG_IGN_IRQ_IF_ERR = (1 << 25), /* ignore IRQ_IF_ERR */ 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_IGN_SERR_INTERNAL = (1 << 27), /* ignore SERR_INTERNAL */
AHCI_FLAG_32BIT_ONLY = (1 << 28), /* force 32bit */ AHCI_FLAG_32BIT_ONLY = (1 << 28), /* force 32bit */
AHCI_FLAG_MV_PATA = (1 << 29), /* PATA port */ AHCI_FLAG_MV_PATA = (1 << 29), /* PATA port */
...@@ -332,14 +330,6 @@ static const struct ata_port_info ahci_port_info[] = { ...@@ -332,14 +330,6 @@ static const struct ata_port_info ahci_port_info[] = {
.udma_mask = ATA_UDMA6, .udma_mask = ATA_UDMA6,
.port_ops = &ahci_ops, .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 */ /* board_ahci_vt8251 */
{ {
.flags = AHCI_FLAG_COMMON | AHCI_FLAG_NO_NCQ, .flags = AHCI_FLAG_COMMON | AHCI_FLAG_NO_NCQ,
...@@ -371,8 +361,8 @@ static const struct ata_port_info ahci_port_info[] = { ...@@ -371,8 +361,8 @@ static const struct ata_port_info ahci_port_info[] = {
.sht = &ahci_sht, .sht = &ahci_sht,
.flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
AHCI_FLAG_HONOR_PI | AHCI_FLAG_NO_NCQ | AHCI_FLAG_NO_NCQ | AHCI_FLAG_NO_MSI |
AHCI_FLAG_NO_MSI | AHCI_FLAG_MV_PATA, AHCI_FLAG_MV_PATA,
.link_flags = AHCI_LFLAG_COMMON, .link_flags = AHCI_LFLAG_COMMON,
.pio_mask = 0x1f, /* pio0-4 */ .pio_mask = 0x1f, /* pio0-4 */
.udma_mask = ATA_UDMA6, .udma_mask = ATA_UDMA6,
...@@ -392,23 +382,23 @@ static const struct pci_device_id ahci_pci_tbl[] = { ...@@ -392,23 +382,23 @@ static const struct pci_device_id ahci_pci_tbl[] = {
{ PCI_VDEVICE(INTEL, 0x2682), board_ahci }, /* ESB2 */ { PCI_VDEVICE(INTEL, 0x2682), board_ahci }, /* ESB2 */
{ PCI_VDEVICE(INTEL, 0x2683), board_ahci }, /* ESB2 */ { PCI_VDEVICE(INTEL, 0x2683), board_ahci }, /* ESB2 */
{ PCI_VDEVICE(INTEL, 0x27c6), board_ahci }, /* ICH7-M DH */ { PCI_VDEVICE(INTEL, 0x27c6), board_ahci }, /* ICH7-M DH */
{ PCI_VDEVICE(INTEL, 0x2821), board_ahci_pi }, /* ICH8 */ { PCI_VDEVICE(INTEL, 0x2821), board_ahci }, /* ICH8 */
{ PCI_VDEVICE(INTEL, 0x2822), board_ahci_pi }, /* ICH8 */ { PCI_VDEVICE(INTEL, 0x2822), board_ahci }, /* ICH8 */
{ PCI_VDEVICE(INTEL, 0x2824), board_ahci_pi }, /* ICH8 */ { PCI_VDEVICE(INTEL, 0x2824), board_ahci }, /* ICH8 */
{ PCI_VDEVICE(INTEL, 0x2829), board_ahci_pi }, /* ICH8M */ { PCI_VDEVICE(INTEL, 0x2829), board_ahci }, /* ICH8M */
{ PCI_VDEVICE(INTEL, 0x282a), board_ahci_pi }, /* ICH8M */ { PCI_VDEVICE(INTEL, 0x282a), board_ahci }, /* ICH8M */
{ PCI_VDEVICE(INTEL, 0x2922), board_ahci_pi }, /* ICH9 */ { PCI_VDEVICE(INTEL, 0x2922), board_ahci }, /* ICH9 */
{ PCI_VDEVICE(INTEL, 0x2923), board_ahci_pi }, /* ICH9 */ { PCI_VDEVICE(INTEL, 0x2923), board_ahci }, /* ICH9 */
{ PCI_VDEVICE(INTEL, 0x2924), board_ahci_pi }, /* ICH9 */ { PCI_VDEVICE(INTEL, 0x2924), board_ahci }, /* ICH9 */
{ PCI_VDEVICE(INTEL, 0x2925), board_ahci_pi }, /* ICH9 */ { PCI_VDEVICE(INTEL, 0x2925), board_ahci }, /* ICH9 */
{ PCI_VDEVICE(INTEL, 0x2927), board_ahci_pi }, /* ICH9 */ { PCI_VDEVICE(INTEL, 0x2927), board_ahci }, /* ICH9 */
{ PCI_VDEVICE(INTEL, 0x2929), board_ahci_pi }, /* ICH9M */ { PCI_VDEVICE(INTEL, 0x2929), board_ahci }, /* ICH9M */
{ PCI_VDEVICE(INTEL, 0x292a), board_ahci_pi }, /* ICH9M */ { PCI_VDEVICE(INTEL, 0x292a), board_ahci }, /* ICH9M */
{ PCI_VDEVICE(INTEL, 0x292b), board_ahci_pi }, /* ICH9M */ { PCI_VDEVICE(INTEL, 0x292b), board_ahci }, /* ICH9M */
{ PCI_VDEVICE(INTEL, 0x292c), board_ahci_pi }, /* ICH9M */ { PCI_VDEVICE(INTEL, 0x292c), board_ahci }, /* ICH9M */
{ PCI_VDEVICE(INTEL, 0x292f), board_ahci_pi }, /* ICH9M */ { PCI_VDEVICE(INTEL, 0x292f), board_ahci }, /* ICH9M */
{ PCI_VDEVICE(INTEL, 0x294d), board_ahci_pi }, /* ICH9 */ { PCI_VDEVICE(INTEL, 0x294d), board_ahci }, /* ICH9 */
{ PCI_VDEVICE(INTEL, 0x294e), board_ahci_pi }, /* ICH9M */ { PCI_VDEVICE(INTEL, 0x294e), board_ahci }, /* ICH9M */
/* JMicron 360/1/3/5/6, match class to avoid IDE function */ /* 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, { 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,16 +552,6 @@ static void ahci_save_initial_config(struct pci_dev *pdev,
cap &= ~HOST_CAP_NCQ; 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 * Temporary Marvell 6145 hack: PATA port presence
* is asserted through the standard AHCI port * is asserted through the standard AHCI port
...@@ -587,7 +567,7 @@ static void ahci_save_initial_config(struct pci_dev *pdev, ...@@ -587,7 +567,7 @@ static void ahci_save_initial_config(struct pci_dev *pdev,
} }
/* cross check port_map and cap.n_ports */ /* cross check port_map and cap.n_ports */
if (pi->flags & AHCI_FLAG_HONOR_PI) { if (port_map) {
u32 tmp_port_map = port_map; u32 tmp_port_map = port_map;
int n_ports = ahci_nr_ports(cap); int n_ports = ahci_nr_ports(cap);
...@@ -598,17 +578,26 @@ static void ahci_save_initial_config(struct pci_dev *pdev, ...@@ -598,17 +578,26 @@ static void ahci_save_initial_config(struct pci_dev *pdev,
} }
} }
/* Whine if inconsistent. No need to update cap. /* If n_ports and port_map are inconsistent, whine and
* port_map is used to determine number of ports. * 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, dev_printk(KERN_WARNING, &pdev->dev,
"nr_ports (%u) and implemented port map " "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); ahci_nr_ports(cap), port_map);
} else { port_map = 0;
}
}
/* fabricate port_map from cap.nr_ports */ /* fabricate port_map from cap.nr_ports */
if (!port_map) {
port_map = (1 << ahci_nr_ports(cap)) - 1; 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 */ /* record values to use during operation */
......
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