diff options
Diffstat (limited to 'drivers/ata/ahci.c')
-rw-r--r-- | drivers/ata/ahci.c | 57 |
1 files changed, 30 insertions, 27 deletions
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index c31b6636632..fb9f6925293 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -498,6 +498,7 @@ static void ahci_save_initial_config(struct ata_probe_ent *probe_ent) struct ahci_host_priv *hpriv = probe_ent->private_data; void __iomem *mmio = probe_ent->iomap[AHCI_PCI_BAR]; u32 cap, port_map; + int i; /* Values prefixed with saved_ are written back to host after * reset. Values without are used for driver operation. @@ -515,6 +516,31 @@ static void ahci_save_initial_config(struct ata_probe_ent *probe_ent) hpriv->saved_port_map = port_map; } + /* cross check port_map and cap.n_ports */ + if (probe_ent->port_flags & AHCI_FLAG_HONOR_PI) { + u32 tmp_port_map = port_map; + int n_ports = ahci_nr_ports(cap); + + for (i = 0; i < AHCI_MAX_PORTS && n_ports; i++) { + if (tmp_port_map & (1 << i)) { + n_ports--; + tmp_port_map &= ~(1 << i); + } + } + + /* Whine if inconsistent. No need to update cap. + * port_map is used to determine number of ports. + */ + if (n_ports || tmp_port_map) + dev_printk(KERN_WARNING, probe_ent->dev, + "nr_ports (%u) and implemented port map " + "(0x%x) don't match\n", + ahci_nr_ports(cap), port_map); + } else { + /* fabricate port_map from cap.nr_ports */ + port_map = (1 << ahci_nr_ports(cap)) - 1; + } + /* record values to use during operation */ hpriv->cap = cap; hpriv->port_map = port_map; @@ -1589,41 +1615,18 @@ static int ahci_host_init(struct ata_probe_ent *probe_ent) struct ahci_host_priv *hpriv = probe_ent->private_data; struct pci_dev *pdev = to_pci_dev(probe_ent->dev); void __iomem *mmio = probe_ent->iomap[AHCI_PCI_BAR]; - unsigned int i, cap_n_ports, using_dac; + unsigned int i, using_dac; int rc; rc = ahci_reset_controller(mmio, pdev, hpriv); if (rc) return rc; - cap_n_ports = ahci_nr_ports(hpriv->cap); + probe_ent->n_ports = fls(hpriv->port_map); + probe_ent->dummy_port_mask = ~hpriv->port_map; VPRINTK("cap 0x%x port_map 0x%x n_ports %d\n", - hpriv->cap, hpriv->port_map, cap_n_ports); - - if (probe_ent->port_flags & AHCI_FLAG_HONOR_PI) { - unsigned int n_ports = cap_n_ports; - u32 port_map = hpriv->port_map; - int max_port = 0; - - for (i = 0; i < AHCI_MAX_PORTS && n_ports; i++) { - if (port_map & (1 << i)) { - n_ports--; - port_map &= ~(1 << i); - max_port = i; - } else - probe_ent->dummy_port_mask |= 1 << i; - } - - if (n_ports || port_map) - dev_printk(KERN_WARNING, &pdev->dev, - "nr_ports (%u) and implemented port map " - "(0x%x) don't match\n", - cap_n_ports, hpriv->port_map); - - probe_ent->n_ports = max_port + 1; - } else - probe_ent->n_ports = cap_n_ports; + hpriv->cap, hpriv->port_map, probe_ent->n_ports); using_dac = hpriv->cap & HOST_CAP_64; if (using_dac && |