162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  ahci.c - AHCI SATA support
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *  Maintained by:  Tejun Heo <tj@kernel.org>
662306a36Sopenharmony_ci *    		    Please ALWAYS copy linux-ide@vger.kernel.org
762306a36Sopenharmony_ci *		    on emails.
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci *  Copyright 2004-2005 Red Hat, Inc.
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci * libata documentation is available via 'make {ps|pdf}docs',
1262306a36Sopenharmony_ci * as Documentation/driver-api/libata.rst
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci * AHCI hardware documentation:
1562306a36Sopenharmony_ci * http://www.intel.com/technology/serialata/pdf/rev1_0.pdf
1662306a36Sopenharmony_ci * http://www.intel.com/technology/serialata/pdf/rev1_1.pdf
1762306a36Sopenharmony_ci */
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#include <linux/kernel.h>
2062306a36Sopenharmony_ci#include <linux/module.h>
2162306a36Sopenharmony_ci#include <linux/pci.h>
2262306a36Sopenharmony_ci#include <linux/blkdev.h>
2362306a36Sopenharmony_ci#include <linux/delay.h>
2462306a36Sopenharmony_ci#include <linux/interrupt.h>
2562306a36Sopenharmony_ci#include <linux/dma-mapping.h>
2662306a36Sopenharmony_ci#include <linux/device.h>
2762306a36Sopenharmony_ci#include <linux/dmi.h>
2862306a36Sopenharmony_ci#include <linux/gfp.h>
2962306a36Sopenharmony_ci#include <scsi/scsi_host.h>
3062306a36Sopenharmony_ci#include <scsi/scsi_cmnd.h>
3162306a36Sopenharmony_ci#include <linux/libata.h>
3262306a36Sopenharmony_ci#include <linux/ahci-remap.h>
3362306a36Sopenharmony_ci#include <linux/io-64-nonatomic-lo-hi.h>
3462306a36Sopenharmony_ci#include "ahci.h"
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci#define DRV_NAME	"ahci"
3762306a36Sopenharmony_ci#define DRV_VERSION	"3.0"
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_cienum {
4062306a36Sopenharmony_ci	AHCI_PCI_BAR_STA2X11	= 0,
4162306a36Sopenharmony_ci	AHCI_PCI_BAR_CAVIUM	= 0,
4262306a36Sopenharmony_ci	AHCI_PCI_BAR_LOONGSON	= 0,
4362306a36Sopenharmony_ci	AHCI_PCI_BAR_ENMOTUS	= 2,
4462306a36Sopenharmony_ci	AHCI_PCI_BAR_CAVIUM_GEN5	= 4,
4562306a36Sopenharmony_ci	AHCI_PCI_BAR_STANDARD	= 5,
4662306a36Sopenharmony_ci};
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_cienum board_ids {
4962306a36Sopenharmony_ci	/* board IDs by feature in alphabetical order */
5062306a36Sopenharmony_ci	board_ahci,
5162306a36Sopenharmony_ci	board_ahci_43bit_dma,
5262306a36Sopenharmony_ci	board_ahci_ign_iferr,
5362306a36Sopenharmony_ci	board_ahci_low_power,
5462306a36Sopenharmony_ci	board_ahci_no_debounce_delay,
5562306a36Sopenharmony_ci	board_ahci_nomsi,
5662306a36Sopenharmony_ci	board_ahci_noncq,
5762306a36Sopenharmony_ci	board_ahci_nosntf,
5862306a36Sopenharmony_ci	board_ahci_yes_fbs,
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	/* board IDs for specific chipsets in alphabetical order */
6162306a36Sopenharmony_ci	board_ahci_al,
6262306a36Sopenharmony_ci	board_ahci_avn,
6362306a36Sopenharmony_ci	board_ahci_mcp65,
6462306a36Sopenharmony_ci	board_ahci_mcp77,
6562306a36Sopenharmony_ci	board_ahci_mcp89,
6662306a36Sopenharmony_ci	board_ahci_mv,
6762306a36Sopenharmony_ci	board_ahci_sb600,
6862306a36Sopenharmony_ci	board_ahci_sb700,	/* for SB700 and SB800 */
6962306a36Sopenharmony_ci	board_ahci_vt8251,
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	/*
7262306a36Sopenharmony_ci	 * board IDs for Intel chipsets that support more than 6 ports
7362306a36Sopenharmony_ci	 * *and* end up needing the PCS quirk.
7462306a36Sopenharmony_ci	 */
7562306a36Sopenharmony_ci	board_ahci_pcs7,
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	/* aliases */
7862306a36Sopenharmony_ci	board_ahci_mcp_linux	= board_ahci_mcp65,
7962306a36Sopenharmony_ci	board_ahci_mcp67	= board_ahci_mcp65,
8062306a36Sopenharmony_ci	board_ahci_mcp73	= board_ahci_mcp65,
8162306a36Sopenharmony_ci	board_ahci_mcp79	= board_ahci_mcp77,
8262306a36Sopenharmony_ci};
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_cistatic int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
8562306a36Sopenharmony_cistatic void ahci_remove_one(struct pci_dev *dev);
8662306a36Sopenharmony_cistatic void ahci_shutdown_one(struct pci_dev *dev);
8762306a36Sopenharmony_cistatic void ahci_intel_pcs_quirk(struct pci_dev *pdev, struct ahci_host_priv *hpriv);
8862306a36Sopenharmony_cistatic int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
8962306a36Sopenharmony_ci				 unsigned long deadline);
9062306a36Sopenharmony_cistatic int ahci_avn_hardreset(struct ata_link *link, unsigned int *class,
9162306a36Sopenharmony_ci			      unsigned long deadline);
9262306a36Sopenharmony_cistatic void ahci_mcp89_apple_enable(struct pci_dev *pdev);
9362306a36Sopenharmony_cistatic bool is_mcp89_apple(struct pci_dev *pdev);
9462306a36Sopenharmony_cistatic int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
9562306a36Sopenharmony_ci				unsigned long deadline);
9662306a36Sopenharmony_ci#ifdef CONFIG_PM
9762306a36Sopenharmony_cistatic int ahci_pci_device_runtime_suspend(struct device *dev);
9862306a36Sopenharmony_cistatic int ahci_pci_device_runtime_resume(struct device *dev);
9962306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
10062306a36Sopenharmony_cistatic int ahci_pci_device_suspend(struct device *dev);
10162306a36Sopenharmony_cistatic int ahci_pci_device_resume(struct device *dev);
10262306a36Sopenharmony_ci#endif
10362306a36Sopenharmony_ci#endif /* CONFIG_PM */
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_cistatic const struct scsi_host_template ahci_sht = {
10662306a36Sopenharmony_ci	AHCI_SHT("ahci"),
10762306a36Sopenharmony_ci};
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_cistatic struct ata_port_operations ahci_vt8251_ops = {
11062306a36Sopenharmony_ci	.inherits		= &ahci_ops,
11162306a36Sopenharmony_ci	.hardreset		= ahci_vt8251_hardreset,
11262306a36Sopenharmony_ci};
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_cistatic struct ata_port_operations ahci_p5wdh_ops = {
11562306a36Sopenharmony_ci	.inherits		= &ahci_ops,
11662306a36Sopenharmony_ci	.hardreset		= ahci_p5wdh_hardreset,
11762306a36Sopenharmony_ci};
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_cistatic struct ata_port_operations ahci_avn_ops = {
12062306a36Sopenharmony_ci	.inherits		= &ahci_ops,
12162306a36Sopenharmony_ci	.hardreset		= ahci_avn_hardreset,
12262306a36Sopenharmony_ci};
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_cistatic const struct ata_port_info ahci_port_info[] = {
12562306a36Sopenharmony_ci	/* by features */
12662306a36Sopenharmony_ci	[board_ahci] = {
12762306a36Sopenharmony_ci		.flags		= AHCI_FLAG_COMMON,
12862306a36Sopenharmony_ci		.pio_mask	= ATA_PIO4,
12962306a36Sopenharmony_ci		.udma_mask	= ATA_UDMA6,
13062306a36Sopenharmony_ci		.port_ops	= &ahci_ops,
13162306a36Sopenharmony_ci	},
13262306a36Sopenharmony_ci	[board_ahci_43bit_dma] = {
13362306a36Sopenharmony_ci		AHCI_HFLAGS	(AHCI_HFLAG_43BIT_ONLY),
13462306a36Sopenharmony_ci		.flags		= AHCI_FLAG_COMMON,
13562306a36Sopenharmony_ci		.pio_mask	= ATA_PIO4,
13662306a36Sopenharmony_ci		.udma_mask	= ATA_UDMA6,
13762306a36Sopenharmony_ci		.port_ops	= &ahci_ops,
13862306a36Sopenharmony_ci	},
13962306a36Sopenharmony_ci	[board_ahci_ign_iferr] = {
14062306a36Sopenharmony_ci		AHCI_HFLAGS	(AHCI_HFLAG_IGN_IRQ_IF_ERR),
14162306a36Sopenharmony_ci		.flags		= AHCI_FLAG_COMMON,
14262306a36Sopenharmony_ci		.pio_mask	= ATA_PIO4,
14362306a36Sopenharmony_ci		.udma_mask	= ATA_UDMA6,
14462306a36Sopenharmony_ci		.port_ops	= &ahci_ops,
14562306a36Sopenharmony_ci	},
14662306a36Sopenharmony_ci	[board_ahci_low_power] = {
14762306a36Sopenharmony_ci		AHCI_HFLAGS	(AHCI_HFLAG_USE_LPM_POLICY),
14862306a36Sopenharmony_ci		.flags		= AHCI_FLAG_COMMON,
14962306a36Sopenharmony_ci		.pio_mask	= ATA_PIO4,
15062306a36Sopenharmony_ci		.udma_mask	= ATA_UDMA6,
15162306a36Sopenharmony_ci		.port_ops	= &ahci_ops,
15262306a36Sopenharmony_ci	},
15362306a36Sopenharmony_ci	[board_ahci_no_debounce_delay] = {
15462306a36Sopenharmony_ci		.flags		= AHCI_FLAG_COMMON,
15562306a36Sopenharmony_ci		.link_flags	= ATA_LFLAG_NO_DEBOUNCE_DELAY,
15662306a36Sopenharmony_ci		.pio_mask	= ATA_PIO4,
15762306a36Sopenharmony_ci		.udma_mask	= ATA_UDMA6,
15862306a36Sopenharmony_ci		.port_ops	= &ahci_ops,
15962306a36Sopenharmony_ci	},
16062306a36Sopenharmony_ci	[board_ahci_nomsi] = {
16162306a36Sopenharmony_ci		AHCI_HFLAGS	(AHCI_HFLAG_NO_MSI),
16262306a36Sopenharmony_ci		.flags		= AHCI_FLAG_COMMON,
16362306a36Sopenharmony_ci		.pio_mask	= ATA_PIO4,
16462306a36Sopenharmony_ci		.udma_mask	= ATA_UDMA6,
16562306a36Sopenharmony_ci		.port_ops	= &ahci_ops,
16662306a36Sopenharmony_ci	},
16762306a36Sopenharmony_ci	[board_ahci_noncq] = {
16862306a36Sopenharmony_ci		AHCI_HFLAGS	(AHCI_HFLAG_NO_NCQ),
16962306a36Sopenharmony_ci		.flags		= AHCI_FLAG_COMMON,
17062306a36Sopenharmony_ci		.pio_mask	= ATA_PIO4,
17162306a36Sopenharmony_ci		.udma_mask	= ATA_UDMA6,
17262306a36Sopenharmony_ci		.port_ops	= &ahci_ops,
17362306a36Sopenharmony_ci	},
17462306a36Sopenharmony_ci	[board_ahci_nosntf] = {
17562306a36Sopenharmony_ci		AHCI_HFLAGS	(AHCI_HFLAG_NO_SNTF),
17662306a36Sopenharmony_ci		.flags		= AHCI_FLAG_COMMON,
17762306a36Sopenharmony_ci		.pio_mask	= ATA_PIO4,
17862306a36Sopenharmony_ci		.udma_mask	= ATA_UDMA6,
17962306a36Sopenharmony_ci		.port_ops	= &ahci_ops,
18062306a36Sopenharmony_ci	},
18162306a36Sopenharmony_ci	[board_ahci_yes_fbs] = {
18262306a36Sopenharmony_ci		AHCI_HFLAGS	(AHCI_HFLAG_YES_FBS),
18362306a36Sopenharmony_ci		.flags		= AHCI_FLAG_COMMON,
18462306a36Sopenharmony_ci		.pio_mask	= ATA_PIO4,
18562306a36Sopenharmony_ci		.udma_mask	= ATA_UDMA6,
18662306a36Sopenharmony_ci		.port_ops	= &ahci_ops,
18762306a36Sopenharmony_ci	},
18862306a36Sopenharmony_ci	/* by chipsets */
18962306a36Sopenharmony_ci	[board_ahci_al] = {
19062306a36Sopenharmony_ci		AHCI_HFLAGS	(AHCI_HFLAG_NO_PMP | AHCI_HFLAG_NO_MSI),
19162306a36Sopenharmony_ci		.flags		= AHCI_FLAG_COMMON,
19262306a36Sopenharmony_ci		.pio_mask	= ATA_PIO4,
19362306a36Sopenharmony_ci		.udma_mask	= ATA_UDMA6,
19462306a36Sopenharmony_ci		.port_ops	= &ahci_ops,
19562306a36Sopenharmony_ci	},
19662306a36Sopenharmony_ci	[board_ahci_avn] = {
19762306a36Sopenharmony_ci		.flags		= AHCI_FLAG_COMMON,
19862306a36Sopenharmony_ci		.pio_mask	= ATA_PIO4,
19962306a36Sopenharmony_ci		.udma_mask	= ATA_UDMA6,
20062306a36Sopenharmony_ci		.port_ops	= &ahci_avn_ops,
20162306a36Sopenharmony_ci	},
20262306a36Sopenharmony_ci	[board_ahci_mcp65] = {
20362306a36Sopenharmony_ci		AHCI_HFLAGS	(AHCI_HFLAG_NO_FPDMA_AA | AHCI_HFLAG_NO_PMP |
20462306a36Sopenharmony_ci				 AHCI_HFLAG_YES_NCQ),
20562306a36Sopenharmony_ci		.flags		= AHCI_FLAG_COMMON | ATA_FLAG_NO_DIPM,
20662306a36Sopenharmony_ci		.pio_mask	= ATA_PIO4,
20762306a36Sopenharmony_ci		.udma_mask	= ATA_UDMA6,
20862306a36Sopenharmony_ci		.port_ops	= &ahci_ops,
20962306a36Sopenharmony_ci	},
21062306a36Sopenharmony_ci	[board_ahci_mcp77] = {
21162306a36Sopenharmony_ci		AHCI_HFLAGS	(AHCI_HFLAG_NO_FPDMA_AA | AHCI_HFLAG_NO_PMP),
21262306a36Sopenharmony_ci		.flags		= AHCI_FLAG_COMMON,
21362306a36Sopenharmony_ci		.pio_mask	= ATA_PIO4,
21462306a36Sopenharmony_ci		.udma_mask	= ATA_UDMA6,
21562306a36Sopenharmony_ci		.port_ops	= &ahci_ops,
21662306a36Sopenharmony_ci	},
21762306a36Sopenharmony_ci	[board_ahci_mcp89] = {
21862306a36Sopenharmony_ci		AHCI_HFLAGS	(AHCI_HFLAG_NO_FPDMA_AA),
21962306a36Sopenharmony_ci		.flags		= AHCI_FLAG_COMMON,
22062306a36Sopenharmony_ci		.pio_mask	= ATA_PIO4,
22162306a36Sopenharmony_ci		.udma_mask	= ATA_UDMA6,
22262306a36Sopenharmony_ci		.port_ops	= &ahci_ops,
22362306a36Sopenharmony_ci	},
22462306a36Sopenharmony_ci	[board_ahci_mv] = {
22562306a36Sopenharmony_ci		AHCI_HFLAGS	(AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_MSI |
22662306a36Sopenharmony_ci				 AHCI_HFLAG_MV_PATA | AHCI_HFLAG_NO_PMP),
22762306a36Sopenharmony_ci		.flags		= ATA_FLAG_SATA | ATA_FLAG_PIO_DMA,
22862306a36Sopenharmony_ci		.pio_mask	= ATA_PIO4,
22962306a36Sopenharmony_ci		.udma_mask	= ATA_UDMA6,
23062306a36Sopenharmony_ci		.port_ops	= &ahci_ops,
23162306a36Sopenharmony_ci	},
23262306a36Sopenharmony_ci	[board_ahci_sb600] = {
23362306a36Sopenharmony_ci		AHCI_HFLAGS	(AHCI_HFLAG_IGN_SERR_INTERNAL |
23462306a36Sopenharmony_ci				 AHCI_HFLAG_NO_MSI | AHCI_HFLAG_SECT255 |
23562306a36Sopenharmony_ci				 AHCI_HFLAG_32BIT_ONLY),
23662306a36Sopenharmony_ci		.flags		= AHCI_FLAG_COMMON,
23762306a36Sopenharmony_ci		.pio_mask	= ATA_PIO4,
23862306a36Sopenharmony_ci		.udma_mask	= ATA_UDMA6,
23962306a36Sopenharmony_ci		.port_ops	= &ahci_pmp_retry_srst_ops,
24062306a36Sopenharmony_ci	},
24162306a36Sopenharmony_ci	[board_ahci_sb700] = {	/* for SB700 and SB800 */
24262306a36Sopenharmony_ci		AHCI_HFLAGS	(AHCI_HFLAG_IGN_SERR_INTERNAL),
24362306a36Sopenharmony_ci		.flags		= AHCI_FLAG_COMMON,
24462306a36Sopenharmony_ci		.pio_mask	= ATA_PIO4,
24562306a36Sopenharmony_ci		.udma_mask	= ATA_UDMA6,
24662306a36Sopenharmony_ci		.port_ops	= &ahci_pmp_retry_srst_ops,
24762306a36Sopenharmony_ci	},
24862306a36Sopenharmony_ci	[board_ahci_vt8251] = {
24962306a36Sopenharmony_ci		AHCI_HFLAGS	(AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_PMP),
25062306a36Sopenharmony_ci		.flags		= AHCI_FLAG_COMMON,
25162306a36Sopenharmony_ci		.pio_mask	= ATA_PIO4,
25262306a36Sopenharmony_ci		.udma_mask	= ATA_UDMA6,
25362306a36Sopenharmony_ci		.port_ops	= &ahci_vt8251_ops,
25462306a36Sopenharmony_ci	},
25562306a36Sopenharmony_ci	[board_ahci_pcs7] = {
25662306a36Sopenharmony_ci		.flags		= AHCI_FLAG_COMMON,
25762306a36Sopenharmony_ci		.pio_mask	= ATA_PIO4,
25862306a36Sopenharmony_ci		.udma_mask	= ATA_UDMA6,
25962306a36Sopenharmony_ci		.port_ops	= &ahci_ops,
26062306a36Sopenharmony_ci	},
26162306a36Sopenharmony_ci};
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_cistatic const struct pci_device_id ahci_pci_tbl[] = {
26462306a36Sopenharmony_ci	/* Intel */
26562306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x06d6), board_ahci }, /* Comet Lake PCH-H RAID */
26662306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x2652), board_ahci }, /* ICH6 */
26762306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x2653), board_ahci }, /* ICH6M */
26862306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x27c1), board_ahci }, /* ICH7 */
26962306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x27c5), board_ahci }, /* ICH7M */
27062306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x27c3), board_ahci }, /* ICH7R */
27162306a36Sopenharmony_ci	{ PCI_VDEVICE(AL, 0x5288), board_ahci_ign_iferr }, /* ULi M5288 */
27262306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x2681), board_ahci }, /* ESB2 */
27362306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x2682), board_ahci }, /* ESB2 */
27462306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x2683), board_ahci }, /* ESB2 */
27562306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x27c6), board_ahci }, /* ICH7-M DH */
27662306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x2821), board_ahci }, /* ICH8 */
27762306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x2822), board_ahci_nosntf }, /* ICH8/Lewisburg RAID*/
27862306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x2824), board_ahci }, /* ICH8 */
27962306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x2829), board_ahci }, /* ICH8M */
28062306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x282a), board_ahci }, /* ICH8M */
28162306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x2922), board_ahci }, /* ICH9 */
28262306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x2923), board_ahci }, /* ICH9 */
28362306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x2924), board_ahci }, /* ICH9 */
28462306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x2925), board_ahci }, /* ICH9 */
28562306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x2927), board_ahci }, /* ICH9 */
28662306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x2929), board_ahci_low_power }, /* ICH9M */
28762306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x292a), board_ahci_low_power }, /* ICH9M */
28862306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x292b), board_ahci_low_power }, /* ICH9M */
28962306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x292c), board_ahci_low_power }, /* ICH9M */
29062306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x292f), board_ahci_low_power }, /* ICH9M */
29162306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x294d), board_ahci }, /* ICH9 */
29262306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x294e), board_ahci_low_power }, /* ICH9M */
29362306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x502a), board_ahci }, /* Tolapai */
29462306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x502b), board_ahci }, /* Tolapai */
29562306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x3a05), board_ahci }, /* ICH10 */
29662306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x3a22), board_ahci }, /* ICH10 */
29762306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x3a25), board_ahci }, /* ICH10 */
29862306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x3b22), board_ahci }, /* PCH AHCI */
29962306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x3b23), board_ahci }, /* PCH AHCI */
30062306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x3b24), board_ahci }, /* PCH RAID */
30162306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x3b25), board_ahci }, /* PCH RAID */
30262306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x3b29), board_ahci_low_power }, /* PCH M AHCI */
30362306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x3b2b), board_ahci }, /* PCH RAID */
30462306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x3b2c), board_ahci_low_power }, /* PCH M RAID */
30562306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x3b2f), board_ahci }, /* PCH AHCI */
30662306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x19b0), board_ahci_pcs7 }, /* DNV AHCI */
30762306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x19b1), board_ahci_pcs7 }, /* DNV AHCI */
30862306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x19b2), board_ahci_pcs7 }, /* DNV AHCI */
30962306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x19b3), board_ahci_pcs7 }, /* DNV AHCI */
31062306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x19b4), board_ahci_pcs7 }, /* DNV AHCI */
31162306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x19b5), board_ahci_pcs7 }, /* DNV AHCI */
31262306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x19b6), board_ahci_pcs7 }, /* DNV AHCI */
31362306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x19b7), board_ahci_pcs7 }, /* DNV AHCI */
31462306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x19bE), board_ahci_pcs7 }, /* DNV AHCI */
31562306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x19bF), board_ahci_pcs7 }, /* DNV AHCI */
31662306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x19c0), board_ahci_pcs7 }, /* DNV AHCI */
31762306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x19c1), board_ahci_pcs7 }, /* DNV AHCI */
31862306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x19c2), board_ahci_pcs7 }, /* DNV AHCI */
31962306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x19c3), board_ahci_pcs7 }, /* DNV AHCI */
32062306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x19c4), board_ahci_pcs7 }, /* DNV AHCI */
32162306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x19c5), board_ahci_pcs7 }, /* DNV AHCI */
32262306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x19c6), board_ahci_pcs7 }, /* DNV AHCI */
32362306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x19c7), board_ahci_pcs7 }, /* DNV AHCI */
32462306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x19cE), board_ahci_pcs7 }, /* DNV AHCI */
32562306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x19cF), board_ahci_pcs7 }, /* DNV AHCI */
32662306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x1c02), board_ahci }, /* CPT AHCI */
32762306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x1c03), board_ahci_low_power }, /* CPT M AHCI */
32862306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x1c04), board_ahci }, /* CPT RAID */
32962306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x1c05), board_ahci_low_power }, /* CPT M RAID */
33062306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x1c06), board_ahci }, /* CPT RAID */
33162306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x1c07), board_ahci }, /* CPT RAID */
33262306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x1d02), board_ahci }, /* PBG AHCI */
33362306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x1d04), board_ahci }, /* PBG RAID */
33462306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x1d06), board_ahci }, /* PBG RAID */
33562306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x2323), board_ahci }, /* DH89xxCC AHCI */
33662306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x1e02), board_ahci }, /* Panther Point AHCI */
33762306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x1e03), board_ahci_low_power }, /* Panther M AHCI */
33862306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x1e04), board_ahci }, /* Panther Point RAID */
33962306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x1e05), board_ahci }, /* Panther Point RAID */
34062306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x1e06), board_ahci }, /* Panther Point RAID */
34162306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x1e07), board_ahci_low_power }, /* Panther M RAID */
34262306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x1e0e), board_ahci }, /* Panther Point RAID */
34362306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x8c02), board_ahci }, /* Lynx Point AHCI */
34462306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x8c03), board_ahci_low_power }, /* Lynx M AHCI */
34562306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x8c04), board_ahci }, /* Lynx Point RAID */
34662306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x8c05), board_ahci_low_power }, /* Lynx M RAID */
34762306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x8c06), board_ahci }, /* Lynx Point RAID */
34862306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x8c07), board_ahci_low_power }, /* Lynx M RAID */
34962306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x8c0e), board_ahci }, /* Lynx Point RAID */
35062306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x8c0f), board_ahci_low_power }, /* Lynx M RAID */
35162306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x9c02), board_ahci_low_power }, /* Lynx LP AHCI */
35262306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x9c03), board_ahci_low_power }, /* Lynx LP AHCI */
35362306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x9c04), board_ahci_low_power }, /* Lynx LP RAID */
35462306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x9c05), board_ahci_low_power }, /* Lynx LP RAID */
35562306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x9c06), board_ahci_low_power }, /* Lynx LP RAID */
35662306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x9c07), board_ahci_low_power }, /* Lynx LP RAID */
35762306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x9c0e), board_ahci_low_power }, /* Lynx LP RAID */
35862306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x9c0f), board_ahci_low_power }, /* Lynx LP RAID */
35962306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x9dd3), board_ahci_low_power }, /* Cannon Lake PCH-LP AHCI */
36062306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x1f22), board_ahci }, /* Avoton AHCI */
36162306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x1f23), board_ahci }, /* Avoton AHCI */
36262306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x1f24), board_ahci }, /* Avoton RAID */
36362306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x1f25), board_ahci }, /* Avoton RAID */
36462306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x1f26), board_ahci }, /* Avoton RAID */
36562306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x1f27), board_ahci }, /* Avoton RAID */
36662306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x1f2e), board_ahci }, /* Avoton RAID */
36762306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x1f2f), board_ahci }, /* Avoton RAID */
36862306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x1f32), board_ahci_avn }, /* Avoton AHCI */
36962306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x1f33), board_ahci_avn }, /* Avoton AHCI */
37062306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x1f34), board_ahci_avn }, /* Avoton RAID */
37162306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x1f35), board_ahci_avn }, /* Avoton RAID */
37262306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x1f36), board_ahci_avn }, /* Avoton RAID */
37362306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x1f37), board_ahci_avn }, /* Avoton RAID */
37462306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x1f3e), board_ahci_avn }, /* Avoton RAID */
37562306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x1f3f), board_ahci_avn }, /* Avoton RAID */
37662306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x2823), board_ahci }, /* Wellsburg/Lewisburg AHCI*/
37762306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x2826), board_ahci }, /* *burg SATA0 'RAID' */
37862306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x2827), board_ahci }, /* *burg SATA1 'RAID' */
37962306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x282f), board_ahci }, /* *burg SATA2 'RAID' */
38062306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x43d4), board_ahci }, /* Rocket Lake PCH-H RAID */
38162306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x43d5), board_ahci }, /* Rocket Lake PCH-H RAID */
38262306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x43d6), board_ahci }, /* Rocket Lake PCH-H RAID */
38362306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x43d7), board_ahci }, /* Rocket Lake PCH-H RAID */
38462306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x8d02), board_ahci }, /* Wellsburg AHCI */
38562306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x8d04), board_ahci }, /* Wellsburg RAID */
38662306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x8d06), board_ahci }, /* Wellsburg RAID */
38762306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x8d0e), board_ahci }, /* Wellsburg RAID */
38862306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x8d62), board_ahci }, /* Wellsburg AHCI */
38962306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x8d64), board_ahci }, /* Wellsburg RAID */
39062306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x8d66), board_ahci }, /* Wellsburg RAID */
39162306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x8d6e), board_ahci }, /* Wellsburg RAID */
39262306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x23a3), board_ahci }, /* Coleto Creek AHCI */
39362306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x9c83), board_ahci_low_power }, /* Wildcat LP AHCI */
39462306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x9c85), board_ahci_low_power }, /* Wildcat LP RAID */
39562306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x9c87), board_ahci_low_power }, /* Wildcat LP RAID */
39662306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x9c8f), board_ahci_low_power }, /* Wildcat LP RAID */
39762306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x8c82), board_ahci }, /* 9 Series AHCI */
39862306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x8c83), board_ahci_low_power }, /* 9 Series M AHCI */
39962306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x8c84), board_ahci }, /* 9 Series RAID */
40062306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x8c85), board_ahci_low_power }, /* 9 Series M RAID */
40162306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x8c86), board_ahci }, /* 9 Series RAID */
40262306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x8c87), board_ahci_low_power }, /* 9 Series M RAID */
40362306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x8c8e), board_ahci }, /* 9 Series RAID */
40462306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x8c8f), board_ahci_low_power }, /* 9 Series M RAID */
40562306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x9d03), board_ahci_low_power }, /* Sunrise LP AHCI */
40662306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x9d05), board_ahci_low_power }, /* Sunrise LP RAID */
40762306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x9d07), board_ahci_low_power }, /* Sunrise LP RAID */
40862306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0xa102), board_ahci }, /* Sunrise Point-H AHCI */
40962306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0xa103), board_ahci_low_power }, /* Sunrise M AHCI */
41062306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0xa105), board_ahci }, /* Sunrise Point-H RAID */
41162306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0xa106), board_ahci }, /* Sunrise Point-H RAID */
41262306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0xa107), board_ahci_low_power }, /* Sunrise M RAID */
41362306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0xa10f), board_ahci }, /* Sunrise Point-H RAID */
41462306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0xa182), board_ahci }, /* Lewisburg AHCI*/
41562306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0xa186), board_ahci }, /* Lewisburg RAID*/
41662306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0xa1d2), board_ahci }, /* Lewisburg RAID*/
41762306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0xa1d6), board_ahci }, /* Lewisburg RAID*/
41862306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0xa202), board_ahci }, /* Lewisburg AHCI*/
41962306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0xa206), board_ahci }, /* Lewisburg RAID*/
42062306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0xa252), board_ahci }, /* Lewisburg RAID*/
42162306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0xa256), board_ahci }, /* Lewisburg RAID*/
42262306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0xa356), board_ahci }, /* Cannon Lake PCH-H RAID */
42362306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x06d7), board_ahci }, /* Comet Lake-H RAID */
42462306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0xa386), board_ahci }, /* Comet Lake PCH-V RAID */
42562306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x0f22), board_ahci_low_power }, /* Bay Trail AHCI */
42662306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x0f23), board_ahci_low_power }, /* Bay Trail AHCI */
42762306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x22a3), board_ahci_low_power }, /* Cherry Tr. AHCI */
42862306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x5ae3), board_ahci_low_power }, /* ApolloLake AHCI */
42962306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x34d3), board_ahci_low_power }, /* Ice Lake LP AHCI */
43062306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x02d3), board_ahci_low_power }, /* Comet Lake PCH-U AHCI */
43162306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x02d7), board_ahci_low_power }, /* Comet Lake PCH RAID */
43262306a36Sopenharmony_ci	/* Elkhart Lake IDs 0x4b60 & 0x4b62 https://sata-io.org/product/8803 not tested yet */
43362306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x4b63), board_ahci_low_power }, /* Elkhart Lake AHCI */
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	/* JMicron 360/1/3/5/6, match class to avoid IDE function */
43662306a36Sopenharmony_ci	{ PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
43762306a36Sopenharmony_ci	  PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci_ign_iferr },
43862306a36Sopenharmony_ci	/* JMicron 362B and 362C have an AHCI function with IDE class code */
43962306a36Sopenharmony_ci	{ PCI_VDEVICE(JMICRON, 0x2362), board_ahci_ign_iferr },
44062306a36Sopenharmony_ci	{ PCI_VDEVICE(JMICRON, 0x236f), board_ahci_ign_iferr },
44162306a36Sopenharmony_ci	/* May need to update quirk_jmicron_async_suspend() for additions */
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	/* ATI */
44462306a36Sopenharmony_ci	{ PCI_VDEVICE(ATI, 0x4380), board_ahci_sb600 }, /* ATI SB600 */
44562306a36Sopenharmony_ci	{ PCI_VDEVICE(ATI, 0x4390), board_ahci_sb700 }, /* ATI SB700/800 */
44662306a36Sopenharmony_ci	{ PCI_VDEVICE(ATI, 0x4391), board_ahci_sb700 }, /* ATI SB700/800 */
44762306a36Sopenharmony_ci	{ PCI_VDEVICE(ATI, 0x4392), board_ahci_sb700 }, /* ATI SB700/800 */
44862306a36Sopenharmony_ci	{ PCI_VDEVICE(ATI, 0x4393), board_ahci_sb700 }, /* ATI SB700/800 */
44962306a36Sopenharmony_ci	{ PCI_VDEVICE(ATI, 0x4394), board_ahci_sb700 }, /* ATI SB700/800 */
45062306a36Sopenharmony_ci	{ PCI_VDEVICE(ATI, 0x4395), board_ahci_sb700 }, /* ATI SB700/800 */
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci	/* Amazon's Annapurna Labs support */
45362306a36Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_AMAZON_ANNAPURNA_LABS, 0x0031),
45462306a36Sopenharmony_ci		.class = PCI_CLASS_STORAGE_SATA_AHCI,
45562306a36Sopenharmony_ci		.class_mask = 0xffffff,
45662306a36Sopenharmony_ci		board_ahci_al },
45762306a36Sopenharmony_ci	/* AMD */
45862306a36Sopenharmony_ci	{ PCI_VDEVICE(AMD, 0x7800), board_ahci }, /* AMD Hudson-2 */
45962306a36Sopenharmony_ci	{ PCI_VDEVICE(AMD, 0x7801), board_ahci_no_debounce_delay }, /* AMD Hudson-2 (AHCI mode) */
46062306a36Sopenharmony_ci	{ PCI_VDEVICE(AMD, 0x7900), board_ahci }, /* AMD CZ */
46162306a36Sopenharmony_ci	{ PCI_VDEVICE(AMD, 0x7901), board_ahci_low_power }, /* AMD Green Sardine */
46262306a36Sopenharmony_ci	/* AMD is using RAID class only for ahci controllers */
46362306a36Sopenharmony_ci	{ PCI_VENDOR_ID_AMD, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
46462306a36Sopenharmony_ci	  PCI_CLASS_STORAGE_RAID << 8, 0xffffff, board_ahci },
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	/* Dell S140/S150 */
46762306a36Sopenharmony_ci	{ PCI_VENDOR_ID_INTEL, PCI_ANY_ID, PCI_SUBVENDOR_ID_DELL, PCI_ANY_ID,
46862306a36Sopenharmony_ci	  PCI_CLASS_STORAGE_RAID << 8, 0xffffff, board_ahci },
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci	/* VIA */
47162306a36Sopenharmony_ci	{ PCI_VDEVICE(VIA, 0x3349), board_ahci_vt8251 }, /* VIA VT8251 */
47262306a36Sopenharmony_ci	{ PCI_VDEVICE(VIA, 0x6287), board_ahci_vt8251 }, /* VIA VT8251 */
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	/* NVIDIA */
47562306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x044c), board_ahci_mcp65 },	/* MCP65 */
47662306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x044d), board_ahci_mcp65 },	/* MCP65 */
47762306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x044e), board_ahci_mcp65 },	/* MCP65 */
47862306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x044f), board_ahci_mcp65 },	/* MCP65 */
47962306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x045c), board_ahci_mcp65 },	/* MCP65 */
48062306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x045d), board_ahci_mcp65 },	/* MCP65 */
48162306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x045e), board_ahci_mcp65 },	/* MCP65 */
48262306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x045f), board_ahci_mcp65 },	/* MCP65 */
48362306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x0550), board_ahci_mcp67 },	/* MCP67 */
48462306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x0551), board_ahci_mcp67 },	/* MCP67 */
48562306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x0552), board_ahci_mcp67 },	/* MCP67 */
48662306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x0553), board_ahci_mcp67 },	/* MCP67 */
48762306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x0554), board_ahci_mcp67 },	/* MCP67 */
48862306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x0555), board_ahci_mcp67 },	/* MCP67 */
48962306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x0556), board_ahci_mcp67 },	/* MCP67 */
49062306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x0557), board_ahci_mcp67 },	/* MCP67 */
49162306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x0558), board_ahci_mcp67 },	/* MCP67 */
49262306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x0559), board_ahci_mcp67 },	/* MCP67 */
49362306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x055a), board_ahci_mcp67 },	/* MCP67 */
49462306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x055b), board_ahci_mcp67 },	/* MCP67 */
49562306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x0580), board_ahci_mcp_linux },	/* Linux ID */
49662306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x0581), board_ahci_mcp_linux },	/* Linux ID */
49762306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x0582), board_ahci_mcp_linux },	/* Linux ID */
49862306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x0583), board_ahci_mcp_linux },	/* Linux ID */
49962306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x0584), board_ahci_mcp_linux },	/* Linux ID */
50062306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x0585), board_ahci_mcp_linux },	/* Linux ID */
50162306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x0586), board_ahci_mcp_linux },	/* Linux ID */
50262306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x0587), board_ahci_mcp_linux },	/* Linux ID */
50362306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x0588), board_ahci_mcp_linux },	/* Linux ID */
50462306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x0589), board_ahci_mcp_linux },	/* Linux ID */
50562306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x058a), board_ahci_mcp_linux },	/* Linux ID */
50662306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x058b), board_ahci_mcp_linux },	/* Linux ID */
50762306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x058c), board_ahci_mcp_linux },	/* Linux ID */
50862306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x058d), board_ahci_mcp_linux },	/* Linux ID */
50962306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x058e), board_ahci_mcp_linux },	/* Linux ID */
51062306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x058f), board_ahci_mcp_linux },	/* Linux ID */
51162306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x07f0), board_ahci_mcp73 },	/* MCP73 */
51262306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x07f1), board_ahci_mcp73 },	/* MCP73 */
51362306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x07f2), board_ahci_mcp73 },	/* MCP73 */
51462306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x07f3), board_ahci_mcp73 },	/* MCP73 */
51562306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x07f4), board_ahci_mcp73 },	/* MCP73 */
51662306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x07f5), board_ahci_mcp73 },	/* MCP73 */
51762306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x07f6), board_ahci_mcp73 },	/* MCP73 */
51862306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x07f7), board_ahci_mcp73 },	/* MCP73 */
51962306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x07f8), board_ahci_mcp73 },	/* MCP73 */
52062306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x07f9), board_ahci_mcp73 },	/* MCP73 */
52162306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x07fa), board_ahci_mcp73 },	/* MCP73 */
52262306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x07fb), board_ahci_mcp73 },	/* MCP73 */
52362306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x0ad0), board_ahci_mcp77 },	/* MCP77 */
52462306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x0ad1), board_ahci_mcp77 },	/* MCP77 */
52562306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x0ad2), board_ahci_mcp77 },	/* MCP77 */
52662306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x0ad3), board_ahci_mcp77 },	/* MCP77 */
52762306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x0ad4), board_ahci_mcp77 },	/* MCP77 */
52862306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x0ad5), board_ahci_mcp77 },	/* MCP77 */
52962306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x0ad6), board_ahci_mcp77 },	/* MCP77 */
53062306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x0ad7), board_ahci_mcp77 },	/* MCP77 */
53162306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x0ad8), board_ahci_mcp77 },	/* MCP77 */
53262306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x0ad9), board_ahci_mcp77 },	/* MCP77 */
53362306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x0ada), board_ahci_mcp77 },	/* MCP77 */
53462306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x0adb), board_ahci_mcp77 },	/* MCP77 */
53562306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x0ab4), board_ahci_mcp79 },	/* MCP79 */
53662306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x0ab5), board_ahci_mcp79 },	/* MCP79 */
53762306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x0ab6), board_ahci_mcp79 },	/* MCP79 */
53862306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x0ab7), board_ahci_mcp79 },	/* MCP79 */
53962306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x0ab8), board_ahci_mcp79 },	/* MCP79 */
54062306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x0ab9), board_ahci_mcp79 },	/* MCP79 */
54162306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x0aba), board_ahci_mcp79 },	/* MCP79 */
54262306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x0abb), board_ahci_mcp79 },	/* MCP79 */
54362306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x0abc), board_ahci_mcp79 },	/* MCP79 */
54462306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x0abd), board_ahci_mcp79 },	/* MCP79 */
54562306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x0abe), board_ahci_mcp79 },	/* MCP79 */
54662306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x0abf), board_ahci_mcp79 },	/* MCP79 */
54762306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x0d84), board_ahci_mcp89 },	/* MCP89 */
54862306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x0d85), board_ahci_mcp89 },	/* MCP89 */
54962306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x0d86), board_ahci_mcp89 },	/* MCP89 */
55062306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x0d87), board_ahci_mcp89 },	/* MCP89 */
55162306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x0d88), board_ahci_mcp89 },	/* MCP89 */
55262306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x0d89), board_ahci_mcp89 },	/* MCP89 */
55362306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x0d8a), board_ahci_mcp89 },	/* MCP89 */
55462306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x0d8b), board_ahci_mcp89 },	/* MCP89 */
55562306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x0d8c), board_ahci_mcp89 },	/* MCP89 */
55662306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x0d8d), board_ahci_mcp89 },	/* MCP89 */
55762306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x0d8e), board_ahci_mcp89 },	/* MCP89 */
55862306a36Sopenharmony_ci	{ PCI_VDEVICE(NVIDIA, 0x0d8f), board_ahci_mcp89 },	/* MCP89 */
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	/* SiS */
56162306a36Sopenharmony_ci	{ PCI_VDEVICE(SI, 0x1184), board_ahci },		/* SiS 966 */
56262306a36Sopenharmony_ci	{ PCI_VDEVICE(SI, 0x1185), board_ahci },		/* SiS 968 */
56362306a36Sopenharmony_ci	{ PCI_VDEVICE(SI, 0x0186), board_ahci },		/* SiS 968 */
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	/* ST Microelectronics */
56662306a36Sopenharmony_ci	{ PCI_VDEVICE(STMICRO, 0xCC06), board_ahci },		/* ST ConneXt */
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci	/* Marvell */
56962306a36Sopenharmony_ci	{ PCI_VDEVICE(MARVELL, 0x6145), board_ahci_mv },	/* 6145 */
57062306a36Sopenharmony_ci	{ PCI_VDEVICE(MARVELL, 0x6121), board_ahci_mv },	/* 6121 */
57162306a36Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9123),
57262306a36Sopenharmony_ci	  .class = PCI_CLASS_STORAGE_SATA_AHCI,
57362306a36Sopenharmony_ci	  .class_mask = 0xffffff,
57462306a36Sopenharmony_ci	  .driver_data = board_ahci_yes_fbs },			/* 88se9128 */
57562306a36Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9125),
57662306a36Sopenharmony_ci	  .driver_data = board_ahci_yes_fbs },			/* 88se9125 */
57762306a36Sopenharmony_ci	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_MARVELL_EXT, 0x9178,
57862306a36Sopenharmony_ci			 PCI_VENDOR_ID_MARVELL_EXT, 0x9170),
57962306a36Sopenharmony_ci	  .driver_data = board_ahci_yes_fbs },			/* 88se9170 */
58062306a36Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x917a),
58162306a36Sopenharmony_ci	  .driver_data = board_ahci_yes_fbs },			/* 88se9172 */
58262306a36Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9172),
58362306a36Sopenharmony_ci	  .driver_data = board_ahci_yes_fbs },			/* 88se9182 */
58462306a36Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9182),
58562306a36Sopenharmony_ci	  .driver_data = board_ahci_yes_fbs },			/* 88se9172 */
58662306a36Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9192),
58762306a36Sopenharmony_ci	  .driver_data = board_ahci_yes_fbs },			/* 88se9172 on some Gigabyte */
58862306a36Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x91a0),
58962306a36Sopenharmony_ci	  .driver_data = board_ahci_yes_fbs },
59062306a36Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x91a2), 	/* 88se91a2 */
59162306a36Sopenharmony_ci	  .driver_data = board_ahci_yes_fbs },
59262306a36Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x91a3),
59362306a36Sopenharmony_ci	  .driver_data = board_ahci_yes_fbs },
59462306a36Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9230),
59562306a36Sopenharmony_ci	  .driver_data = board_ahci_yes_fbs },
59662306a36Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9235),
59762306a36Sopenharmony_ci	  .driver_data = board_ahci_no_debounce_delay },
59862306a36Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_TTI, 0x0642), /* highpoint rocketraid 642L */
59962306a36Sopenharmony_ci	  .driver_data = board_ahci_yes_fbs },
60062306a36Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_TTI, 0x0645), /* highpoint rocketraid 644L */
60162306a36Sopenharmony_ci	  .driver_data = board_ahci_yes_fbs },
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci	/* Promise */
60462306a36Sopenharmony_ci	{ PCI_VDEVICE(PROMISE, 0x3f20), board_ahci },	/* PDC42819 */
60562306a36Sopenharmony_ci	{ PCI_VDEVICE(PROMISE, 0x3781), board_ahci },   /* FastTrak TX8660 ahci-mode */
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci	/* ASMedia */
60862306a36Sopenharmony_ci	{ PCI_VDEVICE(ASMEDIA, 0x0601), board_ahci_43bit_dma },	/* ASM1060 */
60962306a36Sopenharmony_ci	{ PCI_VDEVICE(ASMEDIA, 0x0602), board_ahci_43bit_dma },	/* ASM1060 */
61062306a36Sopenharmony_ci	{ PCI_VDEVICE(ASMEDIA, 0x0611), board_ahci_43bit_dma },	/* ASM1061 */
61162306a36Sopenharmony_ci	{ PCI_VDEVICE(ASMEDIA, 0x0612), board_ahci_43bit_dma },	/* ASM1061/1062 */
61262306a36Sopenharmony_ci	{ PCI_VDEVICE(ASMEDIA, 0x0621), board_ahci_43bit_dma },	/* ASM1061R */
61362306a36Sopenharmony_ci	{ PCI_VDEVICE(ASMEDIA, 0x0622), board_ahci_43bit_dma },	/* ASM1062R */
61462306a36Sopenharmony_ci	{ PCI_VDEVICE(ASMEDIA, 0x0624), board_ahci_43bit_dma },	/* ASM1062+JMB575 */
61562306a36Sopenharmony_ci	{ PCI_VDEVICE(ASMEDIA, 0x1062), board_ahci },	/* ASM1062A */
61662306a36Sopenharmony_ci	{ PCI_VDEVICE(ASMEDIA, 0x1064), board_ahci },	/* ASM1064 */
61762306a36Sopenharmony_ci	{ PCI_VDEVICE(ASMEDIA, 0x1164), board_ahci },   /* ASM1164 */
61862306a36Sopenharmony_ci	{ PCI_VDEVICE(ASMEDIA, 0x1165), board_ahci },   /* ASM1165 */
61962306a36Sopenharmony_ci	{ PCI_VDEVICE(ASMEDIA, 0x1166), board_ahci },   /* ASM1166 */
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci	/*
62262306a36Sopenharmony_ci	 * Samsung SSDs found on some macbooks.  NCQ times out if MSI is
62362306a36Sopenharmony_ci	 * enabled.  https://bugzilla.kernel.org/show_bug.cgi?id=60731
62462306a36Sopenharmony_ci	 */
62562306a36Sopenharmony_ci	{ PCI_VDEVICE(SAMSUNG, 0x1600), board_ahci_nomsi },
62662306a36Sopenharmony_ci	{ PCI_VDEVICE(SAMSUNG, 0xa800), board_ahci_nomsi },
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	/* Enmotus */
62962306a36Sopenharmony_ci	{ PCI_DEVICE(0x1c44, 0x8000), board_ahci },
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci	/* Loongson */
63262306a36Sopenharmony_ci	{ PCI_VDEVICE(LOONGSON, 0x7a08), board_ahci },
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci	/* Generic, PCI class code for AHCI */
63562306a36Sopenharmony_ci	{ PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
63662306a36Sopenharmony_ci	  PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci },
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci	{ }	/* terminate list */
63962306a36Sopenharmony_ci};
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_cistatic const struct dev_pm_ops ahci_pci_pm_ops = {
64262306a36Sopenharmony_ci	SET_SYSTEM_SLEEP_PM_OPS(ahci_pci_device_suspend, ahci_pci_device_resume)
64362306a36Sopenharmony_ci	SET_RUNTIME_PM_OPS(ahci_pci_device_runtime_suspend,
64462306a36Sopenharmony_ci			   ahci_pci_device_runtime_resume, NULL)
64562306a36Sopenharmony_ci};
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_cistatic struct pci_driver ahci_pci_driver = {
64862306a36Sopenharmony_ci	.name			= DRV_NAME,
64962306a36Sopenharmony_ci	.id_table		= ahci_pci_tbl,
65062306a36Sopenharmony_ci	.probe			= ahci_init_one,
65162306a36Sopenharmony_ci	.remove			= ahci_remove_one,
65262306a36Sopenharmony_ci	.shutdown		= ahci_shutdown_one,
65362306a36Sopenharmony_ci	.driver = {
65462306a36Sopenharmony_ci		.pm		= &ahci_pci_pm_ops,
65562306a36Sopenharmony_ci	},
65662306a36Sopenharmony_ci};
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_PATA_MARVELL)
65962306a36Sopenharmony_cistatic int marvell_enable;
66062306a36Sopenharmony_ci#else
66162306a36Sopenharmony_cistatic int marvell_enable = 1;
66262306a36Sopenharmony_ci#endif
66362306a36Sopenharmony_cimodule_param(marvell_enable, int, 0644);
66462306a36Sopenharmony_ciMODULE_PARM_DESC(marvell_enable, "Marvell SATA via AHCI (1 = enabled)");
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_cistatic int mobile_lpm_policy = -1;
66762306a36Sopenharmony_cimodule_param(mobile_lpm_policy, int, 0644);
66862306a36Sopenharmony_ciMODULE_PARM_DESC(mobile_lpm_policy, "Default LPM policy for mobile chipsets");
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_cistatic void ahci_pci_save_initial_config(struct pci_dev *pdev,
67162306a36Sopenharmony_ci					 struct ahci_host_priv *hpriv)
67262306a36Sopenharmony_ci{
67362306a36Sopenharmony_ci	if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA && pdev->device == 0x1166) {
67462306a36Sopenharmony_ci		dev_info(&pdev->dev, "ASM1166 has only six ports\n");
67562306a36Sopenharmony_ci		hpriv->saved_port_map = 0x3f;
67662306a36Sopenharmony_ci	}
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci	if (pdev->vendor == PCI_VENDOR_ID_JMICRON && pdev->device == 0x2361) {
67962306a36Sopenharmony_ci		dev_info(&pdev->dev, "JMB361 has only one port\n");
68062306a36Sopenharmony_ci		hpriv->saved_port_map = 1;
68162306a36Sopenharmony_ci	}
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ci	/*
68462306a36Sopenharmony_ci	 * Temporary Marvell 6145 hack: PATA port presence
68562306a36Sopenharmony_ci	 * is asserted through the standard AHCI port
68662306a36Sopenharmony_ci	 * presence register, as bit 4 (counting from 0)
68762306a36Sopenharmony_ci	 */
68862306a36Sopenharmony_ci	if (hpriv->flags & AHCI_HFLAG_MV_PATA) {
68962306a36Sopenharmony_ci		if (pdev->device == 0x6121)
69062306a36Sopenharmony_ci			hpriv->mask_port_map = 0x3;
69162306a36Sopenharmony_ci		else
69262306a36Sopenharmony_ci			hpriv->mask_port_map = 0xf;
69362306a36Sopenharmony_ci		dev_info(&pdev->dev,
69462306a36Sopenharmony_ci			  "Disabling your PATA port. Use the boot option 'ahci.marvell_enable=0' to avoid this.\n");
69562306a36Sopenharmony_ci	}
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci	ahci_save_initial_config(&pdev->dev, hpriv);
69862306a36Sopenharmony_ci}
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_cistatic int ahci_pci_reset_controller(struct ata_host *host)
70162306a36Sopenharmony_ci{
70262306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(host->dev);
70362306a36Sopenharmony_ci	struct ahci_host_priv *hpriv = host->private_data;
70462306a36Sopenharmony_ci	int rc;
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci	rc = ahci_reset_controller(host);
70762306a36Sopenharmony_ci	if (rc)
70862306a36Sopenharmony_ci		return rc;
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ci	/*
71162306a36Sopenharmony_ci	 * If platform firmware failed to enable ports, try to enable
71262306a36Sopenharmony_ci	 * them here.
71362306a36Sopenharmony_ci	 */
71462306a36Sopenharmony_ci	ahci_intel_pcs_quirk(pdev, hpriv);
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_ci	return 0;
71762306a36Sopenharmony_ci}
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_cistatic void ahci_pci_init_controller(struct ata_host *host)
72062306a36Sopenharmony_ci{
72162306a36Sopenharmony_ci	struct ahci_host_priv *hpriv = host->private_data;
72262306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(host->dev);
72362306a36Sopenharmony_ci	void __iomem *port_mmio;
72462306a36Sopenharmony_ci	u32 tmp;
72562306a36Sopenharmony_ci	int mv;
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci	if (hpriv->flags & AHCI_HFLAG_MV_PATA) {
72862306a36Sopenharmony_ci		if (pdev->device == 0x6121)
72962306a36Sopenharmony_ci			mv = 2;
73062306a36Sopenharmony_ci		else
73162306a36Sopenharmony_ci			mv = 4;
73262306a36Sopenharmony_ci		port_mmio = __ahci_port_base(hpriv, mv);
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_ci		writel(0, port_mmio + PORT_IRQ_MASK);
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci		/* clear port IRQ */
73762306a36Sopenharmony_ci		tmp = readl(port_mmio + PORT_IRQ_STAT);
73862306a36Sopenharmony_ci		dev_dbg(&pdev->dev, "PORT_IRQ_STAT 0x%x\n", tmp);
73962306a36Sopenharmony_ci		if (tmp)
74062306a36Sopenharmony_ci			writel(tmp, port_mmio + PORT_IRQ_STAT);
74162306a36Sopenharmony_ci	}
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci	ahci_init_controller(host);
74462306a36Sopenharmony_ci}
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_cistatic int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
74762306a36Sopenharmony_ci				 unsigned long deadline)
74862306a36Sopenharmony_ci{
74962306a36Sopenharmony_ci	struct ata_port *ap = link->ap;
75062306a36Sopenharmony_ci	struct ahci_host_priv *hpriv = ap->host->private_data;
75162306a36Sopenharmony_ci	bool online;
75262306a36Sopenharmony_ci	int rc;
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci	hpriv->stop_engine(ap);
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_ci	rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context),
75762306a36Sopenharmony_ci				 deadline, &online, NULL);
75862306a36Sopenharmony_ci
75962306a36Sopenharmony_ci	hpriv->start_engine(ap);
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci	/* vt8251 doesn't clear BSY on signature FIS reception,
76262306a36Sopenharmony_ci	 * request follow-up softreset.
76362306a36Sopenharmony_ci	 */
76462306a36Sopenharmony_ci	return online ? -EAGAIN : rc;
76562306a36Sopenharmony_ci}
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_cistatic int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
76862306a36Sopenharmony_ci				unsigned long deadline)
76962306a36Sopenharmony_ci{
77062306a36Sopenharmony_ci	struct ata_port *ap = link->ap;
77162306a36Sopenharmony_ci	struct ahci_port_priv *pp = ap->private_data;
77262306a36Sopenharmony_ci	struct ahci_host_priv *hpriv = ap->host->private_data;
77362306a36Sopenharmony_ci	u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
77462306a36Sopenharmony_ci	struct ata_taskfile tf;
77562306a36Sopenharmony_ci	bool online;
77662306a36Sopenharmony_ci	int rc;
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_ci	hpriv->stop_engine(ap);
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_ci	/* clear D2H reception area to properly wait for D2H FIS */
78162306a36Sopenharmony_ci	ata_tf_init(link->device, &tf);
78262306a36Sopenharmony_ci	tf.status = ATA_BUSY;
78362306a36Sopenharmony_ci	ata_tf_to_fis(&tf, 0, 0, d2h_fis);
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ci	rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context),
78662306a36Sopenharmony_ci				 deadline, &online, NULL);
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci	hpriv->start_engine(ap);
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_ci	/* The pseudo configuration device on SIMG4726 attached to
79162306a36Sopenharmony_ci	 * ASUS P5W-DH Deluxe doesn't send signature FIS after
79262306a36Sopenharmony_ci	 * hardreset if no device is attached to the first downstream
79362306a36Sopenharmony_ci	 * port && the pseudo device locks up on SRST w/ PMP==0.  To
79462306a36Sopenharmony_ci	 * work around this, wait for !BSY only briefly.  If BSY isn't
79562306a36Sopenharmony_ci	 * cleared, perform CLO and proceed to IDENTIFY (achieved by
79662306a36Sopenharmony_ci	 * ATA_LFLAG_NO_SRST and ATA_LFLAG_ASSUME_ATA).
79762306a36Sopenharmony_ci	 *
79862306a36Sopenharmony_ci	 * Wait for two seconds.  Devices attached to downstream port
79962306a36Sopenharmony_ci	 * which can't process the following IDENTIFY after this will
80062306a36Sopenharmony_ci	 * have to be reset again.  For most cases, this should
80162306a36Sopenharmony_ci	 * suffice while making probing snappish enough.
80262306a36Sopenharmony_ci	 */
80362306a36Sopenharmony_ci	if (online) {
80462306a36Sopenharmony_ci		rc = ata_wait_after_reset(link, jiffies + 2 * HZ,
80562306a36Sopenharmony_ci					  ahci_check_ready);
80662306a36Sopenharmony_ci		if (rc)
80762306a36Sopenharmony_ci			ahci_kick_engine(ap);
80862306a36Sopenharmony_ci	}
80962306a36Sopenharmony_ci	return rc;
81062306a36Sopenharmony_ci}
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci/*
81362306a36Sopenharmony_ci * ahci_avn_hardreset - attempt more aggressive recovery of Avoton ports.
81462306a36Sopenharmony_ci *
81562306a36Sopenharmony_ci * It has been observed with some SSDs that the timing of events in the
81662306a36Sopenharmony_ci * link synchronization phase can leave the port in a state that can not
81762306a36Sopenharmony_ci * be recovered by a SATA-hard-reset alone.  The failing signature is
81862306a36Sopenharmony_ci * SStatus.DET stuck at 1 ("Device presence detected but Phy
81962306a36Sopenharmony_ci * communication not established").  It was found that unloading and
82062306a36Sopenharmony_ci * reloading the driver when this problem occurs allows the drive
82162306a36Sopenharmony_ci * connection to be recovered (DET advanced to 0x3).  The critical
82262306a36Sopenharmony_ci * component of reloading the driver is that the port state machines are
82362306a36Sopenharmony_ci * reset by bouncing "port enable" in the AHCI PCS configuration
82462306a36Sopenharmony_ci * register.  So, reproduce that effect by bouncing a port whenever we
82562306a36Sopenharmony_ci * see DET==1 after a reset.
82662306a36Sopenharmony_ci */
82762306a36Sopenharmony_cistatic int ahci_avn_hardreset(struct ata_link *link, unsigned int *class,
82862306a36Sopenharmony_ci			      unsigned long deadline)
82962306a36Sopenharmony_ci{
83062306a36Sopenharmony_ci	const unsigned int *timing = sata_ehc_deb_timing(&link->eh_context);
83162306a36Sopenharmony_ci	struct ata_port *ap = link->ap;
83262306a36Sopenharmony_ci	struct ahci_port_priv *pp = ap->private_data;
83362306a36Sopenharmony_ci	struct ahci_host_priv *hpriv = ap->host->private_data;
83462306a36Sopenharmony_ci	u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
83562306a36Sopenharmony_ci	unsigned long tmo = deadline - jiffies;
83662306a36Sopenharmony_ci	struct ata_taskfile tf;
83762306a36Sopenharmony_ci	bool online;
83862306a36Sopenharmony_ci	int rc, i;
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci	hpriv->stop_engine(ap);
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_ci	for (i = 0; i < 2; i++) {
84362306a36Sopenharmony_ci		u16 val;
84462306a36Sopenharmony_ci		u32 sstatus;
84562306a36Sopenharmony_ci		int port = ap->port_no;
84662306a36Sopenharmony_ci		struct ata_host *host = ap->host;
84762306a36Sopenharmony_ci		struct pci_dev *pdev = to_pci_dev(host->dev);
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_ci		/* clear D2H reception area to properly wait for D2H FIS */
85062306a36Sopenharmony_ci		ata_tf_init(link->device, &tf);
85162306a36Sopenharmony_ci		tf.status = ATA_BUSY;
85262306a36Sopenharmony_ci		ata_tf_to_fis(&tf, 0, 0, d2h_fis);
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_ci		rc = sata_link_hardreset(link, timing, deadline, &online,
85562306a36Sopenharmony_ci				ahci_check_ready);
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_ci		if (sata_scr_read(link, SCR_STATUS, &sstatus) != 0 ||
85862306a36Sopenharmony_ci				(sstatus & 0xf) != 1)
85962306a36Sopenharmony_ci			break;
86062306a36Sopenharmony_ci
86162306a36Sopenharmony_ci		ata_link_info(link,  "avn bounce port%d\n", port);
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_ci		pci_read_config_word(pdev, 0x92, &val);
86462306a36Sopenharmony_ci		val &= ~(1 << port);
86562306a36Sopenharmony_ci		pci_write_config_word(pdev, 0x92, val);
86662306a36Sopenharmony_ci		ata_msleep(ap, 1000);
86762306a36Sopenharmony_ci		val |= 1 << port;
86862306a36Sopenharmony_ci		pci_write_config_word(pdev, 0x92, val);
86962306a36Sopenharmony_ci		deadline += tmo;
87062306a36Sopenharmony_ci	}
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci	hpriv->start_engine(ap);
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_ci	if (online)
87562306a36Sopenharmony_ci		*class = ahci_dev_classify(ap);
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_ci	return rc;
87862306a36Sopenharmony_ci}
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_ci#ifdef CONFIG_PM
88262306a36Sopenharmony_cistatic void ahci_pci_disable_interrupts(struct ata_host *host)
88362306a36Sopenharmony_ci{
88462306a36Sopenharmony_ci	struct ahci_host_priv *hpriv = host->private_data;
88562306a36Sopenharmony_ci	void __iomem *mmio = hpriv->mmio;
88662306a36Sopenharmony_ci	u32 ctl;
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ci	/* AHCI spec rev1.1 section 8.3.3:
88962306a36Sopenharmony_ci	 * Software must disable interrupts prior to requesting a
89062306a36Sopenharmony_ci	 * transition of the HBA to D3 state.
89162306a36Sopenharmony_ci	 */
89262306a36Sopenharmony_ci	ctl = readl(mmio + HOST_CTL);
89362306a36Sopenharmony_ci	ctl &= ~HOST_IRQ_EN;
89462306a36Sopenharmony_ci	writel(ctl, mmio + HOST_CTL);
89562306a36Sopenharmony_ci	readl(mmio + HOST_CTL); /* flush */
89662306a36Sopenharmony_ci}
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_cistatic int ahci_pci_device_runtime_suspend(struct device *dev)
89962306a36Sopenharmony_ci{
90062306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(dev);
90162306a36Sopenharmony_ci	struct ata_host *host = pci_get_drvdata(pdev);
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ci	ahci_pci_disable_interrupts(host);
90462306a36Sopenharmony_ci	return 0;
90562306a36Sopenharmony_ci}
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_cistatic int ahci_pci_device_runtime_resume(struct device *dev)
90862306a36Sopenharmony_ci{
90962306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(dev);
91062306a36Sopenharmony_ci	struct ata_host *host = pci_get_drvdata(pdev);
91162306a36Sopenharmony_ci	int rc;
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_ci	rc = ahci_pci_reset_controller(host);
91462306a36Sopenharmony_ci	if (rc)
91562306a36Sopenharmony_ci		return rc;
91662306a36Sopenharmony_ci	ahci_pci_init_controller(host);
91762306a36Sopenharmony_ci	return 0;
91862306a36Sopenharmony_ci}
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
92162306a36Sopenharmony_cistatic int ahci_pci_device_suspend(struct device *dev)
92262306a36Sopenharmony_ci{
92362306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(dev);
92462306a36Sopenharmony_ci	struct ata_host *host = pci_get_drvdata(pdev);
92562306a36Sopenharmony_ci	struct ahci_host_priv *hpriv = host->private_data;
92662306a36Sopenharmony_ci
92762306a36Sopenharmony_ci	if (hpriv->flags & AHCI_HFLAG_NO_SUSPEND) {
92862306a36Sopenharmony_ci		dev_err(&pdev->dev,
92962306a36Sopenharmony_ci			"BIOS update required for suspend/resume\n");
93062306a36Sopenharmony_ci		return -EIO;
93162306a36Sopenharmony_ci	}
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_ci	ahci_pci_disable_interrupts(host);
93462306a36Sopenharmony_ci	ata_host_suspend(host, PMSG_SUSPEND);
93562306a36Sopenharmony_ci	return 0;
93662306a36Sopenharmony_ci}
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_cistatic int ahci_pci_device_resume(struct device *dev)
93962306a36Sopenharmony_ci{
94062306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(dev);
94162306a36Sopenharmony_ci	struct ata_host *host = pci_get_drvdata(pdev);
94262306a36Sopenharmony_ci	int rc;
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_ci	/* Apple BIOS helpfully mangles the registers on resume */
94562306a36Sopenharmony_ci	if (is_mcp89_apple(pdev))
94662306a36Sopenharmony_ci		ahci_mcp89_apple_enable(pdev);
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_ci	if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
94962306a36Sopenharmony_ci		rc = ahci_pci_reset_controller(host);
95062306a36Sopenharmony_ci		if (rc)
95162306a36Sopenharmony_ci			return rc;
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_ci		ahci_pci_init_controller(host);
95462306a36Sopenharmony_ci	}
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_ci	ata_host_resume(host);
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_ci	return 0;
95962306a36Sopenharmony_ci}
96062306a36Sopenharmony_ci#endif
96162306a36Sopenharmony_ci
96262306a36Sopenharmony_ci#endif /* CONFIG_PM */
96362306a36Sopenharmony_ci
96462306a36Sopenharmony_cistatic int ahci_configure_dma_masks(struct pci_dev *pdev,
96562306a36Sopenharmony_ci				    struct ahci_host_priv *hpriv)
96662306a36Sopenharmony_ci{
96762306a36Sopenharmony_ci	int dma_bits;
96862306a36Sopenharmony_ci	int rc;
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_ci	if (hpriv->cap & HOST_CAP_64) {
97162306a36Sopenharmony_ci		dma_bits = 64;
97262306a36Sopenharmony_ci		if (hpriv->flags & AHCI_HFLAG_43BIT_ONLY)
97362306a36Sopenharmony_ci			dma_bits = 43;
97462306a36Sopenharmony_ci	} else {
97562306a36Sopenharmony_ci		dma_bits = 32;
97662306a36Sopenharmony_ci	}
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_ci	/*
97962306a36Sopenharmony_ci	 * If the device fixup already set the dma_mask to some non-standard
98062306a36Sopenharmony_ci	 * value, don't extend it here. This happens on STA2X11, for example.
98162306a36Sopenharmony_ci	 *
98262306a36Sopenharmony_ci	 * XXX: manipulating the DMA mask from platform code is completely
98362306a36Sopenharmony_ci	 * bogus, platform code should use dev->bus_dma_limit instead..
98462306a36Sopenharmony_ci	 */
98562306a36Sopenharmony_ci	if (pdev->dma_mask && pdev->dma_mask < DMA_BIT_MASK(32))
98662306a36Sopenharmony_ci		return 0;
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_ci	rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(dma_bits));
98962306a36Sopenharmony_ci	if (rc)
99062306a36Sopenharmony_ci		dev_err(&pdev->dev, "DMA enable failed\n");
99162306a36Sopenharmony_ci	return rc;
99262306a36Sopenharmony_ci}
99362306a36Sopenharmony_ci
99462306a36Sopenharmony_cistatic void ahci_pci_print_info(struct ata_host *host)
99562306a36Sopenharmony_ci{
99662306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(host->dev);
99762306a36Sopenharmony_ci	u16 cc;
99862306a36Sopenharmony_ci	const char *scc_s;
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_ci	pci_read_config_word(pdev, 0x0a, &cc);
100162306a36Sopenharmony_ci	if (cc == PCI_CLASS_STORAGE_IDE)
100262306a36Sopenharmony_ci		scc_s = "IDE";
100362306a36Sopenharmony_ci	else if (cc == PCI_CLASS_STORAGE_SATA)
100462306a36Sopenharmony_ci		scc_s = "SATA";
100562306a36Sopenharmony_ci	else if (cc == PCI_CLASS_STORAGE_RAID)
100662306a36Sopenharmony_ci		scc_s = "RAID";
100762306a36Sopenharmony_ci	else
100862306a36Sopenharmony_ci		scc_s = "unknown";
100962306a36Sopenharmony_ci
101062306a36Sopenharmony_ci	ahci_print_info(host, scc_s);
101162306a36Sopenharmony_ci}
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_ci/* On ASUS P5W DH Deluxe, the second port of PCI device 00:1f.2 is
101462306a36Sopenharmony_ci * hardwired to on-board SIMG 4726.  The chipset is ICH8 and doesn't
101562306a36Sopenharmony_ci * support PMP and the 4726 either directly exports the device
101662306a36Sopenharmony_ci * attached to the first downstream port or acts as a hardware storage
101762306a36Sopenharmony_ci * controller and emulate a single ATA device (can be RAID 0/1 or some
101862306a36Sopenharmony_ci * other configuration).
101962306a36Sopenharmony_ci *
102062306a36Sopenharmony_ci * When there's no device attached to the first downstream port of the
102162306a36Sopenharmony_ci * 4726, "Config Disk" appears, which is a pseudo ATA device to
102262306a36Sopenharmony_ci * configure the 4726.  However, ATA emulation of the device is very
102362306a36Sopenharmony_ci * lame.  It doesn't send signature D2H Reg FIS after the initial
102462306a36Sopenharmony_ci * hardreset, pukes on SRST w/ PMP==0 and has bunch of other issues.
102562306a36Sopenharmony_ci *
102662306a36Sopenharmony_ci * The following function works around the problem by always using
102762306a36Sopenharmony_ci * hardreset on the port and not depending on receiving signature FIS
102862306a36Sopenharmony_ci * afterward.  If signature FIS isn't received soon, ATA class is
102962306a36Sopenharmony_ci * assumed without follow-up softreset.
103062306a36Sopenharmony_ci */
103162306a36Sopenharmony_cistatic void ahci_p5wdh_workaround(struct ata_host *host)
103262306a36Sopenharmony_ci{
103362306a36Sopenharmony_ci	static const struct dmi_system_id sysids[] = {
103462306a36Sopenharmony_ci		{
103562306a36Sopenharmony_ci			.ident = "P5W DH Deluxe",
103662306a36Sopenharmony_ci			.matches = {
103762306a36Sopenharmony_ci				DMI_MATCH(DMI_SYS_VENDOR,
103862306a36Sopenharmony_ci					  "ASUSTEK COMPUTER INC"),
103962306a36Sopenharmony_ci				DMI_MATCH(DMI_PRODUCT_NAME, "P5W DH Deluxe"),
104062306a36Sopenharmony_ci			},
104162306a36Sopenharmony_ci		},
104262306a36Sopenharmony_ci		{ }
104362306a36Sopenharmony_ci	};
104462306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(host->dev);
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_ci	if (pdev->bus->number == 0 && pdev->devfn == PCI_DEVFN(0x1f, 2) &&
104762306a36Sopenharmony_ci	    dmi_check_system(sysids)) {
104862306a36Sopenharmony_ci		struct ata_port *ap = host->ports[1];
104962306a36Sopenharmony_ci
105062306a36Sopenharmony_ci		dev_info(&pdev->dev,
105162306a36Sopenharmony_ci			 "enabling ASUS P5W DH Deluxe on-board SIMG4726 workaround\n");
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_ci		ap->ops = &ahci_p5wdh_ops;
105462306a36Sopenharmony_ci		ap->link.flags |= ATA_LFLAG_NO_SRST | ATA_LFLAG_ASSUME_ATA;
105562306a36Sopenharmony_ci	}
105662306a36Sopenharmony_ci}
105762306a36Sopenharmony_ci
105862306a36Sopenharmony_ci/*
105962306a36Sopenharmony_ci * Macbook7,1 firmware forcibly disables MCP89 AHCI and changes PCI ID when
106062306a36Sopenharmony_ci * booting in BIOS compatibility mode.  We restore the registers but not ID.
106162306a36Sopenharmony_ci */
106262306a36Sopenharmony_cistatic void ahci_mcp89_apple_enable(struct pci_dev *pdev)
106362306a36Sopenharmony_ci{
106462306a36Sopenharmony_ci	u32 val;
106562306a36Sopenharmony_ci
106662306a36Sopenharmony_ci	printk(KERN_INFO "ahci: enabling MCP89 AHCI mode\n");
106762306a36Sopenharmony_ci
106862306a36Sopenharmony_ci	pci_read_config_dword(pdev, 0xf8, &val);
106962306a36Sopenharmony_ci	val |= 1 << 0x1b;
107062306a36Sopenharmony_ci	/* the following changes the device ID, but appears not to affect function */
107162306a36Sopenharmony_ci	/* val = (val & ~0xf0000000) | 0x80000000; */
107262306a36Sopenharmony_ci	pci_write_config_dword(pdev, 0xf8, val);
107362306a36Sopenharmony_ci
107462306a36Sopenharmony_ci	pci_read_config_dword(pdev, 0x54c, &val);
107562306a36Sopenharmony_ci	val |= 1 << 0xc;
107662306a36Sopenharmony_ci	pci_write_config_dword(pdev, 0x54c, val);
107762306a36Sopenharmony_ci
107862306a36Sopenharmony_ci	pci_read_config_dword(pdev, 0x4a4, &val);
107962306a36Sopenharmony_ci	val &= 0xff;
108062306a36Sopenharmony_ci	val |= 0x01060100;
108162306a36Sopenharmony_ci	pci_write_config_dword(pdev, 0x4a4, val);
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_ci	pci_read_config_dword(pdev, 0x54c, &val);
108462306a36Sopenharmony_ci	val &= ~(1 << 0xc);
108562306a36Sopenharmony_ci	pci_write_config_dword(pdev, 0x54c, val);
108662306a36Sopenharmony_ci
108762306a36Sopenharmony_ci	pci_read_config_dword(pdev, 0xf8, &val);
108862306a36Sopenharmony_ci	val &= ~(1 << 0x1b);
108962306a36Sopenharmony_ci	pci_write_config_dword(pdev, 0xf8, val);
109062306a36Sopenharmony_ci}
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_cistatic bool is_mcp89_apple(struct pci_dev *pdev)
109362306a36Sopenharmony_ci{
109462306a36Sopenharmony_ci	return pdev->vendor == PCI_VENDOR_ID_NVIDIA &&
109562306a36Sopenharmony_ci		pdev->device == PCI_DEVICE_ID_NVIDIA_NFORCE_MCP89_SATA &&
109662306a36Sopenharmony_ci		pdev->subsystem_vendor == PCI_VENDOR_ID_APPLE &&
109762306a36Sopenharmony_ci		pdev->subsystem_device == 0xcb89;
109862306a36Sopenharmony_ci}
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_ci/* only some SB600 ahci controllers can do 64bit DMA */
110162306a36Sopenharmony_cistatic bool ahci_sb600_enable_64bit(struct pci_dev *pdev)
110262306a36Sopenharmony_ci{
110362306a36Sopenharmony_ci	static const struct dmi_system_id sysids[] = {
110462306a36Sopenharmony_ci		/*
110562306a36Sopenharmony_ci		 * The oldest version known to be broken is 0901 and
110662306a36Sopenharmony_ci		 * working is 1501 which was released on 2007-10-26.
110762306a36Sopenharmony_ci		 * Enable 64bit DMA on 1501 and anything newer.
110862306a36Sopenharmony_ci		 *
110962306a36Sopenharmony_ci		 * Please read bko#9412 for more info.
111062306a36Sopenharmony_ci		 */
111162306a36Sopenharmony_ci		{
111262306a36Sopenharmony_ci			.ident = "ASUS M2A-VM",
111362306a36Sopenharmony_ci			.matches = {
111462306a36Sopenharmony_ci				DMI_MATCH(DMI_BOARD_VENDOR,
111562306a36Sopenharmony_ci					  "ASUSTeK Computer INC."),
111662306a36Sopenharmony_ci				DMI_MATCH(DMI_BOARD_NAME, "M2A-VM"),
111762306a36Sopenharmony_ci			},
111862306a36Sopenharmony_ci			.driver_data = "20071026",	/* yyyymmdd */
111962306a36Sopenharmony_ci		},
112062306a36Sopenharmony_ci		/*
112162306a36Sopenharmony_ci		 * All BIOS versions for the MSI K9A2 Platinum (MS-7376)
112262306a36Sopenharmony_ci		 * support 64bit DMA.
112362306a36Sopenharmony_ci		 *
112462306a36Sopenharmony_ci		 * BIOS versions earlier than 1.5 had the Manufacturer DMI
112562306a36Sopenharmony_ci		 * fields as "MICRO-STAR INTERANTIONAL CO.,LTD".
112662306a36Sopenharmony_ci		 * This spelling mistake was fixed in BIOS version 1.5, so
112762306a36Sopenharmony_ci		 * 1.5 and later have the Manufacturer as
112862306a36Sopenharmony_ci		 * "MICRO-STAR INTERNATIONAL CO.,LTD".
112962306a36Sopenharmony_ci		 * So try to match on DMI_BOARD_VENDOR of "MICRO-STAR INTER".
113062306a36Sopenharmony_ci		 *
113162306a36Sopenharmony_ci		 * BIOS versions earlier than 1.9 had a Board Product Name
113262306a36Sopenharmony_ci		 * DMI field of "MS-7376". This was changed to be
113362306a36Sopenharmony_ci		 * "K9A2 Platinum (MS-7376)" in version 1.9, but we can still
113462306a36Sopenharmony_ci		 * match on DMI_BOARD_NAME of "MS-7376".
113562306a36Sopenharmony_ci		 */
113662306a36Sopenharmony_ci		{
113762306a36Sopenharmony_ci			.ident = "MSI K9A2 Platinum",
113862306a36Sopenharmony_ci			.matches = {
113962306a36Sopenharmony_ci				DMI_MATCH(DMI_BOARD_VENDOR,
114062306a36Sopenharmony_ci					  "MICRO-STAR INTER"),
114162306a36Sopenharmony_ci				DMI_MATCH(DMI_BOARD_NAME, "MS-7376"),
114262306a36Sopenharmony_ci			},
114362306a36Sopenharmony_ci		},
114462306a36Sopenharmony_ci		/*
114562306a36Sopenharmony_ci		 * All BIOS versions for the MSI K9AGM2 (MS-7327) support
114662306a36Sopenharmony_ci		 * 64bit DMA.
114762306a36Sopenharmony_ci		 *
114862306a36Sopenharmony_ci		 * This board also had the typo mentioned above in the
114962306a36Sopenharmony_ci		 * Manufacturer DMI field (fixed in BIOS version 1.5), so
115062306a36Sopenharmony_ci		 * match on DMI_BOARD_VENDOR of "MICRO-STAR INTER" again.
115162306a36Sopenharmony_ci		 */
115262306a36Sopenharmony_ci		{
115362306a36Sopenharmony_ci			.ident = "MSI K9AGM2",
115462306a36Sopenharmony_ci			.matches = {
115562306a36Sopenharmony_ci				DMI_MATCH(DMI_BOARD_VENDOR,
115662306a36Sopenharmony_ci					  "MICRO-STAR INTER"),
115762306a36Sopenharmony_ci				DMI_MATCH(DMI_BOARD_NAME, "MS-7327"),
115862306a36Sopenharmony_ci			},
115962306a36Sopenharmony_ci		},
116062306a36Sopenharmony_ci		/*
116162306a36Sopenharmony_ci		 * All BIOS versions for the Asus M3A support 64bit DMA.
116262306a36Sopenharmony_ci		 * (all release versions from 0301 to 1206 were tested)
116362306a36Sopenharmony_ci		 */
116462306a36Sopenharmony_ci		{
116562306a36Sopenharmony_ci			.ident = "ASUS M3A",
116662306a36Sopenharmony_ci			.matches = {
116762306a36Sopenharmony_ci				DMI_MATCH(DMI_BOARD_VENDOR,
116862306a36Sopenharmony_ci					  "ASUSTeK Computer INC."),
116962306a36Sopenharmony_ci				DMI_MATCH(DMI_BOARD_NAME, "M3A"),
117062306a36Sopenharmony_ci			},
117162306a36Sopenharmony_ci		},
117262306a36Sopenharmony_ci		{ }
117362306a36Sopenharmony_ci	};
117462306a36Sopenharmony_ci	const struct dmi_system_id *match;
117562306a36Sopenharmony_ci	int year, month, date;
117662306a36Sopenharmony_ci	char buf[9];
117762306a36Sopenharmony_ci
117862306a36Sopenharmony_ci	match = dmi_first_match(sysids);
117962306a36Sopenharmony_ci	if (pdev->bus->number != 0 || pdev->devfn != PCI_DEVFN(0x12, 0) ||
118062306a36Sopenharmony_ci	    !match)
118162306a36Sopenharmony_ci		return false;
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_ci	if (!match->driver_data)
118462306a36Sopenharmony_ci		goto enable_64bit;
118562306a36Sopenharmony_ci
118662306a36Sopenharmony_ci	dmi_get_date(DMI_BIOS_DATE, &year, &month, &date);
118762306a36Sopenharmony_ci	snprintf(buf, sizeof(buf), "%04d%02d%02d", year, month, date);
118862306a36Sopenharmony_ci
118962306a36Sopenharmony_ci	if (strcmp(buf, match->driver_data) >= 0)
119062306a36Sopenharmony_ci		goto enable_64bit;
119162306a36Sopenharmony_ci	else {
119262306a36Sopenharmony_ci		dev_warn(&pdev->dev,
119362306a36Sopenharmony_ci			 "%s: BIOS too old, forcing 32bit DMA, update BIOS\n",
119462306a36Sopenharmony_ci			 match->ident);
119562306a36Sopenharmony_ci		return false;
119662306a36Sopenharmony_ci	}
119762306a36Sopenharmony_ci
119862306a36Sopenharmony_cienable_64bit:
119962306a36Sopenharmony_ci	dev_warn(&pdev->dev, "%s: enabling 64bit DMA\n", match->ident);
120062306a36Sopenharmony_ci	return true;
120162306a36Sopenharmony_ci}
120262306a36Sopenharmony_ci
120362306a36Sopenharmony_cistatic bool ahci_broken_system_poweroff(struct pci_dev *pdev)
120462306a36Sopenharmony_ci{
120562306a36Sopenharmony_ci	static const struct dmi_system_id broken_systems[] = {
120662306a36Sopenharmony_ci		{
120762306a36Sopenharmony_ci			.ident = "HP Compaq nx6310",
120862306a36Sopenharmony_ci			.matches = {
120962306a36Sopenharmony_ci				DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
121062306a36Sopenharmony_ci				DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq nx6310"),
121162306a36Sopenharmony_ci			},
121262306a36Sopenharmony_ci			/* PCI slot number of the controller */
121362306a36Sopenharmony_ci			.driver_data = (void *)0x1FUL,
121462306a36Sopenharmony_ci		},
121562306a36Sopenharmony_ci		{
121662306a36Sopenharmony_ci			.ident = "HP Compaq 6720s",
121762306a36Sopenharmony_ci			.matches = {
121862306a36Sopenharmony_ci				DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
121962306a36Sopenharmony_ci				DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq 6720s"),
122062306a36Sopenharmony_ci			},
122162306a36Sopenharmony_ci			/* PCI slot number of the controller */
122262306a36Sopenharmony_ci			.driver_data = (void *)0x1FUL,
122362306a36Sopenharmony_ci		},
122462306a36Sopenharmony_ci
122562306a36Sopenharmony_ci		{ }	/* terminate list */
122662306a36Sopenharmony_ci	};
122762306a36Sopenharmony_ci	const struct dmi_system_id *dmi = dmi_first_match(broken_systems);
122862306a36Sopenharmony_ci
122962306a36Sopenharmony_ci	if (dmi) {
123062306a36Sopenharmony_ci		unsigned long slot = (unsigned long)dmi->driver_data;
123162306a36Sopenharmony_ci		/* apply the quirk only to on-board controllers */
123262306a36Sopenharmony_ci		return slot == PCI_SLOT(pdev->devfn);
123362306a36Sopenharmony_ci	}
123462306a36Sopenharmony_ci
123562306a36Sopenharmony_ci	return false;
123662306a36Sopenharmony_ci}
123762306a36Sopenharmony_ci
123862306a36Sopenharmony_cistatic bool ahci_broken_suspend(struct pci_dev *pdev)
123962306a36Sopenharmony_ci{
124062306a36Sopenharmony_ci	static const struct dmi_system_id sysids[] = {
124162306a36Sopenharmony_ci		/*
124262306a36Sopenharmony_ci		 * On HP dv[4-6] and HDX18 with earlier BIOSen, link
124362306a36Sopenharmony_ci		 * to the harddisk doesn't become online after
124462306a36Sopenharmony_ci		 * resuming from STR.  Warn and fail suspend.
124562306a36Sopenharmony_ci		 *
124662306a36Sopenharmony_ci		 * http://bugzilla.kernel.org/show_bug.cgi?id=12276
124762306a36Sopenharmony_ci		 *
124862306a36Sopenharmony_ci		 * Use dates instead of versions to match as HP is
124962306a36Sopenharmony_ci		 * apparently recycling both product and version
125062306a36Sopenharmony_ci		 * strings.
125162306a36Sopenharmony_ci		 *
125262306a36Sopenharmony_ci		 * http://bugzilla.kernel.org/show_bug.cgi?id=15462
125362306a36Sopenharmony_ci		 */
125462306a36Sopenharmony_ci		{
125562306a36Sopenharmony_ci			.ident = "dv4",
125662306a36Sopenharmony_ci			.matches = {
125762306a36Sopenharmony_ci				DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
125862306a36Sopenharmony_ci				DMI_MATCH(DMI_PRODUCT_NAME,
125962306a36Sopenharmony_ci					  "HP Pavilion dv4 Notebook PC"),
126062306a36Sopenharmony_ci			},
126162306a36Sopenharmony_ci			.driver_data = "20090105",	/* F.30 */
126262306a36Sopenharmony_ci		},
126362306a36Sopenharmony_ci		{
126462306a36Sopenharmony_ci			.ident = "dv5",
126562306a36Sopenharmony_ci			.matches = {
126662306a36Sopenharmony_ci				DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
126762306a36Sopenharmony_ci				DMI_MATCH(DMI_PRODUCT_NAME,
126862306a36Sopenharmony_ci					  "HP Pavilion dv5 Notebook PC"),
126962306a36Sopenharmony_ci			},
127062306a36Sopenharmony_ci			.driver_data = "20090506",	/* F.16 */
127162306a36Sopenharmony_ci		},
127262306a36Sopenharmony_ci		{
127362306a36Sopenharmony_ci			.ident = "dv6",
127462306a36Sopenharmony_ci			.matches = {
127562306a36Sopenharmony_ci				DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
127662306a36Sopenharmony_ci				DMI_MATCH(DMI_PRODUCT_NAME,
127762306a36Sopenharmony_ci					  "HP Pavilion dv6 Notebook PC"),
127862306a36Sopenharmony_ci			},
127962306a36Sopenharmony_ci			.driver_data = "20090423",	/* F.21 */
128062306a36Sopenharmony_ci		},
128162306a36Sopenharmony_ci		{
128262306a36Sopenharmony_ci			.ident = "HDX18",
128362306a36Sopenharmony_ci			.matches = {
128462306a36Sopenharmony_ci				DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
128562306a36Sopenharmony_ci				DMI_MATCH(DMI_PRODUCT_NAME,
128662306a36Sopenharmony_ci					  "HP HDX18 Notebook PC"),
128762306a36Sopenharmony_ci			},
128862306a36Sopenharmony_ci			.driver_data = "20090430",	/* F.23 */
128962306a36Sopenharmony_ci		},
129062306a36Sopenharmony_ci		/*
129162306a36Sopenharmony_ci		 * Acer eMachines G725 has the same problem.  BIOS
129262306a36Sopenharmony_ci		 * V1.03 is known to be broken.  V3.04 is known to
129362306a36Sopenharmony_ci		 * work.  Between, there are V1.06, V2.06 and V3.03
129462306a36Sopenharmony_ci		 * that we don't have much idea about.  For now,
129562306a36Sopenharmony_ci		 * blacklist anything older than V3.04.
129662306a36Sopenharmony_ci		 *
129762306a36Sopenharmony_ci		 * http://bugzilla.kernel.org/show_bug.cgi?id=15104
129862306a36Sopenharmony_ci		 */
129962306a36Sopenharmony_ci		{
130062306a36Sopenharmony_ci			.ident = "G725",
130162306a36Sopenharmony_ci			.matches = {
130262306a36Sopenharmony_ci				DMI_MATCH(DMI_SYS_VENDOR, "eMachines"),
130362306a36Sopenharmony_ci				DMI_MATCH(DMI_PRODUCT_NAME, "eMachines G725"),
130462306a36Sopenharmony_ci			},
130562306a36Sopenharmony_ci			.driver_data = "20091216",	/* V3.04 */
130662306a36Sopenharmony_ci		},
130762306a36Sopenharmony_ci		{ }	/* terminate list */
130862306a36Sopenharmony_ci	};
130962306a36Sopenharmony_ci	const struct dmi_system_id *dmi = dmi_first_match(sysids);
131062306a36Sopenharmony_ci	int year, month, date;
131162306a36Sopenharmony_ci	char buf[9];
131262306a36Sopenharmony_ci
131362306a36Sopenharmony_ci	if (!dmi || pdev->bus->number || pdev->devfn != PCI_DEVFN(0x1f, 2))
131462306a36Sopenharmony_ci		return false;
131562306a36Sopenharmony_ci
131662306a36Sopenharmony_ci	dmi_get_date(DMI_BIOS_DATE, &year, &month, &date);
131762306a36Sopenharmony_ci	snprintf(buf, sizeof(buf), "%04d%02d%02d", year, month, date);
131862306a36Sopenharmony_ci
131962306a36Sopenharmony_ci	return strcmp(buf, dmi->driver_data) < 0;
132062306a36Sopenharmony_ci}
132162306a36Sopenharmony_ci
132262306a36Sopenharmony_cistatic bool ahci_broken_lpm(struct pci_dev *pdev)
132362306a36Sopenharmony_ci{
132462306a36Sopenharmony_ci	static const struct dmi_system_id sysids[] = {
132562306a36Sopenharmony_ci		/* Various Lenovo 50 series have LPM issues with older BIOSen */
132662306a36Sopenharmony_ci		{
132762306a36Sopenharmony_ci			.matches = {
132862306a36Sopenharmony_ci				DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
132962306a36Sopenharmony_ci				DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X250"),
133062306a36Sopenharmony_ci			},
133162306a36Sopenharmony_ci			.driver_data = "20180406", /* 1.31 */
133262306a36Sopenharmony_ci		},
133362306a36Sopenharmony_ci		{
133462306a36Sopenharmony_ci			.matches = {
133562306a36Sopenharmony_ci				DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
133662306a36Sopenharmony_ci				DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad L450"),
133762306a36Sopenharmony_ci			},
133862306a36Sopenharmony_ci			.driver_data = "20180420", /* 1.28 */
133962306a36Sopenharmony_ci		},
134062306a36Sopenharmony_ci		{
134162306a36Sopenharmony_ci			.matches = {
134262306a36Sopenharmony_ci				DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
134362306a36Sopenharmony_ci				DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T450s"),
134462306a36Sopenharmony_ci			},
134562306a36Sopenharmony_ci			.driver_data = "20180315", /* 1.33 */
134662306a36Sopenharmony_ci		},
134762306a36Sopenharmony_ci		{
134862306a36Sopenharmony_ci			.matches = {
134962306a36Sopenharmony_ci				DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
135062306a36Sopenharmony_ci				DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad W541"),
135162306a36Sopenharmony_ci			},
135262306a36Sopenharmony_ci			/*
135362306a36Sopenharmony_ci			 * Note date based on release notes, 2.35 has been
135462306a36Sopenharmony_ci			 * reported to be good, but I've been unable to get
135562306a36Sopenharmony_ci			 * a hold of the reporter to get the DMI BIOS date.
135662306a36Sopenharmony_ci			 * TODO: fix this.
135762306a36Sopenharmony_ci			 */
135862306a36Sopenharmony_ci			.driver_data = "20180310", /* 2.35 */
135962306a36Sopenharmony_ci		},
136062306a36Sopenharmony_ci		{ }	/* terminate list */
136162306a36Sopenharmony_ci	};
136262306a36Sopenharmony_ci	const struct dmi_system_id *dmi = dmi_first_match(sysids);
136362306a36Sopenharmony_ci	int year, month, date;
136462306a36Sopenharmony_ci	char buf[9];
136562306a36Sopenharmony_ci
136662306a36Sopenharmony_ci	if (!dmi)
136762306a36Sopenharmony_ci		return false;
136862306a36Sopenharmony_ci
136962306a36Sopenharmony_ci	dmi_get_date(DMI_BIOS_DATE, &year, &month, &date);
137062306a36Sopenharmony_ci	snprintf(buf, sizeof(buf), "%04d%02d%02d", year, month, date);
137162306a36Sopenharmony_ci
137262306a36Sopenharmony_ci	return strcmp(buf, dmi->driver_data) < 0;
137362306a36Sopenharmony_ci}
137462306a36Sopenharmony_ci
137562306a36Sopenharmony_cistatic bool ahci_broken_online(struct pci_dev *pdev)
137662306a36Sopenharmony_ci{
137762306a36Sopenharmony_ci#define ENCODE_BUSDEVFN(bus, slot, func)			\
137862306a36Sopenharmony_ci	(void *)(unsigned long)(((bus) << 8) | PCI_DEVFN((slot), (func)))
137962306a36Sopenharmony_ci	static const struct dmi_system_id sysids[] = {
138062306a36Sopenharmony_ci		/*
138162306a36Sopenharmony_ci		 * There are several gigabyte boards which use
138262306a36Sopenharmony_ci		 * SIMG5723s configured as hardware RAID.  Certain
138362306a36Sopenharmony_ci		 * 5723 firmware revisions shipped there keep the link
138462306a36Sopenharmony_ci		 * online but fail to answer properly to SRST or
138562306a36Sopenharmony_ci		 * IDENTIFY when no device is attached downstream
138662306a36Sopenharmony_ci		 * causing libata to retry quite a few times leading
138762306a36Sopenharmony_ci		 * to excessive detection delay.
138862306a36Sopenharmony_ci		 *
138962306a36Sopenharmony_ci		 * As these firmwares respond to the second reset try
139062306a36Sopenharmony_ci		 * with invalid device signature, considering unknown
139162306a36Sopenharmony_ci		 * sig as offline works around the problem acceptably.
139262306a36Sopenharmony_ci		 */
139362306a36Sopenharmony_ci		{
139462306a36Sopenharmony_ci			.ident = "EP45-DQ6",
139562306a36Sopenharmony_ci			.matches = {
139662306a36Sopenharmony_ci				DMI_MATCH(DMI_BOARD_VENDOR,
139762306a36Sopenharmony_ci					  "Gigabyte Technology Co., Ltd."),
139862306a36Sopenharmony_ci				DMI_MATCH(DMI_BOARD_NAME, "EP45-DQ6"),
139962306a36Sopenharmony_ci			},
140062306a36Sopenharmony_ci			.driver_data = ENCODE_BUSDEVFN(0x0a, 0x00, 0),
140162306a36Sopenharmony_ci		},
140262306a36Sopenharmony_ci		{
140362306a36Sopenharmony_ci			.ident = "EP45-DS5",
140462306a36Sopenharmony_ci			.matches = {
140562306a36Sopenharmony_ci				DMI_MATCH(DMI_BOARD_VENDOR,
140662306a36Sopenharmony_ci					  "Gigabyte Technology Co., Ltd."),
140762306a36Sopenharmony_ci				DMI_MATCH(DMI_BOARD_NAME, "EP45-DS5"),
140862306a36Sopenharmony_ci			},
140962306a36Sopenharmony_ci			.driver_data = ENCODE_BUSDEVFN(0x03, 0x00, 0),
141062306a36Sopenharmony_ci		},
141162306a36Sopenharmony_ci		{ }	/* terminate list */
141262306a36Sopenharmony_ci	};
141362306a36Sopenharmony_ci#undef ENCODE_BUSDEVFN
141462306a36Sopenharmony_ci	const struct dmi_system_id *dmi = dmi_first_match(sysids);
141562306a36Sopenharmony_ci	unsigned int val;
141662306a36Sopenharmony_ci
141762306a36Sopenharmony_ci	if (!dmi)
141862306a36Sopenharmony_ci		return false;
141962306a36Sopenharmony_ci
142062306a36Sopenharmony_ci	val = (unsigned long)dmi->driver_data;
142162306a36Sopenharmony_ci
142262306a36Sopenharmony_ci	return pdev->bus->number == (val >> 8) && pdev->devfn == (val & 0xff);
142362306a36Sopenharmony_ci}
142462306a36Sopenharmony_ci
142562306a36Sopenharmony_cistatic bool ahci_broken_devslp(struct pci_dev *pdev)
142662306a36Sopenharmony_ci{
142762306a36Sopenharmony_ci	/* device with broken DEVSLP but still showing SDS capability */
142862306a36Sopenharmony_ci	static const struct pci_device_id ids[] = {
142962306a36Sopenharmony_ci		{ PCI_VDEVICE(INTEL, 0x0f23)}, /* Valleyview SoC */
143062306a36Sopenharmony_ci		{}
143162306a36Sopenharmony_ci	};
143262306a36Sopenharmony_ci
143362306a36Sopenharmony_ci	return pci_match_id(ids, pdev);
143462306a36Sopenharmony_ci}
143562306a36Sopenharmony_ci
143662306a36Sopenharmony_ci#ifdef CONFIG_ATA_ACPI
143762306a36Sopenharmony_cistatic void ahci_gtf_filter_workaround(struct ata_host *host)
143862306a36Sopenharmony_ci{
143962306a36Sopenharmony_ci	static const struct dmi_system_id sysids[] = {
144062306a36Sopenharmony_ci		/*
144162306a36Sopenharmony_ci		 * Aspire 3810T issues a bunch of SATA enable commands
144262306a36Sopenharmony_ci		 * via _GTF including an invalid one and one which is
144362306a36Sopenharmony_ci		 * rejected by the device.  Among the successful ones
144462306a36Sopenharmony_ci		 * is FPDMA non-zero offset enable which when enabled
144562306a36Sopenharmony_ci		 * only on the drive side leads to NCQ command
144662306a36Sopenharmony_ci		 * failures.  Filter it out.
144762306a36Sopenharmony_ci		 */
144862306a36Sopenharmony_ci		{
144962306a36Sopenharmony_ci			.ident = "Aspire 3810T",
145062306a36Sopenharmony_ci			.matches = {
145162306a36Sopenharmony_ci				DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
145262306a36Sopenharmony_ci				DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3810T"),
145362306a36Sopenharmony_ci			},
145462306a36Sopenharmony_ci			.driver_data = (void *)ATA_ACPI_FILTER_FPDMA_OFFSET,
145562306a36Sopenharmony_ci		},
145662306a36Sopenharmony_ci		{ }
145762306a36Sopenharmony_ci	};
145862306a36Sopenharmony_ci	const struct dmi_system_id *dmi = dmi_first_match(sysids);
145962306a36Sopenharmony_ci	unsigned int filter;
146062306a36Sopenharmony_ci	int i;
146162306a36Sopenharmony_ci
146262306a36Sopenharmony_ci	if (!dmi)
146362306a36Sopenharmony_ci		return;
146462306a36Sopenharmony_ci
146562306a36Sopenharmony_ci	filter = (unsigned long)dmi->driver_data;
146662306a36Sopenharmony_ci	dev_info(host->dev, "applying extra ACPI _GTF filter 0x%x for %s\n",
146762306a36Sopenharmony_ci		 filter, dmi->ident);
146862306a36Sopenharmony_ci
146962306a36Sopenharmony_ci	for (i = 0; i < host->n_ports; i++) {
147062306a36Sopenharmony_ci		struct ata_port *ap = host->ports[i];
147162306a36Sopenharmony_ci		struct ata_link *link;
147262306a36Sopenharmony_ci		struct ata_device *dev;
147362306a36Sopenharmony_ci
147462306a36Sopenharmony_ci		ata_for_each_link(link, ap, EDGE)
147562306a36Sopenharmony_ci			ata_for_each_dev(dev, link, ALL)
147662306a36Sopenharmony_ci				dev->gtf_filter |= filter;
147762306a36Sopenharmony_ci	}
147862306a36Sopenharmony_ci}
147962306a36Sopenharmony_ci#else
148062306a36Sopenharmony_cistatic inline void ahci_gtf_filter_workaround(struct ata_host *host)
148162306a36Sopenharmony_ci{}
148262306a36Sopenharmony_ci#endif
148362306a36Sopenharmony_ci
148462306a36Sopenharmony_ci/*
148562306a36Sopenharmony_ci * On the Acer Aspire Switch Alpha 12, sometimes all SATA ports are detected
148662306a36Sopenharmony_ci * as DUMMY, or detected but eventually get a "link down" and never get up
148762306a36Sopenharmony_ci * again. When this happens, CAP.NP may hold a value of 0x00 or 0x01, and the
148862306a36Sopenharmony_ci * port_map may hold a value of 0x00.
148962306a36Sopenharmony_ci *
149062306a36Sopenharmony_ci * Overriding CAP.NP to 0x02 and the port_map to 0x7 will reveal all 3 ports
149162306a36Sopenharmony_ci * and can significantly reduce the occurrence of the problem.
149262306a36Sopenharmony_ci *
149362306a36Sopenharmony_ci * https://bugzilla.kernel.org/show_bug.cgi?id=189471
149462306a36Sopenharmony_ci */
149562306a36Sopenharmony_cistatic void acer_sa5_271_workaround(struct ahci_host_priv *hpriv,
149662306a36Sopenharmony_ci				    struct pci_dev *pdev)
149762306a36Sopenharmony_ci{
149862306a36Sopenharmony_ci	static const struct dmi_system_id sysids[] = {
149962306a36Sopenharmony_ci		{
150062306a36Sopenharmony_ci			.ident = "Acer Switch Alpha 12",
150162306a36Sopenharmony_ci			.matches = {
150262306a36Sopenharmony_ci				DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
150362306a36Sopenharmony_ci				DMI_MATCH(DMI_PRODUCT_NAME, "Switch SA5-271")
150462306a36Sopenharmony_ci			},
150562306a36Sopenharmony_ci		},
150662306a36Sopenharmony_ci		{ }
150762306a36Sopenharmony_ci	};
150862306a36Sopenharmony_ci
150962306a36Sopenharmony_ci	if (dmi_check_system(sysids)) {
151062306a36Sopenharmony_ci		dev_info(&pdev->dev, "enabling Acer Switch Alpha 12 workaround\n");
151162306a36Sopenharmony_ci		if ((hpriv->saved_cap & 0xC734FF00) == 0xC734FF00) {
151262306a36Sopenharmony_ci			hpriv->port_map = 0x7;
151362306a36Sopenharmony_ci			hpriv->cap = 0xC734FF02;
151462306a36Sopenharmony_ci		}
151562306a36Sopenharmony_ci	}
151662306a36Sopenharmony_ci}
151762306a36Sopenharmony_ci
151862306a36Sopenharmony_ci#ifdef CONFIG_ARM64
151962306a36Sopenharmony_ci/*
152062306a36Sopenharmony_ci * Due to ERRATA#22536, ThunderX needs to handle HOST_IRQ_STAT differently.
152162306a36Sopenharmony_ci * Workaround is to make sure all pending IRQs are served before leaving
152262306a36Sopenharmony_ci * handler.
152362306a36Sopenharmony_ci */
152462306a36Sopenharmony_cistatic irqreturn_t ahci_thunderx_irq_handler(int irq, void *dev_instance)
152562306a36Sopenharmony_ci{
152662306a36Sopenharmony_ci	struct ata_host *host = dev_instance;
152762306a36Sopenharmony_ci	struct ahci_host_priv *hpriv;
152862306a36Sopenharmony_ci	unsigned int rc = 0;
152962306a36Sopenharmony_ci	void __iomem *mmio;
153062306a36Sopenharmony_ci	u32 irq_stat, irq_masked;
153162306a36Sopenharmony_ci	unsigned int handled = 1;
153262306a36Sopenharmony_ci
153362306a36Sopenharmony_ci	hpriv = host->private_data;
153462306a36Sopenharmony_ci	mmio = hpriv->mmio;
153562306a36Sopenharmony_ci	irq_stat = readl(mmio + HOST_IRQ_STAT);
153662306a36Sopenharmony_ci	if (!irq_stat)
153762306a36Sopenharmony_ci		return IRQ_NONE;
153862306a36Sopenharmony_ci
153962306a36Sopenharmony_ci	do {
154062306a36Sopenharmony_ci		irq_masked = irq_stat & hpriv->port_map;
154162306a36Sopenharmony_ci		spin_lock(&host->lock);
154262306a36Sopenharmony_ci		rc = ahci_handle_port_intr(host, irq_masked);
154362306a36Sopenharmony_ci		if (!rc)
154462306a36Sopenharmony_ci			handled = 0;
154562306a36Sopenharmony_ci		writel(irq_stat, mmio + HOST_IRQ_STAT);
154662306a36Sopenharmony_ci		irq_stat = readl(mmio + HOST_IRQ_STAT);
154762306a36Sopenharmony_ci		spin_unlock(&host->lock);
154862306a36Sopenharmony_ci	} while (irq_stat);
154962306a36Sopenharmony_ci
155062306a36Sopenharmony_ci	return IRQ_RETVAL(handled);
155162306a36Sopenharmony_ci}
155262306a36Sopenharmony_ci#endif
155362306a36Sopenharmony_ci
155462306a36Sopenharmony_cistatic void ahci_remap_check(struct pci_dev *pdev, int bar,
155562306a36Sopenharmony_ci		struct ahci_host_priv *hpriv)
155662306a36Sopenharmony_ci{
155762306a36Sopenharmony_ci	int i;
155862306a36Sopenharmony_ci	u32 cap;
155962306a36Sopenharmony_ci
156062306a36Sopenharmony_ci	/*
156162306a36Sopenharmony_ci	 * Check if this device might have remapped nvme devices.
156262306a36Sopenharmony_ci	 */
156362306a36Sopenharmony_ci	if (pdev->vendor != PCI_VENDOR_ID_INTEL ||
156462306a36Sopenharmony_ci	    pci_resource_len(pdev, bar) < SZ_512K ||
156562306a36Sopenharmony_ci	    bar != AHCI_PCI_BAR_STANDARD ||
156662306a36Sopenharmony_ci	    !(readl(hpriv->mmio + AHCI_VSCAP) & 1))
156762306a36Sopenharmony_ci		return;
156862306a36Sopenharmony_ci
156962306a36Sopenharmony_ci	cap = readq(hpriv->mmio + AHCI_REMAP_CAP);
157062306a36Sopenharmony_ci	for (i = 0; i < AHCI_MAX_REMAP; i++) {
157162306a36Sopenharmony_ci		if ((cap & (1 << i)) == 0)
157262306a36Sopenharmony_ci			continue;
157362306a36Sopenharmony_ci		if (readl(hpriv->mmio + ahci_remap_dcc(i))
157462306a36Sopenharmony_ci				!= PCI_CLASS_STORAGE_EXPRESS)
157562306a36Sopenharmony_ci			continue;
157662306a36Sopenharmony_ci
157762306a36Sopenharmony_ci		/* We've found a remapped device */
157862306a36Sopenharmony_ci		hpriv->remapped_nvme++;
157962306a36Sopenharmony_ci	}
158062306a36Sopenharmony_ci
158162306a36Sopenharmony_ci	if (!hpriv->remapped_nvme)
158262306a36Sopenharmony_ci		return;
158362306a36Sopenharmony_ci
158462306a36Sopenharmony_ci	dev_warn(&pdev->dev, "Found %u remapped NVMe devices.\n",
158562306a36Sopenharmony_ci		 hpriv->remapped_nvme);
158662306a36Sopenharmony_ci	dev_warn(&pdev->dev,
158762306a36Sopenharmony_ci		 "Switch your BIOS from RAID to AHCI mode to use them.\n");
158862306a36Sopenharmony_ci
158962306a36Sopenharmony_ci	/*
159062306a36Sopenharmony_ci	 * Don't rely on the msi-x capability in the remap case,
159162306a36Sopenharmony_ci	 * share the legacy interrupt across ahci and remapped devices.
159262306a36Sopenharmony_ci	 */
159362306a36Sopenharmony_ci	hpriv->flags |= AHCI_HFLAG_NO_MSI;
159462306a36Sopenharmony_ci}
159562306a36Sopenharmony_ci
159662306a36Sopenharmony_cistatic int ahci_get_irq_vector(struct ata_host *host, int port)
159762306a36Sopenharmony_ci{
159862306a36Sopenharmony_ci	return pci_irq_vector(to_pci_dev(host->dev), port);
159962306a36Sopenharmony_ci}
160062306a36Sopenharmony_ci
160162306a36Sopenharmony_cistatic int ahci_init_msi(struct pci_dev *pdev, unsigned int n_ports,
160262306a36Sopenharmony_ci			struct ahci_host_priv *hpriv)
160362306a36Sopenharmony_ci{
160462306a36Sopenharmony_ci	int nvec;
160562306a36Sopenharmony_ci
160662306a36Sopenharmony_ci	if (hpriv->flags & AHCI_HFLAG_NO_MSI)
160762306a36Sopenharmony_ci		return -ENODEV;
160862306a36Sopenharmony_ci
160962306a36Sopenharmony_ci	/*
161062306a36Sopenharmony_ci	 * If number of MSIs is less than number of ports then Sharing Last
161162306a36Sopenharmony_ci	 * Message mode could be enforced. In this case assume that advantage
161262306a36Sopenharmony_ci	 * of multipe MSIs is negated and use single MSI mode instead.
161362306a36Sopenharmony_ci	 */
161462306a36Sopenharmony_ci	if (n_ports > 1) {
161562306a36Sopenharmony_ci		nvec = pci_alloc_irq_vectors(pdev, n_ports, INT_MAX,
161662306a36Sopenharmony_ci				PCI_IRQ_MSIX | PCI_IRQ_MSI);
161762306a36Sopenharmony_ci		if (nvec > 0) {
161862306a36Sopenharmony_ci			if (!(readl(hpriv->mmio + HOST_CTL) & HOST_MRSM)) {
161962306a36Sopenharmony_ci				hpriv->get_irq_vector = ahci_get_irq_vector;
162062306a36Sopenharmony_ci				hpriv->flags |= AHCI_HFLAG_MULTI_MSI;
162162306a36Sopenharmony_ci				return nvec;
162262306a36Sopenharmony_ci			}
162362306a36Sopenharmony_ci
162462306a36Sopenharmony_ci			/*
162562306a36Sopenharmony_ci			 * Fallback to single MSI mode if the controller
162662306a36Sopenharmony_ci			 * enforced MRSM mode.
162762306a36Sopenharmony_ci			 */
162862306a36Sopenharmony_ci			printk(KERN_INFO
162962306a36Sopenharmony_ci				"ahci: MRSM is on, fallback to single MSI\n");
163062306a36Sopenharmony_ci			pci_free_irq_vectors(pdev);
163162306a36Sopenharmony_ci		}
163262306a36Sopenharmony_ci	}
163362306a36Sopenharmony_ci
163462306a36Sopenharmony_ci	/*
163562306a36Sopenharmony_ci	 * If the host is not capable of supporting per-port vectors, fall
163662306a36Sopenharmony_ci	 * back to single MSI before finally attempting single MSI-X.
163762306a36Sopenharmony_ci	 */
163862306a36Sopenharmony_ci	nvec = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSI);
163962306a36Sopenharmony_ci	if (nvec == 1)
164062306a36Sopenharmony_ci		return nvec;
164162306a36Sopenharmony_ci	return pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSIX);
164262306a36Sopenharmony_ci}
164362306a36Sopenharmony_ci
164462306a36Sopenharmony_cistatic void ahci_update_initial_lpm_policy(struct ata_port *ap,
164562306a36Sopenharmony_ci					   struct ahci_host_priv *hpriv)
164662306a36Sopenharmony_ci{
164762306a36Sopenharmony_ci	int policy = CONFIG_SATA_MOBILE_LPM_POLICY;
164862306a36Sopenharmony_ci
164962306a36Sopenharmony_ci
165062306a36Sopenharmony_ci	/* Ignore processing for chipsets that don't use policy */
165162306a36Sopenharmony_ci	if (!(hpriv->flags & AHCI_HFLAG_USE_LPM_POLICY))
165262306a36Sopenharmony_ci		return;
165362306a36Sopenharmony_ci
165462306a36Sopenharmony_ci	/* user modified policy via module param */
165562306a36Sopenharmony_ci	if (mobile_lpm_policy != -1) {
165662306a36Sopenharmony_ci		policy = mobile_lpm_policy;
165762306a36Sopenharmony_ci		goto update_policy;
165862306a36Sopenharmony_ci	}
165962306a36Sopenharmony_ci
166062306a36Sopenharmony_ci	if (policy > ATA_LPM_MED_POWER && pm_suspend_default_s2idle()) {
166162306a36Sopenharmony_ci		if (hpriv->cap & HOST_CAP_PART)
166262306a36Sopenharmony_ci			policy = ATA_LPM_MIN_POWER_WITH_PARTIAL;
166362306a36Sopenharmony_ci		else if (hpriv->cap & HOST_CAP_SSC)
166462306a36Sopenharmony_ci			policy = ATA_LPM_MIN_POWER;
166562306a36Sopenharmony_ci	}
166662306a36Sopenharmony_ci
166762306a36Sopenharmony_ciupdate_policy:
166862306a36Sopenharmony_ci	if (policy >= ATA_LPM_UNKNOWN && policy <= ATA_LPM_MIN_POWER)
166962306a36Sopenharmony_ci		ap->target_lpm_policy = policy;
167062306a36Sopenharmony_ci}
167162306a36Sopenharmony_ci
167262306a36Sopenharmony_cistatic void ahci_intel_pcs_quirk(struct pci_dev *pdev, struct ahci_host_priv *hpriv)
167362306a36Sopenharmony_ci{
167462306a36Sopenharmony_ci	const struct pci_device_id *id = pci_match_id(ahci_pci_tbl, pdev);
167562306a36Sopenharmony_ci	u16 tmp16;
167662306a36Sopenharmony_ci
167762306a36Sopenharmony_ci	/*
167862306a36Sopenharmony_ci	 * Only apply the 6-port PCS quirk for known legacy platforms.
167962306a36Sopenharmony_ci	 */
168062306a36Sopenharmony_ci	if (!id || id->vendor != PCI_VENDOR_ID_INTEL)
168162306a36Sopenharmony_ci		return;
168262306a36Sopenharmony_ci
168362306a36Sopenharmony_ci	/* Skip applying the quirk on Denverton and beyond */
168462306a36Sopenharmony_ci	if (((enum board_ids) id->driver_data) >= board_ahci_pcs7)
168562306a36Sopenharmony_ci		return;
168662306a36Sopenharmony_ci
168762306a36Sopenharmony_ci	/*
168862306a36Sopenharmony_ci	 * port_map is determined from PORTS_IMPL PCI register which is
168962306a36Sopenharmony_ci	 * implemented as write or write-once register.  If the register
169062306a36Sopenharmony_ci	 * isn't programmed, ahci automatically generates it from number
169162306a36Sopenharmony_ci	 * of ports, which is good enough for PCS programming. It is
169262306a36Sopenharmony_ci	 * otherwise expected that platform firmware enables the ports
169362306a36Sopenharmony_ci	 * before the OS boots.
169462306a36Sopenharmony_ci	 */
169562306a36Sopenharmony_ci	pci_read_config_word(pdev, PCS_6, &tmp16);
169662306a36Sopenharmony_ci	if ((tmp16 & hpriv->port_map) != hpriv->port_map) {
169762306a36Sopenharmony_ci		tmp16 |= hpriv->port_map;
169862306a36Sopenharmony_ci		pci_write_config_word(pdev, PCS_6, tmp16);
169962306a36Sopenharmony_ci	}
170062306a36Sopenharmony_ci}
170162306a36Sopenharmony_ci
170262306a36Sopenharmony_cistatic ssize_t remapped_nvme_show(struct device *dev,
170362306a36Sopenharmony_ci				  struct device_attribute *attr,
170462306a36Sopenharmony_ci				  char *buf)
170562306a36Sopenharmony_ci{
170662306a36Sopenharmony_ci	struct ata_host *host = dev_get_drvdata(dev);
170762306a36Sopenharmony_ci	struct ahci_host_priv *hpriv = host->private_data;
170862306a36Sopenharmony_ci
170962306a36Sopenharmony_ci	return sysfs_emit(buf, "%u\n", hpriv->remapped_nvme);
171062306a36Sopenharmony_ci}
171162306a36Sopenharmony_ci
171262306a36Sopenharmony_cistatic DEVICE_ATTR_RO(remapped_nvme);
171362306a36Sopenharmony_ci
171462306a36Sopenharmony_cistatic int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
171562306a36Sopenharmony_ci{
171662306a36Sopenharmony_ci	unsigned int board_id = ent->driver_data;
171762306a36Sopenharmony_ci	struct ata_port_info pi = ahci_port_info[board_id];
171862306a36Sopenharmony_ci	const struct ata_port_info *ppi[] = { &pi, NULL };
171962306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
172062306a36Sopenharmony_ci	struct ahci_host_priv *hpriv;
172162306a36Sopenharmony_ci	struct ata_host *host;
172262306a36Sopenharmony_ci	int n_ports, i, rc;
172362306a36Sopenharmony_ci	int ahci_pci_bar = AHCI_PCI_BAR_STANDARD;
172462306a36Sopenharmony_ci
172562306a36Sopenharmony_ci	WARN_ON((int)ATA_MAX_QUEUE > AHCI_MAX_CMDS);
172662306a36Sopenharmony_ci
172762306a36Sopenharmony_ci	ata_print_version_once(&pdev->dev, DRV_VERSION);
172862306a36Sopenharmony_ci
172962306a36Sopenharmony_ci	/* The AHCI driver can only drive the SATA ports, the PATA driver
173062306a36Sopenharmony_ci	   can drive them all so if both drivers are selected make sure
173162306a36Sopenharmony_ci	   AHCI stays out of the way */
173262306a36Sopenharmony_ci	if (pdev->vendor == PCI_VENDOR_ID_MARVELL && !marvell_enable)
173362306a36Sopenharmony_ci		return -ENODEV;
173462306a36Sopenharmony_ci
173562306a36Sopenharmony_ci	/* Apple BIOS on MCP89 prevents us using AHCI */
173662306a36Sopenharmony_ci	if (is_mcp89_apple(pdev))
173762306a36Sopenharmony_ci		ahci_mcp89_apple_enable(pdev);
173862306a36Sopenharmony_ci
173962306a36Sopenharmony_ci	/* Promise's PDC42819 is a SAS/SATA controller that has an AHCI mode.
174062306a36Sopenharmony_ci	 * At the moment, we can only use the AHCI mode. Let the users know
174162306a36Sopenharmony_ci	 * that for SAS drives they're out of luck.
174262306a36Sopenharmony_ci	 */
174362306a36Sopenharmony_ci	if (pdev->vendor == PCI_VENDOR_ID_PROMISE)
174462306a36Sopenharmony_ci		dev_info(&pdev->dev,
174562306a36Sopenharmony_ci			 "PDC42819 can only drive SATA devices with this driver\n");
174662306a36Sopenharmony_ci
174762306a36Sopenharmony_ci	/* Some devices use non-standard BARs */
174862306a36Sopenharmony_ci	if (pdev->vendor == PCI_VENDOR_ID_STMICRO && pdev->device == 0xCC06)
174962306a36Sopenharmony_ci		ahci_pci_bar = AHCI_PCI_BAR_STA2X11;
175062306a36Sopenharmony_ci	else if (pdev->vendor == 0x1c44 && pdev->device == 0x8000)
175162306a36Sopenharmony_ci		ahci_pci_bar = AHCI_PCI_BAR_ENMOTUS;
175262306a36Sopenharmony_ci	else if (pdev->vendor == PCI_VENDOR_ID_CAVIUM) {
175362306a36Sopenharmony_ci		if (pdev->device == 0xa01c)
175462306a36Sopenharmony_ci			ahci_pci_bar = AHCI_PCI_BAR_CAVIUM;
175562306a36Sopenharmony_ci		if (pdev->device == 0xa084)
175662306a36Sopenharmony_ci			ahci_pci_bar = AHCI_PCI_BAR_CAVIUM_GEN5;
175762306a36Sopenharmony_ci	} else if (pdev->vendor == PCI_VENDOR_ID_LOONGSON) {
175862306a36Sopenharmony_ci		if (pdev->device == 0x7a08)
175962306a36Sopenharmony_ci			ahci_pci_bar = AHCI_PCI_BAR_LOONGSON;
176062306a36Sopenharmony_ci	}
176162306a36Sopenharmony_ci
176262306a36Sopenharmony_ci	/* acquire resources */
176362306a36Sopenharmony_ci	rc = pcim_enable_device(pdev);
176462306a36Sopenharmony_ci	if (rc)
176562306a36Sopenharmony_ci		return rc;
176662306a36Sopenharmony_ci
176762306a36Sopenharmony_ci	if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
176862306a36Sopenharmony_ci	    (pdev->device == 0x2652 || pdev->device == 0x2653)) {
176962306a36Sopenharmony_ci		u8 map;
177062306a36Sopenharmony_ci
177162306a36Sopenharmony_ci		/* ICH6s share the same PCI ID for both piix and ahci
177262306a36Sopenharmony_ci		 * modes.  Enabling ahci mode while MAP indicates
177362306a36Sopenharmony_ci		 * combined mode is a bad idea.  Yield to ata_piix.
177462306a36Sopenharmony_ci		 */
177562306a36Sopenharmony_ci		pci_read_config_byte(pdev, ICH_MAP, &map);
177662306a36Sopenharmony_ci		if (map & 0x3) {
177762306a36Sopenharmony_ci			dev_info(&pdev->dev,
177862306a36Sopenharmony_ci				 "controller is in combined mode, can't enable AHCI mode\n");
177962306a36Sopenharmony_ci			return -ENODEV;
178062306a36Sopenharmony_ci		}
178162306a36Sopenharmony_ci	}
178262306a36Sopenharmony_ci
178362306a36Sopenharmony_ci	/* AHCI controllers often implement SFF compatible interface.
178462306a36Sopenharmony_ci	 * Grab all PCI BARs just in case.
178562306a36Sopenharmony_ci	 */
178662306a36Sopenharmony_ci	rc = pcim_iomap_regions_request_all(pdev, 1 << ahci_pci_bar, DRV_NAME);
178762306a36Sopenharmony_ci	if (rc == -EBUSY)
178862306a36Sopenharmony_ci		pcim_pin_device(pdev);
178962306a36Sopenharmony_ci	if (rc)
179062306a36Sopenharmony_ci		return rc;
179162306a36Sopenharmony_ci
179262306a36Sopenharmony_ci	hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
179362306a36Sopenharmony_ci	if (!hpriv)
179462306a36Sopenharmony_ci		return -ENOMEM;
179562306a36Sopenharmony_ci	hpriv->flags |= (unsigned long)pi.private_data;
179662306a36Sopenharmony_ci
179762306a36Sopenharmony_ci	/* MCP65 revision A1 and A2 can't do MSI */
179862306a36Sopenharmony_ci	if (board_id == board_ahci_mcp65 &&
179962306a36Sopenharmony_ci	    (pdev->revision == 0xa1 || pdev->revision == 0xa2))
180062306a36Sopenharmony_ci		hpriv->flags |= AHCI_HFLAG_NO_MSI;
180162306a36Sopenharmony_ci
180262306a36Sopenharmony_ci	/* SB800 does NOT need the workaround to ignore SERR_INTERNAL */
180362306a36Sopenharmony_ci	if (board_id == board_ahci_sb700 && pdev->revision >= 0x40)
180462306a36Sopenharmony_ci		hpriv->flags &= ~AHCI_HFLAG_IGN_SERR_INTERNAL;
180562306a36Sopenharmony_ci
180662306a36Sopenharmony_ci	/* only some SB600s can do 64bit DMA */
180762306a36Sopenharmony_ci	if (ahci_sb600_enable_64bit(pdev))
180862306a36Sopenharmony_ci		hpriv->flags &= ~AHCI_HFLAG_32BIT_ONLY;
180962306a36Sopenharmony_ci
181062306a36Sopenharmony_ci	hpriv->mmio = pcim_iomap_table(pdev)[ahci_pci_bar];
181162306a36Sopenharmony_ci
181262306a36Sopenharmony_ci	/* detect remapped nvme devices */
181362306a36Sopenharmony_ci	ahci_remap_check(pdev, ahci_pci_bar, hpriv);
181462306a36Sopenharmony_ci
181562306a36Sopenharmony_ci	sysfs_add_file_to_group(&pdev->dev.kobj,
181662306a36Sopenharmony_ci				&dev_attr_remapped_nvme.attr,
181762306a36Sopenharmony_ci				NULL);
181862306a36Sopenharmony_ci
181962306a36Sopenharmony_ci	/* must set flag prior to save config in order to take effect */
182062306a36Sopenharmony_ci	if (ahci_broken_devslp(pdev))
182162306a36Sopenharmony_ci		hpriv->flags |= AHCI_HFLAG_NO_DEVSLP;
182262306a36Sopenharmony_ci
182362306a36Sopenharmony_ci#ifdef CONFIG_ARM64
182462306a36Sopenharmony_ci	if (pdev->vendor == PCI_VENDOR_ID_HUAWEI &&
182562306a36Sopenharmony_ci	    pdev->device == 0xa235 &&
182662306a36Sopenharmony_ci	    pdev->revision < 0x30)
182762306a36Sopenharmony_ci		hpriv->flags |= AHCI_HFLAG_NO_SXS;
182862306a36Sopenharmony_ci
182962306a36Sopenharmony_ci	if (pdev->vendor == 0x177d && pdev->device == 0xa01c)
183062306a36Sopenharmony_ci		hpriv->irq_handler = ahci_thunderx_irq_handler;
183162306a36Sopenharmony_ci#endif
183262306a36Sopenharmony_ci
183362306a36Sopenharmony_ci	/* save initial config */
183462306a36Sopenharmony_ci	ahci_pci_save_initial_config(pdev, hpriv);
183562306a36Sopenharmony_ci
183662306a36Sopenharmony_ci	/* prepare host */
183762306a36Sopenharmony_ci	if (hpriv->cap & HOST_CAP_NCQ) {
183862306a36Sopenharmony_ci		pi.flags |= ATA_FLAG_NCQ;
183962306a36Sopenharmony_ci		/*
184062306a36Sopenharmony_ci		 * Auto-activate optimization is supposed to be
184162306a36Sopenharmony_ci		 * supported on all AHCI controllers indicating NCQ
184262306a36Sopenharmony_ci		 * capability, but it seems to be broken on some
184362306a36Sopenharmony_ci		 * chipsets including NVIDIAs.
184462306a36Sopenharmony_ci		 */
184562306a36Sopenharmony_ci		if (!(hpriv->flags & AHCI_HFLAG_NO_FPDMA_AA))
184662306a36Sopenharmony_ci			pi.flags |= ATA_FLAG_FPDMA_AA;
184762306a36Sopenharmony_ci
184862306a36Sopenharmony_ci		/*
184962306a36Sopenharmony_ci		 * All AHCI controllers should be forward-compatible
185062306a36Sopenharmony_ci		 * with the new auxiliary field. This code should be
185162306a36Sopenharmony_ci		 * conditionalized if any buggy AHCI controllers are
185262306a36Sopenharmony_ci		 * encountered.
185362306a36Sopenharmony_ci		 */
185462306a36Sopenharmony_ci		pi.flags |= ATA_FLAG_FPDMA_AUX;
185562306a36Sopenharmony_ci	}
185662306a36Sopenharmony_ci
185762306a36Sopenharmony_ci	if (hpriv->cap & HOST_CAP_PMP)
185862306a36Sopenharmony_ci		pi.flags |= ATA_FLAG_PMP;
185962306a36Sopenharmony_ci
186062306a36Sopenharmony_ci	ahci_set_em_messages(hpriv, &pi);
186162306a36Sopenharmony_ci
186262306a36Sopenharmony_ci	if (ahci_broken_system_poweroff(pdev)) {
186362306a36Sopenharmony_ci		pi.flags |= ATA_FLAG_NO_POWEROFF_SPINDOWN;
186462306a36Sopenharmony_ci		dev_info(&pdev->dev,
186562306a36Sopenharmony_ci			"quirky BIOS, skipping spindown on poweroff\n");
186662306a36Sopenharmony_ci	}
186762306a36Sopenharmony_ci
186862306a36Sopenharmony_ci	if (ahci_broken_lpm(pdev)) {
186962306a36Sopenharmony_ci		pi.flags |= ATA_FLAG_NO_LPM;
187062306a36Sopenharmony_ci		dev_warn(&pdev->dev,
187162306a36Sopenharmony_ci			 "BIOS update required for Link Power Management support\n");
187262306a36Sopenharmony_ci	}
187362306a36Sopenharmony_ci
187462306a36Sopenharmony_ci	if (ahci_broken_suspend(pdev)) {
187562306a36Sopenharmony_ci		hpriv->flags |= AHCI_HFLAG_NO_SUSPEND;
187662306a36Sopenharmony_ci		dev_warn(&pdev->dev,
187762306a36Sopenharmony_ci			 "BIOS update required for suspend/resume\n");
187862306a36Sopenharmony_ci	}
187962306a36Sopenharmony_ci
188062306a36Sopenharmony_ci	if (ahci_broken_online(pdev)) {
188162306a36Sopenharmony_ci		hpriv->flags |= AHCI_HFLAG_SRST_TOUT_IS_OFFLINE;
188262306a36Sopenharmony_ci		dev_info(&pdev->dev,
188362306a36Sopenharmony_ci			 "online status unreliable, applying workaround\n");
188462306a36Sopenharmony_ci	}
188562306a36Sopenharmony_ci
188662306a36Sopenharmony_ci
188762306a36Sopenharmony_ci	/* Acer SA5-271 workaround modifies private_data */
188862306a36Sopenharmony_ci	acer_sa5_271_workaround(hpriv, pdev);
188962306a36Sopenharmony_ci
189062306a36Sopenharmony_ci	/* CAP.NP sometimes indicate the index of the last enabled
189162306a36Sopenharmony_ci	 * port, at other times, that of the last possible port, so
189262306a36Sopenharmony_ci	 * determining the maximum port number requires looking at
189362306a36Sopenharmony_ci	 * both CAP.NP and port_map.
189462306a36Sopenharmony_ci	 */
189562306a36Sopenharmony_ci	n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map));
189662306a36Sopenharmony_ci
189762306a36Sopenharmony_ci	host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);
189862306a36Sopenharmony_ci	if (!host)
189962306a36Sopenharmony_ci		return -ENOMEM;
190062306a36Sopenharmony_ci	host->private_data = hpriv;
190162306a36Sopenharmony_ci
190262306a36Sopenharmony_ci	if (ahci_init_msi(pdev, n_ports, hpriv) < 0) {
190362306a36Sopenharmony_ci		/* legacy intx interrupts */
190462306a36Sopenharmony_ci		pci_intx(pdev, 1);
190562306a36Sopenharmony_ci	}
190662306a36Sopenharmony_ci	hpriv->irq = pci_irq_vector(pdev, 0);
190762306a36Sopenharmony_ci
190862306a36Sopenharmony_ci	if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss)
190962306a36Sopenharmony_ci		host->flags |= ATA_HOST_PARALLEL_SCAN;
191062306a36Sopenharmony_ci	else
191162306a36Sopenharmony_ci		dev_info(&pdev->dev, "SSS flag set, parallel bus scan disabled\n");
191262306a36Sopenharmony_ci
191362306a36Sopenharmony_ci	if (!(hpriv->cap & HOST_CAP_PART))
191462306a36Sopenharmony_ci		host->flags |= ATA_HOST_NO_PART;
191562306a36Sopenharmony_ci
191662306a36Sopenharmony_ci	if (!(hpriv->cap & HOST_CAP_SSC))
191762306a36Sopenharmony_ci		host->flags |= ATA_HOST_NO_SSC;
191862306a36Sopenharmony_ci
191962306a36Sopenharmony_ci	if (!(hpriv->cap2 & HOST_CAP2_SDS))
192062306a36Sopenharmony_ci		host->flags |= ATA_HOST_NO_DEVSLP;
192162306a36Sopenharmony_ci
192262306a36Sopenharmony_ci	if (pi.flags & ATA_FLAG_EM)
192362306a36Sopenharmony_ci		ahci_reset_em(host);
192462306a36Sopenharmony_ci
192562306a36Sopenharmony_ci	for (i = 0; i < host->n_ports; i++) {
192662306a36Sopenharmony_ci		struct ata_port *ap = host->ports[i];
192762306a36Sopenharmony_ci
192862306a36Sopenharmony_ci		ata_port_pbar_desc(ap, ahci_pci_bar, -1, "abar");
192962306a36Sopenharmony_ci		ata_port_pbar_desc(ap, ahci_pci_bar,
193062306a36Sopenharmony_ci				   0x100 + ap->port_no * 0x80, "port");
193162306a36Sopenharmony_ci
193262306a36Sopenharmony_ci		/* set enclosure management message type */
193362306a36Sopenharmony_ci		if (ap->flags & ATA_FLAG_EM)
193462306a36Sopenharmony_ci			ap->em_message_type = hpriv->em_msg_type;
193562306a36Sopenharmony_ci
193662306a36Sopenharmony_ci		ahci_update_initial_lpm_policy(ap, hpriv);
193762306a36Sopenharmony_ci
193862306a36Sopenharmony_ci		/* disabled/not-implemented port */
193962306a36Sopenharmony_ci		if (!(hpriv->port_map & (1 << i)))
194062306a36Sopenharmony_ci			ap->ops = &ata_dummy_port_ops;
194162306a36Sopenharmony_ci	}
194262306a36Sopenharmony_ci
194362306a36Sopenharmony_ci	/* apply workaround for ASUS P5W DH Deluxe mainboard */
194462306a36Sopenharmony_ci	ahci_p5wdh_workaround(host);
194562306a36Sopenharmony_ci
194662306a36Sopenharmony_ci	/* apply gtf filter quirk */
194762306a36Sopenharmony_ci	ahci_gtf_filter_workaround(host);
194862306a36Sopenharmony_ci
194962306a36Sopenharmony_ci	/* initialize adapter */
195062306a36Sopenharmony_ci	rc = ahci_configure_dma_masks(pdev, hpriv);
195162306a36Sopenharmony_ci	if (rc)
195262306a36Sopenharmony_ci		return rc;
195362306a36Sopenharmony_ci
195462306a36Sopenharmony_ci	rc = ahci_pci_reset_controller(host);
195562306a36Sopenharmony_ci	if (rc)
195662306a36Sopenharmony_ci		return rc;
195762306a36Sopenharmony_ci
195862306a36Sopenharmony_ci	ahci_pci_init_controller(host);
195962306a36Sopenharmony_ci	ahci_pci_print_info(host);
196062306a36Sopenharmony_ci
196162306a36Sopenharmony_ci	pci_set_master(pdev);
196262306a36Sopenharmony_ci
196362306a36Sopenharmony_ci	rc = ahci_host_activate(host, &ahci_sht);
196462306a36Sopenharmony_ci	if (rc)
196562306a36Sopenharmony_ci		return rc;
196662306a36Sopenharmony_ci
196762306a36Sopenharmony_ci	pm_runtime_put_noidle(&pdev->dev);
196862306a36Sopenharmony_ci	return 0;
196962306a36Sopenharmony_ci}
197062306a36Sopenharmony_ci
197162306a36Sopenharmony_cistatic void ahci_shutdown_one(struct pci_dev *pdev)
197262306a36Sopenharmony_ci{
197362306a36Sopenharmony_ci	ata_pci_shutdown_one(pdev);
197462306a36Sopenharmony_ci}
197562306a36Sopenharmony_ci
197662306a36Sopenharmony_cistatic void ahci_remove_one(struct pci_dev *pdev)
197762306a36Sopenharmony_ci{
197862306a36Sopenharmony_ci	sysfs_remove_file_from_group(&pdev->dev.kobj,
197962306a36Sopenharmony_ci				     &dev_attr_remapped_nvme.attr,
198062306a36Sopenharmony_ci				     NULL);
198162306a36Sopenharmony_ci	pm_runtime_get_noresume(&pdev->dev);
198262306a36Sopenharmony_ci	ata_pci_remove_one(pdev);
198362306a36Sopenharmony_ci}
198462306a36Sopenharmony_ci
198562306a36Sopenharmony_cimodule_pci_driver(ahci_pci_driver);
198662306a36Sopenharmony_ci
198762306a36Sopenharmony_ciMODULE_AUTHOR("Jeff Garzik");
198862306a36Sopenharmony_ciMODULE_DESCRIPTION("AHCI SATA low-level driver");
198962306a36Sopenharmony_ciMODULE_LICENSE("GPL");
199062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, ahci_pci_tbl);
199162306a36Sopenharmony_ciMODULE_VERSION(DRV_VERSION);
1992