Skip to content

Commit c312ef1

Browse files
djbwaxboe
authored andcommitted
libata/ahci: Drop PCS quirk for Denverton and beyond
The Linux ahci driver has historically implemented a configuration fixup for platforms / platform-firmware that fails to enable the ports prior to OS hand-off at boot. The fixup was originally implemented way back before ahci moved from drivers/scsi/ to drivers/ata/, and was updated in 2007 via commit 49f2909 "ahci: update PCS programming". The quirk sets a port-enable bitmap in the PCS register at offset 0x92. This quirk could be applied generically up until the arrival of the Denverton (DNV) platform. The DNV AHCI controller architecture supports more than 6 ports and along with that the PCS register location and format were updated to allow for more possible ports in the bitmap. DNV AHCI expands the register to 32-bits and moves it to offset 0x94. As it stands there are no known problem reports with existing Linux trying to set bits at offset 0x92 which indicates that the quirk is not applicable. Likely it is not applicable on a wider range of platforms, but it is difficult to discern which platforms if any still depend on the quirk. Rather than try to fix the PCS quirk to consider the DNV register layout instead require explicit opt-in. The assumption is that the OS driver need not touch this register, and platforms can be added with a new boad_ahci_pcs7 board-id when / if problematic platforms are found in the future. The logic in ahci_intel_pcs_quirk() looks for all Intel AHCI instances with "legacy" board-ids and otherwise skips the quirk if the board was matched by class-code. Reported-by: Stephen Douthit <[email protected]> Cc: Christoph Hellwig <[email protected]> Reviewed-by: Stephen Douthit <[email protected]> Signed-off-by: Dan Williams <[email protected]> Signed-off-by: Jens Axboe <[email protected]>
1 parent 60fc35f commit c312ef1

File tree

2 files changed

+71
-47
lines changed

2 files changed

+71
-47
lines changed

drivers/ata/ahci.c

Lines changed: 69 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,12 @@ enum board_ids {
6565
board_ahci_sb700, /* for SB700 and SB800 */
6666
board_ahci_vt8251,
6767

68+
/*
69+
* board IDs for Intel chipsets that support more than 6 ports
70+
* *and* end up needing the PCS quirk.
71+
*/
72+
board_ahci_pcs7,
73+
6874
/* aliases */
6975
board_ahci_mcp_linux = board_ahci_mcp65,
7076
board_ahci_mcp67 = board_ahci_mcp65,
@@ -220,6 +226,12 @@ static const struct ata_port_info ahci_port_info[] = {
220226
.udma_mask = ATA_UDMA6,
221227
.port_ops = &ahci_vt8251_ops,
222228
},
229+
[board_ahci_pcs7] = {
230+
.flags = AHCI_FLAG_COMMON,
231+
.pio_mask = ATA_PIO4,
232+
.udma_mask = ATA_UDMA6,
233+
.port_ops = &ahci_ops,
234+
},
223235
};
224236

225237
static const struct pci_device_id ahci_pci_tbl[] = {
@@ -264,26 +276,26 @@ static const struct pci_device_id ahci_pci_tbl[] = {
264276
{ PCI_VDEVICE(INTEL, 0x3b2b), board_ahci }, /* PCH RAID */
265277
{ PCI_VDEVICE(INTEL, 0x3b2c), board_ahci_mobile }, /* PCH M RAID */
266278
{ PCI_VDEVICE(INTEL, 0x3b2f), board_ahci }, /* PCH AHCI */
267-
{ PCI_VDEVICE(INTEL, 0x19b0), board_ahci }, /* DNV AHCI */
268-
{ PCI_VDEVICE(INTEL, 0x19b1), board_ahci }, /* DNV AHCI */
269-
{ PCI_VDEVICE(INTEL, 0x19b2), board_ahci }, /* DNV AHCI */
270-
{ PCI_VDEVICE(INTEL, 0x19b3), board_ahci }, /* DNV AHCI */
271-
{ PCI_VDEVICE(INTEL, 0x19b4), board_ahci }, /* DNV AHCI */
272-
{ PCI_VDEVICE(INTEL, 0x19b5), board_ahci }, /* DNV AHCI */
273-
{ PCI_VDEVICE(INTEL, 0x19b6), board_ahci }, /* DNV AHCI */
274-
{ PCI_VDEVICE(INTEL, 0x19b7), board_ahci }, /* DNV AHCI */
275-
{ PCI_VDEVICE(INTEL, 0x19bE), board_ahci }, /* DNV AHCI */
276-
{ PCI_VDEVICE(INTEL, 0x19bF), board_ahci }, /* DNV AHCI */
277-
{ PCI_VDEVICE(INTEL, 0x19c0), board_ahci }, /* DNV AHCI */
278-
{ PCI_VDEVICE(INTEL, 0x19c1), board_ahci }, /* DNV AHCI */
279-
{ PCI_VDEVICE(INTEL, 0x19c2), board_ahci }, /* DNV AHCI */
280-
{ PCI_VDEVICE(INTEL, 0x19c3), board_ahci }, /* DNV AHCI */
281-
{ PCI_VDEVICE(INTEL, 0x19c4), board_ahci }, /* DNV AHCI */
282-
{ PCI_VDEVICE(INTEL, 0x19c5), board_ahci }, /* DNV AHCI */
283-
{ PCI_VDEVICE(INTEL, 0x19c6), board_ahci }, /* DNV AHCI */
284-
{ PCI_VDEVICE(INTEL, 0x19c7), board_ahci }, /* DNV AHCI */
285-
{ PCI_VDEVICE(INTEL, 0x19cE), board_ahci }, /* DNV AHCI */
286-
{ PCI_VDEVICE(INTEL, 0x19cF), board_ahci }, /* DNV AHCI */
279+
{ PCI_VDEVICE(INTEL, 0x19b0), board_ahci_pcs7 }, /* DNV AHCI */
280+
{ PCI_VDEVICE(INTEL, 0x19b1), board_ahci_pcs7 }, /* DNV AHCI */
281+
{ PCI_VDEVICE(INTEL, 0x19b2), board_ahci_pcs7 }, /* DNV AHCI */
282+
{ PCI_VDEVICE(INTEL, 0x19b3), board_ahci_pcs7 }, /* DNV AHCI */
283+
{ PCI_VDEVICE(INTEL, 0x19b4), board_ahci_pcs7 }, /* DNV AHCI */
284+
{ PCI_VDEVICE(INTEL, 0x19b5), board_ahci_pcs7 }, /* DNV AHCI */
285+
{ PCI_VDEVICE(INTEL, 0x19b6), board_ahci_pcs7 }, /* DNV AHCI */
286+
{ PCI_VDEVICE(INTEL, 0x19b7), board_ahci_pcs7 }, /* DNV AHCI */
287+
{ PCI_VDEVICE(INTEL, 0x19bE), board_ahci_pcs7 }, /* DNV AHCI */
288+
{ PCI_VDEVICE(INTEL, 0x19bF), board_ahci_pcs7 }, /* DNV AHCI */
289+
{ PCI_VDEVICE(INTEL, 0x19c0), board_ahci_pcs7 }, /* DNV AHCI */
290+
{ PCI_VDEVICE(INTEL, 0x19c1), board_ahci_pcs7 }, /* DNV AHCI */
291+
{ PCI_VDEVICE(INTEL, 0x19c2), board_ahci_pcs7 }, /* DNV AHCI */
292+
{ PCI_VDEVICE(INTEL, 0x19c3), board_ahci_pcs7 }, /* DNV AHCI */
293+
{ PCI_VDEVICE(INTEL, 0x19c4), board_ahci_pcs7 }, /* DNV AHCI */
294+
{ PCI_VDEVICE(INTEL, 0x19c5), board_ahci_pcs7 }, /* DNV AHCI */
295+
{ PCI_VDEVICE(INTEL, 0x19c6), board_ahci_pcs7 }, /* DNV AHCI */
296+
{ PCI_VDEVICE(INTEL, 0x19c7), board_ahci_pcs7 }, /* DNV AHCI */
297+
{ PCI_VDEVICE(INTEL, 0x19cE), board_ahci_pcs7 }, /* DNV AHCI */
298+
{ PCI_VDEVICE(INTEL, 0x19cF), board_ahci_pcs7 }, /* DNV AHCI */
287299
{ PCI_VDEVICE(INTEL, 0x1c02), board_ahci }, /* CPT AHCI */
288300
{ PCI_VDEVICE(INTEL, 0x1c03), board_ahci_mobile }, /* CPT M AHCI */
289301
{ PCI_VDEVICE(INTEL, 0x1c04), board_ahci }, /* CPT RAID */
@@ -623,30 +635,6 @@ static void ahci_pci_save_initial_config(struct pci_dev *pdev,
623635
ahci_save_initial_config(&pdev->dev, hpriv);
624636
}
625637

626-
static int ahci_pci_reset_controller(struct ata_host *host)
627-
{
628-
struct pci_dev *pdev = to_pci_dev(host->dev);
629-
int rc;
630-
631-
rc = ahci_reset_controller(host);
632-
if (rc)
633-
return rc;
634-
635-
if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
636-
struct ahci_host_priv *hpriv = host->private_data;
637-
u16 tmp16;
638-
639-
/* configure PCS */
640-
pci_read_config_word(pdev, 0x92, &tmp16);
641-
if ((tmp16 & hpriv->port_map) != hpriv->port_map) {
642-
tmp16 |= hpriv->port_map;
643-
pci_write_config_word(pdev, 0x92, tmp16);
644-
}
645-
}
646-
647-
return 0;
648-
}
649-
650638
static void ahci_pci_init_controller(struct ata_host *host)
651639
{
652640
struct ahci_host_priv *hpriv = host->private_data;
@@ -849,7 +837,7 @@ static int ahci_pci_device_runtime_resume(struct device *dev)
849837
struct ata_host *host = pci_get_drvdata(pdev);
850838
int rc;
851839

852-
rc = ahci_pci_reset_controller(host);
840+
rc = ahci_reset_controller(host);
853841
if (rc)
854842
return rc;
855843
ahci_pci_init_controller(host);
@@ -884,7 +872,7 @@ static int ahci_pci_device_resume(struct device *dev)
884872
ahci_mcp89_apple_enable(pdev);
885873

886874
if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
887-
rc = ahci_pci_reset_controller(host);
875+
rc = ahci_reset_controller(host);
888876
if (rc)
889877
return rc;
890878

@@ -1602,6 +1590,34 @@ static void ahci_update_initial_lpm_policy(struct ata_port *ap,
16021590
ap->target_lpm_policy = policy;
16031591
}
16041592

1593+
static void ahci_intel_pcs_quirk(struct pci_dev *pdev, struct ahci_host_priv *hpriv)
1594+
{
1595+
const struct pci_device_id *id = pci_match_id(ahci_pci_tbl, pdev);
1596+
u16 tmp16;
1597+
1598+
/*
1599+
* Only apply the 6-port PCS quirk for known legacy platforms.
1600+
*/
1601+
if (!id || id->vendor != PCI_VENDOR_ID_INTEL)
1602+
return;
1603+
if (((enum board_ids) id->driver_data) < board_ahci_pcs7)
1604+
return;
1605+
1606+
/*
1607+
* port_map is determined from PORTS_IMPL PCI register which is
1608+
* implemented as write or write-once register. If the register
1609+
* isn't programmed, ahci automatically generates it from number
1610+
* of ports, which is good enough for PCS programming. It is
1611+
* otherwise expected that platform firmware enables the ports
1612+
* before the OS boots.
1613+
*/
1614+
pci_read_config_word(pdev, PCS_6, &tmp16);
1615+
if ((tmp16 & hpriv->port_map) != hpriv->port_map) {
1616+
tmp16 |= hpriv->port_map;
1617+
pci_write_config_word(pdev, PCS_6, tmp16);
1618+
}
1619+
}
1620+
16051621
static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
16061622
{
16071623
unsigned int board_id = ent->driver_data;
@@ -1714,6 +1730,12 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
17141730
/* save initial config */
17151731
ahci_pci_save_initial_config(pdev, hpriv);
17161732

1733+
/*
1734+
* If platform firmware failed to enable ports, try to enable
1735+
* them here.
1736+
*/
1737+
ahci_intel_pcs_quirk(pdev, hpriv);
1738+
17171739
/* prepare host */
17181740
if (hpriv->cap & HOST_CAP_NCQ) {
17191741
pi.flags |= ATA_FLAG_NCQ;
@@ -1823,7 +1845,7 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
18231845
if (rc)
18241846
return rc;
18251847

1826-
rc = ahci_pci_reset_controller(host);
1848+
rc = ahci_reset_controller(host);
18271849
if (rc)
18281850
return rc;
18291851

drivers/ata/ahci.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,8 @@ enum {
247247
ATA_FLAG_ACPI_SATA | ATA_FLAG_AN,
248248

249249
ICH_MAP = 0x90, /* ICH MAP register */
250+
PCS_6 = 0x92, /* 6 port PCS */
251+
PCS_7 = 0x94, /* 7+ port PCS (Denverton) */
250252

251253
/* em constants */
252254
EM_MAX_SLOTS = 8,

0 commit comments

Comments
 (0)