|
|
@@ -81,6 +81,12 @@ enum board_ids {
|
|
|
board_ahci_sb700, /* for SB700 and SB800 */
|
|
|
board_ahci_vt8251,
|
|
|
|
|
|
+ /*
|
|
|
+ * board IDs for Intel chipsets that support more than 6 ports
|
|
|
+ * *and* end up needing the PCS quirk.
|
|
|
+ */
|
|
|
+ board_ahci_pcs7,
|
|
|
+
|
|
|
/* aliases */
|
|
|
board_ahci_mcp_linux = board_ahci_mcp65,
|
|
|
board_ahci_mcp67 = board_ahci_mcp65,
|
|
|
@@ -236,6 +242,12 @@ static const struct ata_port_info ahci_port_info[] = {
|
|
|
.udma_mask = ATA_UDMA6,
|
|
|
.port_ops = &ahci_vt8251_ops,
|
|
|
},
|
|
|
+ [board_ahci_pcs7] = {
|
|
|
+ .flags = AHCI_FLAG_COMMON,
|
|
|
+ .pio_mask = ATA_PIO4,
|
|
|
+ .udma_mask = ATA_UDMA6,
|
|
|
+ .port_ops = &ahci_ops,
|
|
|
+ },
|
|
|
};
|
|
|
|
|
|
static const struct pci_device_id ahci_pci_tbl[] = {
|
|
|
@@ -280,26 +292,26 @@ static const struct pci_device_id ahci_pci_tbl[] = {
|
|
|
{ PCI_VDEVICE(INTEL, 0x3b2b), board_ahci }, /* PCH RAID */
|
|
|
{ PCI_VDEVICE(INTEL, 0x3b2c), board_ahci_mobile }, /* PCH M RAID */
|
|
|
{ PCI_VDEVICE(INTEL, 0x3b2f), board_ahci }, /* PCH AHCI */
|
|
|
- { PCI_VDEVICE(INTEL, 0x19b0), board_ahci }, /* DNV AHCI */
|
|
|
- { PCI_VDEVICE(INTEL, 0x19b1), board_ahci }, /* DNV AHCI */
|
|
|
- { PCI_VDEVICE(INTEL, 0x19b2), board_ahci }, /* DNV AHCI */
|
|
|
- { PCI_VDEVICE(INTEL, 0x19b3), board_ahci }, /* DNV AHCI */
|
|
|
- { PCI_VDEVICE(INTEL, 0x19b4), board_ahci }, /* DNV AHCI */
|
|
|
- { PCI_VDEVICE(INTEL, 0x19b5), board_ahci }, /* DNV AHCI */
|
|
|
- { PCI_VDEVICE(INTEL, 0x19b6), board_ahci }, /* DNV AHCI */
|
|
|
- { PCI_VDEVICE(INTEL, 0x19b7), board_ahci }, /* DNV AHCI */
|
|
|
- { PCI_VDEVICE(INTEL, 0x19bE), board_ahci }, /* DNV AHCI */
|
|
|
- { PCI_VDEVICE(INTEL, 0x19bF), board_ahci }, /* DNV AHCI */
|
|
|
- { PCI_VDEVICE(INTEL, 0x19c0), board_ahci }, /* DNV AHCI */
|
|
|
- { PCI_VDEVICE(INTEL, 0x19c1), board_ahci }, /* DNV AHCI */
|
|
|
- { PCI_VDEVICE(INTEL, 0x19c2), board_ahci }, /* DNV AHCI */
|
|
|
- { PCI_VDEVICE(INTEL, 0x19c3), board_ahci }, /* DNV AHCI */
|
|
|
- { PCI_VDEVICE(INTEL, 0x19c4), board_ahci }, /* DNV AHCI */
|
|
|
- { PCI_VDEVICE(INTEL, 0x19c5), board_ahci }, /* DNV AHCI */
|
|
|
- { PCI_VDEVICE(INTEL, 0x19c6), board_ahci }, /* DNV AHCI */
|
|
|
- { PCI_VDEVICE(INTEL, 0x19c7), board_ahci }, /* DNV AHCI */
|
|
|
- { PCI_VDEVICE(INTEL, 0x19cE), board_ahci }, /* DNV AHCI */
|
|
|
- { PCI_VDEVICE(INTEL, 0x19cF), board_ahci }, /* DNV AHCI */
|
|
|
+ { PCI_VDEVICE(INTEL, 0x19b0), board_ahci_pcs7 }, /* DNV AHCI */
|
|
|
+ { PCI_VDEVICE(INTEL, 0x19b1), board_ahci_pcs7 }, /* DNV AHCI */
|
|
|
+ { PCI_VDEVICE(INTEL, 0x19b2), board_ahci_pcs7 }, /* DNV AHCI */
|
|
|
+ { PCI_VDEVICE(INTEL, 0x19b3), board_ahci_pcs7 }, /* DNV AHCI */
|
|
|
+ { PCI_VDEVICE(INTEL, 0x19b4), board_ahci_pcs7 }, /* DNV AHCI */
|
|
|
+ { PCI_VDEVICE(INTEL, 0x19b5), board_ahci_pcs7 }, /* DNV AHCI */
|
|
|
+ { PCI_VDEVICE(INTEL, 0x19b6), board_ahci_pcs7 }, /* DNV AHCI */
|
|
|
+ { PCI_VDEVICE(INTEL, 0x19b7), board_ahci_pcs7 }, /* DNV AHCI */
|
|
|
+ { PCI_VDEVICE(INTEL, 0x19bE), board_ahci_pcs7 }, /* DNV AHCI */
|
|
|
+ { PCI_VDEVICE(INTEL, 0x19bF), board_ahci_pcs7 }, /* DNV AHCI */
|
|
|
+ { PCI_VDEVICE(INTEL, 0x19c0), board_ahci_pcs7 }, /* DNV AHCI */
|
|
|
+ { PCI_VDEVICE(INTEL, 0x19c1), board_ahci_pcs7 }, /* DNV AHCI */
|
|
|
+ { PCI_VDEVICE(INTEL, 0x19c2), board_ahci_pcs7 }, /* DNV AHCI */
|
|
|
+ { PCI_VDEVICE(INTEL, 0x19c3), board_ahci_pcs7 }, /* DNV AHCI */
|
|
|
+ { PCI_VDEVICE(INTEL, 0x19c4), board_ahci_pcs7 }, /* DNV AHCI */
|
|
|
+ { PCI_VDEVICE(INTEL, 0x19c5), board_ahci_pcs7 }, /* DNV AHCI */
|
|
|
+ { PCI_VDEVICE(INTEL, 0x19c6), board_ahci_pcs7 }, /* DNV AHCI */
|
|
|
+ { PCI_VDEVICE(INTEL, 0x19c7), board_ahci_pcs7 }, /* DNV AHCI */
|
|
|
+ { PCI_VDEVICE(INTEL, 0x19cE), board_ahci_pcs7 }, /* DNV AHCI */
|
|
|
+ { PCI_VDEVICE(INTEL, 0x19cF), board_ahci_pcs7 }, /* DNV AHCI */
|
|
|
{ PCI_VDEVICE(INTEL, 0x1c02), board_ahci }, /* CPT AHCI */
|
|
|
{ PCI_VDEVICE(INTEL, 0x1c03), board_ahci_mobile }, /* CPT M AHCI */
|
|
|
{ PCI_VDEVICE(INTEL, 0x1c04), board_ahci }, /* CPT RAID */
|
|
|
@@ -639,30 +651,6 @@ static void ahci_pci_save_initial_config(struct pci_dev *pdev,
|
|
|
ahci_save_initial_config(&pdev->dev, hpriv);
|
|
|
}
|
|
|
|
|
|
-static int ahci_pci_reset_controller(struct ata_host *host)
|
|
|
-{
|
|
|
- struct pci_dev *pdev = to_pci_dev(host->dev);
|
|
|
- int rc;
|
|
|
-
|
|
|
- rc = ahci_reset_controller(host);
|
|
|
- if (rc)
|
|
|
- return rc;
|
|
|
-
|
|
|
- if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
|
|
|
- struct ahci_host_priv *hpriv = host->private_data;
|
|
|
- u16 tmp16;
|
|
|
-
|
|
|
- /* configure PCS */
|
|
|
- pci_read_config_word(pdev, 0x92, &tmp16);
|
|
|
- if ((tmp16 & hpriv->port_map) != hpriv->port_map) {
|
|
|
- tmp16 |= hpriv->port_map;
|
|
|
- pci_write_config_word(pdev, 0x92, tmp16);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
static void ahci_pci_init_controller(struct ata_host *host)
|
|
|
{
|
|
|
struct ahci_host_priv *hpriv = host->private_data;
|
|
|
@@ -865,7 +853,7 @@ static int ahci_pci_device_runtime_resume(struct device *dev)
|
|
|
struct ata_host *host = pci_get_drvdata(pdev);
|
|
|
int rc;
|
|
|
|
|
|
- rc = ahci_pci_reset_controller(host);
|
|
|
+ rc = ahci_reset_controller(host);
|
|
|
if (rc)
|
|
|
return rc;
|
|
|
ahci_pci_init_controller(host);
|
|
|
@@ -900,7 +888,7 @@ static int ahci_pci_device_resume(struct device *dev)
|
|
|
ahci_mcp89_apple_enable(pdev);
|
|
|
|
|
|
if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
|
|
|
- rc = ahci_pci_reset_controller(host);
|
|
|
+ rc = ahci_reset_controller(host);
|
|
|
if (rc)
|
|
|
return rc;
|
|
|
|
|
|
@@ -1635,6 +1623,34 @@ update_policy:
|
|
|
ap->target_lpm_policy = policy;
|
|
|
}
|
|
|
|
|
|
+static void ahci_intel_pcs_quirk(struct pci_dev *pdev, struct ahci_host_priv *hpriv)
|
|
|
+{
|
|
|
+ const struct pci_device_id *id = pci_match_id(ahci_pci_tbl, pdev);
|
|
|
+ u16 tmp16;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Only apply the 6-port PCS quirk for known legacy platforms.
|
|
|
+ */
|
|
|
+ if (!id || id->vendor != PCI_VENDOR_ID_INTEL)
|
|
|
+ return;
|
|
|
+ if (((enum board_ids) id->driver_data) < board_ahci_pcs7)
|
|
|
+ return;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * port_map is determined from PORTS_IMPL PCI register which is
|
|
|
+ * implemented as write or write-once register. If the register
|
|
|
+ * isn't programmed, ahci automatically generates it from number
|
|
|
+ * of ports, which is good enough for PCS programming. It is
|
|
|
+ * otherwise expected that platform firmware enables the ports
|
|
|
+ * before the OS boots.
|
|
|
+ */
|
|
|
+ pci_read_config_word(pdev, PCS_6, &tmp16);
|
|
|
+ if ((tmp16 & hpriv->port_map) != hpriv->port_map) {
|
|
|
+ tmp16 |= hpriv->port_map;
|
|
|
+ pci_write_config_word(pdev, PCS_6, tmp16);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|
|
{
|
|
|
unsigned int board_id = ent->driver_data;
|
|
|
@@ -1747,6 +1763,12 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|
|
/* save initial config */
|
|
|
ahci_pci_save_initial_config(pdev, hpriv);
|
|
|
|
|
|
+ /*
|
|
|
+ * If platform firmware failed to enable ports, try to enable
|
|
|
+ * them here.
|
|
|
+ */
|
|
|
+ ahci_intel_pcs_quirk(pdev, hpriv);
|
|
|
+
|
|
|
/* prepare host */
|
|
|
if (hpriv->cap & HOST_CAP_NCQ) {
|
|
|
pi.flags |= ATA_FLAG_NCQ;
|
|
|
@@ -1856,7 +1878,7 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|
|
if (rc)
|
|
|
return rc;
|
|
|
|
|
|
- rc = ahci_pci_reset_controller(host);
|
|
|
+ rc = ahci_reset_controller(host);
|
|
|
if (rc)
|
|
|
return rc;
|
|
|
|