xref: /openbmc/linux/drivers/ata/ahci.c (revision 1f9b7a5d023a94666dcdaf8235f3008d4c1710ba)
1c82ee6d3SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2c6fd2807SJeff Garzik /*
3c6fd2807SJeff Garzik  *  ahci.c - AHCI SATA support
4c6fd2807SJeff Garzik  *
58c3d3d4bSTejun Heo  *  Maintained by:  Tejun Heo <tj@kernel.org>
6c6fd2807SJeff Garzik  *    		    Please ALWAYS copy linux-ide@vger.kernel.org
7c6fd2807SJeff Garzik  *		    on emails.
8c6fd2807SJeff Garzik  *
9c6fd2807SJeff Garzik  *  Copyright 2004-2005 Red Hat, Inc.
10c6fd2807SJeff Garzik  *
11c6fd2807SJeff Garzik  * libata documentation is available via 'make {ps|pdf}docs',
1219285f3cSMauro Carvalho Chehab  * as Documentation/driver-api/libata.rst
13c6fd2807SJeff Garzik  *
14c6fd2807SJeff Garzik  * AHCI hardware documentation:
15c6fd2807SJeff Garzik  * http://www.intel.com/technology/serialata/pdf/rev1_0.pdf
16c6fd2807SJeff Garzik  * http://www.intel.com/technology/serialata/pdf/rev1_1.pdf
17c6fd2807SJeff Garzik  */
18c6fd2807SJeff Garzik 
19c6fd2807SJeff Garzik #include <linux/kernel.h>
20c6fd2807SJeff Garzik #include <linux/module.h>
21c6fd2807SJeff Garzik #include <linux/pci.h>
22c6fd2807SJeff Garzik #include <linux/blkdev.h>
23c6fd2807SJeff Garzik #include <linux/delay.h>
24c6fd2807SJeff Garzik #include <linux/interrupt.h>
25c6fd2807SJeff Garzik #include <linux/dma-mapping.h>
26c6fd2807SJeff Garzik #include <linux/device.h>
27edc93052STejun Heo #include <linux/dmi.h>
285a0e3ad6STejun Heo #include <linux/gfp.h>
29c6fd2807SJeff Garzik #include <scsi/scsi_host.h>
30c6fd2807SJeff Garzik #include <scsi/scsi_cmnd.h>
31c6fd2807SJeff Garzik #include <linux/libata.h>
32aecec8b6SChristoph Hellwig #include <linux/ahci-remap.h>
33aecec8b6SChristoph Hellwig #include <linux/io-64-nonatomic-lo-hi.h>
34365cfa1eSAnton Vorontsov #include "ahci.h"
35c6fd2807SJeff Garzik 
36c6fd2807SJeff Garzik #define DRV_NAME	"ahci"
377d50b60bSTejun Heo #define DRV_VERSION	"3.0"
38c6fd2807SJeff Garzik 
39c6fd2807SJeff Garzik enum {
40318893e1SAlessandro Rubini 	AHCI_PCI_BAR_STA2X11	= 0,
41b7ae128dSRobert Richter 	AHCI_PCI_BAR_CAVIUM	= 0,
42e49bd683STiezhu Yang 	AHCI_PCI_BAR_LOONGSON	= 0,
437f9c9f8eSHugh Daschbach 	AHCI_PCI_BAR_ENMOTUS	= 2,
44b1314e3fSRadha Mohan Chintakuntla 	AHCI_PCI_BAR_CAVIUM_GEN5	= 4,
45318893e1SAlessandro Rubini 	AHCI_PCI_BAR_STANDARD	= 5,
46441577efSTejun Heo };
47c6fd2807SJeff Garzik 
48441577efSTejun Heo enum board_ids {
49441577efSTejun Heo 	/* board IDs by feature in alphabetical order */
50441577efSTejun Heo 	board_ahci,
51b0dd4d7aSLennert Buytenhek 	board_ahci_43bit_dma,
52441577efSTejun Heo 	board_ahci_ign_iferr,
53099849afSMario Limonciello 	board_ahci_low_power,
54a17ab7abSPaul Menzel 	board_ahci_no_debounce_delay,
5566a7cbc3STejun Heo 	board_ahci_nomsi,
5667809f85SLevente Kurusa 	board_ahci_noncq,
57441577efSTejun Heo 	board_ahci_nosntf,
585f173107STejun Heo 	board_ahci_yes_fbs,
59441577efSTejun Heo 
60441577efSTejun Heo 	/* board IDs for specific chipsets in alphabetical order */
617d523bdcSHanna Hawa 	board_ahci_al,
62dbfe8ef5SDan Williams 	board_ahci_avn,
63441577efSTejun Heo 	board_ahci_mcp65,
6483f2b963STejun Heo 	board_ahci_mcp77,
6583f2b963STejun Heo 	board_ahci_mcp89,
66441577efSTejun Heo 	board_ahci_mv,
67441577efSTejun Heo 	board_ahci_sb600,
68441577efSTejun Heo 	board_ahci_sb700,	/* for SB700 and SB800 */
69441577efSTejun Heo 	board_ahci_vt8251,
70441577efSTejun Heo 
71c312ef17SDan Williams 	/*
72c312ef17SDan Williams 	 * board IDs for Intel chipsets that support more than 6 ports
73c312ef17SDan Williams 	 * *and* end up needing the PCS quirk.
74c312ef17SDan Williams 	 */
75c312ef17SDan Williams 	board_ahci_pcs7,
76c312ef17SDan Williams 
77441577efSTejun Heo 	/* aliases */
78441577efSTejun Heo 	board_ahci_mcp_linux	= board_ahci_mcp65,
79441577efSTejun Heo 	board_ahci_mcp67	= board_ahci_mcp65,
80441577efSTejun Heo 	board_ahci_mcp73	= board_ahci_mcp65,
8183f2b963STejun Heo 	board_ahci_mcp79	= board_ahci_mcp77,
82c6fd2807SJeff Garzik };
83c6fd2807SJeff Garzik 
84c6fd2807SJeff Garzik static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
8502e53293SMika Westerberg static void ahci_remove_one(struct pci_dev *dev);
8610a663a1SPrabhakar Kushwaha static void ahci_shutdown_one(struct pci_dev *dev);
8737e14e4fSAdam Vodopjan static void ahci_intel_pcs_quirk(struct pci_dev *pdev, struct ahci_host_priv *hpriv);
88a1efdabaSTejun Heo static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
89a1efdabaSTejun Heo 				 unsigned long deadline);
90dbfe8ef5SDan Williams static int ahci_avn_hardreset(struct ata_link *link, unsigned int *class,
91dbfe8ef5SDan Williams 			      unsigned long deadline);
92cb85696dSJames Laird static void ahci_mcp89_apple_enable(struct pci_dev *pdev);
93cb85696dSJames Laird static bool is_mcp89_apple(struct pci_dev *pdev);
94a1efdabaSTejun Heo static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
95a1efdabaSTejun Heo 				unsigned long deadline);
9602e53293SMika Westerberg #ifdef CONFIG_PM
9702e53293SMika Westerberg static int ahci_pci_device_runtime_suspend(struct device *dev);
9802e53293SMika Westerberg static int ahci_pci_device_runtime_resume(struct device *dev);
99f1d848f9SMika Westerberg #ifdef CONFIG_PM_SLEEP
100f1d848f9SMika Westerberg static int ahci_pci_device_suspend(struct device *dev);
101f1d848f9SMika Westerberg static int ahci_pci_device_resume(struct device *dev);
102438ac6d5STejun Heo #endif
10302e53293SMika Westerberg #endif /* CONFIG_PM */
104c6fd2807SJeff Garzik 
10525df73d9SBart Van Assche static const struct scsi_host_template ahci_sht = {
106fad16e7aSTejun Heo 	AHCI_SHT("ahci"),
107fad16e7aSTejun Heo };
108fad16e7aSTejun Heo 
109029cfd6bSTejun Heo static struct ata_port_operations ahci_vt8251_ops = {
110029cfd6bSTejun Heo 	.inherits		= &ahci_ops,
111a1efdabaSTejun Heo 	.hardreset		= ahci_vt8251_hardreset,
112ad616ffbSTejun Heo };
113ad616ffbSTejun Heo 
114029cfd6bSTejun Heo static struct ata_port_operations ahci_p5wdh_ops = {
115029cfd6bSTejun Heo 	.inherits		= &ahci_ops,
116a1efdabaSTejun Heo 	.hardreset		= ahci_p5wdh_hardreset,
117edc93052STejun Heo };
118edc93052STejun Heo 
119dbfe8ef5SDan Williams static struct ata_port_operations ahci_avn_ops = {
120dbfe8ef5SDan Williams 	.inherits		= &ahci_ops,
121dbfe8ef5SDan Williams 	.hardreset		= ahci_avn_hardreset,
122dbfe8ef5SDan Williams };
123dbfe8ef5SDan Williams 
124c6fd2807SJeff Garzik static const struct ata_port_info ahci_port_info[] = {
125441577efSTejun Heo 	/* by features */
126facb8fa6SJeffrin Jose 	[board_ahci] = {
1271188c0d8STejun Heo 		.flags		= AHCI_FLAG_COMMON,
12814bdef98SErik Inge Bolsø 		.pio_mask	= ATA_PIO4,
129469248abSJeff Garzik 		.udma_mask	= ATA_UDMA6,
130c6fd2807SJeff Garzik 		.port_ops	= &ahci_ops,
131c6fd2807SJeff Garzik 	},
132b0dd4d7aSLennert Buytenhek 	[board_ahci_43bit_dma] = {
133b0dd4d7aSLennert Buytenhek 		AHCI_HFLAGS	(AHCI_HFLAG_43BIT_ONLY),
134b0dd4d7aSLennert Buytenhek 		.flags		= AHCI_FLAG_COMMON,
135b0dd4d7aSLennert Buytenhek 		.pio_mask	= ATA_PIO4,
136b0dd4d7aSLennert Buytenhek 		.udma_mask	= ATA_UDMA6,
137b0dd4d7aSLennert Buytenhek 		.port_ops	= &ahci_ops,
138b0dd4d7aSLennert Buytenhek 	},
139facb8fa6SJeffrin Jose 	[board_ahci_ign_iferr] = {
140417a1a6dSTejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_IGN_IRQ_IF_ERR),
141417a1a6dSTejun Heo 		.flags		= AHCI_FLAG_COMMON,
14214bdef98SErik Inge Bolsø 		.pio_mask	= ATA_PIO4,
143469248abSJeff Garzik 		.udma_mask	= ATA_UDMA6,
14441669553STejun Heo 		.port_ops	= &ahci_ops,
14541669553STejun Heo 	},
146099849afSMario Limonciello 	[board_ahci_low_power] = {
147e5c89479SMario Limonciello 		AHCI_HFLAGS	(AHCI_HFLAG_USE_LPM_POLICY),
148ebb82e3cSHans de Goede 		.flags		= AHCI_FLAG_COMMON,
149ebb82e3cSHans de Goede 		.pio_mask	= ATA_PIO4,
150ebb82e3cSHans de Goede 		.udma_mask	= ATA_UDMA6,
151ebb82e3cSHans de Goede 		.port_ops	= &ahci_ops,
152ebb82e3cSHans de Goede 	},
153a17ab7abSPaul Menzel 	[board_ahci_no_debounce_delay] = {
154a17ab7abSPaul Menzel 		.flags		= AHCI_FLAG_COMMON,
155a17ab7abSPaul Menzel 		.link_flags	= ATA_LFLAG_NO_DEBOUNCE_DELAY,
156a17ab7abSPaul Menzel 		.pio_mask	= ATA_PIO4,
157a17ab7abSPaul Menzel 		.udma_mask	= ATA_UDMA6,
158a17ab7abSPaul Menzel 		.port_ops	= &ahci_ops,
159a17ab7abSPaul Menzel 	},
16066a7cbc3STejun Heo 	[board_ahci_nomsi] = {
16166a7cbc3STejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_NO_MSI),
16266a7cbc3STejun Heo 		.flags		= AHCI_FLAG_COMMON,
16366a7cbc3STejun Heo 		.pio_mask	= ATA_PIO4,
16466a7cbc3STejun Heo 		.udma_mask	= ATA_UDMA6,
16566a7cbc3STejun Heo 		.port_ops	= &ahci_ops,
16666a7cbc3STejun Heo 	},
16767809f85SLevente Kurusa 	[board_ahci_noncq] = {
16867809f85SLevente Kurusa 		AHCI_HFLAGS	(AHCI_HFLAG_NO_NCQ),
16967809f85SLevente Kurusa 		.flags		= AHCI_FLAG_COMMON,
17067809f85SLevente Kurusa 		.pio_mask	= ATA_PIO4,
17167809f85SLevente Kurusa 		.udma_mask	= ATA_UDMA6,
17267809f85SLevente Kurusa 		.port_ops	= &ahci_ops,
17367809f85SLevente Kurusa 	},
174facb8fa6SJeffrin Jose 	[board_ahci_nosntf] = {
175441577efSTejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_NO_SNTF),
176441577efSTejun Heo 		.flags		= AHCI_FLAG_COMMON,
177441577efSTejun Heo 		.pio_mask	= ATA_PIO4,
178441577efSTejun Heo 		.udma_mask	= ATA_UDMA6,
179441577efSTejun Heo 		.port_ops	= &ahci_ops,
180441577efSTejun Heo 	},
181facb8fa6SJeffrin Jose 	[board_ahci_yes_fbs] = {
1825f173107STejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_YES_FBS),
1835f173107STejun Heo 		.flags		= AHCI_FLAG_COMMON,
1845f173107STejun Heo 		.pio_mask	= ATA_PIO4,
1855f173107STejun Heo 		.udma_mask	= ATA_UDMA6,
1865f173107STejun Heo 		.port_ops	= &ahci_ops,
1875f173107STejun Heo 	},
188441577efSTejun Heo 	/* by chipsets */
1897d523bdcSHanna Hawa 	[board_ahci_al] = {
1907d523bdcSHanna Hawa 		AHCI_HFLAGS	(AHCI_HFLAG_NO_PMP | AHCI_HFLAG_NO_MSI),
1917d523bdcSHanna Hawa 		.flags		= AHCI_FLAG_COMMON,
1927d523bdcSHanna Hawa 		.pio_mask	= ATA_PIO4,
1937d523bdcSHanna Hawa 		.udma_mask	= ATA_UDMA6,
1947d523bdcSHanna Hawa 		.port_ops	= &ahci_ops,
1957d523bdcSHanna Hawa 	},
196dbfe8ef5SDan Williams 	[board_ahci_avn] = {
197dbfe8ef5SDan Williams 		.flags		= AHCI_FLAG_COMMON,
198dbfe8ef5SDan Williams 		.pio_mask	= ATA_PIO4,
199dbfe8ef5SDan Williams 		.udma_mask	= ATA_UDMA6,
200dbfe8ef5SDan Williams 		.port_ops	= &ahci_avn_ops,
201dbfe8ef5SDan Williams 	},
202facb8fa6SJeffrin Jose 	[board_ahci_mcp65] = {
20383f2b963STejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_NO_FPDMA_AA | AHCI_HFLAG_NO_PMP |
20483f2b963STejun Heo 				 AHCI_HFLAG_YES_NCQ),
205ae01b249STejun Heo 		.flags		= AHCI_FLAG_COMMON | ATA_FLAG_NO_DIPM,
20683f2b963STejun Heo 		.pio_mask	= ATA_PIO4,
20783f2b963STejun Heo 		.udma_mask	= ATA_UDMA6,
20883f2b963STejun Heo 		.port_ops	= &ahci_ops,
20983f2b963STejun Heo 	},
210facb8fa6SJeffrin Jose 	[board_ahci_mcp77] = {
21183f2b963STejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_NO_FPDMA_AA | AHCI_HFLAG_NO_PMP),
21283f2b963STejun Heo 		.flags		= AHCI_FLAG_COMMON,
21383f2b963STejun Heo 		.pio_mask	= ATA_PIO4,
21483f2b963STejun Heo 		.udma_mask	= ATA_UDMA6,
21583f2b963STejun Heo 		.port_ops	= &ahci_ops,
21683f2b963STejun Heo 	},
217facb8fa6SJeffrin Jose 	[board_ahci_mcp89] = {
21883f2b963STejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_NO_FPDMA_AA),
219441577efSTejun Heo 		.flags		= AHCI_FLAG_COMMON,
220441577efSTejun Heo 		.pio_mask	= ATA_PIO4,
221441577efSTejun Heo 		.udma_mask	= ATA_UDMA6,
222441577efSTejun Heo 		.port_ops	= &ahci_ops,
223441577efSTejun Heo 	},
224facb8fa6SJeffrin Jose 	[board_ahci_mv] = {
225441577efSTejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_MSI |
226441577efSTejun Heo 				 AHCI_HFLAG_MV_PATA | AHCI_HFLAG_NO_PMP),
2279cbe056fSSergei Shtylyov 		.flags		= ATA_FLAG_SATA | ATA_FLAG_PIO_DMA,
228441577efSTejun Heo 		.pio_mask	= ATA_PIO4,
229441577efSTejun Heo 		.udma_mask	= ATA_UDMA6,
230441577efSTejun Heo 		.port_ops	= &ahci_ops,
231441577efSTejun Heo 	},
232facb8fa6SJeffrin Jose 	[board_ahci_sb600] = {
233417a1a6dSTejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_IGN_SERR_INTERNAL |
2342fcad9d2STejun Heo 				 AHCI_HFLAG_NO_MSI | AHCI_HFLAG_SECT255 |
2352fcad9d2STejun Heo 				 AHCI_HFLAG_32BIT_ONLY),
236417a1a6dSTejun Heo 		.flags		= AHCI_FLAG_COMMON,
23714bdef98SErik Inge Bolsø 		.pio_mask	= ATA_PIO4,
238469248abSJeff Garzik 		.udma_mask	= ATA_UDMA6,
239345347c5SYuan-Hsin Chen 		.port_ops	= &ahci_pmp_retry_srst_ops,
24055a61604SConke Hu 	},
241facb8fa6SJeffrin Jose 	[board_ahci_sb700] = {	/* for SB700 and SB800 */
242bd17243aSShane Huang 		AHCI_HFLAGS	(AHCI_HFLAG_IGN_SERR_INTERNAL),
243e39fc8c9SShane Huang 		.flags		= AHCI_FLAG_COMMON,
24414bdef98SErik Inge Bolsø 		.pio_mask	= ATA_PIO4,
245e39fc8c9SShane Huang 		.udma_mask	= ATA_UDMA6,
246345347c5SYuan-Hsin Chen 		.port_ops	= &ahci_pmp_retry_srst_ops,
247e39fc8c9SShane Huang 	},
248facb8fa6SJeffrin Jose 	[board_ahci_vt8251] = {
249441577efSTejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_PMP),
250e297d99eSTejun Heo 		.flags		= AHCI_FLAG_COMMON,
25114bdef98SErik Inge Bolsø 		.pio_mask	= ATA_PIO4,
252e297d99eSTejun Heo 		.udma_mask	= ATA_UDMA6,
253441577efSTejun Heo 		.port_ops	= &ahci_vt8251_ops,
2541b677afdSShaohua Li 	},
255c312ef17SDan Williams 	[board_ahci_pcs7] = {
256c312ef17SDan Williams 		.flags		= AHCI_FLAG_COMMON,
257c312ef17SDan Williams 		.pio_mask	= ATA_PIO4,
258c312ef17SDan Williams 		.udma_mask	= ATA_UDMA6,
259c312ef17SDan Williams 		.port_ops	= &ahci_ops,
260c312ef17SDan Williams 	},
261c6fd2807SJeff Garzik };
262c6fd2807SJeff Garzik 
263c6fd2807SJeff Garzik static const struct pci_device_id ahci_pci_tbl[] = {
264c6fd2807SJeff Garzik 	/* Intel */
2655e125d13SMika Westerberg 	{ PCI_VDEVICE(INTEL, 0x06d6), board_ahci }, /* Comet Lake PCH-H RAID */
26654bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2652), board_ahci }, /* ICH6 */
26754bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2653), board_ahci }, /* ICH6M */
26854bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c1), board_ahci }, /* ICH7 */
26954bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c5), board_ahci }, /* ICH7M */
27054bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c3), board_ahci }, /* ICH7R */
27182490c09STejun Heo 	{ PCI_VDEVICE(AL, 0x5288), board_ahci_ign_iferr }, /* ULi M5288 */
27254bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2681), board_ahci }, /* ESB2 */
27354bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2682), board_ahci }, /* ESB2 */
27454bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2683), board_ahci }, /* ESB2 */
27554bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c6), board_ahci }, /* ICH7-M DH */
2767a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2821), board_ahci }, /* ICH8 */
2770e96dc47SKrzysztof Kozlowski 	{ PCI_VDEVICE(INTEL, 0x2822), board_ahci_nosntf }, /* ICH8/Lewisburg RAID*/
2787a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2824), board_ahci }, /* ICH8 */
2797a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2829), board_ahci }, /* ICH8M */
2807a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x282a), board_ahci }, /* ICH8M */
2817a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2922), board_ahci }, /* ICH9 */
2827a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2923), board_ahci }, /* ICH9 */
2837a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2924), board_ahci }, /* ICH9 */
2847a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2925), board_ahci }, /* ICH9 */
2857a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2927), board_ahci }, /* ICH9 */
286099849afSMario Limonciello 	{ PCI_VDEVICE(INTEL, 0x2929), board_ahci_low_power }, /* ICH9M */
287099849afSMario Limonciello 	{ PCI_VDEVICE(INTEL, 0x292a), board_ahci_low_power }, /* ICH9M */
288099849afSMario Limonciello 	{ PCI_VDEVICE(INTEL, 0x292b), board_ahci_low_power }, /* ICH9M */
289099849afSMario Limonciello 	{ PCI_VDEVICE(INTEL, 0x292c), board_ahci_low_power }, /* ICH9M */
290099849afSMario Limonciello 	{ PCI_VDEVICE(INTEL, 0x292f), board_ahci_low_power }, /* ICH9M */
2917a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x294d), board_ahci }, /* ICH9 */
292099849afSMario Limonciello 	{ PCI_VDEVICE(INTEL, 0x294e), board_ahci_low_power }, /* ICH9M */
293d4155e6fSJason Gaston 	{ PCI_VDEVICE(INTEL, 0x502a), board_ahci }, /* Tolapai */
294d4155e6fSJason Gaston 	{ PCI_VDEVICE(INTEL, 0x502b), board_ahci }, /* Tolapai */
29516ad1ad9SJason Gaston 	{ PCI_VDEVICE(INTEL, 0x3a05), board_ahci }, /* ICH10 */
296b2dde6afSMark Goodwin 	{ PCI_VDEVICE(INTEL, 0x3a22), board_ahci }, /* ICH10 */
29716ad1ad9SJason Gaston 	{ PCI_VDEVICE(INTEL, 0x3a25), board_ahci }, /* ICH10 */
298c1f57d9bSDavid Milburn 	{ PCI_VDEVICE(INTEL, 0x3b22), board_ahci }, /* PCH AHCI */
299c1f57d9bSDavid Milburn 	{ PCI_VDEVICE(INTEL, 0x3b23), board_ahci }, /* PCH AHCI */
300adcb5308SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x3b24), board_ahci }, /* PCH RAID */
3018e48b6b3SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x3b25), board_ahci }, /* PCH RAID */
302099849afSMario Limonciello 	{ PCI_VDEVICE(INTEL, 0x3b29), board_ahci_low_power }, /* PCH M AHCI */
303adcb5308SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x3b2b), board_ahci }, /* PCH RAID */
304099849afSMario Limonciello 	{ PCI_VDEVICE(INTEL, 0x3b2c), board_ahci_low_power }, /* PCH M RAID */
305c1f57d9bSDavid Milburn 	{ PCI_VDEVICE(INTEL, 0x3b2f), board_ahci }, /* PCH AHCI */
306c312ef17SDan Williams 	{ PCI_VDEVICE(INTEL, 0x19b0), board_ahci_pcs7 }, /* DNV AHCI */
307c312ef17SDan Williams 	{ PCI_VDEVICE(INTEL, 0x19b1), board_ahci_pcs7 }, /* DNV AHCI */
308c312ef17SDan Williams 	{ PCI_VDEVICE(INTEL, 0x19b2), board_ahci_pcs7 }, /* DNV AHCI */
309c312ef17SDan Williams 	{ PCI_VDEVICE(INTEL, 0x19b3), board_ahci_pcs7 }, /* DNV AHCI */
310c312ef17SDan Williams 	{ PCI_VDEVICE(INTEL, 0x19b4), board_ahci_pcs7 }, /* DNV AHCI */
311c312ef17SDan Williams 	{ PCI_VDEVICE(INTEL, 0x19b5), board_ahci_pcs7 }, /* DNV AHCI */
312c312ef17SDan Williams 	{ PCI_VDEVICE(INTEL, 0x19b6), board_ahci_pcs7 }, /* DNV AHCI */
313c312ef17SDan Williams 	{ PCI_VDEVICE(INTEL, 0x19b7), board_ahci_pcs7 }, /* DNV AHCI */
314c312ef17SDan Williams 	{ PCI_VDEVICE(INTEL, 0x19bE), board_ahci_pcs7 }, /* DNV AHCI */
315c312ef17SDan Williams 	{ PCI_VDEVICE(INTEL, 0x19bF), board_ahci_pcs7 }, /* DNV AHCI */
316c312ef17SDan Williams 	{ PCI_VDEVICE(INTEL, 0x19c0), board_ahci_pcs7 }, /* DNV AHCI */
317c312ef17SDan Williams 	{ PCI_VDEVICE(INTEL, 0x19c1), board_ahci_pcs7 }, /* DNV AHCI */
318c312ef17SDan Williams 	{ PCI_VDEVICE(INTEL, 0x19c2), board_ahci_pcs7 }, /* DNV AHCI */
319c312ef17SDan Williams 	{ PCI_VDEVICE(INTEL, 0x19c3), board_ahci_pcs7 }, /* DNV AHCI */
320c312ef17SDan Williams 	{ PCI_VDEVICE(INTEL, 0x19c4), board_ahci_pcs7 }, /* DNV AHCI */
321c312ef17SDan Williams 	{ PCI_VDEVICE(INTEL, 0x19c5), board_ahci_pcs7 }, /* DNV AHCI */
322c312ef17SDan Williams 	{ PCI_VDEVICE(INTEL, 0x19c6), board_ahci_pcs7 }, /* DNV AHCI */
323c312ef17SDan Williams 	{ PCI_VDEVICE(INTEL, 0x19c7), board_ahci_pcs7 }, /* DNV AHCI */
324c312ef17SDan Williams 	{ PCI_VDEVICE(INTEL, 0x19cE), board_ahci_pcs7 }, /* DNV AHCI */
325c312ef17SDan Williams 	{ PCI_VDEVICE(INTEL, 0x19cF), board_ahci_pcs7 }, /* DNV AHCI */
3265623cab8SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1c02), board_ahci }, /* CPT AHCI */
327099849afSMario Limonciello 	{ PCI_VDEVICE(INTEL, 0x1c03), board_ahci_low_power }, /* CPT M AHCI */
3285623cab8SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1c04), board_ahci }, /* CPT RAID */
329099849afSMario Limonciello 	{ PCI_VDEVICE(INTEL, 0x1c05), board_ahci_low_power }, /* CPT M RAID */
3305623cab8SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1c06), board_ahci }, /* CPT RAID */
3315623cab8SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1c07), board_ahci }, /* CPT RAID */
332992b3fb9SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1d02), board_ahci }, /* PBG AHCI */
333992b3fb9SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1d04), board_ahci }, /* PBG RAID */
334992b3fb9SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1d06), board_ahci }, /* PBG RAID */
335a4a461a6SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x2323), board_ahci }, /* DH89xxCC AHCI */
336181e3ceaSSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1e02), board_ahci }, /* Panther Point AHCI */
337099849afSMario Limonciello 	{ PCI_VDEVICE(INTEL, 0x1e03), board_ahci_low_power }, /* Panther M AHCI */
338181e3ceaSSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1e04), board_ahci }, /* Panther Point RAID */
339181e3ceaSSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1e05), board_ahci }, /* Panther Point RAID */
340181e3ceaSSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1e06), board_ahci }, /* Panther Point RAID */
341099849afSMario Limonciello 	{ PCI_VDEVICE(INTEL, 0x1e07), board_ahci_low_power }, /* Panther M RAID */
3422cab7a4cSSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1e0e), board_ahci }, /* Panther Point RAID */
343ea4ace66SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x8c02), board_ahci }, /* Lynx Point AHCI */
344099849afSMario Limonciello 	{ PCI_VDEVICE(INTEL, 0x8c03), board_ahci_low_power }, /* Lynx M AHCI */
345ea4ace66SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x8c04), board_ahci }, /* Lynx Point RAID */
346099849afSMario Limonciello 	{ PCI_VDEVICE(INTEL, 0x8c05), board_ahci_low_power }, /* Lynx M RAID */
347ea4ace66SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x8c06), board_ahci }, /* Lynx Point RAID */
348099849afSMario Limonciello 	{ PCI_VDEVICE(INTEL, 0x8c07), board_ahci_low_power }, /* Lynx M RAID */
349ea4ace66SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x8c0e), board_ahci }, /* Lynx Point RAID */
350099849afSMario Limonciello 	{ PCI_VDEVICE(INTEL, 0x8c0f), board_ahci_low_power }, /* Lynx M RAID */
351099849afSMario Limonciello 	{ PCI_VDEVICE(INTEL, 0x9c02), board_ahci_low_power }, /* Lynx LP AHCI */
352099849afSMario Limonciello 	{ PCI_VDEVICE(INTEL, 0x9c03), board_ahci_low_power }, /* Lynx LP AHCI */
353099849afSMario Limonciello 	{ PCI_VDEVICE(INTEL, 0x9c04), board_ahci_low_power }, /* Lynx LP RAID */
354099849afSMario Limonciello 	{ PCI_VDEVICE(INTEL, 0x9c05), board_ahci_low_power }, /* Lynx LP RAID */
355099849afSMario Limonciello 	{ PCI_VDEVICE(INTEL, 0x9c06), board_ahci_low_power }, /* Lynx LP RAID */
356099849afSMario Limonciello 	{ PCI_VDEVICE(INTEL, 0x9c07), board_ahci_low_power }, /* Lynx LP RAID */
357099849afSMario Limonciello 	{ PCI_VDEVICE(INTEL, 0x9c0e), board_ahci_low_power }, /* Lynx LP RAID */
358099849afSMario Limonciello 	{ PCI_VDEVICE(INTEL, 0x9c0f), board_ahci_low_power }, /* Lynx LP RAID */
359099849afSMario Limonciello 	{ PCI_VDEVICE(INTEL, 0x9dd3), board_ahci_low_power }, /* Cannon Lake PCH-LP AHCI */
36029e674ddSSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1f22), board_ahci }, /* Avoton AHCI */
36129e674ddSSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1f23), board_ahci }, /* Avoton AHCI */
36229e674ddSSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1f24), board_ahci }, /* Avoton RAID */
36329e674ddSSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1f25), board_ahci }, /* Avoton RAID */
36429e674ddSSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1f26), board_ahci }, /* Avoton RAID */
36529e674ddSSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1f27), board_ahci }, /* Avoton RAID */
36629e674ddSSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1f2e), board_ahci }, /* Avoton RAID */
36729e674ddSSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1f2f), board_ahci }, /* Avoton RAID */
368dbfe8ef5SDan Williams 	{ PCI_VDEVICE(INTEL, 0x1f32), board_ahci_avn }, /* Avoton AHCI */
369dbfe8ef5SDan Williams 	{ PCI_VDEVICE(INTEL, 0x1f33), board_ahci_avn }, /* Avoton AHCI */
370dbfe8ef5SDan Williams 	{ PCI_VDEVICE(INTEL, 0x1f34), board_ahci_avn }, /* Avoton RAID */
371dbfe8ef5SDan Williams 	{ PCI_VDEVICE(INTEL, 0x1f35), board_ahci_avn }, /* Avoton RAID */
372dbfe8ef5SDan Williams 	{ PCI_VDEVICE(INTEL, 0x1f36), board_ahci_avn }, /* Avoton RAID */
373dbfe8ef5SDan Williams 	{ PCI_VDEVICE(INTEL, 0x1f37), board_ahci_avn }, /* Avoton RAID */
374dbfe8ef5SDan Williams 	{ PCI_VDEVICE(INTEL, 0x1f3e), board_ahci_avn }, /* Avoton RAID */
375dbfe8ef5SDan Williams 	{ PCI_VDEVICE(INTEL, 0x1f3f), board_ahci_avn }, /* Avoton RAID */
3760e96dc47SKrzysztof Kozlowski 	{ PCI_VDEVICE(INTEL, 0x2823), board_ahci }, /* Wellsburg/Lewisburg AHCI*/
3775716fb0dSDan Williams 	{ PCI_VDEVICE(INTEL, 0x2826), board_ahci }, /* *burg SATA0 'RAID' */
3785716fb0dSDan Williams 	{ PCI_VDEVICE(INTEL, 0x2827), board_ahci }, /* *burg SATA1 'RAID' */
3795716fb0dSDan Williams 	{ PCI_VDEVICE(INTEL, 0x282f), board_ahci }, /* *burg SATA2 'RAID' */
3808e85f605SMika Westerberg 	{ PCI_VDEVICE(INTEL, 0x43d4), board_ahci }, /* Rocket Lake PCH-H RAID */
3818e85f605SMika Westerberg 	{ PCI_VDEVICE(INTEL, 0x43d5), board_ahci }, /* Rocket Lake PCH-H RAID */
3828e85f605SMika Westerberg 	{ PCI_VDEVICE(INTEL, 0x43d6), board_ahci }, /* Rocket Lake PCH-H RAID */
3838e85f605SMika Westerberg 	{ PCI_VDEVICE(INTEL, 0x43d7), board_ahci }, /* Rocket Lake PCH-H RAID */
384151743fdSJames Ralston 	{ PCI_VDEVICE(INTEL, 0x8d02), board_ahci }, /* Wellsburg AHCI */
385151743fdSJames Ralston 	{ PCI_VDEVICE(INTEL, 0x8d04), board_ahci }, /* Wellsburg RAID */
386151743fdSJames Ralston 	{ PCI_VDEVICE(INTEL, 0x8d06), board_ahci }, /* Wellsburg RAID */
387151743fdSJames Ralston 	{ PCI_VDEVICE(INTEL, 0x8d0e), board_ahci }, /* Wellsburg RAID */
388151743fdSJames Ralston 	{ PCI_VDEVICE(INTEL, 0x8d62), board_ahci }, /* Wellsburg AHCI */
389151743fdSJames Ralston 	{ PCI_VDEVICE(INTEL, 0x8d64), board_ahci }, /* Wellsburg RAID */
390151743fdSJames Ralston 	{ PCI_VDEVICE(INTEL, 0x8d66), board_ahci }, /* Wellsburg RAID */
391151743fdSJames Ralston 	{ PCI_VDEVICE(INTEL, 0x8d6e), board_ahci }, /* Wellsburg RAID */
3921cfc7df3SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x23a3), board_ahci }, /* Coleto Creek AHCI */
393099849afSMario Limonciello 	{ PCI_VDEVICE(INTEL, 0x9c83), board_ahci_low_power }, /* Wildcat LP AHCI */
394099849afSMario Limonciello 	{ PCI_VDEVICE(INTEL, 0x9c85), board_ahci_low_power }, /* Wildcat LP RAID */
395099849afSMario Limonciello 	{ PCI_VDEVICE(INTEL, 0x9c87), board_ahci_low_power }, /* Wildcat LP RAID */
396099849afSMario Limonciello 	{ PCI_VDEVICE(INTEL, 0x9c8f), board_ahci_low_power }, /* Wildcat LP RAID */
3971b071a09SJames Ralston 	{ PCI_VDEVICE(INTEL, 0x8c82), board_ahci }, /* 9 Series AHCI */
398099849afSMario Limonciello 	{ PCI_VDEVICE(INTEL, 0x8c83), board_ahci_low_power }, /* 9 Series M AHCI */
3991b071a09SJames Ralston 	{ PCI_VDEVICE(INTEL, 0x8c84), board_ahci }, /* 9 Series RAID */
400099849afSMario Limonciello 	{ PCI_VDEVICE(INTEL, 0x8c85), board_ahci_low_power }, /* 9 Series M RAID */
4011b071a09SJames Ralston 	{ PCI_VDEVICE(INTEL, 0x8c86), board_ahci }, /* 9 Series RAID */
402099849afSMario Limonciello 	{ PCI_VDEVICE(INTEL, 0x8c87), board_ahci_low_power }, /* 9 Series M RAID */
4031b071a09SJames Ralston 	{ PCI_VDEVICE(INTEL, 0x8c8e), board_ahci }, /* 9 Series RAID */
404099849afSMario Limonciello 	{ PCI_VDEVICE(INTEL, 0x8c8f), board_ahci_low_power }, /* 9 Series M RAID */
405099849afSMario Limonciello 	{ PCI_VDEVICE(INTEL, 0x9d03), board_ahci_low_power }, /* Sunrise LP AHCI */
406099849afSMario Limonciello 	{ PCI_VDEVICE(INTEL, 0x9d05), board_ahci_low_power }, /* Sunrise LP RAID */
407099849afSMario Limonciello 	{ PCI_VDEVICE(INTEL, 0x9d07), board_ahci_low_power }, /* Sunrise LP RAID */
408c5967b79SCharles_Rose@Dell.com 	{ PCI_VDEVICE(INTEL, 0xa102), board_ahci }, /* Sunrise Point-H AHCI */
409099849afSMario Limonciello 	{ PCI_VDEVICE(INTEL, 0xa103), board_ahci_low_power }, /* Sunrise M AHCI */
410690000b9SJames Ralston 	{ PCI_VDEVICE(INTEL, 0xa105), board_ahci }, /* Sunrise Point-H RAID */
411c5967b79SCharles_Rose@Dell.com 	{ PCI_VDEVICE(INTEL, 0xa106), board_ahci }, /* Sunrise Point-H RAID */
412099849afSMario Limonciello 	{ PCI_VDEVICE(INTEL, 0xa107), board_ahci_low_power }, /* Sunrise M RAID */
413690000b9SJames Ralston 	{ PCI_VDEVICE(INTEL, 0xa10f), board_ahci }, /* Sunrise Point-H RAID */
4144d92f009SAlexandra Yates 	{ PCI_VDEVICE(INTEL, 0xa182), board_ahci }, /* Lewisburg AHCI*/
4154d92f009SAlexandra Yates 	{ PCI_VDEVICE(INTEL, 0xa186), board_ahci }, /* Lewisburg RAID*/
416f5bdd66cSAlexandra Yates 	{ PCI_VDEVICE(INTEL, 0xa1d2), board_ahci }, /* Lewisburg RAID*/
417f5bdd66cSAlexandra Yates 	{ PCI_VDEVICE(INTEL, 0xa1d6), board_ahci }, /* Lewisburg RAID*/
4184d92f009SAlexandra Yates 	{ PCI_VDEVICE(INTEL, 0xa202), board_ahci }, /* Lewisburg AHCI*/
4194d92f009SAlexandra Yates 	{ PCI_VDEVICE(INTEL, 0xa206), board_ahci }, /* Lewisburg RAID*/
420f5bdd66cSAlexandra Yates 	{ PCI_VDEVICE(INTEL, 0xa252), board_ahci }, /* Lewisburg RAID*/
421f5bdd66cSAlexandra Yates 	{ PCI_VDEVICE(INTEL, 0xa256), board_ahci }, /* Lewisburg RAID*/
422f919dde0SMika Westerberg 	{ PCI_VDEVICE(INTEL, 0xa356), board_ahci }, /* Cannon Lake PCH-H RAID */
42332d25454SKai-Heng Feng 	{ PCI_VDEVICE(INTEL, 0x06d7), board_ahci }, /* Comet Lake-H RAID */
42458c42b0bSMika Westerberg 	{ PCI_VDEVICE(INTEL, 0xa386), board_ahci }, /* Comet Lake PCH-V RAID */
425099849afSMario Limonciello 	{ PCI_VDEVICE(INTEL, 0x0f22), board_ahci_low_power }, /* Bay Trail AHCI */
426099849afSMario Limonciello 	{ PCI_VDEVICE(INTEL, 0x0f23), board_ahci_low_power }, /* Bay Trail AHCI */
427099849afSMario Limonciello 	{ PCI_VDEVICE(INTEL, 0x22a3), board_ahci_low_power }, /* Cherry Tr. AHCI */
428099849afSMario Limonciello 	{ PCI_VDEVICE(INTEL, 0x5ae3), board_ahci_low_power }, /* ApolloLake AHCI */
429099849afSMario Limonciello 	{ PCI_VDEVICE(INTEL, 0x34d3), board_ahci_low_power }, /* Ice Lake LP AHCI */
430099849afSMario Limonciello 	{ PCI_VDEVICE(INTEL, 0x02d3), board_ahci_low_power }, /* Comet Lake PCH-U AHCI */
431099849afSMario Limonciello 	{ PCI_VDEVICE(INTEL, 0x02d7), board_ahci_low_power }, /* Comet Lake PCH RAID */
4322a2df98eSWerner Fischer 	/* Elkhart Lake IDs 0x4b60 & 0x4b62 https://sata-io.org/product/8803 not tested yet */
4332a2df98eSWerner Fischer 	{ PCI_VDEVICE(INTEL, 0x4b63), board_ahci_low_power }, /* Elkhart Lake AHCI */
434c6fd2807SJeff Garzik 
435e34bb370STejun Heo 	/* JMicron 360/1/3/5/6, match class to avoid IDE function */
436e34bb370STejun Heo 	{ PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
437e34bb370STejun Heo 	  PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci_ign_iferr },
4381fefb8fdSBen Hutchings 	/* JMicron 362B and 362C have an AHCI function with IDE class code */
4391fefb8fdSBen Hutchings 	{ PCI_VDEVICE(JMICRON, 0x2362), board_ahci_ign_iferr },
4401fefb8fdSBen Hutchings 	{ PCI_VDEVICE(JMICRON, 0x236f), board_ahci_ign_iferr },
44191f15fb3SZhang Rui 	/* May need to update quirk_jmicron_async_suspend() for additions */
442c6fd2807SJeff Garzik 
443c6fd2807SJeff Garzik 	/* ATI */
444c65ec1c2SConke Hu 	{ PCI_VDEVICE(ATI, 0x4380), board_ahci_sb600 }, /* ATI SB600 */
445e39fc8c9SShane Huang 	{ PCI_VDEVICE(ATI, 0x4390), board_ahci_sb700 }, /* ATI SB700/800 */
446e39fc8c9SShane Huang 	{ PCI_VDEVICE(ATI, 0x4391), board_ahci_sb700 }, /* ATI SB700/800 */
447e39fc8c9SShane Huang 	{ PCI_VDEVICE(ATI, 0x4392), board_ahci_sb700 }, /* ATI SB700/800 */
448e39fc8c9SShane Huang 	{ PCI_VDEVICE(ATI, 0x4393), board_ahci_sb700 }, /* ATI SB700/800 */
449e39fc8c9SShane Huang 	{ PCI_VDEVICE(ATI, 0x4394), board_ahci_sb700 }, /* ATI SB700/800 */
450e39fc8c9SShane Huang 	{ PCI_VDEVICE(ATI, 0x4395), board_ahci_sb700 }, /* ATI SB700/800 */
451c6fd2807SJeff Garzik 
4527d523bdcSHanna Hawa 	/* Amazon's Annapurna Labs support */
4537d523bdcSHanna Hawa 	{ PCI_DEVICE(PCI_VENDOR_ID_AMAZON_ANNAPURNA_LABS, 0x0031),
4547d523bdcSHanna Hawa 		.class = PCI_CLASS_STORAGE_SATA_AHCI,
4557d523bdcSHanna Hawa 		.class_mask = 0xffffff,
4567d523bdcSHanna Hawa 		board_ahci_al },
457e2dd90b1SShane Huang 	/* AMD */
4585deab536SShane Huang 	{ PCI_VDEVICE(AMD, 0x7800), board_ahci }, /* AMD Hudson-2 */
459a17ab7abSPaul Menzel 	{ PCI_VDEVICE(AMD, 0x7801), board_ahci_no_debounce_delay }, /* AMD Hudson-2 (AHCI mode) */
460fafe5c3dSShane Huang 	{ PCI_VDEVICE(AMD, 0x7900), board_ahci }, /* AMD CZ */
461099849afSMario Limonciello 	{ PCI_VDEVICE(AMD, 0x7901), board_ahci_low_power }, /* AMD Green Sardine */
462e2dd90b1SShane Huang 	/* AMD is using RAID class only for ahci controllers */
463e2dd90b1SShane Huang 	{ PCI_VENDOR_ID_AMD, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
464e2dd90b1SShane Huang 	  PCI_CLASS_STORAGE_RAID << 8, 0xffffff, board_ahci },
465e2dd90b1SShane Huang 
4669c54cd10SCharles Rose 	/* Dell S140/S150 */
4679c54cd10SCharles Rose 	{ PCI_VENDOR_ID_INTEL, PCI_ANY_ID, PCI_SUBVENDOR_ID_DELL, PCI_ANY_ID,
4689c54cd10SCharles Rose 	  PCI_CLASS_STORAGE_RAID << 8, 0xffffff, board_ahci },
4699c54cd10SCharles Rose 
470c6fd2807SJeff Garzik 	/* VIA */
47154bb3a94SJeff Garzik 	{ PCI_VDEVICE(VIA, 0x3349), board_ahci_vt8251 }, /* VIA VT8251 */
472bf335542STejun Heo 	{ PCI_VDEVICE(VIA, 0x6287), board_ahci_vt8251 }, /* VIA VT8251 */
473c6fd2807SJeff Garzik 
474c6fd2807SJeff Garzik 	/* NVIDIA */
475e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x044c), board_ahci_mcp65 },	/* MCP65 */
476e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x044d), board_ahci_mcp65 },	/* MCP65 */
477e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x044e), board_ahci_mcp65 },	/* MCP65 */
478e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x044f), board_ahci_mcp65 },	/* MCP65 */
479e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x045c), board_ahci_mcp65 },	/* MCP65 */
480e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x045d), board_ahci_mcp65 },	/* MCP65 */
481e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x045e), board_ahci_mcp65 },	/* MCP65 */
482e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x045f), board_ahci_mcp65 },	/* MCP65 */
483441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0550), board_ahci_mcp67 },	/* MCP67 */
484441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0551), board_ahci_mcp67 },	/* MCP67 */
485441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0552), board_ahci_mcp67 },	/* MCP67 */
486441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0553), board_ahci_mcp67 },	/* MCP67 */
487441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0554), board_ahci_mcp67 },	/* MCP67 */
488441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0555), board_ahci_mcp67 },	/* MCP67 */
489441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0556), board_ahci_mcp67 },	/* MCP67 */
490441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0557), board_ahci_mcp67 },	/* MCP67 */
491441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0558), board_ahci_mcp67 },	/* MCP67 */
492441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0559), board_ahci_mcp67 },	/* MCP67 */
493441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x055a), board_ahci_mcp67 },	/* MCP67 */
494441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x055b), board_ahci_mcp67 },	/* MCP67 */
495441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0580), board_ahci_mcp_linux },	/* Linux ID */
496441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0581), board_ahci_mcp_linux },	/* Linux ID */
497441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0582), board_ahci_mcp_linux },	/* Linux ID */
498441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0583), board_ahci_mcp_linux },	/* Linux ID */
499441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0584), board_ahci_mcp_linux },	/* Linux ID */
500441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0585), board_ahci_mcp_linux },	/* Linux ID */
501441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0586), board_ahci_mcp_linux },	/* Linux ID */
502441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0587), board_ahci_mcp_linux },	/* Linux ID */
503441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0588), board_ahci_mcp_linux },	/* Linux ID */
504441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0589), board_ahci_mcp_linux },	/* Linux ID */
505441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x058a), board_ahci_mcp_linux },	/* Linux ID */
506441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x058b), board_ahci_mcp_linux },	/* Linux ID */
507441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x058c), board_ahci_mcp_linux },	/* Linux ID */
508441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x058d), board_ahci_mcp_linux },	/* Linux ID */
509441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x058e), board_ahci_mcp_linux },	/* Linux ID */
510441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x058f), board_ahci_mcp_linux },	/* Linux ID */
511441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f0), board_ahci_mcp73 },	/* MCP73 */
512441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f1), board_ahci_mcp73 },	/* MCP73 */
513441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f2), board_ahci_mcp73 },	/* MCP73 */
514441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f3), board_ahci_mcp73 },	/* MCP73 */
515441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f4), board_ahci_mcp73 },	/* MCP73 */
516441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f5), board_ahci_mcp73 },	/* MCP73 */
517441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f6), board_ahci_mcp73 },	/* MCP73 */
518441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f7), board_ahci_mcp73 },	/* MCP73 */
519441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f8), board_ahci_mcp73 },	/* MCP73 */
520441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f9), board_ahci_mcp73 },	/* MCP73 */
521441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07fa), board_ahci_mcp73 },	/* MCP73 */
522441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07fb), board_ahci_mcp73 },	/* MCP73 */
523441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ad0), board_ahci_mcp77 },	/* MCP77 */
524441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ad1), board_ahci_mcp77 },	/* MCP77 */
525441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ad2), board_ahci_mcp77 },	/* MCP77 */
526441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ad3), board_ahci_mcp77 },	/* MCP77 */
527441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ad4), board_ahci_mcp77 },	/* MCP77 */
528441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ad5), board_ahci_mcp77 },	/* MCP77 */
529441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ad6), board_ahci_mcp77 },	/* MCP77 */
530441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ad7), board_ahci_mcp77 },	/* MCP77 */
531441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ad8), board_ahci_mcp77 },	/* MCP77 */
532441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ad9), board_ahci_mcp77 },	/* MCP77 */
533441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ada), board_ahci_mcp77 },	/* MCP77 */
534441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0adb), board_ahci_mcp77 },	/* MCP77 */
535441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ab4), board_ahci_mcp79 },	/* MCP79 */
536441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ab5), board_ahci_mcp79 },	/* MCP79 */
537441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ab6), board_ahci_mcp79 },	/* MCP79 */
538441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ab7), board_ahci_mcp79 },	/* MCP79 */
539441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ab8), board_ahci_mcp79 },	/* MCP79 */
540441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ab9), board_ahci_mcp79 },	/* MCP79 */
541441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0aba), board_ahci_mcp79 },	/* MCP79 */
542441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0abb), board_ahci_mcp79 },	/* MCP79 */
543441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0abc), board_ahci_mcp79 },	/* MCP79 */
544441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0abd), board_ahci_mcp79 },	/* MCP79 */
545441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0abe), board_ahci_mcp79 },	/* MCP79 */
546441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0abf), board_ahci_mcp79 },	/* MCP79 */
547441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0d84), board_ahci_mcp89 },	/* MCP89 */
548441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0d85), board_ahci_mcp89 },	/* MCP89 */
549441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0d86), board_ahci_mcp89 },	/* MCP89 */
550441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0d87), board_ahci_mcp89 },	/* MCP89 */
551441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0d88), board_ahci_mcp89 },	/* MCP89 */
552441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0d89), board_ahci_mcp89 },	/* MCP89 */
553441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0d8a), board_ahci_mcp89 },	/* MCP89 */
554441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0d8b), board_ahci_mcp89 },	/* MCP89 */
555441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0d8c), board_ahci_mcp89 },	/* MCP89 */
556441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0d8d), board_ahci_mcp89 },	/* MCP89 */
557441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0d8e), board_ahci_mcp89 },	/* MCP89 */
558441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0d8f), board_ahci_mcp89 },	/* MCP89 */
559c6fd2807SJeff Garzik 
560c6fd2807SJeff Garzik 	/* SiS */
56120e2de4aSTejun Heo 	{ PCI_VDEVICE(SI, 0x1184), board_ahci },		/* SiS 966 */
56220e2de4aSTejun Heo 	{ PCI_VDEVICE(SI, 0x1185), board_ahci },		/* SiS 968 */
56320e2de4aSTejun Heo 	{ PCI_VDEVICE(SI, 0x0186), board_ahci },		/* SiS 968 */
564c6fd2807SJeff Garzik 
565318893e1SAlessandro Rubini 	/* ST Microelectronics */
566318893e1SAlessandro Rubini 	{ PCI_VDEVICE(STMICRO, 0xCC06), board_ahci },		/* ST ConneXt */
567318893e1SAlessandro Rubini 
568cd70c266SJeff Garzik 	/* Marvell */
569cd70c266SJeff Garzik 	{ PCI_VDEVICE(MARVELL, 0x6145), board_ahci_mv },	/* 6145 */
570c40e7cb8SJose Alberto Reguero 	{ PCI_VDEVICE(MARVELL, 0x6121), board_ahci_mv },	/* 6121 */
57169fd3157SMyron Stowe 	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9123),
57210aca06cSAnssi Hannula 	  .class = PCI_CLASS_STORAGE_SATA_AHCI,
57310aca06cSAnssi Hannula 	  .class_mask = 0xffffff,
5745f173107STejun Heo 	  .driver_data = board_ahci_yes_fbs },			/* 88se9128 */
57569fd3157SMyron Stowe 	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9125),
576467b41c6SPer Jessen 	  .driver_data = board_ahci_yes_fbs },			/* 88se9125 */
577e098f5cbSSimon Guinot 	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_MARVELL_EXT, 0x9178,
578e098f5cbSSimon Guinot 			 PCI_VENDOR_ID_MARVELL_EXT, 0x9170),
579e098f5cbSSimon Guinot 	  .driver_data = board_ahci_yes_fbs },			/* 88se9170 */
58069fd3157SMyron Stowe 	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x917a),
581642d8925SMatt Johnson 	  .driver_data = board_ahci_yes_fbs },			/* 88se9172 */
582fcce9a35SGeorge Spelvin 	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9172),
583c5edfff9SMurali Karicheri 	  .driver_data = board_ahci_yes_fbs },			/* 88se9182 */
584c5edfff9SMurali Karicheri 	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9182),
585fcce9a35SGeorge Spelvin 	  .driver_data = board_ahci_yes_fbs },			/* 88se9172 */
58669fd3157SMyron Stowe 	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9192),
58717c60c6bSAlan Cox 	  .driver_data = board_ahci_yes_fbs },			/* 88se9172 on some Gigabyte */
588754a292fSAndreas Schrägle 	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x91a0),
589754a292fSAndreas Schrägle 	  .driver_data = board_ahci_yes_fbs },
590a40cf3f3SJohannes Thumshirn 	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x91a2), 	/* 88se91a2 */
591a40cf3f3SJohannes Thumshirn 	  .driver_data = board_ahci_yes_fbs },
59269fd3157SMyron Stowe 	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x91a3),
59350be5e36STejun Heo 	  .driver_data = board_ahci_yes_fbs },
5946d5278a6SSamir Benmendil 	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9230),
5956d5278a6SSamir Benmendil 	  .driver_data = board_ahci_yes_fbs },
596f4a8d4f2SPaul Menzel 	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9235),
597f4a8d4f2SPaul Menzel 	  .driver_data = board_ahci_no_debounce_delay },
59828b2182dSHans de Goede 	{ PCI_DEVICE(PCI_VENDOR_ID_TTI, 0x0642), /* highpoint rocketraid 642L */
59928b2182dSHans de Goede 	  .driver_data = board_ahci_yes_fbs },
60028b2182dSHans de Goede 	{ PCI_DEVICE(PCI_VENDOR_ID_TTI, 0x0645), /* highpoint rocketraid 644L */
601d2518365SJérôme Carretero 	  .driver_data = board_ahci_yes_fbs },
602cd70c266SJeff Garzik 
603c77a036bSMark Nelson 	/* Promise */
604c77a036bSMark Nelson 	{ PCI_VDEVICE(PROMISE, 0x3f20), board_ahci },	/* PDC42819 */
605b32bfc06SRomain Degez 	{ PCI_VDEVICE(PROMISE, 0x3781), board_ahci },   /* FastTrak TX8660 ahci-mode */
606c77a036bSMark Nelson 
607b0dd4d7aSLennert Buytenhek 	/* ASMedia */
6087b4f6ecaSAlan Cox 	{ PCI_VDEVICE(ASMEDIA, 0x0601), board_ahci },	/* ASM1060 */
6097b4f6ecaSAlan Cox 	{ PCI_VDEVICE(ASMEDIA, 0x0602), board_ahci },	/* ASM1060 */
610b0dd4d7aSLennert Buytenhek 	{ PCI_VDEVICE(ASMEDIA, 0x0611), board_ahci_43bit_dma },	/* ASM1061 */
611b0dd4d7aSLennert Buytenhek 	{ PCI_VDEVICE(ASMEDIA, 0x0612), board_ahci_43bit_dma },	/* ASM1061/1062 */
6120ce968f3SShawn Lin 	{ PCI_VDEVICE(ASMEDIA, 0x0621), board_ahci },   /* ASM1061R */
6130ce968f3SShawn Lin 	{ PCI_VDEVICE(ASMEDIA, 0x0622), board_ahci },   /* ASM1062R */
6148c0ff6afSIstván Pongrácz 	{ PCI_VDEVICE(ASMEDIA, 0x0624), board_ahci },   /* ASM1062+JMB575 */
615*1f9b7a5dSSzuying Chen 	{ PCI_VDEVICE(ASMEDIA, 0x1062), board_ahci },	/* ASM1062A */
616*1f9b7a5dSSzuying Chen 	{ PCI_VDEVICE(ASMEDIA, 0x1064), board_ahci },	/* ASM1064 */
617*1f9b7a5dSSzuying Chen 	{ PCI_VDEVICE(ASMEDIA, 0x1164), board_ahci },   /* ASM1164 */
618*1f9b7a5dSSzuying Chen 	{ PCI_VDEVICE(ASMEDIA, 0x1165), board_ahci },   /* ASM1165 */
619*1f9b7a5dSSzuying Chen 	{ PCI_VDEVICE(ASMEDIA, 0x1166), board_ahci },   /* ASM1166 */
620c9703765SKeng-Yu Lin 
62167809f85SLevente Kurusa 	/*
62266a7cbc3STejun Heo 	 * Samsung SSDs found on some macbooks.  NCQ times out if MSI is
62366a7cbc3STejun Heo 	 * enabled.  https://bugzilla.kernel.org/show_bug.cgi?id=60731
62467809f85SLevente Kurusa 	 */
62566a7cbc3STejun Heo 	{ PCI_VDEVICE(SAMSUNG, 0x1600), board_ahci_nomsi },
6262b21ef0aSTejun Heo 	{ PCI_VDEVICE(SAMSUNG, 0xa800), board_ahci_nomsi },
62767809f85SLevente Kurusa 
6287f9c9f8eSHugh Daschbach 	/* Enmotus */
6297f9c9f8eSHugh Daschbach 	{ PCI_DEVICE(0x1c44, 0x8000), board_ahci },
6307f9c9f8eSHugh Daschbach 
631e49bd683STiezhu Yang 	/* Loongson */
632e49bd683STiezhu Yang 	{ PCI_VDEVICE(LOONGSON, 0x7a08), board_ahci },
633e49bd683STiezhu Yang 
634415ae2b5SJeff Garzik 	/* Generic, PCI class code for AHCI */
635415ae2b5SJeff Garzik 	{ PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
636c9f89475SConke Hu 	  PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci },
637415ae2b5SJeff Garzik 
638c6fd2807SJeff Garzik 	{ }	/* terminate list */
639c6fd2807SJeff Garzik };
640c6fd2807SJeff Garzik 
641f1d848f9SMika Westerberg static const struct dev_pm_ops ahci_pci_pm_ops = {
642f1d848f9SMika Westerberg 	SET_SYSTEM_SLEEP_PM_OPS(ahci_pci_device_suspend, ahci_pci_device_resume)
64302e53293SMika Westerberg 	SET_RUNTIME_PM_OPS(ahci_pci_device_runtime_suspend,
64402e53293SMika Westerberg 			   ahci_pci_device_runtime_resume, NULL)
645f1d848f9SMika Westerberg };
646c6fd2807SJeff Garzik 
647c6fd2807SJeff Garzik static struct pci_driver ahci_pci_driver = {
648c6fd2807SJeff Garzik 	.name			= DRV_NAME,
649c6fd2807SJeff Garzik 	.id_table		= ahci_pci_tbl,
650c6fd2807SJeff Garzik 	.probe			= ahci_init_one,
65102e53293SMika Westerberg 	.remove			= ahci_remove_one,
65210a663a1SPrabhakar Kushwaha 	.shutdown		= ahci_shutdown_one,
653f1d848f9SMika Westerberg 	.driver = {
654f1d848f9SMika Westerberg 		.pm		= &ahci_pci_pm_ops,
655f1d848f9SMika Westerberg 	},
656c6fd2807SJeff Garzik };
657c6fd2807SJeff Garzik 
6585219d653SJavier Martinez Canillas #if IS_ENABLED(CONFIG_PATA_MARVELL)
6595b66c829SAlan Cox static int marvell_enable;
6605b66c829SAlan Cox #else
6615b66c829SAlan Cox static int marvell_enable = 1;
6625b66c829SAlan Cox #endif
6635b66c829SAlan Cox module_param(marvell_enable, int, 0644);
6645b66c829SAlan Cox MODULE_PARM_DESC(marvell_enable, "Marvell SATA via AHCI (1 = enabled)");
6655b66c829SAlan Cox 
666b1a9585cSSrinivas Pandruvada static int mobile_lpm_policy = -1;
667ebb82e3cSHans de Goede module_param(mobile_lpm_policy, int, 0644);
668ebb82e3cSHans de Goede MODULE_PARM_DESC(mobile_lpm_policy, "Default LPM policy for mobile chipsets");
6695b66c829SAlan Cox 
670394d6e53SAnton Vorontsov static void ahci_pci_save_initial_config(struct pci_dev *pdev,
671394d6e53SAnton Vorontsov 					 struct ahci_host_priv *hpriv)
672394d6e53SAnton Vorontsov {
67389f67051SConrad Kostecki 	if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA && pdev->device == 0x1166) {
67489f67051SConrad Kostecki 		dev_info(&pdev->dev, "ASM1166 has only six ports\n");
67589f67051SConrad Kostecki 		hpriv->saved_port_map = 0x3f;
67689f67051SConrad Kostecki 	}
67789f67051SConrad Kostecki 
678394d6e53SAnton Vorontsov 	if (pdev->vendor == PCI_VENDOR_ID_JMICRON && pdev->device == 0x2361) {
679394d6e53SAnton Vorontsov 		dev_info(&pdev->dev, "JMB361 has only one port\n");
68088589772SSerge Semin 		hpriv->saved_port_map = 1;
681394d6e53SAnton Vorontsov 	}
682394d6e53SAnton Vorontsov 
683394d6e53SAnton Vorontsov 	/*
684394d6e53SAnton Vorontsov 	 * Temporary Marvell 6145 hack: PATA port presence
685394d6e53SAnton Vorontsov 	 * is asserted through the standard AHCI port
686394d6e53SAnton Vorontsov 	 * presence register, as bit 4 (counting from 0)
687394d6e53SAnton Vorontsov 	 */
688394d6e53SAnton Vorontsov 	if (hpriv->flags & AHCI_HFLAG_MV_PATA) {
689394d6e53SAnton Vorontsov 		if (pdev->device == 0x6121)
6909a23c1d6SAntoine Tenart 			hpriv->mask_port_map = 0x3;
691394d6e53SAnton Vorontsov 		else
6929a23c1d6SAntoine Tenart 			hpriv->mask_port_map = 0xf;
693394d6e53SAnton Vorontsov 		dev_info(&pdev->dev,
694394d6e53SAnton Vorontsov 			  "Disabling your PATA port. Use the boot option 'ahci.marvell_enable=0' to avoid this.\n");
695394d6e53SAnton Vorontsov 	}
696394d6e53SAnton Vorontsov 
697725c7b57SAntoine Ténart 	ahci_save_initial_config(&pdev->dev, hpriv);
698394d6e53SAnton Vorontsov }
699394d6e53SAnton Vorontsov 
70037e14e4fSAdam Vodopjan static int ahci_pci_reset_controller(struct ata_host *host)
70137e14e4fSAdam Vodopjan {
70237e14e4fSAdam Vodopjan 	struct pci_dev *pdev = to_pci_dev(host->dev);
70337e14e4fSAdam Vodopjan 	struct ahci_host_priv *hpriv = host->private_data;
70437e14e4fSAdam Vodopjan 	int rc;
70537e14e4fSAdam Vodopjan 
70637e14e4fSAdam Vodopjan 	rc = ahci_reset_controller(host);
70737e14e4fSAdam Vodopjan 	if (rc)
70837e14e4fSAdam Vodopjan 		return rc;
70937e14e4fSAdam Vodopjan 
71037e14e4fSAdam Vodopjan 	/*
71137e14e4fSAdam Vodopjan 	 * If platform firmware failed to enable ports, try to enable
71237e14e4fSAdam Vodopjan 	 * them here.
71337e14e4fSAdam Vodopjan 	 */
71437e14e4fSAdam Vodopjan 	ahci_intel_pcs_quirk(pdev, hpriv);
71537e14e4fSAdam Vodopjan 
71637e14e4fSAdam Vodopjan 	return 0;
71737e14e4fSAdam Vodopjan }
71837e14e4fSAdam Vodopjan 
719781d6550SAnton Vorontsov static void ahci_pci_init_controller(struct ata_host *host)
720781d6550SAnton Vorontsov {
721781d6550SAnton Vorontsov 	struct ahci_host_priv *hpriv = host->private_data;
722781d6550SAnton Vorontsov 	struct pci_dev *pdev = to_pci_dev(host->dev);
723781d6550SAnton Vorontsov 	void __iomem *port_mmio;
724781d6550SAnton Vorontsov 	u32 tmp;
725c40e7cb8SJose Alberto Reguero 	int mv;
7262bcd866bSJeff Garzik 
727417a1a6dSTejun Heo 	if (hpriv->flags & AHCI_HFLAG_MV_PATA) {
728c40e7cb8SJose Alberto Reguero 		if (pdev->device == 0x6121)
729c40e7cb8SJose Alberto Reguero 			mv = 2;
730c40e7cb8SJose Alberto Reguero 		else
731c40e7cb8SJose Alberto Reguero 			mv = 4;
7327cbbfbe0SSerge Semin 		port_mmio = __ahci_port_base(hpriv, mv);
733cd70c266SJeff Garzik 
734cd70c266SJeff Garzik 		writel(0, port_mmio + PORT_IRQ_MASK);
735cd70c266SJeff Garzik 
736cd70c266SJeff Garzik 		/* clear port IRQ */
737cd70c266SJeff Garzik 		tmp = readl(port_mmio + PORT_IRQ_STAT);
73893c77114SHannes Reinecke 		dev_dbg(&pdev->dev, "PORT_IRQ_STAT 0x%x\n", tmp);
739cd70c266SJeff Garzik 		if (tmp)
740cd70c266SJeff Garzik 			writel(tmp, port_mmio + PORT_IRQ_STAT);
741cd70c266SJeff Garzik 	}
742cd70c266SJeff Garzik 
743781d6550SAnton Vorontsov 	ahci_init_controller(host);
744c6fd2807SJeff Garzik }
745c6fd2807SJeff Garzik 
746cc0680a5STejun Heo static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
747d4b2bab4STejun Heo 				 unsigned long deadline)
748ad616ffbSTejun Heo {
749cc0680a5STejun Heo 	struct ata_port *ap = link->ap;
750039ece38SHans de Goede 	struct ahci_host_priv *hpriv = ap->host->private_data;
7519dadd45bSTejun Heo 	bool online;
752ad616ffbSTejun Heo 	int rc;
753ad616ffbSTejun Heo 
754fa89f53bSEvan Wang 	hpriv->stop_engine(ap);
755ad616ffbSTejun Heo 
756cc0680a5STejun Heo 	rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context),
7579dadd45bSTejun Heo 				 deadline, &online, NULL);
758ad616ffbSTejun Heo 
759039ece38SHans de Goede 	hpriv->start_engine(ap);
760ad616ffbSTejun Heo 
761ad616ffbSTejun Heo 	/* vt8251 doesn't clear BSY on signature FIS reception,
762ad616ffbSTejun Heo 	 * request follow-up softreset.
763ad616ffbSTejun Heo 	 */
7649dadd45bSTejun Heo 	return online ? -EAGAIN : rc;
765ad616ffbSTejun Heo }
766ad616ffbSTejun Heo 
767edc93052STejun Heo static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
768edc93052STejun Heo 				unsigned long deadline)
769edc93052STejun Heo {
770edc93052STejun Heo 	struct ata_port *ap = link->ap;
771edc93052STejun Heo 	struct ahci_port_priv *pp = ap->private_data;
772039ece38SHans de Goede 	struct ahci_host_priv *hpriv = ap->host->private_data;
773edc93052STejun Heo 	u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
774edc93052STejun Heo 	struct ata_taskfile tf;
7759dadd45bSTejun Heo 	bool online;
776edc93052STejun Heo 	int rc;
777edc93052STejun Heo 
778fa89f53bSEvan Wang 	hpriv->stop_engine(ap);
779edc93052STejun Heo 
780edc93052STejun Heo 	/* clear D2H reception area to properly wait for D2H FIS */
781edc93052STejun Heo 	ata_tf_init(link->device, &tf);
782efcef265SSergey Shtylyov 	tf.status = ATA_BUSY;
783edc93052STejun Heo 	ata_tf_to_fis(&tf, 0, 0, d2h_fis);
784edc93052STejun Heo 
785edc93052STejun Heo 	rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context),
7869dadd45bSTejun Heo 				 deadline, &online, NULL);
787edc93052STejun Heo 
788039ece38SHans de Goede 	hpriv->start_engine(ap);
789edc93052STejun Heo 
790edc93052STejun Heo 	/* The pseudo configuration device on SIMG4726 attached to
791edc93052STejun Heo 	 * ASUS P5W-DH Deluxe doesn't send signature FIS after
792edc93052STejun Heo 	 * hardreset if no device is attached to the first downstream
793edc93052STejun Heo 	 * port && the pseudo device locks up on SRST w/ PMP==0.  To
794edc93052STejun Heo 	 * work around this, wait for !BSY only briefly.  If BSY isn't
795edc93052STejun Heo 	 * cleared, perform CLO and proceed to IDENTIFY (achieved by
796edc93052STejun Heo 	 * ATA_LFLAG_NO_SRST and ATA_LFLAG_ASSUME_ATA).
797edc93052STejun Heo 	 *
798edc93052STejun Heo 	 * Wait for two seconds.  Devices attached to downstream port
799edc93052STejun Heo 	 * which can't process the following IDENTIFY after this will
800edc93052STejun Heo 	 * have to be reset again.  For most cases, this should
801edc93052STejun Heo 	 * suffice while making probing snappish enough.
802edc93052STejun Heo 	 */
8039dadd45bSTejun Heo 	if (online) {
8049dadd45bSTejun Heo 		rc = ata_wait_after_reset(link, jiffies + 2 * HZ,
8059dadd45bSTejun Heo 					  ahci_check_ready);
806edc93052STejun Heo 		if (rc)
80778d5ae39SShane Huang 			ahci_kick_engine(ap);
8089dadd45bSTejun Heo 	}
8099dadd45bSTejun Heo 	return rc;
810edc93052STejun Heo }
811edc93052STejun Heo 
812dbfe8ef5SDan Williams /*
813dbfe8ef5SDan Williams  * ahci_avn_hardreset - attempt more aggressive recovery of Avoton ports.
814dbfe8ef5SDan Williams  *
815dbfe8ef5SDan Williams  * It has been observed with some SSDs that the timing of events in the
816dbfe8ef5SDan Williams  * link synchronization phase can leave the port in a state that can not
817dbfe8ef5SDan Williams  * be recovered by a SATA-hard-reset alone.  The failing signature is
818dbfe8ef5SDan Williams  * SStatus.DET stuck at 1 ("Device presence detected but Phy
819dbfe8ef5SDan Williams  * communication not established").  It was found that unloading and
820dbfe8ef5SDan Williams  * reloading the driver when this problem occurs allows the drive
821dbfe8ef5SDan Williams  * connection to be recovered (DET advanced to 0x3).  The critical
822dbfe8ef5SDan Williams  * component of reloading the driver is that the port state machines are
823dbfe8ef5SDan Williams  * reset by bouncing "port enable" in the AHCI PCS configuration
824dbfe8ef5SDan Williams  * register.  So, reproduce that effect by bouncing a port whenever we
825dbfe8ef5SDan Williams  * see DET==1 after a reset.
826dbfe8ef5SDan Williams  */
827dbfe8ef5SDan Williams static int ahci_avn_hardreset(struct ata_link *link, unsigned int *class,
828dbfe8ef5SDan Williams 			      unsigned long deadline)
829dbfe8ef5SDan Williams {
830d14d41ccSSergey Shtylyov 	const unsigned int *timing = sata_ehc_deb_timing(&link->eh_context);
831dbfe8ef5SDan Williams 	struct ata_port *ap = link->ap;
832dbfe8ef5SDan Williams 	struct ahci_port_priv *pp = ap->private_data;
833dbfe8ef5SDan Williams 	struct ahci_host_priv *hpriv = ap->host->private_data;
834dbfe8ef5SDan Williams 	u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
835dbfe8ef5SDan Williams 	unsigned long tmo = deadline - jiffies;
836dbfe8ef5SDan Williams 	struct ata_taskfile tf;
837dbfe8ef5SDan Williams 	bool online;
838dbfe8ef5SDan Williams 	int rc, i;
839dbfe8ef5SDan Williams 
840fa89f53bSEvan Wang 	hpriv->stop_engine(ap);
841dbfe8ef5SDan Williams 
842dbfe8ef5SDan Williams 	for (i = 0; i < 2; i++) {
843dbfe8ef5SDan Williams 		u16 val;
844dbfe8ef5SDan Williams 		u32 sstatus;
845dbfe8ef5SDan Williams 		int port = ap->port_no;
846dbfe8ef5SDan Williams 		struct ata_host *host = ap->host;
847dbfe8ef5SDan Williams 		struct pci_dev *pdev = to_pci_dev(host->dev);
848dbfe8ef5SDan Williams 
849dbfe8ef5SDan Williams 		/* clear D2H reception area to properly wait for D2H FIS */
850dbfe8ef5SDan Williams 		ata_tf_init(link->device, &tf);
851efcef265SSergey Shtylyov 		tf.status = ATA_BUSY;
852dbfe8ef5SDan Williams 		ata_tf_to_fis(&tf, 0, 0, d2h_fis);
853dbfe8ef5SDan Williams 
854dbfe8ef5SDan Williams 		rc = sata_link_hardreset(link, timing, deadline, &online,
855dbfe8ef5SDan Williams 				ahci_check_ready);
856dbfe8ef5SDan Williams 
857dbfe8ef5SDan Williams 		if (sata_scr_read(link, SCR_STATUS, &sstatus) != 0 ||
858dbfe8ef5SDan Williams 				(sstatus & 0xf) != 1)
859dbfe8ef5SDan Williams 			break;
860dbfe8ef5SDan Williams 
861e276c9bdSXu Wang 		ata_link_info(link,  "avn bounce port%d\n", port);
862dbfe8ef5SDan Williams 
863dbfe8ef5SDan Williams 		pci_read_config_word(pdev, 0x92, &val);
864dbfe8ef5SDan Williams 		val &= ~(1 << port);
865dbfe8ef5SDan Williams 		pci_write_config_word(pdev, 0x92, val);
866dbfe8ef5SDan Williams 		ata_msleep(ap, 1000);
867dbfe8ef5SDan Williams 		val |= 1 << port;
868dbfe8ef5SDan Williams 		pci_write_config_word(pdev, 0x92, val);
869dbfe8ef5SDan Williams 		deadline += tmo;
870dbfe8ef5SDan Williams 	}
871dbfe8ef5SDan Williams 
872dbfe8ef5SDan Williams 	hpriv->start_engine(ap);
873dbfe8ef5SDan Williams 
874dbfe8ef5SDan Williams 	if (online)
875dbfe8ef5SDan Williams 		*class = ahci_dev_classify(ap);
876dbfe8ef5SDan Williams 
877dbfe8ef5SDan Williams 	return rc;
878dbfe8ef5SDan Williams }
879dbfe8ef5SDan Williams 
880dbfe8ef5SDan Williams 
88102e53293SMika Westerberg #ifdef CONFIG_PM
88202e53293SMika Westerberg static void ahci_pci_disable_interrupts(struct ata_host *host)
883c6fd2807SJeff Garzik {
8849b10ae86STejun Heo 	struct ahci_host_priv *hpriv = host->private_data;
885d8993349SAnton Vorontsov 	void __iomem *mmio = hpriv->mmio;
886c6fd2807SJeff Garzik 	u32 ctl;
887c6fd2807SJeff Garzik 
888c6fd2807SJeff Garzik 	/* AHCI spec rev1.1 section 8.3.3:
889c6fd2807SJeff Garzik 	 * Software must disable interrupts prior to requesting a
890c6fd2807SJeff Garzik 	 * transition of the HBA to D3 state.
891c6fd2807SJeff Garzik 	 */
892c6fd2807SJeff Garzik 	ctl = readl(mmio + HOST_CTL);
893c6fd2807SJeff Garzik 	ctl &= ~HOST_IRQ_EN;
894c6fd2807SJeff Garzik 	writel(ctl, mmio + HOST_CTL);
895c6fd2807SJeff Garzik 	readl(mmio + HOST_CTL); /* flush */
89602e53293SMika Westerberg }
897f1d848f9SMika Westerberg 
89802e53293SMika Westerberg static int ahci_pci_device_runtime_suspend(struct device *dev)
89902e53293SMika Westerberg {
90002e53293SMika Westerberg 	struct pci_dev *pdev = to_pci_dev(dev);
90102e53293SMika Westerberg 	struct ata_host *host = pci_get_drvdata(pdev);
90202e53293SMika Westerberg 
90302e53293SMika Westerberg 	ahci_pci_disable_interrupts(host);
90402e53293SMika Westerberg 	return 0;
90502e53293SMika Westerberg }
90602e53293SMika Westerberg 
90702e53293SMika Westerberg static int ahci_pci_device_runtime_resume(struct device *dev)
90802e53293SMika Westerberg {
90902e53293SMika Westerberg 	struct pci_dev *pdev = to_pci_dev(dev);
91002e53293SMika Westerberg 	struct ata_host *host = pci_get_drvdata(pdev);
91102e53293SMika Westerberg 	int rc;
91202e53293SMika Westerberg 
91337e14e4fSAdam Vodopjan 	rc = ahci_pci_reset_controller(host);
91402e53293SMika Westerberg 	if (rc)
91502e53293SMika Westerberg 		return rc;
91602e53293SMika Westerberg 	ahci_pci_init_controller(host);
91702e53293SMika Westerberg 	return 0;
91802e53293SMika Westerberg }
91902e53293SMika Westerberg 
92002e53293SMika Westerberg #ifdef CONFIG_PM_SLEEP
92102e53293SMika Westerberg static int ahci_pci_device_suspend(struct device *dev)
92202e53293SMika Westerberg {
92302e53293SMika Westerberg 	struct pci_dev *pdev = to_pci_dev(dev);
92402e53293SMika Westerberg 	struct ata_host *host = pci_get_drvdata(pdev);
92502e53293SMika Westerberg 	struct ahci_host_priv *hpriv = host->private_data;
92602e53293SMika Westerberg 
92702e53293SMika Westerberg 	if (hpriv->flags & AHCI_HFLAG_NO_SUSPEND) {
92802e53293SMika Westerberg 		dev_err(&pdev->dev,
92902e53293SMika Westerberg 			"BIOS update required for suspend/resume\n");
93002e53293SMika Westerberg 		return -EIO;
93102e53293SMika Westerberg 	}
93202e53293SMika Westerberg 
93302e53293SMika Westerberg 	ahci_pci_disable_interrupts(host);
934ec87cf37SSergey Shtylyov 	ata_host_suspend(host, PMSG_SUSPEND);
935ec87cf37SSergey Shtylyov 	return 0;
936c6fd2807SJeff Garzik }
937c6fd2807SJeff Garzik 
938f1d848f9SMika Westerberg static int ahci_pci_device_resume(struct device *dev)
939c6fd2807SJeff Garzik {
940f1d848f9SMika Westerberg 	struct pci_dev *pdev = to_pci_dev(dev);
9410a86e1c8SJingoo Han 	struct ata_host *host = pci_get_drvdata(pdev);
942c6fd2807SJeff Garzik 	int rc;
943c6fd2807SJeff Garzik 
944cb85696dSJames Laird 	/* Apple BIOS helpfully mangles the registers on resume */
945cb85696dSJames Laird 	if (is_mcp89_apple(pdev))
946cb85696dSJames Laird 		ahci_mcp89_apple_enable(pdev);
947cb85696dSJames Laird 
948c6fd2807SJeff Garzik 	if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
94937e14e4fSAdam Vodopjan 		rc = ahci_pci_reset_controller(host);
950c6fd2807SJeff Garzik 		if (rc)
951c6fd2807SJeff Garzik 			return rc;
952c6fd2807SJeff Garzik 
953781d6550SAnton Vorontsov 		ahci_pci_init_controller(host);
954c6fd2807SJeff Garzik 	}
955c6fd2807SJeff Garzik 
956cca3974eSJeff Garzik 	ata_host_resume(host);
957c6fd2807SJeff Garzik 
958c6fd2807SJeff Garzik 	return 0;
959c6fd2807SJeff Garzik }
960438ac6d5STejun Heo #endif
961c6fd2807SJeff Garzik 
96202e53293SMika Westerberg #endif /* CONFIG_PM */
96302e53293SMika Westerberg 
964b0dd4d7aSLennert Buytenhek static int ahci_configure_dma_masks(struct pci_dev *pdev,
965b0dd4d7aSLennert Buytenhek 				    struct ahci_host_priv *hpriv)
966c6fd2807SJeff Garzik {
967b0dd4d7aSLennert Buytenhek 	int dma_bits;
968c6fd2807SJeff Garzik 	int rc;
969c6fd2807SJeff Garzik 
970b0dd4d7aSLennert Buytenhek 	if (hpriv->cap & HOST_CAP_64) {
971b0dd4d7aSLennert Buytenhek 		dma_bits = 64;
972b0dd4d7aSLennert Buytenhek 		if (hpriv->flags & AHCI_HFLAG_43BIT_ONLY)
973b0dd4d7aSLennert Buytenhek 			dma_bits = 43;
974b0dd4d7aSLennert Buytenhek 	} else {
975b0dd4d7aSLennert Buytenhek 		dma_bits = 32;
976b0dd4d7aSLennert Buytenhek 	}
977b0dd4d7aSLennert Buytenhek 
978318893e1SAlessandro Rubini 	/*
979318893e1SAlessandro Rubini 	 * If the device fixup already set the dma_mask to some non-standard
980318893e1SAlessandro Rubini 	 * value, don't extend it here. This happens on STA2X11, for example.
981b1716871SChristoph Hellwig 	 *
982b1716871SChristoph Hellwig 	 * XXX: manipulating the DMA mask from platform code is completely
983a7ba70f1SNicolas Saenz Julienne 	 * bogus, platform code should use dev->bus_dma_limit instead..
984318893e1SAlessandro Rubini 	 */
985318893e1SAlessandro Rubini 	if (pdev->dma_mask && pdev->dma_mask < DMA_BIT_MASK(32))
986318893e1SAlessandro Rubini 		return 0;
987318893e1SAlessandro Rubini 
988b1716871SChristoph Hellwig 	rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(dma_bits));
989b1716871SChristoph Hellwig 	if (rc)
990b1716871SChristoph Hellwig 		dev_err(&pdev->dev, "DMA enable failed\n");
991c6fd2807SJeff Garzik 	return rc;
992c6fd2807SJeff Garzik }
993c6fd2807SJeff Garzik 
994439fcaecSAnton Vorontsov static void ahci_pci_print_info(struct ata_host *host)
995439fcaecSAnton Vorontsov {
996439fcaecSAnton Vorontsov 	struct pci_dev *pdev = to_pci_dev(host->dev);
997439fcaecSAnton Vorontsov 	u16 cc;
998439fcaecSAnton Vorontsov 	const char *scc_s;
999439fcaecSAnton Vorontsov 
1000439fcaecSAnton Vorontsov 	pci_read_config_word(pdev, 0x0a, &cc);
1001439fcaecSAnton Vorontsov 	if (cc == PCI_CLASS_STORAGE_IDE)
1002439fcaecSAnton Vorontsov 		scc_s = "IDE";
1003439fcaecSAnton Vorontsov 	else if (cc == PCI_CLASS_STORAGE_SATA)
1004439fcaecSAnton Vorontsov 		scc_s = "SATA";
1005439fcaecSAnton Vorontsov 	else if (cc == PCI_CLASS_STORAGE_RAID)
1006439fcaecSAnton Vorontsov 		scc_s = "RAID";
1007439fcaecSAnton Vorontsov 	else
1008439fcaecSAnton Vorontsov 		scc_s = "unknown";
1009439fcaecSAnton Vorontsov 
1010439fcaecSAnton Vorontsov 	ahci_print_info(host, scc_s);
1011439fcaecSAnton Vorontsov }
1012439fcaecSAnton Vorontsov 
1013edc93052STejun Heo /* On ASUS P5W DH Deluxe, the second port of PCI device 00:1f.2 is
1014edc93052STejun Heo  * hardwired to on-board SIMG 4726.  The chipset is ICH8 and doesn't
1015edc93052STejun Heo  * support PMP and the 4726 either directly exports the device
1016edc93052STejun Heo  * attached to the first downstream port or acts as a hardware storage
1017edc93052STejun Heo  * controller and emulate a single ATA device (can be RAID 0/1 or some
1018edc93052STejun Heo  * other configuration).
1019edc93052STejun Heo  *
1020edc93052STejun Heo  * When there's no device attached to the first downstream port of the
1021edc93052STejun Heo  * 4726, "Config Disk" appears, which is a pseudo ATA device to
1022edc93052STejun Heo  * configure the 4726.  However, ATA emulation of the device is very
1023edc93052STejun Heo  * lame.  It doesn't send signature D2H Reg FIS after the initial
1024edc93052STejun Heo  * hardreset, pukes on SRST w/ PMP==0 and has bunch of other issues.
1025edc93052STejun Heo  *
1026edc93052STejun Heo  * The following function works around the problem by always using
1027edc93052STejun Heo  * hardreset on the port and not depending on receiving signature FIS
1028edc93052STejun Heo  * afterward.  If signature FIS isn't received soon, ATA class is
1029edc93052STejun Heo  * assumed without follow-up softreset.
1030edc93052STejun Heo  */
1031edc93052STejun Heo static void ahci_p5wdh_workaround(struct ata_host *host)
1032edc93052STejun Heo {
10331bd06867SMathias Krause 	static const struct dmi_system_id sysids[] = {
1034edc93052STejun Heo 		{
1035edc93052STejun Heo 			.ident = "P5W DH Deluxe",
1036edc93052STejun Heo 			.matches = {
1037edc93052STejun Heo 				DMI_MATCH(DMI_SYS_VENDOR,
1038edc93052STejun Heo 					  "ASUSTEK COMPUTER INC"),
1039edc93052STejun Heo 				DMI_MATCH(DMI_PRODUCT_NAME, "P5W DH Deluxe"),
1040edc93052STejun Heo 			},
1041edc93052STejun Heo 		},
1042edc93052STejun Heo 		{ }
1043edc93052STejun Heo 	};
1044edc93052STejun Heo 	struct pci_dev *pdev = to_pci_dev(host->dev);
1045edc93052STejun Heo 
1046edc93052STejun Heo 	if (pdev->bus->number == 0 && pdev->devfn == PCI_DEVFN(0x1f, 2) &&
1047edc93052STejun Heo 	    dmi_check_system(sysids)) {
1048edc93052STejun Heo 		struct ata_port *ap = host->ports[1];
1049edc93052STejun Heo 
1050a44fec1fSJoe Perches 		dev_info(&pdev->dev,
1051a44fec1fSJoe Perches 			 "enabling ASUS P5W DH Deluxe on-board SIMG4726 workaround\n");
1052edc93052STejun Heo 
1053edc93052STejun Heo 		ap->ops = &ahci_p5wdh_ops;
1054edc93052STejun Heo 		ap->link.flags |= ATA_LFLAG_NO_SRST | ATA_LFLAG_ASSUME_ATA;
1055edc93052STejun Heo 	}
1056edc93052STejun Heo }
1057edc93052STejun Heo 
1058cb85696dSJames Laird /*
1059cb85696dSJames Laird  * Macbook7,1 firmware forcibly disables MCP89 AHCI and changes PCI ID when
1060cb85696dSJames Laird  * booting in BIOS compatibility mode.  We restore the registers but not ID.
1061cb85696dSJames Laird  */
1062cb85696dSJames Laird static void ahci_mcp89_apple_enable(struct pci_dev *pdev)
1063cb85696dSJames Laird {
1064cb85696dSJames Laird 	u32 val;
1065cb85696dSJames Laird 
1066cb85696dSJames Laird 	printk(KERN_INFO "ahci: enabling MCP89 AHCI mode\n");
1067cb85696dSJames Laird 
1068cb85696dSJames Laird 	pci_read_config_dword(pdev, 0xf8, &val);
1069cb85696dSJames Laird 	val |= 1 << 0x1b;
1070cb85696dSJames Laird 	/* the following changes the device ID, but appears not to affect function */
1071cb85696dSJames Laird 	/* val = (val & ~0xf0000000) | 0x80000000; */
1072cb85696dSJames Laird 	pci_write_config_dword(pdev, 0xf8, val);
1073cb85696dSJames Laird 
1074cb85696dSJames Laird 	pci_read_config_dword(pdev, 0x54c, &val);
1075cb85696dSJames Laird 	val |= 1 << 0xc;
1076cb85696dSJames Laird 	pci_write_config_dword(pdev, 0x54c, val);
1077cb85696dSJames Laird 
1078cb85696dSJames Laird 	pci_read_config_dword(pdev, 0x4a4, &val);
1079cb85696dSJames Laird 	val &= 0xff;
1080cb85696dSJames Laird 	val |= 0x01060100;
1081cb85696dSJames Laird 	pci_write_config_dword(pdev, 0x4a4, val);
1082cb85696dSJames Laird 
1083cb85696dSJames Laird 	pci_read_config_dword(pdev, 0x54c, &val);
1084cb85696dSJames Laird 	val &= ~(1 << 0xc);
1085cb85696dSJames Laird 	pci_write_config_dword(pdev, 0x54c, val);
1086cb85696dSJames Laird 
1087cb85696dSJames Laird 	pci_read_config_dword(pdev, 0xf8, &val);
1088cb85696dSJames Laird 	val &= ~(1 << 0x1b);
1089cb85696dSJames Laird 	pci_write_config_dword(pdev, 0xf8, val);
1090cb85696dSJames Laird }
1091cb85696dSJames Laird 
1092cb85696dSJames Laird static bool is_mcp89_apple(struct pci_dev *pdev)
1093cb85696dSJames Laird {
1094cb85696dSJames Laird 	return pdev->vendor == PCI_VENDOR_ID_NVIDIA &&
1095cb85696dSJames Laird 		pdev->device == PCI_DEVICE_ID_NVIDIA_NFORCE_MCP89_SATA &&
1096cb85696dSJames Laird 		pdev->subsystem_vendor == PCI_VENDOR_ID_APPLE &&
1097cb85696dSJames Laird 		pdev->subsystem_device == 0xcb89;
1098cb85696dSJames Laird }
1099cb85696dSJames Laird 
11002fcad9d2STejun Heo /* only some SB600 ahci controllers can do 64bit DMA */
11012fcad9d2STejun Heo static bool ahci_sb600_enable_64bit(struct pci_dev *pdev)
110258a09b38SShane Huang {
110358a09b38SShane Huang 	static const struct dmi_system_id sysids[] = {
110403d783bfSTejun Heo 		/*
110503d783bfSTejun Heo 		 * The oldest version known to be broken is 0901 and
110603d783bfSTejun Heo 		 * working is 1501 which was released on 2007-10-26.
11072fcad9d2STejun Heo 		 * Enable 64bit DMA on 1501 and anything newer.
11082fcad9d2STejun Heo 		 *
110903d783bfSTejun Heo 		 * Please read bko#9412 for more info.
111003d783bfSTejun Heo 		 */
111158a09b38SShane Huang 		{
111258a09b38SShane Huang 			.ident = "ASUS M2A-VM",
111358a09b38SShane Huang 			.matches = {
111458a09b38SShane Huang 				DMI_MATCH(DMI_BOARD_VENDOR,
111558a09b38SShane Huang 					  "ASUSTeK Computer INC."),
111658a09b38SShane Huang 				DMI_MATCH(DMI_BOARD_NAME, "M2A-VM"),
111758a09b38SShane Huang 			},
111803d783bfSTejun Heo 			.driver_data = "20071026",	/* yyyymmdd */
111958a09b38SShane Huang 		},
1120e65cc194SMark Nelson 		/*
1121e65cc194SMark Nelson 		 * All BIOS versions for the MSI K9A2 Platinum (MS-7376)
1122e65cc194SMark Nelson 		 * support 64bit DMA.
1123e65cc194SMark Nelson 		 *
1124e65cc194SMark Nelson 		 * BIOS versions earlier than 1.5 had the Manufacturer DMI
1125e65cc194SMark Nelson 		 * fields as "MICRO-STAR INTERANTIONAL CO.,LTD".
1126e65cc194SMark Nelson 		 * This spelling mistake was fixed in BIOS version 1.5, so
1127e65cc194SMark Nelson 		 * 1.5 and later have the Manufacturer as
1128e65cc194SMark Nelson 		 * "MICRO-STAR INTERNATIONAL CO.,LTD".
1129e65cc194SMark Nelson 		 * So try to match on DMI_BOARD_VENDOR of "MICRO-STAR INTER".
1130e65cc194SMark Nelson 		 *
1131e65cc194SMark Nelson 		 * BIOS versions earlier than 1.9 had a Board Product Name
1132e65cc194SMark Nelson 		 * DMI field of "MS-7376". This was changed to be
1133e65cc194SMark Nelson 		 * "K9A2 Platinum (MS-7376)" in version 1.9, but we can still
1134e65cc194SMark Nelson 		 * match on DMI_BOARD_NAME of "MS-7376".
1135e65cc194SMark Nelson 		 */
1136e65cc194SMark Nelson 		{
1137e65cc194SMark Nelson 			.ident = "MSI K9A2 Platinum",
1138e65cc194SMark Nelson 			.matches = {
1139e65cc194SMark Nelson 				DMI_MATCH(DMI_BOARD_VENDOR,
1140e65cc194SMark Nelson 					  "MICRO-STAR INTER"),
1141e65cc194SMark Nelson 				DMI_MATCH(DMI_BOARD_NAME, "MS-7376"),
1142e65cc194SMark Nelson 			},
1143e65cc194SMark Nelson 		},
11443c4aa91fSMark Nelson 		/*
1145ff0173c1SMark Nelson 		 * All BIOS versions for the MSI K9AGM2 (MS-7327) support
1146ff0173c1SMark Nelson 		 * 64bit DMA.
1147ff0173c1SMark Nelson 		 *
1148ff0173c1SMark Nelson 		 * This board also had the typo mentioned above in the
1149ff0173c1SMark Nelson 		 * Manufacturer DMI field (fixed in BIOS version 1.5), so
1150ff0173c1SMark Nelson 		 * match on DMI_BOARD_VENDOR of "MICRO-STAR INTER" again.
1151ff0173c1SMark Nelson 		 */
1152ff0173c1SMark Nelson 		{
1153ff0173c1SMark Nelson 			.ident = "MSI K9AGM2",
1154ff0173c1SMark Nelson 			.matches = {
1155ff0173c1SMark Nelson 				DMI_MATCH(DMI_BOARD_VENDOR,
1156ff0173c1SMark Nelson 					  "MICRO-STAR INTER"),
1157ff0173c1SMark Nelson 				DMI_MATCH(DMI_BOARD_NAME, "MS-7327"),
1158ff0173c1SMark Nelson 			},
1159ff0173c1SMark Nelson 		},
1160ff0173c1SMark Nelson 		/*
11613c4aa91fSMark Nelson 		 * All BIOS versions for the Asus M3A support 64bit DMA.
11623c4aa91fSMark Nelson 		 * (all release versions from 0301 to 1206 were tested)
11633c4aa91fSMark Nelson 		 */
11643c4aa91fSMark Nelson 		{
11653c4aa91fSMark Nelson 			.ident = "ASUS M3A",
11663c4aa91fSMark Nelson 			.matches = {
11673c4aa91fSMark Nelson 				DMI_MATCH(DMI_BOARD_VENDOR,
11683c4aa91fSMark Nelson 					  "ASUSTeK Computer INC."),
11693c4aa91fSMark Nelson 				DMI_MATCH(DMI_BOARD_NAME, "M3A"),
11703c4aa91fSMark Nelson 			},
11713c4aa91fSMark Nelson 		},
117258a09b38SShane Huang 		{ }
117358a09b38SShane Huang 	};
117403d783bfSTejun Heo 	const struct dmi_system_id *match;
11752fcad9d2STejun Heo 	int year, month, date;
11762fcad9d2STejun Heo 	char buf[9];
117758a09b38SShane Huang 
117803d783bfSTejun Heo 	match = dmi_first_match(sysids);
117958a09b38SShane Huang 	if (pdev->bus->number != 0 || pdev->devfn != PCI_DEVFN(0x12, 0) ||
118003d783bfSTejun Heo 	    !match)
118158a09b38SShane Huang 		return false;
118258a09b38SShane Huang 
1183e65cc194SMark Nelson 	if (!match->driver_data)
1184e65cc194SMark Nelson 		goto enable_64bit;
1185e65cc194SMark Nelson 
118603d783bfSTejun Heo 	dmi_get_date(DMI_BIOS_DATE, &year, &month, &date);
118703d783bfSTejun Heo 	snprintf(buf, sizeof(buf), "%04d%02d%02d", year, month, date);
118803d783bfSTejun Heo 
1189e65cc194SMark Nelson 	if (strcmp(buf, match->driver_data) >= 0)
1190e65cc194SMark Nelson 		goto enable_64bit;
1191e65cc194SMark Nelson 	else {
1192a44fec1fSJoe Perches 		dev_warn(&pdev->dev,
1193a44fec1fSJoe Perches 			 "%s: BIOS too old, forcing 32bit DMA, update BIOS\n",
1194a44fec1fSJoe Perches 			 match->ident);
11952fcad9d2STejun Heo 		return false;
11962fcad9d2STejun Heo 	}
1197e65cc194SMark Nelson 
1198e65cc194SMark Nelson enable_64bit:
1199a44fec1fSJoe Perches 	dev_warn(&pdev->dev, "%s: enabling 64bit DMA\n", match->ident);
1200e65cc194SMark Nelson 	return true;
120158a09b38SShane Huang }
120258a09b38SShane Huang 
12031fd68434SRafael J. Wysocki static bool ahci_broken_system_poweroff(struct pci_dev *pdev)
12041fd68434SRafael J. Wysocki {
12051fd68434SRafael J. Wysocki 	static const struct dmi_system_id broken_systems[] = {
12061fd68434SRafael J. Wysocki 		{
12071fd68434SRafael J. Wysocki 			.ident = "HP Compaq nx6310",
12081fd68434SRafael J. Wysocki 			.matches = {
12091fd68434SRafael J. Wysocki 				DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
12101fd68434SRafael J. Wysocki 				DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq nx6310"),
12111fd68434SRafael J. Wysocki 			},
12121fd68434SRafael J. Wysocki 			/* PCI slot number of the controller */
12131fd68434SRafael J. Wysocki 			.driver_data = (void *)0x1FUL,
12141fd68434SRafael J. Wysocki 		},
1215d2f9c061SMaciej Rutecki 		{
1216d2f9c061SMaciej Rutecki 			.ident = "HP Compaq 6720s",
1217d2f9c061SMaciej Rutecki 			.matches = {
1218d2f9c061SMaciej Rutecki 				DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
1219d2f9c061SMaciej Rutecki 				DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq 6720s"),
1220d2f9c061SMaciej Rutecki 			},
1221d2f9c061SMaciej Rutecki 			/* PCI slot number of the controller */
1222d2f9c061SMaciej Rutecki 			.driver_data = (void *)0x1FUL,
1223d2f9c061SMaciej Rutecki 		},
12241fd68434SRafael J. Wysocki 
12251fd68434SRafael J. Wysocki 		{ }	/* terminate list */
12261fd68434SRafael J. Wysocki 	};
12271fd68434SRafael J. Wysocki 	const struct dmi_system_id *dmi = dmi_first_match(broken_systems);
12281fd68434SRafael J. Wysocki 
12291fd68434SRafael J. Wysocki 	if (dmi) {
12301fd68434SRafael J. Wysocki 		unsigned long slot = (unsigned long)dmi->driver_data;
12311fd68434SRafael J. Wysocki 		/* apply the quirk only to on-board controllers */
12321fd68434SRafael J. Wysocki 		return slot == PCI_SLOT(pdev->devfn);
12331fd68434SRafael J. Wysocki 	}
12341fd68434SRafael J. Wysocki 
12351fd68434SRafael J. Wysocki 	return false;
12361fd68434SRafael J. Wysocki }
12371fd68434SRafael J. Wysocki 
12389b10ae86STejun Heo static bool ahci_broken_suspend(struct pci_dev *pdev)
12399b10ae86STejun Heo {
12409b10ae86STejun Heo 	static const struct dmi_system_id sysids[] = {
12419b10ae86STejun Heo 		/*
12429b10ae86STejun Heo 		 * On HP dv[4-6] and HDX18 with earlier BIOSen, link
12439b10ae86STejun Heo 		 * to the harddisk doesn't become online after
12449b10ae86STejun Heo 		 * resuming from STR.  Warn and fail suspend.
12459deb3431STejun Heo 		 *
12469deb3431STejun Heo 		 * http://bugzilla.kernel.org/show_bug.cgi?id=12276
12479deb3431STejun Heo 		 *
12489deb3431STejun Heo 		 * Use dates instead of versions to match as HP is
12499deb3431STejun Heo 		 * apparently recycling both product and version
12509deb3431STejun Heo 		 * strings.
12519deb3431STejun Heo 		 *
12529deb3431STejun Heo 		 * http://bugzilla.kernel.org/show_bug.cgi?id=15462
12539b10ae86STejun Heo 		 */
12549b10ae86STejun Heo 		{
12559b10ae86STejun Heo 			.ident = "dv4",
12569b10ae86STejun Heo 			.matches = {
12579b10ae86STejun Heo 				DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
12589b10ae86STejun Heo 				DMI_MATCH(DMI_PRODUCT_NAME,
12599b10ae86STejun Heo 					  "HP Pavilion dv4 Notebook PC"),
12609b10ae86STejun Heo 			},
12619deb3431STejun Heo 			.driver_data = "20090105",	/* F.30 */
12629b10ae86STejun Heo 		},
12639b10ae86STejun Heo 		{
12649b10ae86STejun Heo 			.ident = "dv5",
12659b10ae86STejun Heo 			.matches = {
12669b10ae86STejun Heo 				DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
12679b10ae86STejun Heo 				DMI_MATCH(DMI_PRODUCT_NAME,
12689b10ae86STejun Heo 					  "HP Pavilion dv5 Notebook PC"),
12699b10ae86STejun Heo 			},
12709deb3431STejun Heo 			.driver_data = "20090506",	/* F.16 */
12719b10ae86STejun Heo 		},
12729b10ae86STejun Heo 		{
12739b10ae86STejun Heo 			.ident = "dv6",
12749b10ae86STejun Heo 			.matches = {
12759b10ae86STejun Heo 				DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
12769b10ae86STejun Heo 				DMI_MATCH(DMI_PRODUCT_NAME,
12779b10ae86STejun Heo 					  "HP Pavilion dv6 Notebook PC"),
12789b10ae86STejun Heo 			},
12799deb3431STejun Heo 			.driver_data = "20090423",	/* F.21 */
12809b10ae86STejun Heo 		},
12819b10ae86STejun Heo 		{
12829b10ae86STejun Heo 			.ident = "HDX18",
12839b10ae86STejun Heo 			.matches = {
12849b10ae86STejun Heo 				DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
12859b10ae86STejun Heo 				DMI_MATCH(DMI_PRODUCT_NAME,
12869b10ae86STejun Heo 					  "HP HDX18 Notebook PC"),
12879b10ae86STejun Heo 			},
12889deb3431STejun Heo 			.driver_data = "20090430",	/* F.23 */
12899b10ae86STejun Heo 		},
1290cedc9bf9STejun Heo 		/*
1291cedc9bf9STejun Heo 		 * Acer eMachines G725 has the same problem.  BIOS
1292cedc9bf9STejun Heo 		 * V1.03 is known to be broken.  V3.04 is known to
129325985edcSLucas De Marchi 		 * work.  Between, there are V1.06, V2.06 and V3.03
1294cedc9bf9STejun Heo 		 * that we don't have much idea about.  For now,
1295cedc9bf9STejun Heo 		 * blacklist anything older than V3.04.
12969deb3431STejun Heo 		 *
12979deb3431STejun Heo 		 * http://bugzilla.kernel.org/show_bug.cgi?id=15104
1298cedc9bf9STejun Heo 		 */
1299cedc9bf9STejun Heo 		{
1300cedc9bf9STejun Heo 			.ident = "G725",
1301cedc9bf9STejun Heo 			.matches = {
1302cedc9bf9STejun Heo 				DMI_MATCH(DMI_SYS_VENDOR, "eMachines"),
1303cedc9bf9STejun Heo 				DMI_MATCH(DMI_PRODUCT_NAME, "eMachines G725"),
1304cedc9bf9STejun Heo 			},
13059deb3431STejun Heo 			.driver_data = "20091216",	/* V3.04 */
1306cedc9bf9STejun Heo 		},
13079b10ae86STejun Heo 		{ }	/* terminate list */
13089b10ae86STejun Heo 	};
13099b10ae86STejun Heo 	const struct dmi_system_id *dmi = dmi_first_match(sysids);
13109deb3431STejun Heo 	int year, month, date;
13119deb3431STejun Heo 	char buf[9];
13129b10ae86STejun Heo 
13139b10ae86STejun Heo 	if (!dmi || pdev->bus->number || pdev->devfn != PCI_DEVFN(0x1f, 2))
13149b10ae86STejun Heo 		return false;
13159b10ae86STejun Heo 
13169deb3431STejun Heo 	dmi_get_date(DMI_BIOS_DATE, &year, &month, &date);
13179deb3431STejun Heo 	snprintf(buf, sizeof(buf), "%04d%02d%02d", year, month, date);
13189b10ae86STejun Heo 
13199deb3431STejun Heo 	return strcmp(buf, dmi->driver_data) < 0;
13209b10ae86STejun Heo }
13219b10ae86STejun Heo 
1322240630e6SHans de Goede static bool ahci_broken_lpm(struct pci_dev *pdev)
1323240630e6SHans de Goede {
1324240630e6SHans de Goede 	static const struct dmi_system_id sysids[] = {
1325240630e6SHans de Goede 		/* Various Lenovo 50 series have LPM issues with older BIOSen */
1326240630e6SHans de Goede 		{
1327240630e6SHans de Goede 			.matches = {
1328240630e6SHans de Goede 				DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1329240630e6SHans de Goede 				DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X250"),
1330240630e6SHans de Goede 			},
1331240630e6SHans de Goede 			.driver_data = "20180406", /* 1.31 */
1332240630e6SHans de Goede 		},
1333240630e6SHans de Goede 		{
1334240630e6SHans de Goede 			.matches = {
1335240630e6SHans de Goede 				DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1336240630e6SHans de Goede 				DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad L450"),
1337240630e6SHans de Goede 			},
1338240630e6SHans de Goede 			.driver_data = "20180420", /* 1.28 */
1339240630e6SHans de Goede 		},
1340240630e6SHans de Goede 		{
1341240630e6SHans de Goede 			.matches = {
1342240630e6SHans de Goede 				DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1343240630e6SHans de Goede 				DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T450s"),
1344240630e6SHans de Goede 			},
1345240630e6SHans de Goede 			.driver_data = "20180315", /* 1.33 */
1346240630e6SHans de Goede 		},
1347240630e6SHans de Goede 		{
1348240630e6SHans de Goede 			.matches = {
1349240630e6SHans de Goede 				DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1350240630e6SHans de Goede 				DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad W541"),
1351240630e6SHans de Goede 			},
1352240630e6SHans de Goede 			/*
1353240630e6SHans de Goede 			 * Note date based on release notes, 2.35 has been
1354240630e6SHans de Goede 			 * reported to be good, but I've been unable to get
1355240630e6SHans de Goede 			 * a hold of the reporter to get the DMI BIOS date.
1356240630e6SHans de Goede 			 * TODO: fix this.
1357240630e6SHans de Goede 			 */
1358240630e6SHans de Goede 			.driver_data = "20180310", /* 2.35 */
1359240630e6SHans de Goede 		},
1360240630e6SHans de Goede 		{ }	/* terminate list */
1361240630e6SHans de Goede 	};
1362240630e6SHans de Goede 	const struct dmi_system_id *dmi = dmi_first_match(sysids);
1363240630e6SHans de Goede 	int year, month, date;
1364240630e6SHans de Goede 	char buf[9];
1365240630e6SHans de Goede 
1366240630e6SHans de Goede 	if (!dmi)
1367240630e6SHans de Goede 		return false;
1368240630e6SHans de Goede 
1369240630e6SHans de Goede 	dmi_get_date(DMI_BIOS_DATE, &year, &month, &date);
1370240630e6SHans de Goede 	snprintf(buf, sizeof(buf), "%04d%02d%02d", year, month, date);
1371240630e6SHans de Goede 
1372240630e6SHans de Goede 	return strcmp(buf, dmi->driver_data) < 0;
1373240630e6SHans de Goede }
1374240630e6SHans de Goede 
13755594639aSTejun Heo static bool ahci_broken_online(struct pci_dev *pdev)
13765594639aSTejun Heo {
13775594639aSTejun Heo #define ENCODE_BUSDEVFN(bus, slot, func)			\
13785594639aSTejun Heo 	(void *)(unsigned long)(((bus) << 8) | PCI_DEVFN((slot), (func)))
13795594639aSTejun Heo 	static const struct dmi_system_id sysids[] = {
13805594639aSTejun Heo 		/*
13815594639aSTejun Heo 		 * There are several gigabyte boards which use
13825594639aSTejun Heo 		 * SIMG5723s configured as hardware RAID.  Certain
13835594639aSTejun Heo 		 * 5723 firmware revisions shipped there keep the link
13845594639aSTejun Heo 		 * online but fail to answer properly to SRST or
13855594639aSTejun Heo 		 * IDENTIFY when no device is attached downstream
13865594639aSTejun Heo 		 * causing libata to retry quite a few times leading
13875594639aSTejun Heo 		 * to excessive detection delay.
13885594639aSTejun Heo 		 *
13895594639aSTejun Heo 		 * As these firmwares respond to the second reset try
13905594639aSTejun Heo 		 * with invalid device signature, considering unknown
13915594639aSTejun Heo 		 * sig as offline works around the problem acceptably.
13925594639aSTejun Heo 		 */
13935594639aSTejun Heo 		{
13945594639aSTejun Heo 			.ident = "EP45-DQ6",
13955594639aSTejun Heo 			.matches = {
13965594639aSTejun Heo 				DMI_MATCH(DMI_BOARD_VENDOR,
13975594639aSTejun Heo 					  "Gigabyte Technology Co., Ltd."),
13985594639aSTejun Heo 				DMI_MATCH(DMI_BOARD_NAME, "EP45-DQ6"),
13995594639aSTejun Heo 			},
14005594639aSTejun Heo 			.driver_data = ENCODE_BUSDEVFN(0x0a, 0x00, 0),
14015594639aSTejun Heo 		},
14025594639aSTejun Heo 		{
14035594639aSTejun Heo 			.ident = "EP45-DS5",
14045594639aSTejun Heo 			.matches = {
14055594639aSTejun Heo 				DMI_MATCH(DMI_BOARD_VENDOR,
14065594639aSTejun Heo 					  "Gigabyte Technology Co., Ltd."),
14075594639aSTejun Heo 				DMI_MATCH(DMI_BOARD_NAME, "EP45-DS5"),
14085594639aSTejun Heo 			},
14095594639aSTejun Heo 			.driver_data = ENCODE_BUSDEVFN(0x03, 0x00, 0),
14105594639aSTejun Heo 		},
14115594639aSTejun Heo 		{ }	/* terminate list */
14125594639aSTejun Heo 	};
14135594639aSTejun Heo #undef ENCODE_BUSDEVFN
14145594639aSTejun Heo 	const struct dmi_system_id *dmi = dmi_first_match(sysids);
14155594639aSTejun Heo 	unsigned int val;
14165594639aSTejun Heo 
14175594639aSTejun Heo 	if (!dmi)
14185594639aSTejun Heo 		return false;
14195594639aSTejun Heo 
14205594639aSTejun Heo 	val = (unsigned long)dmi->driver_data;
14215594639aSTejun Heo 
14225594639aSTejun Heo 	return pdev->bus->number == (val >> 8) && pdev->devfn == (val & 0xff);
14235594639aSTejun Heo }
14245594639aSTejun Heo 
14250cf4a7d6SJacob Pan static bool ahci_broken_devslp(struct pci_dev *pdev)
14260cf4a7d6SJacob Pan {
14270cf4a7d6SJacob Pan 	/* device with broken DEVSLP but still showing SDS capability */
14280cf4a7d6SJacob Pan 	static const struct pci_device_id ids[] = {
14290cf4a7d6SJacob Pan 		{ PCI_VDEVICE(INTEL, 0x0f23)}, /* Valleyview SoC */
14300cf4a7d6SJacob Pan 		{}
14310cf4a7d6SJacob Pan 	};
14320cf4a7d6SJacob Pan 
14330cf4a7d6SJacob Pan 	return pci_match_id(ids, pdev);
14340cf4a7d6SJacob Pan }
14350cf4a7d6SJacob Pan 
14368e513217SMarkus Trippelsdorf #ifdef CONFIG_ATA_ACPI
1437f80ae7e4STejun Heo static void ahci_gtf_filter_workaround(struct ata_host *host)
1438f80ae7e4STejun Heo {
1439f80ae7e4STejun Heo 	static const struct dmi_system_id sysids[] = {
1440f80ae7e4STejun Heo 		/*
1441f80ae7e4STejun Heo 		 * Aspire 3810T issues a bunch of SATA enable commands
1442f80ae7e4STejun Heo 		 * via _GTF including an invalid one and one which is
1443f80ae7e4STejun Heo 		 * rejected by the device.  Among the successful ones
1444f80ae7e4STejun Heo 		 * is FPDMA non-zero offset enable which when enabled
1445f80ae7e4STejun Heo 		 * only on the drive side leads to NCQ command
1446f80ae7e4STejun Heo 		 * failures.  Filter it out.
1447f80ae7e4STejun Heo 		 */
1448f80ae7e4STejun Heo 		{
1449f80ae7e4STejun Heo 			.ident = "Aspire 3810T",
1450f80ae7e4STejun Heo 			.matches = {
1451f80ae7e4STejun Heo 				DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
1452f80ae7e4STejun Heo 				DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3810T"),
1453f80ae7e4STejun Heo 			},
1454f80ae7e4STejun Heo 			.driver_data = (void *)ATA_ACPI_FILTER_FPDMA_OFFSET,
1455f80ae7e4STejun Heo 		},
1456f80ae7e4STejun Heo 		{ }
1457f80ae7e4STejun Heo 	};
1458f80ae7e4STejun Heo 	const struct dmi_system_id *dmi = dmi_first_match(sysids);
1459f80ae7e4STejun Heo 	unsigned int filter;
1460f80ae7e4STejun Heo 	int i;
1461f80ae7e4STejun Heo 
1462f80ae7e4STejun Heo 	if (!dmi)
1463f80ae7e4STejun Heo 		return;
1464f80ae7e4STejun Heo 
1465f80ae7e4STejun Heo 	filter = (unsigned long)dmi->driver_data;
1466a44fec1fSJoe Perches 	dev_info(host->dev, "applying extra ACPI _GTF filter 0x%x for %s\n",
1467f80ae7e4STejun Heo 		 filter, dmi->ident);
1468f80ae7e4STejun Heo 
1469f80ae7e4STejun Heo 	for (i = 0; i < host->n_ports; i++) {
1470f80ae7e4STejun Heo 		struct ata_port *ap = host->ports[i];
1471f80ae7e4STejun Heo 		struct ata_link *link;
1472f80ae7e4STejun Heo 		struct ata_device *dev;
1473f80ae7e4STejun Heo 
1474f80ae7e4STejun Heo 		ata_for_each_link(link, ap, EDGE)
1475f80ae7e4STejun Heo 			ata_for_each_dev(dev, link, ALL)
1476f80ae7e4STejun Heo 				dev->gtf_filter |= filter;
1477f80ae7e4STejun Heo 	}
1478f80ae7e4STejun Heo }
14798e513217SMarkus Trippelsdorf #else
14808e513217SMarkus Trippelsdorf static inline void ahci_gtf_filter_workaround(struct ata_host *host)
14818e513217SMarkus Trippelsdorf {}
14828e513217SMarkus Trippelsdorf #endif
1483f80ae7e4STejun Heo 
14848bfd1743SSui Chen /*
14858bfd1743SSui Chen  * On the Acer Aspire Switch Alpha 12, sometimes all SATA ports are detected
14868bfd1743SSui Chen  * as DUMMY, or detected but eventually get a "link down" and never get up
14878bfd1743SSui Chen  * again. When this happens, CAP.NP may hold a value of 0x00 or 0x01, and the
14888bfd1743SSui Chen  * port_map may hold a value of 0x00.
14898bfd1743SSui Chen  *
14908bfd1743SSui Chen  * Overriding CAP.NP to 0x02 and the port_map to 0x7 will reveal all 3 ports
14918bfd1743SSui Chen  * and can significantly reduce the occurrence of the problem.
14928bfd1743SSui Chen  *
14938bfd1743SSui Chen  * https://bugzilla.kernel.org/show_bug.cgi?id=189471
14948bfd1743SSui Chen  */
14958bfd1743SSui Chen static void acer_sa5_271_workaround(struct ahci_host_priv *hpriv,
14968bfd1743SSui Chen 				    struct pci_dev *pdev)
14978bfd1743SSui Chen {
14988bfd1743SSui Chen 	static const struct dmi_system_id sysids[] = {
14998bfd1743SSui Chen 		{
15008bfd1743SSui Chen 			.ident = "Acer Switch Alpha 12",
15018bfd1743SSui Chen 			.matches = {
15028bfd1743SSui Chen 				DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
15038bfd1743SSui Chen 				DMI_MATCH(DMI_PRODUCT_NAME, "Switch SA5-271")
15048bfd1743SSui Chen 			},
15058bfd1743SSui Chen 		},
15068bfd1743SSui Chen 		{ }
15078bfd1743SSui Chen 	};
15088bfd1743SSui Chen 
15098bfd1743SSui Chen 	if (dmi_check_system(sysids)) {
15108bfd1743SSui Chen 		dev_info(&pdev->dev, "enabling Acer Switch Alpha 12 workaround\n");
15118bfd1743SSui Chen 		if ((hpriv->saved_cap & 0xC734FF00) == 0xC734FF00) {
15128bfd1743SSui Chen 			hpriv->port_map = 0x7;
15138bfd1743SSui Chen 			hpriv->cap = 0xC734FF02;
15148bfd1743SSui Chen 		}
15158bfd1743SSui Chen 	}
15168bfd1743SSui Chen }
15178bfd1743SSui Chen 
1518d243bed3STirumalesh Chalamarla #ifdef CONFIG_ARM64
1519d243bed3STirumalesh Chalamarla /*
1520d243bed3STirumalesh Chalamarla  * Due to ERRATA#22536, ThunderX needs to handle HOST_IRQ_STAT differently.
1521d243bed3STirumalesh Chalamarla  * Workaround is to make sure all pending IRQs are served before leaving
1522d243bed3STirumalesh Chalamarla  * handler.
1523d243bed3STirumalesh Chalamarla  */
1524d243bed3STirumalesh Chalamarla static irqreturn_t ahci_thunderx_irq_handler(int irq, void *dev_instance)
1525d243bed3STirumalesh Chalamarla {
1526d243bed3STirumalesh Chalamarla 	struct ata_host *host = dev_instance;
1527d243bed3STirumalesh Chalamarla 	struct ahci_host_priv *hpriv;
1528d243bed3STirumalesh Chalamarla 	unsigned int rc = 0;
1529d243bed3STirumalesh Chalamarla 	void __iomem *mmio;
1530d243bed3STirumalesh Chalamarla 	u32 irq_stat, irq_masked;
1531d243bed3STirumalesh Chalamarla 	unsigned int handled = 1;
1532d243bed3STirumalesh Chalamarla 
1533d243bed3STirumalesh Chalamarla 	hpriv = host->private_data;
1534d243bed3STirumalesh Chalamarla 	mmio = hpriv->mmio;
1535d243bed3STirumalesh Chalamarla 	irq_stat = readl(mmio + HOST_IRQ_STAT);
1536d243bed3STirumalesh Chalamarla 	if (!irq_stat)
1537d243bed3STirumalesh Chalamarla 		return IRQ_NONE;
1538d243bed3STirumalesh Chalamarla 
1539d243bed3STirumalesh Chalamarla 	do {
1540d243bed3STirumalesh Chalamarla 		irq_masked = irq_stat & hpriv->port_map;
1541d243bed3STirumalesh Chalamarla 		spin_lock(&host->lock);
1542d243bed3STirumalesh Chalamarla 		rc = ahci_handle_port_intr(host, irq_masked);
1543d243bed3STirumalesh Chalamarla 		if (!rc)
1544d243bed3STirumalesh Chalamarla 			handled = 0;
1545d243bed3STirumalesh Chalamarla 		writel(irq_stat, mmio + HOST_IRQ_STAT);
1546d243bed3STirumalesh Chalamarla 		irq_stat = readl(mmio + HOST_IRQ_STAT);
1547d243bed3STirumalesh Chalamarla 		spin_unlock(&host->lock);
1548d243bed3STirumalesh Chalamarla 	} while (irq_stat);
1549d243bed3STirumalesh Chalamarla 
1550d243bed3STirumalesh Chalamarla 	return IRQ_RETVAL(handled);
1551d243bed3STirumalesh Chalamarla }
1552d243bed3STirumalesh Chalamarla #endif
1553d243bed3STirumalesh Chalamarla 
1554aecec8b6SChristoph Hellwig static void ahci_remap_check(struct pci_dev *pdev, int bar,
1555aecec8b6SChristoph Hellwig 		struct ahci_host_priv *hpriv)
1556aecec8b6SChristoph Hellwig {
1557894fba7fSKai-Heng Feng 	int i;
1558aecec8b6SChristoph Hellwig 	u32 cap;
1559aecec8b6SChristoph Hellwig 
1560aecec8b6SChristoph Hellwig 	/*
1561aecec8b6SChristoph Hellwig 	 * Check if this device might have remapped nvme devices.
1562aecec8b6SChristoph Hellwig 	 */
1563aecec8b6SChristoph Hellwig 	if (pdev->vendor != PCI_VENDOR_ID_INTEL ||
1564aecec8b6SChristoph Hellwig 	    pci_resource_len(pdev, bar) < SZ_512K ||
1565aecec8b6SChristoph Hellwig 	    bar != AHCI_PCI_BAR_STANDARD ||
1566aecec8b6SChristoph Hellwig 	    !(readl(hpriv->mmio + AHCI_VSCAP) & 1))
1567aecec8b6SChristoph Hellwig 		return;
1568aecec8b6SChristoph Hellwig 
1569aecec8b6SChristoph Hellwig 	cap = readq(hpriv->mmio + AHCI_REMAP_CAP);
1570aecec8b6SChristoph Hellwig 	for (i = 0; i < AHCI_MAX_REMAP; i++) {
1571aecec8b6SChristoph Hellwig 		if ((cap & (1 << i)) == 0)
1572aecec8b6SChristoph Hellwig 			continue;
1573aecec8b6SChristoph Hellwig 		if (readl(hpriv->mmio + ahci_remap_dcc(i))
1574aecec8b6SChristoph Hellwig 				!= PCI_CLASS_STORAGE_EXPRESS)
1575aecec8b6SChristoph Hellwig 			continue;
1576aecec8b6SChristoph Hellwig 
1577aecec8b6SChristoph Hellwig 		/* We've found a remapped device */
1578894fba7fSKai-Heng Feng 		hpriv->remapped_nvme++;
1579aecec8b6SChristoph Hellwig 	}
1580aecec8b6SChristoph Hellwig 
1581894fba7fSKai-Heng Feng 	if (!hpriv->remapped_nvme)
1582aecec8b6SChristoph Hellwig 		return;
1583aecec8b6SChristoph Hellwig 
1584894fba7fSKai-Heng Feng 	dev_warn(&pdev->dev, "Found %u remapped NVMe devices.\n",
1585894fba7fSKai-Heng Feng 		 hpriv->remapped_nvme);
1586f723fa4eSChristoph Hellwig 	dev_warn(&pdev->dev,
1587f723fa4eSChristoph Hellwig 		 "Switch your BIOS from RAID to AHCI mode to use them.\n");
1588f723fa4eSChristoph Hellwig 
1589f723fa4eSChristoph Hellwig 	/*
1590f723fa4eSChristoph Hellwig 	 * Don't rely on the msi-x capability in the remap case,
1591f723fa4eSChristoph Hellwig 	 * share the legacy interrupt across ahci and remapped devices.
1592f723fa4eSChristoph Hellwig 	 */
1593f723fa4eSChristoph Hellwig 	hpriv->flags |= AHCI_HFLAG_NO_MSI;
1594aecec8b6SChristoph Hellwig }
1595aecec8b6SChristoph Hellwig 
15960b9e2988SChristoph Hellwig static int ahci_get_irq_vector(struct ata_host *host, int port)
1597ee2aad42SRobert Richter {
15980b9e2988SChristoph Hellwig 	return pci_irq_vector(to_pci_dev(host->dev), port);
1599ee2aad42SRobert Richter }
1600ee2aad42SRobert Richter 
1601a1c82311SRobert Richter static int ahci_init_msi(struct pci_dev *pdev, unsigned int n_ports,
16027b92b4f6SAlexander Gordeev 			struct ahci_host_priv *hpriv)
16035ca72c4fSAlexander Gordeev {
16040b9e2988SChristoph Hellwig 	int nvec;
16055ca72c4fSAlexander Gordeev 
16067b92b4f6SAlexander Gordeev 	if (hpriv->flags & AHCI_HFLAG_NO_MSI)
1607a1c82311SRobert Richter 		return -ENODEV;
16087b92b4f6SAlexander Gordeev 
16095ca72c4fSAlexander Gordeev 	/*
16107b92b4f6SAlexander Gordeev 	 * If number of MSIs is less than number of ports then Sharing Last
16117b92b4f6SAlexander Gordeev 	 * Message mode could be enforced. In this case assume that advantage
16127b92b4f6SAlexander Gordeev 	 * of multipe MSIs is negated and use single MSI mode instead.
16135ca72c4fSAlexander Gordeev 	 */
161417a51f12SChristoph Hellwig 	if (n_ports > 1) {
16150b9e2988SChristoph Hellwig 		nvec = pci_alloc_irq_vectors(pdev, n_ports, INT_MAX,
16160b9e2988SChristoph Hellwig 				PCI_IRQ_MSIX | PCI_IRQ_MSI);
16170b9e2988SChristoph Hellwig 		if (nvec > 0) {
16180b9e2988SChristoph Hellwig 			if (!(readl(hpriv->mmio + HOST_CTL) & HOST_MRSM)) {
16190b9e2988SChristoph Hellwig 				hpriv->get_irq_vector = ahci_get_irq_vector;
1620c3ebd6a9SAlexander Gordeev 				hpriv->flags |= AHCI_HFLAG_MULTI_MSI;
162121bfd1aaSRobert Richter 				return nvec;
1622a1c82311SRobert Richter 			}
1623a1c82311SRobert Richter 
1624d684a90dSDan Williams 			/*
162517a51f12SChristoph Hellwig 			 * Fallback to single MSI mode if the controller
162617a51f12SChristoph Hellwig 			 * enforced MRSM mode.
1627d684a90dSDan Williams 			 */
162817a51f12SChristoph Hellwig 			printk(KERN_INFO
162917a51f12SChristoph Hellwig 				"ahci: MRSM is on, fallback to single MSI\n");
16300b9e2988SChristoph Hellwig 			pci_free_irq_vectors(pdev);
16310b9e2988SChristoph Hellwig 		}
1632a478b097SChristoph Hellwig 	}
1633d684a90dSDan Williams 
16340b9e2988SChristoph Hellwig 	/*
16350b9e2988SChristoph Hellwig 	 * If the host is not capable of supporting per-port vectors, fall
16360b9e2988SChristoph Hellwig 	 * back to single MSI before finally attempting single MSI-X.
16370b9e2988SChristoph Hellwig 	 */
16380b9e2988SChristoph Hellwig 	nvec = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSI);
16390b9e2988SChristoph Hellwig 	if (nvec == 1)
1640a1c82311SRobert Richter 		return nvec;
16410b9e2988SChristoph Hellwig 	return pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSIX);
16425ca72c4fSAlexander Gordeev }
16435ca72c4fSAlexander Gordeev 
1644b1a9585cSSrinivas Pandruvada static void ahci_update_initial_lpm_policy(struct ata_port *ap,
1645b1a9585cSSrinivas Pandruvada 					   struct ahci_host_priv *hpriv)
1646b1a9585cSSrinivas Pandruvada {
164755b01415SMario Limonciello 	int policy = CONFIG_SATA_MOBILE_LPM_POLICY;
1648b1a9585cSSrinivas Pandruvada 
1649b1a9585cSSrinivas Pandruvada 
1650e5c89479SMario Limonciello 	/* Ignore processing for chipsets that don't use policy */
1651e5c89479SMario Limonciello 	if (!(hpriv->flags & AHCI_HFLAG_USE_LPM_POLICY))
1652b1a9585cSSrinivas Pandruvada 		return;
1653b1a9585cSSrinivas Pandruvada 
1654b1a9585cSSrinivas Pandruvada 	/* user modified policy via module param */
1655b1a9585cSSrinivas Pandruvada 	if (mobile_lpm_policy != -1) {
1656b1a9585cSSrinivas Pandruvada 		policy = mobile_lpm_policy;
1657b1a9585cSSrinivas Pandruvada 		goto update_policy;
1658b1a9585cSSrinivas Pandruvada 	}
1659b1a9585cSSrinivas Pandruvada 
1660fee60730SRafael J. Wysocki 	if (policy > ATA_LPM_MED_POWER && pm_suspend_default_s2idle()) {
1661b1a9585cSSrinivas Pandruvada 		if (hpriv->cap & HOST_CAP_PART)
1662b1a9585cSSrinivas Pandruvada 			policy = ATA_LPM_MIN_POWER_WITH_PARTIAL;
1663b1a9585cSSrinivas Pandruvada 		else if (hpriv->cap & HOST_CAP_SSC)
1664b1a9585cSSrinivas Pandruvada 			policy = ATA_LPM_MIN_POWER;
1665b1a9585cSSrinivas Pandruvada 	}
1666b1a9585cSSrinivas Pandruvada 
1667b1a9585cSSrinivas Pandruvada update_policy:
1668b1a9585cSSrinivas Pandruvada 	if (policy >= ATA_LPM_UNKNOWN && policy <= ATA_LPM_MIN_POWER)
1669b1a9585cSSrinivas Pandruvada 		ap->target_lpm_policy = policy;
1670b1a9585cSSrinivas Pandruvada }
1671b1a9585cSSrinivas Pandruvada 
1672c312ef17SDan Williams static void ahci_intel_pcs_quirk(struct pci_dev *pdev, struct ahci_host_priv *hpriv)
1673c312ef17SDan Williams {
1674c312ef17SDan Williams 	const struct pci_device_id *id = pci_match_id(ahci_pci_tbl, pdev);
1675c312ef17SDan Williams 	u16 tmp16;
1676c312ef17SDan Williams 
1677c312ef17SDan Williams 	/*
1678c312ef17SDan Williams 	 * Only apply the 6-port PCS quirk for known legacy platforms.
1679c312ef17SDan Williams 	 */
1680c312ef17SDan Williams 	if (!id || id->vendor != PCI_VENDOR_ID_INTEL)
1681c312ef17SDan Williams 		return;
168209d6ac8dSDan Williams 
168309d6ac8dSDan Williams 	/* Skip applying the quirk on Denverton and beyond */
168409d6ac8dSDan Williams 	if (((enum board_ids) id->driver_data) >= board_ahci_pcs7)
1685c312ef17SDan Williams 		return;
1686c312ef17SDan Williams 
1687c312ef17SDan Williams 	/*
1688c312ef17SDan Williams 	 * port_map is determined from PORTS_IMPL PCI register which is
1689c312ef17SDan Williams 	 * implemented as write or write-once register.  If the register
1690c312ef17SDan Williams 	 * isn't programmed, ahci automatically generates it from number
1691c312ef17SDan Williams 	 * of ports, which is good enough for PCS programming. It is
1692c312ef17SDan Williams 	 * otherwise expected that platform firmware enables the ports
1693c312ef17SDan Williams 	 * before the OS boots.
1694c312ef17SDan Williams 	 */
1695c312ef17SDan Williams 	pci_read_config_word(pdev, PCS_6, &tmp16);
1696c312ef17SDan Williams 	if ((tmp16 & hpriv->port_map) != hpriv->port_map) {
1697c312ef17SDan Williams 		tmp16 |= hpriv->port_map;
1698c312ef17SDan Williams 		pci_write_config_word(pdev, PCS_6, tmp16);
1699c312ef17SDan Williams 	}
1700c312ef17SDan Williams }
1701c312ef17SDan Williams 
1702894fba7fSKai-Heng Feng static ssize_t remapped_nvme_show(struct device *dev,
1703894fba7fSKai-Heng Feng 				  struct device_attribute *attr,
1704894fba7fSKai-Heng Feng 				  char *buf)
1705894fba7fSKai-Heng Feng {
1706894fba7fSKai-Heng Feng 	struct ata_host *host = dev_get_drvdata(dev);
1707894fba7fSKai-Heng Feng 	struct ahci_host_priv *hpriv = host->private_data;
1708894fba7fSKai-Heng Feng 
1709179a0282SDamien Le Moal 	return sysfs_emit(buf, "%u\n", hpriv->remapped_nvme);
1710894fba7fSKai-Heng Feng }
1711894fba7fSKai-Heng Feng 
1712894fba7fSKai-Heng Feng static DEVICE_ATTR_RO(remapped_nvme);
1713894fba7fSKai-Heng Feng 
1714c6fd2807SJeff Garzik static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
1715c6fd2807SJeff Garzik {
1716e297d99eSTejun Heo 	unsigned int board_id = ent->driver_data;
1717e297d99eSTejun Heo 	struct ata_port_info pi = ahci_port_info[board_id];
17184447d351STejun Heo 	const struct ata_port_info *ppi[] = { &pi, NULL };
171924dc5f33STejun Heo 	struct device *dev = &pdev->dev;
1720c6fd2807SJeff Garzik 	struct ahci_host_priv *hpriv;
17214447d351STejun Heo 	struct ata_host *host;
1722c3ebd6a9SAlexander Gordeev 	int n_ports, i, rc;
1723318893e1SAlessandro Rubini 	int ahci_pci_bar = AHCI_PCI_BAR_STANDARD;
1724c6fd2807SJeff Garzik 
1725b429dd59SJustin P. Mattock 	WARN_ON((int)ATA_MAX_QUEUE > AHCI_MAX_CMDS);
1726c6fd2807SJeff Garzik 
172706296a1eSJoe Perches 	ata_print_version_once(&pdev->dev, DRV_VERSION);
1728c6fd2807SJeff Garzik 
17295b66c829SAlan Cox 	/* The AHCI driver can only drive the SATA ports, the PATA driver
17305b66c829SAlan Cox 	   can drive them all so if both drivers are selected make sure
17315b66c829SAlan Cox 	   AHCI stays out of the way */
17325b66c829SAlan Cox 	if (pdev->vendor == PCI_VENDOR_ID_MARVELL && !marvell_enable)
17335b66c829SAlan Cox 		return -ENODEV;
17345b66c829SAlan Cox 
1735cb85696dSJames Laird 	/* Apple BIOS on MCP89 prevents us using AHCI */
1736cb85696dSJames Laird 	if (is_mcp89_apple(pdev))
1737cb85696dSJames Laird 		ahci_mcp89_apple_enable(pdev);
1738c6353b45STejun Heo 
17397a02267eSMark Nelson 	/* Promise's PDC42819 is a SAS/SATA controller that has an AHCI mode.
17407a02267eSMark Nelson 	 * At the moment, we can only use the AHCI mode. Let the users know
17417a02267eSMark Nelson 	 * that for SAS drives they're out of luck.
17427a02267eSMark Nelson 	 */
17437a02267eSMark Nelson 	if (pdev->vendor == PCI_VENDOR_ID_PROMISE)
1744a44fec1fSJoe Perches 		dev_info(&pdev->dev,
1745a44fec1fSJoe Perches 			 "PDC42819 can only drive SATA devices with this driver\n");
17467a02267eSMark Nelson 
1747b7ae128dSRobert Richter 	/* Some devices use non-standard BARs */
1748318893e1SAlessandro Rubini 	if (pdev->vendor == PCI_VENDOR_ID_STMICRO && pdev->device == 0xCC06)
1749318893e1SAlessandro Rubini 		ahci_pci_bar = AHCI_PCI_BAR_STA2X11;
17507f9c9f8eSHugh Daschbach 	else if (pdev->vendor == 0x1c44 && pdev->device == 0x8000)
17517f9c9f8eSHugh Daschbach 		ahci_pci_bar = AHCI_PCI_BAR_ENMOTUS;
1752b1314e3fSRadha Mohan Chintakuntla 	else if (pdev->vendor == PCI_VENDOR_ID_CAVIUM) {
1753b1314e3fSRadha Mohan Chintakuntla 		if (pdev->device == 0xa01c)
1754b7ae128dSRobert Richter 			ahci_pci_bar = AHCI_PCI_BAR_CAVIUM;
1755b1314e3fSRadha Mohan Chintakuntla 		if (pdev->device == 0xa084)
1756b1314e3fSRadha Mohan Chintakuntla 			ahci_pci_bar = AHCI_PCI_BAR_CAVIUM_GEN5;
1757e49bd683STiezhu Yang 	} else if (pdev->vendor == PCI_VENDOR_ID_LOONGSON) {
1758e49bd683STiezhu Yang 		if (pdev->device == 0x7a08)
1759e49bd683STiezhu Yang 			ahci_pci_bar = AHCI_PCI_BAR_LOONGSON;
1760b1314e3fSRadha Mohan Chintakuntla 	}
1761318893e1SAlessandro Rubini 
17624447d351STejun Heo 	/* acquire resources */
176324dc5f33STejun Heo 	rc = pcim_enable_device(pdev);
1764c6fd2807SJeff Garzik 	if (rc)
1765c6fd2807SJeff Garzik 		return rc;
1766c6fd2807SJeff Garzik 
1767c4f7792cSTejun Heo 	if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
1768c4f7792cSTejun Heo 	    (pdev->device == 0x2652 || pdev->device == 0x2653)) {
1769c4f7792cSTejun Heo 		u8 map;
1770c4f7792cSTejun Heo 
1771c4f7792cSTejun Heo 		/* ICH6s share the same PCI ID for both piix and ahci
1772c4f7792cSTejun Heo 		 * modes.  Enabling ahci mode while MAP indicates
1773c4f7792cSTejun Heo 		 * combined mode is a bad idea.  Yield to ata_piix.
1774c4f7792cSTejun Heo 		 */
1775c4f7792cSTejun Heo 		pci_read_config_byte(pdev, ICH_MAP, &map);
1776c4f7792cSTejun Heo 		if (map & 0x3) {
1777a44fec1fSJoe Perches 			dev_info(&pdev->dev,
1778a44fec1fSJoe Perches 				 "controller is in combined mode, can't enable AHCI mode\n");
1779c4f7792cSTejun Heo 			return -ENODEV;
1780c4f7792cSTejun Heo 		}
1781c4f7792cSTejun Heo 	}
1782c4f7792cSTejun Heo 
17836fec8871SPaul Bolle 	/* AHCI controllers often implement SFF compatible interface.
17846fec8871SPaul Bolle 	 * Grab all PCI BARs just in case.
17856fec8871SPaul Bolle 	 */
17866fec8871SPaul Bolle 	rc = pcim_iomap_regions_request_all(pdev, 1 << ahci_pci_bar, DRV_NAME);
17876fec8871SPaul Bolle 	if (rc == -EBUSY)
17886fec8871SPaul Bolle 		pcim_pin_device(pdev);
17896fec8871SPaul Bolle 	if (rc)
17906fec8871SPaul Bolle 		return rc;
17916fec8871SPaul Bolle 
179224dc5f33STejun Heo 	hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
179324dc5f33STejun Heo 	if (!hpriv)
179424dc5f33STejun Heo 		return -ENOMEM;
1795417a1a6dSTejun Heo 	hpriv->flags |= (unsigned long)pi.private_data;
1796417a1a6dSTejun Heo 
1797e297d99eSTejun Heo 	/* MCP65 revision A1 and A2 can't do MSI */
1798e297d99eSTejun Heo 	if (board_id == board_ahci_mcp65 &&
1799e297d99eSTejun Heo 	    (pdev->revision == 0xa1 || pdev->revision == 0xa2))
1800e297d99eSTejun Heo 		hpriv->flags |= AHCI_HFLAG_NO_MSI;
1801e297d99eSTejun Heo 
1802e427fe04SShane Huang 	/* SB800 does NOT need the workaround to ignore SERR_INTERNAL */
1803e427fe04SShane Huang 	if (board_id == board_ahci_sb700 && pdev->revision >= 0x40)
1804e427fe04SShane Huang 		hpriv->flags &= ~AHCI_HFLAG_IGN_SERR_INTERNAL;
1805e427fe04SShane Huang 
18062fcad9d2STejun Heo 	/* only some SB600s can do 64bit DMA */
18072fcad9d2STejun Heo 	if (ahci_sb600_enable_64bit(pdev))
18082fcad9d2STejun Heo 		hpriv->flags &= ~AHCI_HFLAG_32BIT_ONLY;
180958a09b38SShane Huang 
1810318893e1SAlessandro Rubini 	hpriv->mmio = pcim_iomap_table(pdev)[ahci_pci_bar];
1811d8993349SAnton Vorontsov 
1812aecec8b6SChristoph Hellwig 	/* detect remapped nvme devices */
1813aecec8b6SChristoph Hellwig 	ahci_remap_check(pdev, ahci_pci_bar, hpriv);
1814aecec8b6SChristoph Hellwig 
1815894fba7fSKai-Heng Feng 	sysfs_add_file_to_group(&pdev->dev.kobj,
1816894fba7fSKai-Heng Feng 				&dev_attr_remapped_nvme.attr,
1817894fba7fSKai-Heng Feng 				NULL);
1818894fba7fSKai-Heng Feng 
18190cf4a7d6SJacob Pan 	/* must set flag prior to save config in order to take effect */
18200cf4a7d6SJacob Pan 	if (ahci_broken_devslp(pdev))
18210cf4a7d6SJacob Pan 		hpriv->flags |= AHCI_HFLAG_NO_DEVSLP;
18220cf4a7d6SJacob Pan 
1823d243bed3STirumalesh Chalamarla #ifdef CONFIG_ARM64
1824234e6d2cSXingui Yang 	if (pdev->vendor == PCI_VENDOR_ID_HUAWEI &&
1825234e6d2cSXingui Yang 	    pdev->device == 0xa235 &&
1826234e6d2cSXingui Yang 	    pdev->revision < 0x30)
1827234e6d2cSXingui Yang 		hpriv->flags |= AHCI_HFLAG_NO_SXS;
1828234e6d2cSXingui Yang 
1829d243bed3STirumalesh Chalamarla 	if (pdev->vendor == 0x177d && pdev->device == 0xa01c)
1830d243bed3STirumalesh Chalamarla 		hpriv->irq_handler = ahci_thunderx_irq_handler;
1831d243bed3STirumalesh Chalamarla #endif
1832d243bed3STirumalesh Chalamarla 
18334447d351STejun Heo 	/* save initial config */
1834394d6e53SAnton Vorontsov 	ahci_pci_save_initial_config(pdev, hpriv);
1835c6fd2807SJeff Garzik 
18364447d351STejun Heo 	/* prepare host */
1837453d3131SRobert Hancock 	if (hpriv->cap & HOST_CAP_NCQ) {
1838453d3131SRobert Hancock 		pi.flags |= ATA_FLAG_NCQ;
183983f2b963STejun Heo 		/*
184083f2b963STejun Heo 		 * Auto-activate optimization is supposed to be
184183f2b963STejun Heo 		 * supported on all AHCI controllers indicating NCQ
184283f2b963STejun Heo 		 * capability, but it seems to be broken on some
184383f2b963STejun Heo 		 * chipsets including NVIDIAs.
184483f2b963STejun Heo 		 */
184583f2b963STejun Heo 		if (!(hpriv->flags & AHCI_HFLAG_NO_FPDMA_AA))
1846453d3131SRobert Hancock 			pi.flags |= ATA_FLAG_FPDMA_AA;
184740fb59e7SMarc Carino 
184840fb59e7SMarc Carino 		/*
184940fb59e7SMarc Carino 		 * All AHCI controllers should be forward-compatible
185040fb59e7SMarc Carino 		 * with the new auxiliary field. This code should be
185140fb59e7SMarc Carino 		 * conditionalized if any buggy AHCI controllers are
185240fb59e7SMarc Carino 		 * encountered.
185340fb59e7SMarc Carino 		 */
185440fb59e7SMarc Carino 		pi.flags |= ATA_FLAG_FPDMA_AUX;
1855453d3131SRobert Hancock 	}
18564447d351STejun Heo 
18577d50b60bSTejun Heo 	if (hpriv->cap & HOST_CAP_PMP)
18587d50b60bSTejun Heo 		pi.flags |= ATA_FLAG_PMP;
18597d50b60bSTejun Heo 
18600cbb0e77SAnton Vorontsov 	ahci_set_em_messages(hpriv, &pi);
186118f7ba4cSKristen Carlson Accardi 
18621fd68434SRafael J. Wysocki 	if (ahci_broken_system_poweroff(pdev)) {
18631fd68434SRafael J. Wysocki 		pi.flags |= ATA_FLAG_NO_POWEROFF_SPINDOWN;
18641fd68434SRafael J. Wysocki 		dev_info(&pdev->dev,
18651fd68434SRafael J. Wysocki 			"quirky BIOS, skipping spindown on poweroff\n");
18661fd68434SRafael J. Wysocki 	}
18671fd68434SRafael J. Wysocki 
1868240630e6SHans de Goede 	if (ahci_broken_lpm(pdev)) {
1869240630e6SHans de Goede 		pi.flags |= ATA_FLAG_NO_LPM;
1870240630e6SHans de Goede 		dev_warn(&pdev->dev,
1871240630e6SHans de Goede 			 "BIOS update required for Link Power Management support\n");
1872240630e6SHans de Goede 	}
1873240630e6SHans de Goede 
18749b10ae86STejun Heo 	if (ahci_broken_suspend(pdev)) {
18759b10ae86STejun Heo 		hpriv->flags |= AHCI_HFLAG_NO_SUSPEND;
1876a44fec1fSJoe Perches 		dev_warn(&pdev->dev,
18779b10ae86STejun Heo 			 "BIOS update required for suspend/resume\n");
18789b10ae86STejun Heo 	}
18799b10ae86STejun Heo 
18805594639aSTejun Heo 	if (ahci_broken_online(pdev)) {
18815594639aSTejun Heo 		hpriv->flags |= AHCI_HFLAG_SRST_TOUT_IS_OFFLINE;
18825594639aSTejun Heo 		dev_info(&pdev->dev,
18835594639aSTejun Heo 			 "online status unreliable, applying workaround\n");
18845594639aSTejun Heo 	}
18855594639aSTejun Heo 
18868bfd1743SSui Chen 
18878bfd1743SSui Chen 	/* Acer SA5-271 workaround modifies private_data */
18888bfd1743SSui Chen 	acer_sa5_271_workaround(hpriv, pdev);
18898bfd1743SSui Chen 
1890837f5f8fSTejun Heo 	/* CAP.NP sometimes indicate the index of the last enabled
1891837f5f8fSTejun Heo 	 * port, at other times, that of the last possible port, so
1892837f5f8fSTejun Heo 	 * determining the maximum port number requires looking at
1893837f5f8fSTejun Heo 	 * both CAP.NP and port_map.
1894837f5f8fSTejun Heo 	 */
1895837f5f8fSTejun Heo 	n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map));
1896837f5f8fSTejun Heo 
1897837f5f8fSTejun Heo 	host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);
18984447d351STejun Heo 	if (!host)
18994447d351STejun Heo 		return -ENOMEM;
19004447d351STejun Heo 	host->private_data = hpriv;
19010b9e2988SChristoph Hellwig 
19020b9e2988SChristoph Hellwig 	if (ahci_init_msi(pdev, n_ports, hpriv) < 0) {
19030b9e2988SChristoph Hellwig 		/* legacy intx interrupts */
19040b9e2988SChristoph Hellwig 		pci_intx(pdev, 1);
19050b9e2988SChristoph Hellwig 	}
19060ce57f8aSChristoph Hellwig 	hpriv->irq = pci_irq_vector(pdev, 0);
190721bfd1aaSRobert Richter 
1908f3d7f23fSArjan van de Ven 	if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss)
1909886ad09fSArjan van de Ven 		host->flags |= ATA_HOST_PARALLEL_SCAN;
1910f3d7f23fSArjan van de Ven 	else
1911d2782d96SJingoo Han 		dev_info(&pdev->dev, "SSS flag set, parallel bus scan disabled\n");
1912886ad09fSArjan van de Ven 
191324e0e61dSNiklas Cassel 	if (!(hpriv->cap & HOST_CAP_PART))
191424e0e61dSNiklas Cassel 		host->flags |= ATA_HOST_NO_PART;
191524e0e61dSNiklas Cassel 
191624e0e61dSNiklas Cassel 	if (!(hpriv->cap & HOST_CAP_SSC))
191724e0e61dSNiklas Cassel 		host->flags |= ATA_HOST_NO_SSC;
191824e0e61dSNiklas Cassel 
191924e0e61dSNiklas Cassel 	if (!(hpriv->cap2 & HOST_CAP2_SDS))
192024e0e61dSNiklas Cassel 		host->flags |= ATA_HOST_NO_DEVSLP;
192124e0e61dSNiklas Cassel 
192218f7ba4cSKristen Carlson Accardi 	if (pi.flags & ATA_FLAG_EM)
192318f7ba4cSKristen Carlson Accardi 		ahci_reset_em(host);
192418f7ba4cSKristen Carlson Accardi 
19254447d351STejun Heo 	for (i = 0; i < host->n_ports; i++) {
19264447d351STejun Heo 		struct ata_port *ap = host->ports[i];
19274447d351STejun Heo 
1928318893e1SAlessandro Rubini 		ata_port_pbar_desc(ap, ahci_pci_bar, -1, "abar");
1929318893e1SAlessandro Rubini 		ata_port_pbar_desc(ap, ahci_pci_bar,
1930cbcdd875STejun Heo 				   0x100 + ap->port_no * 0x80, "port");
1931cbcdd875STejun Heo 
193218f7ba4cSKristen Carlson Accardi 		/* set enclosure management message type */
193318f7ba4cSKristen Carlson Accardi 		if (ap->flags & ATA_FLAG_EM)
1934008dbd61SHarry Zhang 			ap->em_message_type = hpriv->em_msg_type;
193518f7ba4cSKristen Carlson Accardi 
1936b1a9585cSSrinivas Pandruvada 		ahci_update_initial_lpm_policy(ap, hpriv);
193718f7ba4cSKristen Carlson Accardi 
1938dab632e8SJeff Garzik 		/* disabled/not-implemented port */
1939350756f6STejun Heo 		if (!(hpriv->port_map & (1 << i)))
1940dab632e8SJeff Garzik 			ap->ops = &ata_dummy_port_ops;
19414447d351STejun Heo 	}
1942c6fd2807SJeff Garzik 
1943edc93052STejun Heo 	/* apply workaround for ASUS P5W DH Deluxe mainboard */
1944edc93052STejun Heo 	ahci_p5wdh_workaround(host);
1945edc93052STejun Heo 
1946f80ae7e4STejun Heo 	/* apply gtf filter quirk */
1947f80ae7e4STejun Heo 	ahci_gtf_filter_workaround(host);
1948f80ae7e4STejun Heo 
1949c6fd2807SJeff Garzik 	/* initialize adapter */
1950b0dd4d7aSLennert Buytenhek 	rc = ahci_configure_dma_masks(pdev, hpriv);
1951c6fd2807SJeff Garzik 	if (rc)
195224dc5f33STejun Heo 		return rc;
1953c6fd2807SJeff Garzik 
195437e14e4fSAdam Vodopjan 	rc = ahci_pci_reset_controller(host);
19554447d351STejun Heo 	if (rc)
19564447d351STejun Heo 		return rc;
1957c6fd2807SJeff Garzik 
1958781d6550SAnton Vorontsov 	ahci_pci_init_controller(host);
1959439fcaecSAnton Vorontsov 	ahci_pci_print_info(host);
1960c6fd2807SJeff Garzik 
19614447d351STejun Heo 	pci_set_master(pdev);
19625ca72c4fSAlexander Gordeev 
196302e53293SMika Westerberg 	rc = ahci_host_activate(host, &ahci_sht);
196402e53293SMika Westerberg 	if (rc)
196502e53293SMika Westerberg 		return rc;
196602e53293SMika Westerberg 
196702e53293SMika Westerberg 	pm_runtime_put_noidle(&pdev->dev);
196802e53293SMika Westerberg 	return 0;
196902e53293SMika Westerberg }
197002e53293SMika Westerberg 
197110a663a1SPrabhakar Kushwaha static void ahci_shutdown_one(struct pci_dev *pdev)
197210a663a1SPrabhakar Kushwaha {
197310a663a1SPrabhakar Kushwaha 	ata_pci_shutdown_one(pdev);
197410a663a1SPrabhakar Kushwaha }
197510a663a1SPrabhakar Kushwaha 
197602e53293SMika Westerberg static void ahci_remove_one(struct pci_dev *pdev)
197702e53293SMika Westerberg {
1978894fba7fSKai-Heng Feng 	sysfs_remove_file_from_group(&pdev->dev.kobj,
1979894fba7fSKai-Heng Feng 				     &dev_attr_remapped_nvme.attr,
1980894fba7fSKai-Heng Feng 				     NULL);
198102e53293SMika Westerberg 	pm_runtime_get_noresume(&pdev->dev);
198202e53293SMika Westerberg 	ata_pci_remove_one(pdev);
1983c6fd2807SJeff Garzik }
1984c6fd2807SJeff Garzik 
19852fc75da0SAxel Lin module_pci_driver(ahci_pci_driver);
1986c6fd2807SJeff Garzik 
1987c6fd2807SJeff Garzik MODULE_AUTHOR("Jeff Garzik");
1988c6fd2807SJeff Garzik MODULE_DESCRIPTION("AHCI SATA low-level driver");
1989c6fd2807SJeff Garzik MODULE_LICENSE("GPL");
1990c6fd2807SJeff Garzik MODULE_DEVICE_TABLE(pci, ahci_pci_tbl);
1991c6fd2807SJeff Garzik MODULE_VERSION(DRV_VERSION);
1992