xref: /openbmc/linux/drivers/ata/ahci.c (revision 179a028225c145171a2e95abbc69b579f72cdf5a)
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>
29ee2aad42SRobert Richter #include <linux/msi.h>
30c6fd2807SJeff Garzik #include <scsi/scsi_host.h>
31c6fd2807SJeff Garzik #include <scsi/scsi_cmnd.h>
32c6fd2807SJeff Garzik #include <linux/libata.h>
33aecec8b6SChristoph Hellwig #include <linux/ahci-remap.h>
34aecec8b6SChristoph Hellwig #include <linux/io-64-nonatomic-lo-hi.h>
35365cfa1eSAnton Vorontsov #include "ahci.h"
36c6fd2807SJeff Garzik 
37c6fd2807SJeff Garzik #define DRV_NAME	"ahci"
387d50b60bSTejun Heo #define DRV_VERSION	"3.0"
39c6fd2807SJeff Garzik 
40c6fd2807SJeff Garzik enum {
41318893e1SAlessandro Rubini 	AHCI_PCI_BAR_STA2X11	= 0,
42b7ae128dSRobert Richter 	AHCI_PCI_BAR_CAVIUM	= 0,
43e49bd683STiezhu Yang 	AHCI_PCI_BAR_LOONGSON	= 0,
447f9c9f8eSHugh Daschbach 	AHCI_PCI_BAR_ENMOTUS	= 2,
45b1314e3fSRadha Mohan Chintakuntla 	AHCI_PCI_BAR_CAVIUM_GEN5	= 4,
46318893e1SAlessandro Rubini 	AHCI_PCI_BAR_STANDARD	= 5,
47441577efSTejun Heo };
48c6fd2807SJeff Garzik 
49441577efSTejun Heo enum board_ids {
50441577efSTejun Heo 	/* board IDs by feature in alphabetical order */
51441577efSTejun Heo 	board_ahci,
52441577efSTejun Heo 	board_ahci_ign_iferr,
53ebb82e3cSHans de Goede 	board_ahci_mobile,
5466a7cbc3STejun Heo 	board_ahci_nomsi,
5567809f85SLevente Kurusa 	board_ahci_noncq,
56441577efSTejun Heo 	board_ahci_nosntf,
575f173107STejun Heo 	board_ahci_yes_fbs,
58441577efSTejun Heo 
59441577efSTejun Heo 	/* board IDs for specific chipsets in alphabetical order */
607d523bdcSHanna Hawa 	board_ahci_al,
61dbfe8ef5SDan Williams 	board_ahci_avn,
62441577efSTejun Heo 	board_ahci_mcp65,
6383f2b963STejun Heo 	board_ahci_mcp77,
6483f2b963STejun Heo 	board_ahci_mcp89,
65441577efSTejun Heo 	board_ahci_mv,
66441577efSTejun Heo 	board_ahci_sb600,
67441577efSTejun Heo 	board_ahci_sb700,	/* for SB700 and SB800 */
68441577efSTejun Heo 	board_ahci_vt8251,
69441577efSTejun Heo 
70c312ef17SDan Williams 	/*
71c312ef17SDan Williams 	 * board IDs for Intel chipsets that support more than 6 ports
72c312ef17SDan Williams 	 * *and* end up needing the PCS quirk.
73c312ef17SDan Williams 	 */
74c312ef17SDan Williams 	board_ahci_pcs7,
75c312ef17SDan Williams 
76441577efSTejun Heo 	/* aliases */
77441577efSTejun Heo 	board_ahci_mcp_linux	= board_ahci_mcp65,
78441577efSTejun Heo 	board_ahci_mcp67	= board_ahci_mcp65,
79441577efSTejun Heo 	board_ahci_mcp73	= board_ahci_mcp65,
8083f2b963STejun Heo 	board_ahci_mcp79	= board_ahci_mcp77,
81c6fd2807SJeff Garzik };
82c6fd2807SJeff Garzik 
83c6fd2807SJeff Garzik static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
8402e53293SMika Westerberg static void ahci_remove_one(struct pci_dev *dev);
8510a663a1SPrabhakar Kushwaha static void ahci_shutdown_one(struct pci_dev *dev);
86a1efdabaSTejun Heo static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
87a1efdabaSTejun Heo 				 unsigned long deadline);
88dbfe8ef5SDan Williams static int ahci_avn_hardreset(struct ata_link *link, unsigned int *class,
89dbfe8ef5SDan Williams 			      unsigned long deadline);
90cb85696dSJames Laird static void ahci_mcp89_apple_enable(struct pci_dev *pdev);
91cb85696dSJames Laird static bool is_mcp89_apple(struct pci_dev *pdev);
92a1efdabaSTejun Heo static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
93a1efdabaSTejun Heo 				unsigned long deadline);
9402e53293SMika Westerberg #ifdef CONFIG_PM
9502e53293SMika Westerberg static int ahci_pci_device_runtime_suspend(struct device *dev);
9602e53293SMika Westerberg static int ahci_pci_device_runtime_resume(struct device *dev);
97f1d848f9SMika Westerberg #ifdef CONFIG_PM_SLEEP
98f1d848f9SMika Westerberg static int ahci_pci_device_suspend(struct device *dev);
99f1d848f9SMika Westerberg static int ahci_pci_device_resume(struct device *dev);
100438ac6d5STejun Heo #endif
10102e53293SMika Westerberg #endif /* CONFIG_PM */
102c6fd2807SJeff Garzik 
103fad16e7aSTejun Heo static struct scsi_host_template ahci_sht = {
104fad16e7aSTejun Heo 	AHCI_SHT("ahci"),
105fad16e7aSTejun Heo };
106fad16e7aSTejun Heo 
107029cfd6bSTejun Heo static struct ata_port_operations ahci_vt8251_ops = {
108029cfd6bSTejun Heo 	.inherits		= &ahci_ops,
109a1efdabaSTejun Heo 	.hardreset		= ahci_vt8251_hardreset,
110ad616ffbSTejun Heo };
111ad616ffbSTejun Heo 
112029cfd6bSTejun Heo static struct ata_port_operations ahci_p5wdh_ops = {
113029cfd6bSTejun Heo 	.inherits		= &ahci_ops,
114a1efdabaSTejun Heo 	.hardreset		= ahci_p5wdh_hardreset,
115edc93052STejun Heo };
116edc93052STejun Heo 
117dbfe8ef5SDan Williams static struct ata_port_operations ahci_avn_ops = {
118dbfe8ef5SDan Williams 	.inherits		= &ahci_ops,
119dbfe8ef5SDan Williams 	.hardreset		= ahci_avn_hardreset,
120dbfe8ef5SDan Williams };
121dbfe8ef5SDan Williams 
122c6fd2807SJeff Garzik static const struct ata_port_info ahci_port_info[] = {
123441577efSTejun Heo 	/* by features */
124facb8fa6SJeffrin Jose 	[board_ahci] = {
1251188c0d8STejun Heo 		.flags		= AHCI_FLAG_COMMON,
12614bdef98SErik Inge Bolsø 		.pio_mask	= ATA_PIO4,
127469248abSJeff Garzik 		.udma_mask	= ATA_UDMA6,
128c6fd2807SJeff Garzik 		.port_ops	= &ahci_ops,
129c6fd2807SJeff Garzik 	},
130facb8fa6SJeffrin Jose 	[board_ahci_ign_iferr] = {
131417a1a6dSTejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_IGN_IRQ_IF_ERR),
132417a1a6dSTejun Heo 		.flags		= AHCI_FLAG_COMMON,
13314bdef98SErik Inge Bolsø 		.pio_mask	= ATA_PIO4,
134469248abSJeff Garzik 		.udma_mask	= ATA_UDMA6,
13541669553STejun Heo 		.port_ops	= &ahci_ops,
13641669553STejun Heo 	},
137ebb82e3cSHans de Goede 	[board_ahci_mobile] = {
138ebb82e3cSHans de Goede 		AHCI_HFLAGS	(AHCI_HFLAG_IS_MOBILE),
139ebb82e3cSHans de Goede 		.flags		= AHCI_FLAG_COMMON,
140ebb82e3cSHans de Goede 		.pio_mask	= ATA_PIO4,
141ebb82e3cSHans de Goede 		.udma_mask	= ATA_UDMA6,
142ebb82e3cSHans de Goede 		.port_ops	= &ahci_ops,
143ebb82e3cSHans de Goede 	},
14466a7cbc3STejun Heo 	[board_ahci_nomsi] = {
14566a7cbc3STejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_NO_MSI),
14666a7cbc3STejun Heo 		.flags		= AHCI_FLAG_COMMON,
14766a7cbc3STejun Heo 		.pio_mask	= ATA_PIO4,
14866a7cbc3STejun Heo 		.udma_mask	= ATA_UDMA6,
14966a7cbc3STejun Heo 		.port_ops	= &ahci_ops,
15066a7cbc3STejun Heo 	},
15167809f85SLevente Kurusa 	[board_ahci_noncq] = {
15267809f85SLevente Kurusa 		AHCI_HFLAGS	(AHCI_HFLAG_NO_NCQ),
15367809f85SLevente Kurusa 		.flags		= AHCI_FLAG_COMMON,
15467809f85SLevente Kurusa 		.pio_mask	= ATA_PIO4,
15567809f85SLevente Kurusa 		.udma_mask	= ATA_UDMA6,
15667809f85SLevente Kurusa 		.port_ops	= &ahci_ops,
15767809f85SLevente Kurusa 	},
158facb8fa6SJeffrin Jose 	[board_ahci_nosntf] = {
159441577efSTejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_NO_SNTF),
160441577efSTejun Heo 		.flags		= AHCI_FLAG_COMMON,
161441577efSTejun Heo 		.pio_mask	= ATA_PIO4,
162441577efSTejun Heo 		.udma_mask	= ATA_UDMA6,
163441577efSTejun Heo 		.port_ops	= &ahci_ops,
164441577efSTejun Heo 	},
165facb8fa6SJeffrin Jose 	[board_ahci_yes_fbs] = {
1665f173107STejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_YES_FBS),
1675f173107STejun Heo 		.flags		= AHCI_FLAG_COMMON,
1685f173107STejun Heo 		.pio_mask	= ATA_PIO4,
1695f173107STejun Heo 		.udma_mask	= ATA_UDMA6,
1705f173107STejun Heo 		.port_ops	= &ahci_ops,
1715f173107STejun Heo 	},
172441577efSTejun Heo 	/* by chipsets */
1737d523bdcSHanna Hawa 	[board_ahci_al] = {
1747d523bdcSHanna Hawa 		AHCI_HFLAGS	(AHCI_HFLAG_NO_PMP | AHCI_HFLAG_NO_MSI),
1757d523bdcSHanna Hawa 		.flags		= AHCI_FLAG_COMMON,
1767d523bdcSHanna Hawa 		.pio_mask	= ATA_PIO4,
1777d523bdcSHanna Hawa 		.udma_mask	= ATA_UDMA6,
1787d523bdcSHanna Hawa 		.port_ops	= &ahci_ops,
1797d523bdcSHanna Hawa 	},
180dbfe8ef5SDan Williams 	[board_ahci_avn] = {
181dbfe8ef5SDan Williams 		.flags		= AHCI_FLAG_COMMON,
182dbfe8ef5SDan Williams 		.pio_mask	= ATA_PIO4,
183dbfe8ef5SDan Williams 		.udma_mask	= ATA_UDMA6,
184dbfe8ef5SDan Williams 		.port_ops	= &ahci_avn_ops,
185dbfe8ef5SDan Williams 	},
186facb8fa6SJeffrin Jose 	[board_ahci_mcp65] = {
18783f2b963STejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_NO_FPDMA_AA | AHCI_HFLAG_NO_PMP |
18883f2b963STejun Heo 				 AHCI_HFLAG_YES_NCQ),
189ae01b249STejun Heo 		.flags		= AHCI_FLAG_COMMON | ATA_FLAG_NO_DIPM,
19083f2b963STejun Heo 		.pio_mask	= ATA_PIO4,
19183f2b963STejun Heo 		.udma_mask	= ATA_UDMA6,
19283f2b963STejun Heo 		.port_ops	= &ahci_ops,
19383f2b963STejun Heo 	},
194facb8fa6SJeffrin Jose 	[board_ahci_mcp77] = {
19583f2b963STejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_NO_FPDMA_AA | AHCI_HFLAG_NO_PMP),
19683f2b963STejun Heo 		.flags		= AHCI_FLAG_COMMON,
19783f2b963STejun Heo 		.pio_mask	= ATA_PIO4,
19883f2b963STejun Heo 		.udma_mask	= ATA_UDMA6,
19983f2b963STejun Heo 		.port_ops	= &ahci_ops,
20083f2b963STejun Heo 	},
201facb8fa6SJeffrin Jose 	[board_ahci_mcp89] = {
20283f2b963STejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_NO_FPDMA_AA),
203441577efSTejun Heo 		.flags		= AHCI_FLAG_COMMON,
204441577efSTejun Heo 		.pio_mask	= ATA_PIO4,
205441577efSTejun Heo 		.udma_mask	= ATA_UDMA6,
206441577efSTejun Heo 		.port_ops	= &ahci_ops,
207441577efSTejun Heo 	},
208facb8fa6SJeffrin Jose 	[board_ahci_mv] = {
209441577efSTejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_MSI |
210441577efSTejun Heo 				 AHCI_HFLAG_MV_PATA | AHCI_HFLAG_NO_PMP),
2119cbe056fSSergei Shtylyov 		.flags		= ATA_FLAG_SATA | ATA_FLAG_PIO_DMA,
212441577efSTejun Heo 		.pio_mask	= ATA_PIO4,
213441577efSTejun Heo 		.udma_mask	= ATA_UDMA6,
214441577efSTejun Heo 		.port_ops	= &ahci_ops,
215441577efSTejun Heo 	},
216facb8fa6SJeffrin Jose 	[board_ahci_sb600] = {
217417a1a6dSTejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_IGN_SERR_INTERNAL |
2182fcad9d2STejun Heo 				 AHCI_HFLAG_NO_MSI | AHCI_HFLAG_SECT255 |
2192fcad9d2STejun Heo 				 AHCI_HFLAG_32BIT_ONLY),
220417a1a6dSTejun Heo 		.flags		= AHCI_FLAG_COMMON,
22114bdef98SErik Inge Bolsø 		.pio_mask	= ATA_PIO4,
222469248abSJeff Garzik 		.udma_mask	= ATA_UDMA6,
223345347c5SYuan-Hsin Chen 		.port_ops	= &ahci_pmp_retry_srst_ops,
22455a61604SConke Hu 	},
225facb8fa6SJeffrin Jose 	[board_ahci_sb700] = {	/* for SB700 and SB800 */
226bd17243aSShane Huang 		AHCI_HFLAGS	(AHCI_HFLAG_IGN_SERR_INTERNAL),
227e39fc8c9SShane Huang 		.flags		= AHCI_FLAG_COMMON,
22814bdef98SErik Inge Bolsø 		.pio_mask	= ATA_PIO4,
229e39fc8c9SShane Huang 		.udma_mask	= ATA_UDMA6,
230345347c5SYuan-Hsin Chen 		.port_ops	= &ahci_pmp_retry_srst_ops,
231e39fc8c9SShane Huang 	},
232facb8fa6SJeffrin Jose 	[board_ahci_vt8251] = {
233441577efSTejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_PMP),
234e297d99eSTejun Heo 		.flags		= AHCI_FLAG_COMMON,
23514bdef98SErik Inge Bolsø 		.pio_mask	= ATA_PIO4,
236e297d99eSTejun Heo 		.udma_mask	= ATA_UDMA6,
237441577efSTejun Heo 		.port_ops	= &ahci_vt8251_ops,
2381b677afdSShaohua Li 	},
239c312ef17SDan Williams 	[board_ahci_pcs7] = {
240c312ef17SDan Williams 		.flags		= AHCI_FLAG_COMMON,
241c312ef17SDan Williams 		.pio_mask	= ATA_PIO4,
242c312ef17SDan Williams 		.udma_mask	= ATA_UDMA6,
243c312ef17SDan Williams 		.port_ops	= &ahci_ops,
244c312ef17SDan Williams 	},
245c6fd2807SJeff Garzik };
246c6fd2807SJeff Garzik 
247c6fd2807SJeff Garzik static const struct pci_device_id ahci_pci_tbl[] = {
248c6fd2807SJeff Garzik 	/* Intel */
2495e125d13SMika Westerberg 	{ PCI_VDEVICE(INTEL, 0x06d6), board_ahci }, /* Comet Lake PCH-H RAID */
25054bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2652), board_ahci }, /* ICH6 */
25154bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2653), board_ahci }, /* ICH6M */
25254bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c1), board_ahci }, /* ICH7 */
25354bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c5), board_ahci }, /* ICH7M */
25454bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c3), board_ahci }, /* ICH7R */
25582490c09STejun Heo 	{ PCI_VDEVICE(AL, 0x5288), board_ahci_ign_iferr }, /* ULi M5288 */
25654bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2681), board_ahci }, /* ESB2 */
25754bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2682), board_ahci }, /* ESB2 */
25854bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2683), board_ahci }, /* ESB2 */
25954bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c6), board_ahci }, /* ICH7-M DH */
2607a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2821), board_ahci }, /* ICH8 */
2610e96dc47SKrzysztof Kozlowski 	{ PCI_VDEVICE(INTEL, 0x2822), board_ahci_nosntf }, /* ICH8/Lewisburg RAID*/
2627a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2824), board_ahci }, /* ICH8 */
2637a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2829), board_ahci }, /* ICH8M */
2647a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x282a), board_ahci }, /* ICH8M */
2657a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2922), board_ahci }, /* ICH9 */
2667a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2923), board_ahci }, /* ICH9 */
2677a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2924), board_ahci }, /* ICH9 */
2687a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2925), board_ahci }, /* ICH9 */
2697a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2927), board_ahci }, /* ICH9 */
270ebb82e3cSHans de Goede 	{ PCI_VDEVICE(INTEL, 0x2929), board_ahci_mobile }, /* ICH9M */
271ebb82e3cSHans de Goede 	{ PCI_VDEVICE(INTEL, 0x292a), board_ahci_mobile }, /* ICH9M */
272ebb82e3cSHans de Goede 	{ PCI_VDEVICE(INTEL, 0x292b), board_ahci_mobile }, /* ICH9M */
273ebb82e3cSHans de Goede 	{ PCI_VDEVICE(INTEL, 0x292c), board_ahci_mobile }, /* ICH9M */
274ebb82e3cSHans de Goede 	{ PCI_VDEVICE(INTEL, 0x292f), board_ahci_mobile }, /* ICH9M */
2757a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x294d), board_ahci }, /* ICH9 */
276ebb82e3cSHans de Goede 	{ PCI_VDEVICE(INTEL, 0x294e), board_ahci_mobile }, /* ICH9M */
277d4155e6fSJason Gaston 	{ PCI_VDEVICE(INTEL, 0x502a), board_ahci }, /* Tolapai */
278d4155e6fSJason Gaston 	{ PCI_VDEVICE(INTEL, 0x502b), board_ahci }, /* Tolapai */
27916ad1ad9SJason Gaston 	{ PCI_VDEVICE(INTEL, 0x3a05), board_ahci }, /* ICH10 */
280b2dde6afSMark Goodwin 	{ PCI_VDEVICE(INTEL, 0x3a22), board_ahci }, /* ICH10 */
28116ad1ad9SJason Gaston 	{ PCI_VDEVICE(INTEL, 0x3a25), board_ahci }, /* ICH10 */
282c1f57d9bSDavid Milburn 	{ PCI_VDEVICE(INTEL, 0x3b22), board_ahci }, /* PCH AHCI */
283c1f57d9bSDavid Milburn 	{ PCI_VDEVICE(INTEL, 0x3b23), board_ahci }, /* PCH AHCI */
284adcb5308SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x3b24), board_ahci }, /* PCH RAID */
2858e48b6b3SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x3b25), board_ahci }, /* PCH RAID */
286ebb82e3cSHans de Goede 	{ PCI_VDEVICE(INTEL, 0x3b29), board_ahci_mobile }, /* PCH M AHCI */
287adcb5308SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x3b2b), board_ahci }, /* PCH RAID */
288ebb82e3cSHans de Goede 	{ PCI_VDEVICE(INTEL, 0x3b2c), board_ahci_mobile }, /* PCH M RAID */
289c1f57d9bSDavid Milburn 	{ PCI_VDEVICE(INTEL, 0x3b2f), board_ahci }, /* PCH AHCI */
290c312ef17SDan Williams 	{ PCI_VDEVICE(INTEL, 0x19b0), board_ahci_pcs7 }, /* DNV AHCI */
291c312ef17SDan Williams 	{ PCI_VDEVICE(INTEL, 0x19b1), board_ahci_pcs7 }, /* DNV AHCI */
292c312ef17SDan Williams 	{ PCI_VDEVICE(INTEL, 0x19b2), board_ahci_pcs7 }, /* DNV AHCI */
293c312ef17SDan Williams 	{ PCI_VDEVICE(INTEL, 0x19b3), board_ahci_pcs7 }, /* DNV AHCI */
294c312ef17SDan Williams 	{ PCI_VDEVICE(INTEL, 0x19b4), board_ahci_pcs7 }, /* DNV AHCI */
295c312ef17SDan Williams 	{ PCI_VDEVICE(INTEL, 0x19b5), board_ahci_pcs7 }, /* DNV AHCI */
296c312ef17SDan Williams 	{ PCI_VDEVICE(INTEL, 0x19b6), board_ahci_pcs7 }, /* DNV AHCI */
297c312ef17SDan Williams 	{ PCI_VDEVICE(INTEL, 0x19b7), board_ahci_pcs7 }, /* DNV AHCI */
298c312ef17SDan Williams 	{ PCI_VDEVICE(INTEL, 0x19bE), board_ahci_pcs7 }, /* DNV AHCI */
299c312ef17SDan Williams 	{ PCI_VDEVICE(INTEL, 0x19bF), board_ahci_pcs7 }, /* DNV AHCI */
300c312ef17SDan Williams 	{ PCI_VDEVICE(INTEL, 0x19c0), board_ahci_pcs7 }, /* DNV AHCI */
301c312ef17SDan Williams 	{ PCI_VDEVICE(INTEL, 0x19c1), board_ahci_pcs7 }, /* DNV AHCI */
302c312ef17SDan Williams 	{ PCI_VDEVICE(INTEL, 0x19c2), board_ahci_pcs7 }, /* DNV AHCI */
303c312ef17SDan Williams 	{ PCI_VDEVICE(INTEL, 0x19c3), board_ahci_pcs7 }, /* DNV AHCI */
304c312ef17SDan Williams 	{ PCI_VDEVICE(INTEL, 0x19c4), board_ahci_pcs7 }, /* DNV AHCI */
305c312ef17SDan Williams 	{ PCI_VDEVICE(INTEL, 0x19c5), board_ahci_pcs7 }, /* DNV AHCI */
306c312ef17SDan Williams 	{ PCI_VDEVICE(INTEL, 0x19c6), board_ahci_pcs7 }, /* DNV AHCI */
307c312ef17SDan Williams 	{ PCI_VDEVICE(INTEL, 0x19c7), board_ahci_pcs7 }, /* DNV AHCI */
308c312ef17SDan Williams 	{ PCI_VDEVICE(INTEL, 0x19cE), board_ahci_pcs7 }, /* DNV AHCI */
309c312ef17SDan Williams 	{ PCI_VDEVICE(INTEL, 0x19cF), board_ahci_pcs7 }, /* DNV AHCI */
3105623cab8SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1c02), board_ahci }, /* CPT AHCI */
311ebb82e3cSHans de Goede 	{ PCI_VDEVICE(INTEL, 0x1c03), board_ahci_mobile }, /* CPT M AHCI */
3125623cab8SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1c04), board_ahci }, /* CPT RAID */
313ebb82e3cSHans de Goede 	{ PCI_VDEVICE(INTEL, 0x1c05), board_ahci_mobile }, /* CPT M RAID */
3145623cab8SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1c06), board_ahci }, /* CPT RAID */
3155623cab8SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1c07), board_ahci }, /* CPT RAID */
316992b3fb9SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1d02), board_ahci }, /* PBG AHCI */
317992b3fb9SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1d04), board_ahci }, /* PBG RAID */
318992b3fb9SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1d06), board_ahci }, /* PBG RAID */
3190e96dc47SKrzysztof Kozlowski 	{ PCI_VDEVICE(INTEL, 0x2826), board_ahci }, /* PBG/Lewisburg RAID*/
320a4a461a6SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x2323), board_ahci }, /* DH89xxCC AHCI */
321181e3ceaSSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1e02), board_ahci }, /* Panther Point AHCI */
322ebb82e3cSHans de Goede 	{ PCI_VDEVICE(INTEL, 0x1e03), board_ahci_mobile }, /* Panther M AHCI */
323181e3ceaSSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1e04), board_ahci }, /* Panther Point RAID */
324181e3ceaSSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1e05), board_ahci }, /* Panther Point RAID */
325181e3ceaSSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1e06), board_ahci }, /* Panther Point RAID */
326ebb82e3cSHans de Goede 	{ PCI_VDEVICE(INTEL, 0x1e07), board_ahci_mobile }, /* Panther M RAID */
3272cab7a4cSSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1e0e), board_ahci }, /* Panther Point RAID */
328ea4ace66SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x8c02), board_ahci }, /* Lynx Point AHCI */
329ebb82e3cSHans de Goede 	{ PCI_VDEVICE(INTEL, 0x8c03), board_ahci_mobile }, /* Lynx M AHCI */
330ea4ace66SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x8c04), board_ahci }, /* Lynx Point RAID */
331ebb82e3cSHans de Goede 	{ PCI_VDEVICE(INTEL, 0x8c05), board_ahci_mobile }, /* Lynx M RAID */
332ea4ace66SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x8c06), board_ahci }, /* Lynx Point RAID */
333ebb82e3cSHans de Goede 	{ PCI_VDEVICE(INTEL, 0x8c07), board_ahci_mobile }, /* Lynx M RAID */
334ea4ace66SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x8c0e), board_ahci }, /* Lynx Point RAID */
335ebb82e3cSHans de Goede 	{ PCI_VDEVICE(INTEL, 0x8c0f), board_ahci_mobile }, /* Lynx M RAID */
336ebb82e3cSHans de Goede 	{ PCI_VDEVICE(INTEL, 0x9c02), board_ahci_mobile }, /* Lynx LP AHCI */
337ebb82e3cSHans de Goede 	{ PCI_VDEVICE(INTEL, 0x9c03), board_ahci_mobile }, /* Lynx LP AHCI */
338ebb82e3cSHans de Goede 	{ PCI_VDEVICE(INTEL, 0x9c04), board_ahci_mobile }, /* Lynx LP RAID */
339ebb82e3cSHans de Goede 	{ PCI_VDEVICE(INTEL, 0x9c05), board_ahci_mobile }, /* Lynx LP RAID */
340ebb82e3cSHans de Goede 	{ PCI_VDEVICE(INTEL, 0x9c06), board_ahci_mobile }, /* Lynx LP RAID */
341ebb82e3cSHans de Goede 	{ PCI_VDEVICE(INTEL, 0x9c07), board_ahci_mobile }, /* Lynx LP RAID */
342ebb82e3cSHans de Goede 	{ PCI_VDEVICE(INTEL, 0x9c0e), board_ahci_mobile }, /* Lynx LP RAID */
343ebb82e3cSHans de Goede 	{ PCI_VDEVICE(INTEL, 0x9c0f), board_ahci_mobile }, /* Lynx LP RAID */
3444544e403SMika Westerberg 	{ PCI_VDEVICE(INTEL, 0x9dd3), board_ahci_mobile }, /* Cannon Lake PCH-LP AHCI */
34529e674ddSSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1f22), board_ahci }, /* Avoton AHCI */
34629e674ddSSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1f23), board_ahci }, /* Avoton AHCI */
34729e674ddSSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1f24), board_ahci }, /* Avoton RAID */
34829e674ddSSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1f25), board_ahci }, /* Avoton RAID */
34929e674ddSSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1f26), board_ahci }, /* Avoton RAID */
35029e674ddSSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1f27), board_ahci }, /* Avoton RAID */
35129e674ddSSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1f2e), board_ahci }, /* Avoton RAID */
35229e674ddSSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1f2f), board_ahci }, /* Avoton RAID */
353dbfe8ef5SDan Williams 	{ PCI_VDEVICE(INTEL, 0x1f32), board_ahci_avn }, /* Avoton AHCI */
354dbfe8ef5SDan Williams 	{ PCI_VDEVICE(INTEL, 0x1f33), board_ahci_avn }, /* Avoton AHCI */
355dbfe8ef5SDan Williams 	{ PCI_VDEVICE(INTEL, 0x1f34), board_ahci_avn }, /* Avoton RAID */
356dbfe8ef5SDan Williams 	{ PCI_VDEVICE(INTEL, 0x1f35), board_ahci_avn }, /* Avoton RAID */
357dbfe8ef5SDan Williams 	{ PCI_VDEVICE(INTEL, 0x1f36), board_ahci_avn }, /* Avoton RAID */
358dbfe8ef5SDan Williams 	{ PCI_VDEVICE(INTEL, 0x1f37), board_ahci_avn }, /* Avoton RAID */
359dbfe8ef5SDan Williams 	{ PCI_VDEVICE(INTEL, 0x1f3e), board_ahci_avn }, /* Avoton RAID */
360dbfe8ef5SDan Williams 	{ PCI_VDEVICE(INTEL, 0x1f3f), board_ahci_avn }, /* Avoton RAID */
3610e96dc47SKrzysztof Kozlowski 	{ PCI_VDEVICE(INTEL, 0x2823), board_ahci }, /* Wellsburg/Lewisburg AHCI*/
3620e96dc47SKrzysztof Kozlowski 	{ PCI_VDEVICE(INTEL, 0x2827), board_ahci }, /* Wellsburg/Lewisburg RAID*/
3638e85f605SMika Westerberg 	{ PCI_VDEVICE(INTEL, 0x43d4), board_ahci }, /* Rocket Lake PCH-H RAID */
3648e85f605SMika Westerberg 	{ PCI_VDEVICE(INTEL, 0x43d5), board_ahci }, /* Rocket Lake PCH-H RAID */
3658e85f605SMika Westerberg 	{ PCI_VDEVICE(INTEL, 0x43d6), board_ahci }, /* Rocket Lake PCH-H RAID */
3668e85f605SMika Westerberg 	{ PCI_VDEVICE(INTEL, 0x43d7), board_ahci }, /* Rocket Lake PCH-H RAID */
367151743fdSJames Ralston 	{ PCI_VDEVICE(INTEL, 0x8d02), board_ahci }, /* Wellsburg AHCI */
368151743fdSJames Ralston 	{ PCI_VDEVICE(INTEL, 0x8d04), board_ahci }, /* Wellsburg RAID */
369151743fdSJames Ralston 	{ PCI_VDEVICE(INTEL, 0x8d06), board_ahci }, /* Wellsburg RAID */
370151743fdSJames Ralston 	{ PCI_VDEVICE(INTEL, 0x8d0e), board_ahci }, /* Wellsburg RAID */
371151743fdSJames Ralston 	{ PCI_VDEVICE(INTEL, 0x8d62), board_ahci }, /* Wellsburg AHCI */
372151743fdSJames Ralston 	{ PCI_VDEVICE(INTEL, 0x8d64), board_ahci }, /* Wellsburg RAID */
373151743fdSJames Ralston 	{ PCI_VDEVICE(INTEL, 0x8d66), board_ahci }, /* Wellsburg RAID */
374151743fdSJames Ralston 	{ PCI_VDEVICE(INTEL, 0x8d6e), board_ahci }, /* Wellsburg RAID */
3751cfc7df3SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x23a3), board_ahci }, /* Coleto Creek AHCI */
376ebb82e3cSHans de Goede 	{ PCI_VDEVICE(INTEL, 0x9c83), board_ahci_mobile }, /* Wildcat LP AHCI */
377ebb82e3cSHans de Goede 	{ PCI_VDEVICE(INTEL, 0x9c85), board_ahci_mobile }, /* Wildcat LP RAID */
378ebb82e3cSHans de Goede 	{ PCI_VDEVICE(INTEL, 0x9c87), board_ahci_mobile }, /* Wildcat LP RAID */
379ebb82e3cSHans de Goede 	{ PCI_VDEVICE(INTEL, 0x9c8f), board_ahci_mobile }, /* Wildcat LP RAID */
3801b071a09SJames Ralston 	{ PCI_VDEVICE(INTEL, 0x8c82), board_ahci }, /* 9 Series AHCI */
381ebb82e3cSHans de Goede 	{ PCI_VDEVICE(INTEL, 0x8c83), board_ahci_mobile }, /* 9 Series M AHCI */
3821b071a09SJames Ralston 	{ PCI_VDEVICE(INTEL, 0x8c84), board_ahci }, /* 9 Series RAID */
383ebb82e3cSHans de Goede 	{ PCI_VDEVICE(INTEL, 0x8c85), board_ahci_mobile }, /* 9 Series M RAID */
3841b071a09SJames Ralston 	{ PCI_VDEVICE(INTEL, 0x8c86), board_ahci }, /* 9 Series RAID */
385ebb82e3cSHans de Goede 	{ PCI_VDEVICE(INTEL, 0x8c87), board_ahci_mobile }, /* 9 Series M RAID */
3861b071a09SJames Ralston 	{ PCI_VDEVICE(INTEL, 0x8c8e), board_ahci }, /* 9 Series RAID */
387ebb82e3cSHans de Goede 	{ PCI_VDEVICE(INTEL, 0x8c8f), board_ahci_mobile }, /* 9 Series M RAID */
388ebb82e3cSHans de Goede 	{ PCI_VDEVICE(INTEL, 0x9d03), board_ahci_mobile }, /* Sunrise LP AHCI */
389ebb82e3cSHans de Goede 	{ PCI_VDEVICE(INTEL, 0x9d05), board_ahci_mobile }, /* Sunrise LP RAID */
390ebb82e3cSHans de Goede 	{ PCI_VDEVICE(INTEL, 0x9d07), board_ahci_mobile }, /* Sunrise LP RAID */
391c5967b79SCharles_Rose@Dell.com 	{ PCI_VDEVICE(INTEL, 0xa102), board_ahci }, /* Sunrise Point-H AHCI */
392ebb82e3cSHans de Goede 	{ PCI_VDEVICE(INTEL, 0xa103), board_ahci_mobile }, /* Sunrise M AHCI */
393690000b9SJames Ralston 	{ PCI_VDEVICE(INTEL, 0xa105), board_ahci }, /* Sunrise Point-H RAID */
394c5967b79SCharles_Rose@Dell.com 	{ PCI_VDEVICE(INTEL, 0xa106), board_ahci }, /* Sunrise Point-H RAID */
395ebb82e3cSHans de Goede 	{ PCI_VDEVICE(INTEL, 0xa107), board_ahci_mobile }, /* Sunrise M RAID */
396690000b9SJames Ralston 	{ PCI_VDEVICE(INTEL, 0xa10f), board_ahci }, /* Sunrise Point-H RAID */
3974d92f009SAlexandra Yates 	{ PCI_VDEVICE(INTEL, 0xa182), board_ahci }, /* Lewisburg AHCI*/
3984d92f009SAlexandra Yates 	{ PCI_VDEVICE(INTEL, 0xa186), board_ahci }, /* Lewisburg RAID*/
399f5bdd66cSAlexandra Yates 	{ PCI_VDEVICE(INTEL, 0xa1d2), board_ahci }, /* Lewisburg RAID*/
400f5bdd66cSAlexandra Yates 	{ PCI_VDEVICE(INTEL, 0xa1d6), board_ahci }, /* Lewisburg RAID*/
4014d92f009SAlexandra Yates 	{ PCI_VDEVICE(INTEL, 0xa202), board_ahci }, /* Lewisburg AHCI*/
4024d92f009SAlexandra Yates 	{ PCI_VDEVICE(INTEL, 0xa206), board_ahci }, /* Lewisburg RAID*/
403f5bdd66cSAlexandra Yates 	{ PCI_VDEVICE(INTEL, 0xa252), board_ahci }, /* Lewisburg RAID*/
404f5bdd66cSAlexandra Yates 	{ PCI_VDEVICE(INTEL, 0xa256), board_ahci }, /* Lewisburg RAID*/
405f919dde0SMika Westerberg 	{ PCI_VDEVICE(INTEL, 0xa356), board_ahci }, /* Cannon Lake PCH-H RAID */
40632d25454SKai-Heng Feng 	{ PCI_VDEVICE(INTEL, 0x06d7), board_ahci }, /* Comet Lake-H RAID */
40758c42b0bSMika Westerberg 	{ PCI_VDEVICE(INTEL, 0xa386), board_ahci }, /* Comet Lake PCH-V RAID */
408ebb82e3cSHans de Goede 	{ PCI_VDEVICE(INTEL, 0x0f22), board_ahci_mobile }, /* Bay Trail AHCI */
409ebb82e3cSHans de Goede 	{ PCI_VDEVICE(INTEL, 0x0f23), board_ahci_mobile }, /* Bay Trail AHCI */
410ebb82e3cSHans de Goede 	{ PCI_VDEVICE(INTEL, 0x22a3), board_ahci_mobile }, /* Cherry Tr. AHCI */
411ebb82e3cSHans de Goede 	{ PCI_VDEVICE(INTEL, 0x5ae3), board_ahci_mobile }, /* ApolloLake AHCI */
412ba445791SMika Westerberg 	{ PCI_VDEVICE(INTEL, 0x34d3), board_ahci_mobile }, /* Ice Lake LP AHCI */
4131f2ef049SKai-Heng Feng 	{ PCI_VDEVICE(INTEL, 0x02d3), board_ahci_mobile }, /* Comet Lake PCH-U AHCI */
4147667e63cSJian-Hong Pan 	{ PCI_VDEVICE(INTEL, 0x02d7), board_ahci_mobile }, /* Comet Lake PCH RAID */
415c6fd2807SJeff Garzik 
416e34bb370STejun Heo 	/* JMicron 360/1/3/5/6, match class to avoid IDE function */
417e34bb370STejun Heo 	{ PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
418e34bb370STejun Heo 	  PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci_ign_iferr },
4191fefb8fdSBen Hutchings 	/* JMicron 362B and 362C have an AHCI function with IDE class code */
4201fefb8fdSBen Hutchings 	{ PCI_VDEVICE(JMICRON, 0x2362), board_ahci_ign_iferr },
4211fefb8fdSBen Hutchings 	{ PCI_VDEVICE(JMICRON, 0x236f), board_ahci_ign_iferr },
42291f15fb3SZhang Rui 	/* May need to update quirk_jmicron_async_suspend() for additions */
423c6fd2807SJeff Garzik 
424c6fd2807SJeff Garzik 	/* ATI */
425c65ec1c2SConke Hu 	{ PCI_VDEVICE(ATI, 0x4380), board_ahci_sb600 }, /* ATI SB600 */
426e39fc8c9SShane Huang 	{ PCI_VDEVICE(ATI, 0x4390), board_ahci_sb700 }, /* ATI SB700/800 */
427e39fc8c9SShane Huang 	{ PCI_VDEVICE(ATI, 0x4391), board_ahci_sb700 }, /* ATI SB700/800 */
428e39fc8c9SShane Huang 	{ PCI_VDEVICE(ATI, 0x4392), board_ahci_sb700 }, /* ATI SB700/800 */
429e39fc8c9SShane Huang 	{ PCI_VDEVICE(ATI, 0x4393), board_ahci_sb700 }, /* ATI SB700/800 */
430e39fc8c9SShane Huang 	{ PCI_VDEVICE(ATI, 0x4394), board_ahci_sb700 }, /* ATI SB700/800 */
431e39fc8c9SShane Huang 	{ PCI_VDEVICE(ATI, 0x4395), board_ahci_sb700 }, /* ATI SB700/800 */
432c6fd2807SJeff Garzik 
4337d523bdcSHanna Hawa 	/* Amazon's Annapurna Labs support */
4347d523bdcSHanna Hawa 	{ PCI_DEVICE(PCI_VENDOR_ID_AMAZON_ANNAPURNA_LABS, 0x0031),
4357d523bdcSHanna Hawa 		.class = PCI_CLASS_STORAGE_SATA_AHCI,
4367d523bdcSHanna Hawa 		.class_mask = 0xffffff,
4377d523bdcSHanna Hawa 		board_ahci_al },
438e2dd90b1SShane Huang 	/* AMD */
4395deab536SShane Huang 	{ PCI_VDEVICE(AMD, 0x7800), board_ahci }, /* AMD Hudson-2 */
440fafe5c3dSShane Huang 	{ PCI_VDEVICE(AMD, 0x7900), board_ahci }, /* AMD CZ */
4411527f692SMario Limonciello 	{ PCI_VDEVICE(AMD, 0x7901), board_ahci_mobile }, /* AMD Green Sardine */
442e2dd90b1SShane Huang 	/* AMD is using RAID class only for ahci controllers */
443e2dd90b1SShane Huang 	{ PCI_VENDOR_ID_AMD, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
444e2dd90b1SShane Huang 	  PCI_CLASS_STORAGE_RAID << 8, 0xffffff, board_ahci },
445e2dd90b1SShane Huang 
4469c54cd10SCharles Rose 	/* Dell S140/S150 */
4479c54cd10SCharles Rose 	{ PCI_VENDOR_ID_INTEL, PCI_ANY_ID, PCI_SUBVENDOR_ID_DELL, PCI_ANY_ID,
4489c54cd10SCharles Rose 	  PCI_CLASS_STORAGE_RAID << 8, 0xffffff, board_ahci },
4499c54cd10SCharles Rose 
450c6fd2807SJeff Garzik 	/* VIA */
45154bb3a94SJeff Garzik 	{ PCI_VDEVICE(VIA, 0x3349), board_ahci_vt8251 }, /* VIA VT8251 */
452bf335542STejun Heo 	{ PCI_VDEVICE(VIA, 0x6287), board_ahci_vt8251 }, /* VIA VT8251 */
453c6fd2807SJeff Garzik 
454c6fd2807SJeff Garzik 	/* NVIDIA */
455e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x044c), board_ahci_mcp65 },	/* MCP65 */
456e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x044d), board_ahci_mcp65 },	/* MCP65 */
457e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x044e), board_ahci_mcp65 },	/* MCP65 */
458e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x044f), board_ahci_mcp65 },	/* MCP65 */
459e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x045c), board_ahci_mcp65 },	/* MCP65 */
460e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x045d), board_ahci_mcp65 },	/* MCP65 */
461e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x045e), board_ahci_mcp65 },	/* MCP65 */
462e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x045f), board_ahci_mcp65 },	/* MCP65 */
463441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0550), board_ahci_mcp67 },	/* MCP67 */
464441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0551), board_ahci_mcp67 },	/* MCP67 */
465441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0552), board_ahci_mcp67 },	/* MCP67 */
466441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0553), board_ahci_mcp67 },	/* MCP67 */
467441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0554), board_ahci_mcp67 },	/* MCP67 */
468441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0555), board_ahci_mcp67 },	/* MCP67 */
469441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0556), board_ahci_mcp67 },	/* MCP67 */
470441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0557), board_ahci_mcp67 },	/* MCP67 */
471441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0558), board_ahci_mcp67 },	/* MCP67 */
472441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0559), board_ahci_mcp67 },	/* MCP67 */
473441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x055a), board_ahci_mcp67 },	/* MCP67 */
474441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x055b), board_ahci_mcp67 },	/* MCP67 */
475441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0580), board_ahci_mcp_linux },	/* Linux ID */
476441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0581), board_ahci_mcp_linux },	/* Linux ID */
477441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0582), board_ahci_mcp_linux },	/* Linux ID */
478441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0583), board_ahci_mcp_linux },	/* Linux ID */
479441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0584), board_ahci_mcp_linux },	/* Linux ID */
480441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0585), board_ahci_mcp_linux },	/* Linux ID */
481441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0586), board_ahci_mcp_linux },	/* Linux ID */
482441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0587), board_ahci_mcp_linux },	/* Linux ID */
483441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0588), board_ahci_mcp_linux },	/* Linux ID */
484441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0589), board_ahci_mcp_linux },	/* Linux ID */
485441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x058a), board_ahci_mcp_linux },	/* Linux ID */
486441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x058b), board_ahci_mcp_linux },	/* Linux ID */
487441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x058c), board_ahci_mcp_linux },	/* Linux ID */
488441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x058d), board_ahci_mcp_linux },	/* Linux ID */
489441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x058e), board_ahci_mcp_linux },	/* Linux ID */
490441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x058f), board_ahci_mcp_linux },	/* Linux ID */
491441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f0), board_ahci_mcp73 },	/* MCP73 */
492441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f1), board_ahci_mcp73 },	/* MCP73 */
493441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f2), board_ahci_mcp73 },	/* MCP73 */
494441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f3), board_ahci_mcp73 },	/* MCP73 */
495441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f4), board_ahci_mcp73 },	/* MCP73 */
496441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f5), board_ahci_mcp73 },	/* MCP73 */
497441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f6), board_ahci_mcp73 },	/* MCP73 */
498441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f7), board_ahci_mcp73 },	/* MCP73 */
499441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f8), board_ahci_mcp73 },	/* MCP73 */
500441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f9), board_ahci_mcp73 },	/* MCP73 */
501441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07fa), board_ahci_mcp73 },	/* MCP73 */
502441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07fb), board_ahci_mcp73 },	/* MCP73 */
503441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ad0), board_ahci_mcp77 },	/* MCP77 */
504441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ad1), board_ahci_mcp77 },	/* MCP77 */
505441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ad2), board_ahci_mcp77 },	/* MCP77 */
506441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ad3), board_ahci_mcp77 },	/* MCP77 */
507441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ad4), board_ahci_mcp77 },	/* MCP77 */
508441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ad5), board_ahci_mcp77 },	/* MCP77 */
509441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ad6), board_ahci_mcp77 },	/* MCP77 */
510441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ad7), board_ahci_mcp77 },	/* MCP77 */
511441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ad8), board_ahci_mcp77 },	/* MCP77 */
512441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ad9), board_ahci_mcp77 },	/* MCP77 */
513441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ada), board_ahci_mcp77 },	/* MCP77 */
514441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0adb), board_ahci_mcp77 },	/* MCP77 */
515441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ab4), board_ahci_mcp79 },	/* MCP79 */
516441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ab5), board_ahci_mcp79 },	/* MCP79 */
517441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ab6), board_ahci_mcp79 },	/* MCP79 */
518441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ab7), board_ahci_mcp79 },	/* MCP79 */
519441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ab8), board_ahci_mcp79 },	/* MCP79 */
520441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ab9), board_ahci_mcp79 },	/* MCP79 */
521441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0aba), board_ahci_mcp79 },	/* MCP79 */
522441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0abb), board_ahci_mcp79 },	/* MCP79 */
523441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0abc), board_ahci_mcp79 },	/* MCP79 */
524441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0abd), board_ahci_mcp79 },	/* MCP79 */
525441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0abe), board_ahci_mcp79 },	/* MCP79 */
526441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0abf), board_ahci_mcp79 },	/* MCP79 */
527441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0d84), board_ahci_mcp89 },	/* MCP89 */
528441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0d85), board_ahci_mcp89 },	/* MCP89 */
529441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0d86), board_ahci_mcp89 },	/* MCP89 */
530441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0d87), board_ahci_mcp89 },	/* MCP89 */
531441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0d88), board_ahci_mcp89 },	/* MCP89 */
532441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0d89), board_ahci_mcp89 },	/* MCP89 */
533441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0d8a), board_ahci_mcp89 },	/* MCP89 */
534441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0d8b), board_ahci_mcp89 },	/* MCP89 */
535441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0d8c), board_ahci_mcp89 },	/* MCP89 */
536441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0d8d), board_ahci_mcp89 },	/* MCP89 */
537441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0d8e), board_ahci_mcp89 },	/* MCP89 */
538441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0d8f), board_ahci_mcp89 },	/* MCP89 */
539c6fd2807SJeff Garzik 
540c6fd2807SJeff Garzik 	/* SiS */
54120e2de4aSTejun Heo 	{ PCI_VDEVICE(SI, 0x1184), board_ahci },		/* SiS 966 */
54220e2de4aSTejun Heo 	{ PCI_VDEVICE(SI, 0x1185), board_ahci },		/* SiS 968 */
54320e2de4aSTejun Heo 	{ PCI_VDEVICE(SI, 0x0186), board_ahci },		/* SiS 968 */
544c6fd2807SJeff Garzik 
545318893e1SAlessandro Rubini 	/* ST Microelectronics */
546318893e1SAlessandro Rubini 	{ PCI_VDEVICE(STMICRO, 0xCC06), board_ahci },		/* ST ConneXt */
547318893e1SAlessandro Rubini 
548cd70c266SJeff Garzik 	/* Marvell */
549cd70c266SJeff Garzik 	{ PCI_VDEVICE(MARVELL, 0x6145), board_ahci_mv },	/* 6145 */
550c40e7cb8SJose Alberto Reguero 	{ PCI_VDEVICE(MARVELL, 0x6121), board_ahci_mv },	/* 6121 */
55169fd3157SMyron Stowe 	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9123),
55210aca06cSAnssi Hannula 	  .class = PCI_CLASS_STORAGE_SATA_AHCI,
55310aca06cSAnssi Hannula 	  .class_mask = 0xffffff,
5545f173107STejun Heo 	  .driver_data = board_ahci_yes_fbs },			/* 88se9128 */
55569fd3157SMyron Stowe 	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9125),
556467b41c6SPer Jessen 	  .driver_data = board_ahci_yes_fbs },			/* 88se9125 */
557e098f5cbSSimon Guinot 	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_MARVELL_EXT, 0x9178,
558e098f5cbSSimon Guinot 			 PCI_VENDOR_ID_MARVELL_EXT, 0x9170),
559e098f5cbSSimon Guinot 	  .driver_data = board_ahci_yes_fbs },			/* 88se9170 */
56069fd3157SMyron Stowe 	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x917a),
561642d8925SMatt Johnson 	  .driver_data = board_ahci_yes_fbs },			/* 88se9172 */
562fcce9a35SGeorge Spelvin 	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9172),
563c5edfff9SMurali Karicheri 	  .driver_data = board_ahci_yes_fbs },			/* 88se9182 */
564c5edfff9SMurali Karicheri 	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9182),
565fcce9a35SGeorge Spelvin 	  .driver_data = board_ahci_yes_fbs },			/* 88se9172 */
56669fd3157SMyron Stowe 	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9192),
56717c60c6bSAlan Cox 	  .driver_data = board_ahci_yes_fbs },			/* 88se9172 on some Gigabyte */
568754a292fSAndreas Schrägle 	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x91a0),
569754a292fSAndreas Schrägle 	  .driver_data = board_ahci_yes_fbs },
570a40cf3f3SJohannes Thumshirn 	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x91a2), 	/* 88se91a2 */
571a40cf3f3SJohannes Thumshirn 	  .driver_data = board_ahci_yes_fbs },
57269fd3157SMyron Stowe 	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x91a3),
57350be5e36STejun Heo 	  .driver_data = board_ahci_yes_fbs },
5746d5278a6SSamir Benmendil 	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9230),
5756d5278a6SSamir Benmendil 	  .driver_data = board_ahci_yes_fbs },
57628b2182dSHans de Goede 	{ PCI_DEVICE(PCI_VENDOR_ID_TTI, 0x0642), /* highpoint rocketraid 642L */
57728b2182dSHans de Goede 	  .driver_data = board_ahci_yes_fbs },
57828b2182dSHans de Goede 	{ PCI_DEVICE(PCI_VENDOR_ID_TTI, 0x0645), /* highpoint rocketraid 644L */
579d2518365SJérôme Carretero 	  .driver_data = board_ahci_yes_fbs },
580cd70c266SJeff Garzik 
581c77a036bSMark Nelson 	/* Promise */
582c77a036bSMark Nelson 	{ PCI_VDEVICE(PROMISE, 0x3f20), board_ahci },	/* PDC42819 */
583b32bfc06SRomain Degez 	{ PCI_VDEVICE(PROMISE, 0x3781), board_ahci },   /* FastTrak TX8660 ahci-mode */
584c77a036bSMark Nelson 
585c9703765SKeng-Yu Lin 	/* Asmedia */
5867b4f6ecaSAlan Cox 	{ PCI_VDEVICE(ASMEDIA, 0x0601), board_ahci },	/* ASM1060 */
5877b4f6ecaSAlan Cox 	{ PCI_VDEVICE(ASMEDIA, 0x0602), board_ahci },	/* ASM1060 */
5887b4f6ecaSAlan Cox 	{ PCI_VDEVICE(ASMEDIA, 0x0611), board_ahci },	/* ASM1061 */
5897b4f6ecaSAlan Cox 	{ PCI_VDEVICE(ASMEDIA, 0x0612), board_ahci },	/* ASM1062 */
5900ce968f3SShawn Lin 	{ PCI_VDEVICE(ASMEDIA, 0x0621), board_ahci },   /* ASM1061R */
5910ce968f3SShawn Lin 	{ PCI_VDEVICE(ASMEDIA, 0x0622), board_ahci },   /* ASM1062R */
5928c0ff6afSIstván Pongrácz 	{ PCI_VDEVICE(ASMEDIA, 0x0624), board_ahci },   /* ASM1062+JMB575 */
593c9703765SKeng-Yu Lin 
59467809f85SLevente Kurusa 	/*
59566a7cbc3STejun Heo 	 * Samsung SSDs found on some macbooks.  NCQ times out if MSI is
59666a7cbc3STejun Heo 	 * enabled.  https://bugzilla.kernel.org/show_bug.cgi?id=60731
59767809f85SLevente Kurusa 	 */
59866a7cbc3STejun Heo 	{ PCI_VDEVICE(SAMSUNG, 0x1600), board_ahci_nomsi },
5992b21ef0aSTejun Heo 	{ PCI_VDEVICE(SAMSUNG, 0xa800), board_ahci_nomsi },
60067809f85SLevente Kurusa 
6017f9c9f8eSHugh Daschbach 	/* Enmotus */
6027f9c9f8eSHugh Daschbach 	{ PCI_DEVICE(0x1c44, 0x8000), board_ahci },
6037f9c9f8eSHugh Daschbach 
604e49bd683STiezhu Yang 	/* Loongson */
605e49bd683STiezhu Yang 	{ PCI_VDEVICE(LOONGSON, 0x7a08), board_ahci },
606e49bd683STiezhu Yang 
607415ae2b5SJeff Garzik 	/* Generic, PCI class code for AHCI */
608415ae2b5SJeff Garzik 	{ PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
609c9f89475SConke Hu 	  PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci },
610415ae2b5SJeff Garzik 
611c6fd2807SJeff Garzik 	{ }	/* terminate list */
612c6fd2807SJeff Garzik };
613c6fd2807SJeff Garzik 
614f1d848f9SMika Westerberg static const struct dev_pm_ops ahci_pci_pm_ops = {
615f1d848f9SMika Westerberg 	SET_SYSTEM_SLEEP_PM_OPS(ahci_pci_device_suspend, ahci_pci_device_resume)
61602e53293SMika Westerberg 	SET_RUNTIME_PM_OPS(ahci_pci_device_runtime_suspend,
61702e53293SMika Westerberg 			   ahci_pci_device_runtime_resume, NULL)
618f1d848f9SMika Westerberg };
619c6fd2807SJeff Garzik 
620c6fd2807SJeff Garzik static struct pci_driver ahci_pci_driver = {
621c6fd2807SJeff Garzik 	.name			= DRV_NAME,
622c6fd2807SJeff Garzik 	.id_table		= ahci_pci_tbl,
623c6fd2807SJeff Garzik 	.probe			= ahci_init_one,
62402e53293SMika Westerberg 	.remove			= ahci_remove_one,
62510a663a1SPrabhakar Kushwaha 	.shutdown		= ahci_shutdown_one,
626f1d848f9SMika Westerberg 	.driver = {
627f1d848f9SMika Westerberg 		.pm		= &ahci_pci_pm_ops,
628f1d848f9SMika Westerberg 	},
629c6fd2807SJeff Garzik };
630c6fd2807SJeff Garzik 
6315219d653SJavier Martinez Canillas #if IS_ENABLED(CONFIG_PATA_MARVELL)
6325b66c829SAlan Cox static int marvell_enable;
6335b66c829SAlan Cox #else
6345b66c829SAlan Cox static int marvell_enable = 1;
6355b66c829SAlan Cox #endif
6365b66c829SAlan Cox module_param(marvell_enable, int, 0644);
6375b66c829SAlan Cox MODULE_PARM_DESC(marvell_enable, "Marvell SATA via AHCI (1 = enabled)");
6385b66c829SAlan Cox 
639b1a9585cSSrinivas Pandruvada static int mobile_lpm_policy = -1;
640ebb82e3cSHans de Goede module_param(mobile_lpm_policy, int, 0644);
641ebb82e3cSHans de Goede MODULE_PARM_DESC(mobile_lpm_policy, "Default LPM policy for mobile chipsets");
6425b66c829SAlan Cox 
643394d6e53SAnton Vorontsov static void ahci_pci_save_initial_config(struct pci_dev *pdev,
644394d6e53SAnton Vorontsov 					 struct ahci_host_priv *hpriv)
645394d6e53SAnton Vorontsov {
646394d6e53SAnton Vorontsov 	if (pdev->vendor == PCI_VENDOR_ID_JMICRON && pdev->device == 0x2361) {
647394d6e53SAnton Vorontsov 		dev_info(&pdev->dev, "JMB361 has only one port\n");
6489a23c1d6SAntoine Tenart 		hpriv->force_port_map = 1;
649394d6e53SAnton Vorontsov 	}
650394d6e53SAnton Vorontsov 
651394d6e53SAnton Vorontsov 	/*
652394d6e53SAnton Vorontsov 	 * Temporary Marvell 6145 hack: PATA port presence
653394d6e53SAnton Vorontsov 	 * is asserted through the standard AHCI port
654394d6e53SAnton Vorontsov 	 * presence register, as bit 4 (counting from 0)
655394d6e53SAnton Vorontsov 	 */
656394d6e53SAnton Vorontsov 	if (hpriv->flags & AHCI_HFLAG_MV_PATA) {
657394d6e53SAnton Vorontsov 		if (pdev->device == 0x6121)
6589a23c1d6SAntoine Tenart 			hpriv->mask_port_map = 0x3;
659394d6e53SAnton Vorontsov 		else
6609a23c1d6SAntoine Tenart 			hpriv->mask_port_map = 0xf;
661394d6e53SAnton Vorontsov 		dev_info(&pdev->dev,
662394d6e53SAnton Vorontsov 			  "Disabling your PATA port. Use the boot option 'ahci.marvell_enable=0' to avoid this.\n");
663394d6e53SAnton Vorontsov 	}
664394d6e53SAnton Vorontsov 
665725c7b57SAntoine Ténart 	ahci_save_initial_config(&pdev->dev, hpriv);
666394d6e53SAnton Vorontsov }
667394d6e53SAnton Vorontsov 
668781d6550SAnton Vorontsov static void ahci_pci_init_controller(struct ata_host *host)
669781d6550SAnton Vorontsov {
670781d6550SAnton Vorontsov 	struct ahci_host_priv *hpriv = host->private_data;
671781d6550SAnton Vorontsov 	struct pci_dev *pdev = to_pci_dev(host->dev);
672781d6550SAnton Vorontsov 	void __iomem *port_mmio;
673781d6550SAnton Vorontsov 	u32 tmp;
674c40e7cb8SJose Alberto Reguero 	int mv;
6752bcd866bSJeff Garzik 
676417a1a6dSTejun Heo 	if (hpriv->flags & AHCI_HFLAG_MV_PATA) {
677c40e7cb8SJose Alberto Reguero 		if (pdev->device == 0x6121)
678c40e7cb8SJose Alberto Reguero 			mv = 2;
679c40e7cb8SJose Alberto Reguero 		else
680c40e7cb8SJose Alberto Reguero 			mv = 4;
681c40e7cb8SJose Alberto Reguero 		port_mmio = __ahci_port_base(host, mv);
682cd70c266SJeff Garzik 
683cd70c266SJeff Garzik 		writel(0, port_mmio + PORT_IRQ_MASK);
684cd70c266SJeff Garzik 
685cd70c266SJeff Garzik 		/* clear port IRQ */
686cd70c266SJeff Garzik 		tmp = readl(port_mmio + PORT_IRQ_STAT);
687cd70c266SJeff Garzik 		VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp);
688cd70c266SJeff Garzik 		if (tmp)
689cd70c266SJeff Garzik 			writel(tmp, port_mmio + PORT_IRQ_STAT);
690cd70c266SJeff Garzik 	}
691cd70c266SJeff Garzik 
692781d6550SAnton Vorontsov 	ahci_init_controller(host);
693c6fd2807SJeff Garzik }
694c6fd2807SJeff Garzik 
695cc0680a5STejun Heo static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
696d4b2bab4STejun Heo 				 unsigned long deadline)
697ad616ffbSTejun Heo {
698cc0680a5STejun Heo 	struct ata_port *ap = link->ap;
699039ece38SHans de Goede 	struct ahci_host_priv *hpriv = ap->host->private_data;
7009dadd45bSTejun Heo 	bool online;
701ad616ffbSTejun Heo 	int rc;
702ad616ffbSTejun Heo 
703ad616ffbSTejun Heo 	DPRINTK("ENTER\n");
704ad616ffbSTejun Heo 
705fa89f53bSEvan Wang 	hpriv->stop_engine(ap);
706ad616ffbSTejun Heo 
707cc0680a5STejun Heo 	rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context),
7089dadd45bSTejun Heo 				 deadline, &online, NULL);
709ad616ffbSTejun Heo 
710039ece38SHans de Goede 	hpriv->start_engine(ap);
711ad616ffbSTejun Heo 
712ad616ffbSTejun Heo 	DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
713ad616ffbSTejun Heo 
714ad616ffbSTejun Heo 	/* vt8251 doesn't clear BSY on signature FIS reception,
715ad616ffbSTejun Heo 	 * request follow-up softreset.
716ad616ffbSTejun Heo 	 */
7179dadd45bSTejun Heo 	return online ? -EAGAIN : rc;
718ad616ffbSTejun Heo }
719ad616ffbSTejun Heo 
720edc93052STejun Heo static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
721edc93052STejun Heo 				unsigned long deadline)
722edc93052STejun Heo {
723edc93052STejun Heo 	struct ata_port *ap = link->ap;
724edc93052STejun Heo 	struct ahci_port_priv *pp = ap->private_data;
725039ece38SHans de Goede 	struct ahci_host_priv *hpriv = ap->host->private_data;
726edc93052STejun Heo 	u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
727edc93052STejun Heo 	struct ata_taskfile tf;
7289dadd45bSTejun Heo 	bool online;
729edc93052STejun Heo 	int rc;
730edc93052STejun Heo 
731fa89f53bSEvan Wang 	hpriv->stop_engine(ap);
732edc93052STejun Heo 
733edc93052STejun Heo 	/* clear D2H reception area to properly wait for D2H FIS */
734edc93052STejun Heo 	ata_tf_init(link->device, &tf);
7359bbb1b0eSSergei Shtylyov 	tf.command = ATA_BUSY;
736edc93052STejun Heo 	ata_tf_to_fis(&tf, 0, 0, d2h_fis);
737edc93052STejun Heo 
738edc93052STejun Heo 	rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context),
7399dadd45bSTejun Heo 				 deadline, &online, NULL);
740edc93052STejun Heo 
741039ece38SHans de Goede 	hpriv->start_engine(ap);
742edc93052STejun Heo 
743edc93052STejun Heo 	/* The pseudo configuration device on SIMG4726 attached to
744edc93052STejun Heo 	 * ASUS P5W-DH Deluxe doesn't send signature FIS after
745edc93052STejun Heo 	 * hardreset if no device is attached to the first downstream
746edc93052STejun Heo 	 * port && the pseudo device locks up on SRST w/ PMP==0.  To
747edc93052STejun Heo 	 * work around this, wait for !BSY only briefly.  If BSY isn't
748edc93052STejun Heo 	 * cleared, perform CLO and proceed to IDENTIFY (achieved by
749edc93052STejun Heo 	 * ATA_LFLAG_NO_SRST and ATA_LFLAG_ASSUME_ATA).
750edc93052STejun Heo 	 *
751edc93052STejun Heo 	 * Wait for two seconds.  Devices attached to downstream port
752edc93052STejun Heo 	 * which can't process the following IDENTIFY after this will
753edc93052STejun Heo 	 * have to be reset again.  For most cases, this should
754edc93052STejun Heo 	 * suffice while making probing snappish enough.
755edc93052STejun Heo 	 */
7569dadd45bSTejun Heo 	if (online) {
7579dadd45bSTejun Heo 		rc = ata_wait_after_reset(link, jiffies + 2 * HZ,
7589dadd45bSTejun Heo 					  ahci_check_ready);
759edc93052STejun Heo 		if (rc)
76078d5ae39SShane Huang 			ahci_kick_engine(ap);
7619dadd45bSTejun Heo 	}
7629dadd45bSTejun Heo 	return rc;
763edc93052STejun Heo }
764edc93052STejun Heo 
765dbfe8ef5SDan Williams /*
766dbfe8ef5SDan Williams  * ahci_avn_hardreset - attempt more aggressive recovery of Avoton ports.
767dbfe8ef5SDan Williams  *
768dbfe8ef5SDan Williams  * It has been observed with some SSDs that the timing of events in the
769dbfe8ef5SDan Williams  * link synchronization phase can leave the port in a state that can not
770dbfe8ef5SDan Williams  * be recovered by a SATA-hard-reset alone.  The failing signature is
771dbfe8ef5SDan Williams  * SStatus.DET stuck at 1 ("Device presence detected but Phy
772dbfe8ef5SDan Williams  * communication not established").  It was found that unloading and
773dbfe8ef5SDan Williams  * reloading the driver when this problem occurs allows the drive
774dbfe8ef5SDan Williams  * connection to be recovered (DET advanced to 0x3).  The critical
775dbfe8ef5SDan Williams  * component of reloading the driver is that the port state machines are
776dbfe8ef5SDan Williams  * reset by bouncing "port enable" in the AHCI PCS configuration
777dbfe8ef5SDan Williams  * register.  So, reproduce that effect by bouncing a port whenever we
778dbfe8ef5SDan Williams  * see DET==1 after a reset.
779dbfe8ef5SDan Williams  */
780dbfe8ef5SDan Williams static int ahci_avn_hardreset(struct ata_link *link, unsigned int *class,
781dbfe8ef5SDan Williams 			      unsigned long deadline)
782dbfe8ef5SDan Williams {
783dbfe8ef5SDan Williams 	const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
784dbfe8ef5SDan Williams 	struct ata_port *ap = link->ap;
785dbfe8ef5SDan Williams 	struct ahci_port_priv *pp = ap->private_data;
786dbfe8ef5SDan Williams 	struct ahci_host_priv *hpriv = ap->host->private_data;
787dbfe8ef5SDan Williams 	u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
788dbfe8ef5SDan Williams 	unsigned long tmo = deadline - jiffies;
789dbfe8ef5SDan Williams 	struct ata_taskfile tf;
790dbfe8ef5SDan Williams 	bool online;
791dbfe8ef5SDan Williams 	int rc, i;
792dbfe8ef5SDan Williams 
793dbfe8ef5SDan Williams 	DPRINTK("ENTER\n");
794dbfe8ef5SDan Williams 
795fa89f53bSEvan Wang 	hpriv->stop_engine(ap);
796dbfe8ef5SDan Williams 
797dbfe8ef5SDan Williams 	for (i = 0; i < 2; i++) {
798dbfe8ef5SDan Williams 		u16 val;
799dbfe8ef5SDan Williams 		u32 sstatus;
800dbfe8ef5SDan Williams 		int port = ap->port_no;
801dbfe8ef5SDan Williams 		struct ata_host *host = ap->host;
802dbfe8ef5SDan Williams 		struct pci_dev *pdev = to_pci_dev(host->dev);
803dbfe8ef5SDan Williams 
804dbfe8ef5SDan Williams 		/* clear D2H reception area to properly wait for D2H FIS */
805dbfe8ef5SDan Williams 		ata_tf_init(link->device, &tf);
806dbfe8ef5SDan Williams 		tf.command = ATA_BUSY;
807dbfe8ef5SDan Williams 		ata_tf_to_fis(&tf, 0, 0, d2h_fis);
808dbfe8ef5SDan Williams 
809dbfe8ef5SDan Williams 		rc = sata_link_hardreset(link, timing, deadline, &online,
810dbfe8ef5SDan Williams 				ahci_check_ready);
811dbfe8ef5SDan Williams 
812dbfe8ef5SDan Williams 		if (sata_scr_read(link, SCR_STATUS, &sstatus) != 0 ||
813dbfe8ef5SDan Williams 				(sstatus & 0xf) != 1)
814dbfe8ef5SDan Williams 			break;
815dbfe8ef5SDan Williams 
816e276c9bdSXu Wang 		ata_link_info(link,  "avn bounce port%d\n", port);
817dbfe8ef5SDan Williams 
818dbfe8ef5SDan Williams 		pci_read_config_word(pdev, 0x92, &val);
819dbfe8ef5SDan Williams 		val &= ~(1 << port);
820dbfe8ef5SDan Williams 		pci_write_config_word(pdev, 0x92, val);
821dbfe8ef5SDan Williams 		ata_msleep(ap, 1000);
822dbfe8ef5SDan Williams 		val |= 1 << port;
823dbfe8ef5SDan Williams 		pci_write_config_word(pdev, 0x92, val);
824dbfe8ef5SDan Williams 		deadline += tmo;
825dbfe8ef5SDan Williams 	}
826dbfe8ef5SDan Williams 
827dbfe8ef5SDan Williams 	hpriv->start_engine(ap);
828dbfe8ef5SDan Williams 
829dbfe8ef5SDan Williams 	if (online)
830dbfe8ef5SDan Williams 		*class = ahci_dev_classify(ap);
831dbfe8ef5SDan Williams 
832dbfe8ef5SDan Williams 	DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
833dbfe8ef5SDan Williams 	return rc;
834dbfe8ef5SDan Williams }
835dbfe8ef5SDan Williams 
836dbfe8ef5SDan Williams 
83702e53293SMika Westerberg #ifdef CONFIG_PM
83802e53293SMika Westerberg static void ahci_pci_disable_interrupts(struct ata_host *host)
839c6fd2807SJeff Garzik {
8409b10ae86STejun Heo 	struct ahci_host_priv *hpriv = host->private_data;
841d8993349SAnton Vorontsov 	void __iomem *mmio = hpriv->mmio;
842c6fd2807SJeff Garzik 	u32 ctl;
843c6fd2807SJeff Garzik 
844c6fd2807SJeff Garzik 	/* AHCI spec rev1.1 section 8.3.3:
845c6fd2807SJeff Garzik 	 * Software must disable interrupts prior to requesting a
846c6fd2807SJeff Garzik 	 * transition of the HBA to D3 state.
847c6fd2807SJeff Garzik 	 */
848c6fd2807SJeff Garzik 	ctl = readl(mmio + HOST_CTL);
849c6fd2807SJeff Garzik 	ctl &= ~HOST_IRQ_EN;
850c6fd2807SJeff Garzik 	writel(ctl, mmio + HOST_CTL);
851c6fd2807SJeff Garzik 	readl(mmio + HOST_CTL); /* flush */
85202e53293SMika Westerberg }
853f1d848f9SMika Westerberg 
85402e53293SMika Westerberg static int ahci_pci_device_runtime_suspend(struct device *dev)
85502e53293SMika Westerberg {
85602e53293SMika Westerberg 	struct pci_dev *pdev = to_pci_dev(dev);
85702e53293SMika Westerberg 	struct ata_host *host = pci_get_drvdata(pdev);
85802e53293SMika Westerberg 
85902e53293SMika Westerberg 	ahci_pci_disable_interrupts(host);
86002e53293SMika Westerberg 	return 0;
86102e53293SMika Westerberg }
86202e53293SMika Westerberg 
86302e53293SMika Westerberg static int ahci_pci_device_runtime_resume(struct device *dev)
86402e53293SMika Westerberg {
86502e53293SMika Westerberg 	struct pci_dev *pdev = to_pci_dev(dev);
86602e53293SMika Westerberg 	struct ata_host *host = pci_get_drvdata(pdev);
86702e53293SMika Westerberg 	int rc;
86802e53293SMika Westerberg 
869c312ef17SDan Williams 	rc = ahci_reset_controller(host);
87002e53293SMika Westerberg 	if (rc)
87102e53293SMika Westerberg 		return rc;
87202e53293SMika Westerberg 	ahci_pci_init_controller(host);
87302e53293SMika Westerberg 	return 0;
87402e53293SMika Westerberg }
87502e53293SMika Westerberg 
87602e53293SMika Westerberg #ifdef CONFIG_PM_SLEEP
87702e53293SMika Westerberg static int ahci_pci_device_suspend(struct device *dev)
87802e53293SMika Westerberg {
87902e53293SMika Westerberg 	struct pci_dev *pdev = to_pci_dev(dev);
88002e53293SMika Westerberg 	struct ata_host *host = pci_get_drvdata(pdev);
88102e53293SMika Westerberg 	struct ahci_host_priv *hpriv = host->private_data;
88202e53293SMika Westerberg 
88302e53293SMika Westerberg 	if (hpriv->flags & AHCI_HFLAG_NO_SUSPEND) {
88402e53293SMika Westerberg 		dev_err(&pdev->dev,
88502e53293SMika Westerberg 			"BIOS update required for suspend/resume\n");
88602e53293SMika Westerberg 		return -EIO;
88702e53293SMika Westerberg 	}
88802e53293SMika Westerberg 
88902e53293SMika Westerberg 	ahci_pci_disable_interrupts(host);
890f1d848f9SMika Westerberg 	return ata_host_suspend(host, PMSG_SUSPEND);
891c6fd2807SJeff Garzik }
892c6fd2807SJeff Garzik 
893f1d848f9SMika Westerberg static int ahci_pci_device_resume(struct device *dev)
894c6fd2807SJeff Garzik {
895f1d848f9SMika Westerberg 	struct pci_dev *pdev = to_pci_dev(dev);
8960a86e1c8SJingoo Han 	struct ata_host *host = pci_get_drvdata(pdev);
897c6fd2807SJeff Garzik 	int rc;
898c6fd2807SJeff Garzik 
899cb85696dSJames Laird 	/* Apple BIOS helpfully mangles the registers on resume */
900cb85696dSJames Laird 	if (is_mcp89_apple(pdev))
901cb85696dSJames Laird 		ahci_mcp89_apple_enable(pdev);
902cb85696dSJames Laird 
903c6fd2807SJeff Garzik 	if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
904c312ef17SDan Williams 		rc = ahci_reset_controller(host);
905c6fd2807SJeff Garzik 		if (rc)
906c6fd2807SJeff Garzik 			return rc;
907c6fd2807SJeff Garzik 
908781d6550SAnton Vorontsov 		ahci_pci_init_controller(host);
909c6fd2807SJeff Garzik 	}
910c6fd2807SJeff Garzik 
911cca3974eSJeff Garzik 	ata_host_resume(host);
912c6fd2807SJeff Garzik 
913c6fd2807SJeff Garzik 	return 0;
914c6fd2807SJeff Garzik }
915438ac6d5STejun Heo #endif
916c6fd2807SJeff Garzik 
91702e53293SMika Westerberg #endif /* CONFIG_PM */
91802e53293SMika Westerberg 
9194447d351STejun Heo static int ahci_configure_dma_masks(struct pci_dev *pdev, int using_dac)
920c6fd2807SJeff Garzik {
921b1716871SChristoph Hellwig 	const int dma_bits = using_dac ? 64 : 32;
922c6fd2807SJeff Garzik 	int rc;
923c6fd2807SJeff Garzik 
924318893e1SAlessandro Rubini 	/*
925318893e1SAlessandro Rubini 	 * If the device fixup already set the dma_mask to some non-standard
926318893e1SAlessandro Rubini 	 * value, don't extend it here. This happens on STA2X11, for example.
927b1716871SChristoph Hellwig 	 *
928b1716871SChristoph Hellwig 	 * XXX: manipulating the DMA mask from platform code is completely
929a7ba70f1SNicolas Saenz Julienne 	 * bogus, platform code should use dev->bus_dma_limit instead..
930318893e1SAlessandro Rubini 	 */
931318893e1SAlessandro Rubini 	if (pdev->dma_mask && pdev->dma_mask < DMA_BIT_MASK(32))
932318893e1SAlessandro Rubini 		return 0;
933318893e1SAlessandro Rubini 
934b1716871SChristoph Hellwig 	rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(dma_bits));
935b1716871SChristoph Hellwig 	if (rc)
936b1716871SChristoph Hellwig 		dev_err(&pdev->dev, "DMA enable failed\n");
937c6fd2807SJeff Garzik 	return rc;
938c6fd2807SJeff Garzik }
939c6fd2807SJeff Garzik 
940439fcaecSAnton Vorontsov static void ahci_pci_print_info(struct ata_host *host)
941439fcaecSAnton Vorontsov {
942439fcaecSAnton Vorontsov 	struct pci_dev *pdev = to_pci_dev(host->dev);
943439fcaecSAnton Vorontsov 	u16 cc;
944439fcaecSAnton Vorontsov 	const char *scc_s;
945439fcaecSAnton Vorontsov 
946439fcaecSAnton Vorontsov 	pci_read_config_word(pdev, 0x0a, &cc);
947439fcaecSAnton Vorontsov 	if (cc == PCI_CLASS_STORAGE_IDE)
948439fcaecSAnton Vorontsov 		scc_s = "IDE";
949439fcaecSAnton Vorontsov 	else if (cc == PCI_CLASS_STORAGE_SATA)
950439fcaecSAnton Vorontsov 		scc_s = "SATA";
951439fcaecSAnton Vorontsov 	else if (cc == PCI_CLASS_STORAGE_RAID)
952439fcaecSAnton Vorontsov 		scc_s = "RAID";
953439fcaecSAnton Vorontsov 	else
954439fcaecSAnton Vorontsov 		scc_s = "unknown";
955439fcaecSAnton Vorontsov 
956439fcaecSAnton Vorontsov 	ahci_print_info(host, scc_s);
957439fcaecSAnton Vorontsov }
958439fcaecSAnton Vorontsov 
959edc93052STejun Heo /* On ASUS P5W DH Deluxe, the second port of PCI device 00:1f.2 is
960edc93052STejun Heo  * hardwired to on-board SIMG 4726.  The chipset is ICH8 and doesn't
961edc93052STejun Heo  * support PMP and the 4726 either directly exports the device
962edc93052STejun Heo  * attached to the first downstream port or acts as a hardware storage
963edc93052STejun Heo  * controller and emulate a single ATA device (can be RAID 0/1 or some
964edc93052STejun Heo  * other configuration).
965edc93052STejun Heo  *
966edc93052STejun Heo  * When there's no device attached to the first downstream port of the
967edc93052STejun Heo  * 4726, "Config Disk" appears, which is a pseudo ATA device to
968edc93052STejun Heo  * configure the 4726.  However, ATA emulation of the device is very
969edc93052STejun Heo  * lame.  It doesn't send signature D2H Reg FIS after the initial
970edc93052STejun Heo  * hardreset, pukes on SRST w/ PMP==0 and has bunch of other issues.
971edc93052STejun Heo  *
972edc93052STejun Heo  * The following function works around the problem by always using
973edc93052STejun Heo  * hardreset on the port and not depending on receiving signature FIS
974edc93052STejun Heo  * afterward.  If signature FIS isn't received soon, ATA class is
975edc93052STejun Heo  * assumed without follow-up softreset.
976edc93052STejun Heo  */
977edc93052STejun Heo static void ahci_p5wdh_workaround(struct ata_host *host)
978edc93052STejun Heo {
9791bd06867SMathias Krause 	static const struct dmi_system_id sysids[] = {
980edc93052STejun Heo 		{
981edc93052STejun Heo 			.ident = "P5W DH Deluxe",
982edc93052STejun Heo 			.matches = {
983edc93052STejun Heo 				DMI_MATCH(DMI_SYS_VENDOR,
984edc93052STejun Heo 					  "ASUSTEK COMPUTER INC"),
985edc93052STejun Heo 				DMI_MATCH(DMI_PRODUCT_NAME, "P5W DH Deluxe"),
986edc93052STejun Heo 			},
987edc93052STejun Heo 		},
988edc93052STejun Heo 		{ }
989edc93052STejun Heo 	};
990edc93052STejun Heo 	struct pci_dev *pdev = to_pci_dev(host->dev);
991edc93052STejun Heo 
992edc93052STejun Heo 	if (pdev->bus->number == 0 && pdev->devfn == PCI_DEVFN(0x1f, 2) &&
993edc93052STejun Heo 	    dmi_check_system(sysids)) {
994edc93052STejun Heo 		struct ata_port *ap = host->ports[1];
995edc93052STejun Heo 
996a44fec1fSJoe Perches 		dev_info(&pdev->dev,
997a44fec1fSJoe Perches 			 "enabling ASUS P5W DH Deluxe on-board SIMG4726 workaround\n");
998edc93052STejun Heo 
999edc93052STejun Heo 		ap->ops = &ahci_p5wdh_ops;
1000edc93052STejun Heo 		ap->link.flags |= ATA_LFLAG_NO_SRST | ATA_LFLAG_ASSUME_ATA;
1001edc93052STejun Heo 	}
1002edc93052STejun Heo }
1003edc93052STejun Heo 
1004cb85696dSJames Laird /*
1005cb85696dSJames Laird  * Macbook7,1 firmware forcibly disables MCP89 AHCI and changes PCI ID when
1006cb85696dSJames Laird  * booting in BIOS compatibility mode.  We restore the registers but not ID.
1007cb85696dSJames Laird  */
1008cb85696dSJames Laird static void ahci_mcp89_apple_enable(struct pci_dev *pdev)
1009cb85696dSJames Laird {
1010cb85696dSJames Laird 	u32 val;
1011cb85696dSJames Laird 
1012cb85696dSJames Laird 	printk(KERN_INFO "ahci: enabling MCP89 AHCI mode\n");
1013cb85696dSJames Laird 
1014cb85696dSJames Laird 	pci_read_config_dword(pdev, 0xf8, &val);
1015cb85696dSJames Laird 	val |= 1 << 0x1b;
1016cb85696dSJames Laird 	/* the following changes the device ID, but appears not to affect function */
1017cb85696dSJames Laird 	/* val = (val & ~0xf0000000) | 0x80000000; */
1018cb85696dSJames Laird 	pci_write_config_dword(pdev, 0xf8, val);
1019cb85696dSJames Laird 
1020cb85696dSJames Laird 	pci_read_config_dword(pdev, 0x54c, &val);
1021cb85696dSJames Laird 	val |= 1 << 0xc;
1022cb85696dSJames Laird 	pci_write_config_dword(pdev, 0x54c, val);
1023cb85696dSJames Laird 
1024cb85696dSJames Laird 	pci_read_config_dword(pdev, 0x4a4, &val);
1025cb85696dSJames Laird 	val &= 0xff;
1026cb85696dSJames Laird 	val |= 0x01060100;
1027cb85696dSJames Laird 	pci_write_config_dword(pdev, 0x4a4, val);
1028cb85696dSJames Laird 
1029cb85696dSJames Laird 	pci_read_config_dword(pdev, 0x54c, &val);
1030cb85696dSJames Laird 	val &= ~(1 << 0xc);
1031cb85696dSJames Laird 	pci_write_config_dword(pdev, 0x54c, val);
1032cb85696dSJames Laird 
1033cb85696dSJames Laird 	pci_read_config_dword(pdev, 0xf8, &val);
1034cb85696dSJames Laird 	val &= ~(1 << 0x1b);
1035cb85696dSJames Laird 	pci_write_config_dword(pdev, 0xf8, val);
1036cb85696dSJames Laird }
1037cb85696dSJames Laird 
1038cb85696dSJames Laird static bool is_mcp89_apple(struct pci_dev *pdev)
1039cb85696dSJames Laird {
1040cb85696dSJames Laird 	return pdev->vendor == PCI_VENDOR_ID_NVIDIA &&
1041cb85696dSJames Laird 		pdev->device == PCI_DEVICE_ID_NVIDIA_NFORCE_MCP89_SATA &&
1042cb85696dSJames Laird 		pdev->subsystem_vendor == PCI_VENDOR_ID_APPLE &&
1043cb85696dSJames Laird 		pdev->subsystem_device == 0xcb89;
1044cb85696dSJames Laird }
1045cb85696dSJames Laird 
10462fcad9d2STejun Heo /* only some SB600 ahci controllers can do 64bit DMA */
10472fcad9d2STejun Heo static bool ahci_sb600_enable_64bit(struct pci_dev *pdev)
104858a09b38SShane Huang {
104958a09b38SShane Huang 	static const struct dmi_system_id sysids[] = {
105003d783bfSTejun Heo 		/*
105103d783bfSTejun Heo 		 * The oldest version known to be broken is 0901 and
105203d783bfSTejun Heo 		 * working is 1501 which was released on 2007-10-26.
10532fcad9d2STejun Heo 		 * Enable 64bit DMA on 1501 and anything newer.
10542fcad9d2STejun Heo 		 *
105503d783bfSTejun Heo 		 * Please read bko#9412 for more info.
105603d783bfSTejun Heo 		 */
105758a09b38SShane Huang 		{
105858a09b38SShane Huang 			.ident = "ASUS M2A-VM",
105958a09b38SShane Huang 			.matches = {
106058a09b38SShane Huang 				DMI_MATCH(DMI_BOARD_VENDOR,
106158a09b38SShane Huang 					  "ASUSTeK Computer INC."),
106258a09b38SShane Huang 				DMI_MATCH(DMI_BOARD_NAME, "M2A-VM"),
106358a09b38SShane Huang 			},
106403d783bfSTejun Heo 			.driver_data = "20071026",	/* yyyymmdd */
106558a09b38SShane Huang 		},
1066e65cc194SMark Nelson 		/*
1067e65cc194SMark Nelson 		 * All BIOS versions for the MSI K9A2 Platinum (MS-7376)
1068e65cc194SMark Nelson 		 * support 64bit DMA.
1069e65cc194SMark Nelson 		 *
1070e65cc194SMark Nelson 		 * BIOS versions earlier than 1.5 had the Manufacturer DMI
1071e65cc194SMark Nelson 		 * fields as "MICRO-STAR INTERANTIONAL CO.,LTD".
1072e65cc194SMark Nelson 		 * This spelling mistake was fixed in BIOS version 1.5, so
1073e65cc194SMark Nelson 		 * 1.5 and later have the Manufacturer as
1074e65cc194SMark Nelson 		 * "MICRO-STAR INTERNATIONAL CO.,LTD".
1075e65cc194SMark Nelson 		 * So try to match on DMI_BOARD_VENDOR of "MICRO-STAR INTER".
1076e65cc194SMark Nelson 		 *
1077e65cc194SMark Nelson 		 * BIOS versions earlier than 1.9 had a Board Product Name
1078e65cc194SMark Nelson 		 * DMI field of "MS-7376". This was changed to be
1079e65cc194SMark Nelson 		 * "K9A2 Platinum (MS-7376)" in version 1.9, but we can still
1080e65cc194SMark Nelson 		 * match on DMI_BOARD_NAME of "MS-7376".
1081e65cc194SMark Nelson 		 */
1082e65cc194SMark Nelson 		{
1083e65cc194SMark Nelson 			.ident = "MSI K9A2 Platinum",
1084e65cc194SMark Nelson 			.matches = {
1085e65cc194SMark Nelson 				DMI_MATCH(DMI_BOARD_VENDOR,
1086e65cc194SMark Nelson 					  "MICRO-STAR INTER"),
1087e65cc194SMark Nelson 				DMI_MATCH(DMI_BOARD_NAME, "MS-7376"),
1088e65cc194SMark Nelson 			},
1089e65cc194SMark Nelson 		},
10903c4aa91fSMark Nelson 		/*
1091ff0173c1SMark Nelson 		 * All BIOS versions for the MSI K9AGM2 (MS-7327) support
1092ff0173c1SMark Nelson 		 * 64bit DMA.
1093ff0173c1SMark Nelson 		 *
1094ff0173c1SMark Nelson 		 * This board also had the typo mentioned above in the
1095ff0173c1SMark Nelson 		 * Manufacturer DMI field (fixed in BIOS version 1.5), so
1096ff0173c1SMark Nelson 		 * match on DMI_BOARD_VENDOR of "MICRO-STAR INTER" again.
1097ff0173c1SMark Nelson 		 */
1098ff0173c1SMark Nelson 		{
1099ff0173c1SMark Nelson 			.ident = "MSI K9AGM2",
1100ff0173c1SMark Nelson 			.matches = {
1101ff0173c1SMark Nelson 				DMI_MATCH(DMI_BOARD_VENDOR,
1102ff0173c1SMark Nelson 					  "MICRO-STAR INTER"),
1103ff0173c1SMark Nelson 				DMI_MATCH(DMI_BOARD_NAME, "MS-7327"),
1104ff0173c1SMark Nelson 			},
1105ff0173c1SMark Nelson 		},
1106ff0173c1SMark Nelson 		/*
11073c4aa91fSMark Nelson 		 * All BIOS versions for the Asus M3A support 64bit DMA.
11083c4aa91fSMark Nelson 		 * (all release versions from 0301 to 1206 were tested)
11093c4aa91fSMark Nelson 		 */
11103c4aa91fSMark Nelson 		{
11113c4aa91fSMark Nelson 			.ident = "ASUS M3A",
11123c4aa91fSMark Nelson 			.matches = {
11133c4aa91fSMark Nelson 				DMI_MATCH(DMI_BOARD_VENDOR,
11143c4aa91fSMark Nelson 					  "ASUSTeK Computer INC."),
11153c4aa91fSMark Nelson 				DMI_MATCH(DMI_BOARD_NAME, "M3A"),
11163c4aa91fSMark Nelson 			},
11173c4aa91fSMark Nelson 		},
111858a09b38SShane Huang 		{ }
111958a09b38SShane Huang 	};
112003d783bfSTejun Heo 	const struct dmi_system_id *match;
11212fcad9d2STejun Heo 	int year, month, date;
11222fcad9d2STejun Heo 	char buf[9];
112358a09b38SShane Huang 
112403d783bfSTejun Heo 	match = dmi_first_match(sysids);
112558a09b38SShane Huang 	if (pdev->bus->number != 0 || pdev->devfn != PCI_DEVFN(0x12, 0) ||
112603d783bfSTejun Heo 	    !match)
112758a09b38SShane Huang 		return false;
112858a09b38SShane Huang 
1129e65cc194SMark Nelson 	if (!match->driver_data)
1130e65cc194SMark Nelson 		goto enable_64bit;
1131e65cc194SMark Nelson 
113203d783bfSTejun Heo 	dmi_get_date(DMI_BIOS_DATE, &year, &month, &date);
113303d783bfSTejun Heo 	snprintf(buf, sizeof(buf), "%04d%02d%02d", year, month, date);
113403d783bfSTejun Heo 
1135e65cc194SMark Nelson 	if (strcmp(buf, match->driver_data) >= 0)
1136e65cc194SMark Nelson 		goto enable_64bit;
1137e65cc194SMark Nelson 	else {
1138a44fec1fSJoe Perches 		dev_warn(&pdev->dev,
1139a44fec1fSJoe Perches 			 "%s: BIOS too old, forcing 32bit DMA, update BIOS\n",
1140a44fec1fSJoe Perches 			 match->ident);
11412fcad9d2STejun Heo 		return false;
11422fcad9d2STejun Heo 	}
1143e65cc194SMark Nelson 
1144e65cc194SMark Nelson enable_64bit:
1145a44fec1fSJoe Perches 	dev_warn(&pdev->dev, "%s: enabling 64bit DMA\n", match->ident);
1146e65cc194SMark Nelson 	return true;
114758a09b38SShane Huang }
114858a09b38SShane Huang 
11491fd68434SRafael J. Wysocki static bool ahci_broken_system_poweroff(struct pci_dev *pdev)
11501fd68434SRafael J. Wysocki {
11511fd68434SRafael J. Wysocki 	static const struct dmi_system_id broken_systems[] = {
11521fd68434SRafael J. Wysocki 		{
11531fd68434SRafael J. Wysocki 			.ident = "HP Compaq nx6310",
11541fd68434SRafael J. Wysocki 			.matches = {
11551fd68434SRafael J. Wysocki 				DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
11561fd68434SRafael J. Wysocki 				DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq nx6310"),
11571fd68434SRafael J. Wysocki 			},
11581fd68434SRafael J. Wysocki 			/* PCI slot number of the controller */
11591fd68434SRafael J. Wysocki 			.driver_data = (void *)0x1FUL,
11601fd68434SRafael J. Wysocki 		},
1161d2f9c061SMaciej Rutecki 		{
1162d2f9c061SMaciej Rutecki 			.ident = "HP Compaq 6720s",
1163d2f9c061SMaciej Rutecki 			.matches = {
1164d2f9c061SMaciej Rutecki 				DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
1165d2f9c061SMaciej Rutecki 				DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq 6720s"),
1166d2f9c061SMaciej Rutecki 			},
1167d2f9c061SMaciej Rutecki 			/* PCI slot number of the controller */
1168d2f9c061SMaciej Rutecki 			.driver_data = (void *)0x1FUL,
1169d2f9c061SMaciej Rutecki 		},
11701fd68434SRafael J. Wysocki 
11711fd68434SRafael J. Wysocki 		{ }	/* terminate list */
11721fd68434SRafael J. Wysocki 	};
11731fd68434SRafael J. Wysocki 	const struct dmi_system_id *dmi = dmi_first_match(broken_systems);
11741fd68434SRafael J. Wysocki 
11751fd68434SRafael J. Wysocki 	if (dmi) {
11761fd68434SRafael J. Wysocki 		unsigned long slot = (unsigned long)dmi->driver_data;
11771fd68434SRafael J. Wysocki 		/* apply the quirk only to on-board controllers */
11781fd68434SRafael J. Wysocki 		return slot == PCI_SLOT(pdev->devfn);
11791fd68434SRafael J. Wysocki 	}
11801fd68434SRafael J. Wysocki 
11811fd68434SRafael J. Wysocki 	return false;
11821fd68434SRafael J. Wysocki }
11831fd68434SRafael J. Wysocki 
11849b10ae86STejun Heo static bool ahci_broken_suspend(struct pci_dev *pdev)
11859b10ae86STejun Heo {
11869b10ae86STejun Heo 	static const struct dmi_system_id sysids[] = {
11879b10ae86STejun Heo 		/*
11889b10ae86STejun Heo 		 * On HP dv[4-6] and HDX18 with earlier BIOSen, link
11899b10ae86STejun Heo 		 * to the harddisk doesn't become online after
11909b10ae86STejun Heo 		 * resuming from STR.  Warn and fail suspend.
11919deb3431STejun Heo 		 *
11929deb3431STejun Heo 		 * http://bugzilla.kernel.org/show_bug.cgi?id=12276
11939deb3431STejun Heo 		 *
11949deb3431STejun Heo 		 * Use dates instead of versions to match as HP is
11959deb3431STejun Heo 		 * apparently recycling both product and version
11969deb3431STejun Heo 		 * strings.
11979deb3431STejun Heo 		 *
11989deb3431STejun Heo 		 * http://bugzilla.kernel.org/show_bug.cgi?id=15462
11999b10ae86STejun Heo 		 */
12009b10ae86STejun Heo 		{
12019b10ae86STejun Heo 			.ident = "dv4",
12029b10ae86STejun Heo 			.matches = {
12039b10ae86STejun Heo 				DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
12049b10ae86STejun Heo 				DMI_MATCH(DMI_PRODUCT_NAME,
12059b10ae86STejun Heo 					  "HP Pavilion dv4 Notebook PC"),
12069b10ae86STejun Heo 			},
12079deb3431STejun Heo 			.driver_data = "20090105",	/* F.30 */
12089b10ae86STejun Heo 		},
12099b10ae86STejun Heo 		{
12109b10ae86STejun Heo 			.ident = "dv5",
12119b10ae86STejun Heo 			.matches = {
12129b10ae86STejun Heo 				DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
12139b10ae86STejun Heo 				DMI_MATCH(DMI_PRODUCT_NAME,
12149b10ae86STejun Heo 					  "HP Pavilion dv5 Notebook PC"),
12159b10ae86STejun Heo 			},
12169deb3431STejun Heo 			.driver_data = "20090506",	/* F.16 */
12179b10ae86STejun Heo 		},
12189b10ae86STejun Heo 		{
12199b10ae86STejun Heo 			.ident = "dv6",
12209b10ae86STejun Heo 			.matches = {
12219b10ae86STejun Heo 				DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
12229b10ae86STejun Heo 				DMI_MATCH(DMI_PRODUCT_NAME,
12239b10ae86STejun Heo 					  "HP Pavilion dv6 Notebook PC"),
12249b10ae86STejun Heo 			},
12259deb3431STejun Heo 			.driver_data = "20090423",	/* F.21 */
12269b10ae86STejun Heo 		},
12279b10ae86STejun Heo 		{
12289b10ae86STejun Heo 			.ident = "HDX18",
12299b10ae86STejun Heo 			.matches = {
12309b10ae86STejun Heo 				DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
12319b10ae86STejun Heo 				DMI_MATCH(DMI_PRODUCT_NAME,
12329b10ae86STejun Heo 					  "HP HDX18 Notebook PC"),
12339b10ae86STejun Heo 			},
12349deb3431STejun Heo 			.driver_data = "20090430",	/* F.23 */
12359b10ae86STejun Heo 		},
1236cedc9bf9STejun Heo 		/*
1237cedc9bf9STejun Heo 		 * Acer eMachines G725 has the same problem.  BIOS
1238cedc9bf9STejun Heo 		 * V1.03 is known to be broken.  V3.04 is known to
123925985edcSLucas De Marchi 		 * work.  Between, there are V1.06, V2.06 and V3.03
1240cedc9bf9STejun Heo 		 * that we don't have much idea about.  For now,
1241cedc9bf9STejun Heo 		 * blacklist anything older than V3.04.
12429deb3431STejun Heo 		 *
12439deb3431STejun Heo 		 * http://bugzilla.kernel.org/show_bug.cgi?id=15104
1244cedc9bf9STejun Heo 		 */
1245cedc9bf9STejun Heo 		{
1246cedc9bf9STejun Heo 			.ident = "G725",
1247cedc9bf9STejun Heo 			.matches = {
1248cedc9bf9STejun Heo 				DMI_MATCH(DMI_SYS_VENDOR, "eMachines"),
1249cedc9bf9STejun Heo 				DMI_MATCH(DMI_PRODUCT_NAME, "eMachines G725"),
1250cedc9bf9STejun Heo 			},
12519deb3431STejun Heo 			.driver_data = "20091216",	/* V3.04 */
1252cedc9bf9STejun Heo 		},
12539b10ae86STejun Heo 		{ }	/* terminate list */
12549b10ae86STejun Heo 	};
12559b10ae86STejun Heo 	const struct dmi_system_id *dmi = dmi_first_match(sysids);
12569deb3431STejun Heo 	int year, month, date;
12579deb3431STejun Heo 	char buf[9];
12589b10ae86STejun Heo 
12599b10ae86STejun Heo 	if (!dmi || pdev->bus->number || pdev->devfn != PCI_DEVFN(0x1f, 2))
12609b10ae86STejun Heo 		return false;
12619b10ae86STejun Heo 
12629deb3431STejun Heo 	dmi_get_date(DMI_BIOS_DATE, &year, &month, &date);
12639deb3431STejun Heo 	snprintf(buf, sizeof(buf), "%04d%02d%02d", year, month, date);
12649b10ae86STejun Heo 
12659deb3431STejun Heo 	return strcmp(buf, dmi->driver_data) < 0;
12669b10ae86STejun Heo }
12679b10ae86STejun Heo 
1268240630e6SHans de Goede static bool ahci_broken_lpm(struct pci_dev *pdev)
1269240630e6SHans de Goede {
1270240630e6SHans de Goede 	static const struct dmi_system_id sysids[] = {
1271240630e6SHans de Goede 		/* Various Lenovo 50 series have LPM issues with older BIOSen */
1272240630e6SHans de Goede 		{
1273240630e6SHans de Goede 			.matches = {
1274240630e6SHans de Goede 				DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1275240630e6SHans de Goede 				DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X250"),
1276240630e6SHans de Goede 			},
1277240630e6SHans de Goede 			.driver_data = "20180406", /* 1.31 */
1278240630e6SHans de Goede 		},
1279240630e6SHans de Goede 		{
1280240630e6SHans de Goede 			.matches = {
1281240630e6SHans de Goede 				DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1282240630e6SHans de Goede 				DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad L450"),
1283240630e6SHans de Goede 			},
1284240630e6SHans de Goede 			.driver_data = "20180420", /* 1.28 */
1285240630e6SHans de Goede 		},
1286240630e6SHans de Goede 		{
1287240630e6SHans de Goede 			.matches = {
1288240630e6SHans de Goede 				DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1289240630e6SHans de Goede 				DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T450s"),
1290240630e6SHans de Goede 			},
1291240630e6SHans de Goede 			.driver_data = "20180315", /* 1.33 */
1292240630e6SHans de Goede 		},
1293240630e6SHans de Goede 		{
1294240630e6SHans de Goede 			.matches = {
1295240630e6SHans de Goede 				DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1296240630e6SHans de Goede 				DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad W541"),
1297240630e6SHans de Goede 			},
1298240630e6SHans de Goede 			/*
1299240630e6SHans de Goede 			 * Note date based on release notes, 2.35 has been
1300240630e6SHans de Goede 			 * reported to be good, but I've been unable to get
1301240630e6SHans de Goede 			 * a hold of the reporter to get the DMI BIOS date.
1302240630e6SHans de Goede 			 * TODO: fix this.
1303240630e6SHans de Goede 			 */
1304240630e6SHans de Goede 			.driver_data = "20180310", /* 2.35 */
1305240630e6SHans de Goede 		},
1306240630e6SHans de Goede 		{ }	/* terminate list */
1307240630e6SHans de Goede 	};
1308240630e6SHans de Goede 	const struct dmi_system_id *dmi = dmi_first_match(sysids);
1309240630e6SHans de Goede 	int year, month, date;
1310240630e6SHans de Goede 	char buf[9];
1311240630e6SHans de Goede 
1312240630e6SHans de Goede 	if (!dmi)
1313240630e6SHans de Goede 		return false;
1314240630e6SHans de Goede 
1315240630e6SHans de Goede 	dmi_get_date(DMI_BIOS_DATE, &year, &month, &date);
1316240630e6SHans de Goede 	snprintf(buf, sizeof(buf), "%04d%02d%02d", year, month, date);
1317240630e6SHans de Goede 
1318240630e6SHans de Goede 	return strcmp(buf, dmi->driver_data) < 0;
1319240630e6SHans de Goede }
1320240630e6SHans de Goede 
13215594639aSTejun Heo static bool ahci_broken_online(struct pci_dev *pdev)
13225594639aSTejun Heo {
13235594639aSTejun Heo #define ENCODE_BUSDEVFN(bus, slot, func)			\
13245594639aSTejun Heo 	(void *)(unsigned long)(((bus) << 8) | PCI_DEVFN((slot), (func)))
13255594639aSTejun Heo 	static const struct dmi_system_id sysids[] = {
13265594639aSTejun Heo 		/*
13275594639aSTejun Heo 		 * There are several gigabyte boards which use
13285594639aSTejun Heo 		 * SIMG5723s configured as hardware RAID.  Certain
13295594639aSTejun Heo 		 * 5723 firmware revisions shipped there keep the link
13305594639aSTejun Heo 		 * online but fail to answer properly to SRST or
13315594639aSTejun Heo 		 * IDENTIFY when no device is attached downstream
13325594639aSTejun Heo 		 * causing libata to retry quite a few times leading
13335594639aSTejun Heo 		 * to excessive detection delay.
13345594639aSTejun Heo 		 *
13355594639aSTejun Heo 		 * As these firmwares respond to the second reset try
13365594639aSTejun Heo 		 * with invalid device signature, considering unknown
13375594639aSTejun Heo 		 * sig as offline works around the problem acceptably.
13385594639aSTejun Heo 		 */
13395594639aSTejun Heo 		{
13405594639aSTejun Heo 			.ident = "EP45-DQ6",
13415594639aSTejun Heo 			.matches = {
13425594639aSTejun Heo 				DMI_MATCH(DMI_BOARD_VENDOR,
13435594639aSTejun Heo 					  "Gigabyte Technology Co., Ltd."),
13445594639aSTejun Heo 				DMI_MATCH(DMI_BOARD_NAME, "EP45-DQ6"),
13455594639aSTejun Heo 			},
13465594639aSTejun Heo 			.driver_data = ENCODE_BUSDEVFN(0x0a, 0x00, 0),
13475594639aSTejun Heo 		},
13485594639aSTejun Heo 		{
13495594639aSTejun Heo 			.ident = "EP45-DS5",
13505594639aSTejun Heo 			.matches = {
13515594639aSTejun Heo 				DMI_MATCH(DMI_BOARD_VENDOR,
13525594639aSTejun Heo 					  "Gigabyte Technology Co., Ltd."),
13535594639aSTejun Heo 				DMI_MATCH(DMI_BOARD_NAME, "EP45-DS5"),
13545594639aSTejun Heo 			},
13555594639aSTejun Heo 			.driver_data = ENCODE_BUSDEVFN(0x03, 0x00, 0),
13565594639aSTejun Heo 		},
13575594639aSTejun Heo 		{ }	/* terminate list */
13585594639aSTejun Heo 	};
13595594639aSTejun Heo #undef ENCODE_BUSDEVFN
13605594639aSTejun Heo 	const struct dmi_system_id *dmi = dmi_first_match(sysids);
13615594639aSTejun Heo 	unsigned int val;
13625594639aSTejun Heo 
13635594639aSTejun Heo 	if (!dmi)
13645594639aSTejun Heo 		return false;
13655594639aSTejun Heo 
13665594639aSTejun Heo 	val = (unsigned long)dmi->driver_data;
13675594639aSTejun Heo 
13685594639aSTejun Heo 	return pdev->bus->number == (val >> 8) && pdev->devfn == (val & 0xff);
13695594639aSTejun Heo }
13705594639aSTejun Heo 
13710cf4a7d6SJacob Pan static bool ahci_broken_devslp(struct pci_dev *pdev)
13720cf4a7d6SJacob Pan {
13730cf4a7d6SJacob Pan 	/* device with broken DEVSLP but still showing SDS capability */
13740cf4a7d6SJacob Pan 	static const struct pci_device_id ids[] = {
13750cf4a7d6SJacob Pan 		{ PCI_VDEVICE(INTEL, 0x0f23)}, /* Valleyview SoC */
13760cf4a7d6SJacob Pan 		{}
13770cf4a7d6SJacob Pan 	};
13780cf4a7d6SJacob Pan 
13790cf4a7d6SJacob Pan 	return pci_match_id(ids, pdev);
13800cf4a7d6SJacob Pan }
13810cf4a7d6SJacob Pan 
13828e513217SMarkus Trippelsdorf #ifdef CONFIG_ATA_ACPI
1383f80ae7e4STejun Heo static void ahci_gtf_filter_workaround(struct ata_host *host)
1384f80ae7e4STejun Heo {
1385f80ae7e4STejun Heo 	static const struct dmi_system_id sysids[] = {
1386f80ae7e4STejun Heo 		/*
1387f80ae7e4STejun Heo 		 * Aspire 3810T issues a bunch of SATA enable commands
1388f80ae7e4STejun Heo 		 * via _GTF including an invalid one and one which is
1389f80ae7e4STejun Heo 		 * rejected by the device.  Among the successful ones
1390f80ae7e4STejun Heo 		 * is FPDMA non-zero offset enable which when enabled
1391f80ae7e4STejun Heo 		 * only on the drive side leads to NCQ command
1392f80ae7e4STejun Heo 		 * failures.  Filter it out.
1393f80ae7e4STejun Heo 		 */
1394f80ae7e4STejun Heo 		{
1395f80ae7e4STejun Heo 			.ident = "Aspire 3810T",
1396f80ae7e4STejun Heo 			.matches = {
1397f80ae7e4STejun Heo 				DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
1398f80ae7e4STejun Heo 				DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3810T"),
1399f80ae7e4STejun Heo 			},
1400f80ae7e4STejun Heo 			.driver_data = (void *)ATA_ACPI_FILTER_FPDMA_OFFSET,
1401f80ae7e4STejun Heo 		},
1402f80ae7e4STejun Heo 		{ }
1403f80ae7e4STejun Heo 	};
1404f80ae7e4STejun Heo 	const struct dmi_system_id *dmi = dmi_first_match(sysids);
1405f80ae7e4STejun Heo 	unsigned int filter;
1406f80ae7e4STejun Heo 	int i;
1407f80ae7e4STejun Heo 
1408f80ae7e4STejun Heo 	if (!dmi)
1409f80ae7e4STejun Heo 		return;
1410f80ae7e4STejun Heo 
1411f80ae7e4STejun Heo 	filter = (unsigned long)dmi->driver_data;
1412a44fec1fSJoe Perches 	dev_info(host->dev, "applying extra ACPI _GTF filter 0x%x for %s\n",
1413f80ae7e4STejun Heo 		 filter, dmi->ident);
1414f80ae7e4STejun Heo 
1415f80ae7e4STejun Heo 	for (i = 0; i < host->n_ports; i++) {
1416f80ae7e4STejun Heo 		struct ata_port *ap = host->ports[i];
1417f80ae7e4STejun Heo 		struct ata_link *link;
1418f80ae7e4STejun Heo 		struct ata_device *dev;
1419f80ae7e4STejun Heo 
1420f80ae7e4STejun Heo 		ata_for_each_link(link, ap, EDGE)
1421f80ae7e4STejun Heo 			ata_for_each_dev(dev, link, ALL)
1422f80ae7e4STejun Heo 				dev->gtf_filter |= filter;
1423f80ae7e4STejun Heo 	}
1424f80ae7e4STejun Heo }
14258e513217SMarkus Trippelsdorf #else
14268e513217SMarkus Trippelsdorf static inline void ahci_gtf_filter_workaround(struct ata_host *host)
14278e513217SMarkus Trippelsdorf {}
14288e513217SMarkus Trippelsdorf #endif
1429f80ae7e4STejun Heo 
14308bfd1743SSui Chen /*
14318bfd1743SSui Chen  * On the Acer Aspire Switch Alpha 12, sometimes all SATA ports are detected
14328bfd1743SSui Chen  * as DUMMY, or detected but eventually get a "link down" and never get up
14338bfd1743SSui Chen  * again. When this happens, CAP.NP may hold a value of 0x00 or 0x01, and the
14348bfd1743SSui Chen  * port_map may hold a value of 0x00.
14358bfd1743SSui Chen  *
14368bfd1743SSui Chen  * Overriding CAP.NP to 0x02 and the port_map to 0x7 will reveal all 3 ports
14378bfd1743SSui Chen  * and can significantly reduce the occurrence of the problem.
14388bfd1743SSui Chen  *
14398bfd1743SSui Chen  * https://bugzilla.kernel.org/show_bug.cgi?id=189471
14408bfd1743SSui Chen  */
14418bfd1743SSui Chen static void acer_sa5_271_workaround(struct ahci_host_priv *hpriv,
14428bfd1743SSui Chen 				    struct pci_dev *pdev)
14438bfd1743SSui Chen {
14448bfd1743SSui Chen 	static const struct dmi_system_id sysids[] = {
14458bfd1743SSui Chen 		{
14468bfd1743SSui Chen 			.ident = "Acer Switch Alpha 12",
14478bfd1743SSui Chen 			.matches = {
14488bfd1743SSui Chen 				DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
14498bfd1743SSui Chen 				DMI_MATCH(DMI_PRODUCT_NAME, "Switch SA5-271")
14508bfd1743SSui Chen 			},
14518bfd1743SSui Chen 		},
14528bfd1743SSui Chen 		{ }
14538bfd1743SSui Chen 	};
14548bfd1743SSui Chen 
14558bfd1743SSui Chen 	if (dmi_check_system(sysids)) {
14568bfd1743SSui Chen 		dev_info(&pdev->dev, "enabling Acer Switch Alpha 12 workaround\n");
14578bfd1743SSui Chen 		if ((hpriv->saved_cap & 0xC734FF00) == 0xC734FF00) {
14588bfd1743SSui Chen 			hpriv->port_map = 0x7;
14598bfd1743SSui Chen 			hpriv->cap = 0xC734FF02;
14608bfd1743SSui Chen 		}
14618bfd1743SSui Chen 	}
14628bfd1743SSui Chen }
14638bfd1743SSui Chen 
1464d243bed3STirumalesh Chalamarla #ifdef CONFIG_ARM64
1465d243bed3STirumalesh Chalamarla /*
1466d243bed3STirumalesh Chalamarla  * Due to ERRATA#22536, ThunderX needs to handle HOST_IRQ_STAT differently.
1467d243bed3STirumalesh Chalamarla  * Workaround is to make sure all pending IRQs are served before leaving
1468d243bed3STirumalesh Chalamarla  * handler.
1469d243bed3STirumalesh Chalamarla  */
1470d243bed3STirumalesh Chalamarla static irqreturn_t ahci_thunderx_irq_handler(int irq, void *dev_instance)
1471d243bed3STirumalesh Chalamarla {
1472d243bed3STirumalesh Chalamarla 	struct ata_host *host = dev_instance;
1473d243bed3STirumalesh Chalamarla 	struct ahci_host_priv *hpriv;
1474d243bed3STirumalesh Chalamarla 	unsigned int rc = 0;
1475d243bed3STirumalesh Chalamarla 	void __iomem *mmio;
1476d243bed3STirumalesh Chalamarla 	u32 irq_stat, irq_masked;
1477d243bed3STirumalesh Chalamarla 	unsigned int handled = 1;
1478d243bed3STirumalesh Chalamarla 
1479d243bed3STirumalesh Chalamarla 	VPRINTK("ENTER\n");
1480d243bed3STirumalesh Chalamarla 	hpriv = host->private_data;
1481d243bed3STirumalesh Chalamarla 	mmio = hpriv->mmio;
1482d243bed3STirumalesh Chalamarla 	irq_stat = readl(mmio + HOST_IRQ_STAT);
1483d243bed3STirumalesh Chalamarla 	if (!irq_stat)
1484d243bed3STirumalesh Chalamarla 		return IRQ_NONE;
1485d243bed3STirumalesh Chalamarla 
1486d243bed3STirumalesh Chalamarla 	do {
1487d243bed3STirumalesh Chalamarla 		irq_masked = irq_stat & hpriv->port_map;
1488d243bed3STirumalesh Chalamarla 		spin_lock(&host->lock);
1489d243bed3STirumalesh Chalamarla 		rc = ahci_handle_port_intr(host, irq_masked);
1490d243bed3STirumalesh Chalamarla 		if (!rc)
1491d243bed3STirumalesh Chalamarla 			handled = 0;
1492d243bed3STirumalesh Chalamarla 		writel(irq_stat, mmio + HOST_IRQ_STAT);
1493d243bed3STirumalesh Chalamarla 		irq_stat = readl(mmio + HOST_IRQ_STAT);
1494d243bed3STirumalesh Chalamarla 		spin_unlock(&host->lock);
1495d243bed3STirumalesh Chalamarla 	} while (irq_stat);
1496d243bed3STirumalesh Chalamarla 	VPRINTK("EXIT\n");
1497d243bed3STirumalesh Chalamarla 
1498d243bed3STirumalesh Chalamarla 	return IRQ_RETVAL(handled);
1499d243bed3STirumalesh Chalamarla }
1500d243bed3STirumalesh Chalamarla #endif
1501d243bed3STirumalesh Chalamarla 
1502aecec8b6SChristoph Hellwig static void ahci_remap_check(struct pci_dev *pdev, int bar,
1503aecec8b6SChristoph Hellwig 		struct ahci_host_priv *hpriv)
1504aecec8b6SChristoph Hellwig {
1505894fba7fSKai-Heng Feng 	int i;
1506aecec8b6SChristoph Hellwig 	u32 cap;
1507aecec8b6SChristoph Hellwig 
1508aecec8b6SChristoph Hellwig 	/*
1509aecec8b6SChristoph Hellwig 	 * Check if this device might have remapped nvme devices.
1510aecec8b6SChristoph Hellwig 	 */
1511aecec8b6SChristoph Hellwig 	if (pdev->vendor != PCI_VENDOR_ID_INTEL ||
1512aecec8b6SChristoph Hellwig 	    pci_resource_len(pdev, bar) < SZ_512K ||
1513aecec8b6SChristoph Hellwig 	    bar != AHCI_PCI_BAR_STANDARD ||
1514aecec8b6SChristoph Hellwig 	    !(readl(hpriv->mmio + AHCI_VSCAP) & 1))
1515aecec8b6SChristoph Hellwig 		return;
1516aecec8b6SChristoph Hellwig 
1517aecec8b6SChristoph Hellwig 	cap = readq(hpriv->mmio + AHCI_REMAP_CAP);
1518aecec8b6SChristoph Hellwig 	for (i = 0; i < AHCI_MAX_REMAP; i++) {
1519aecec8b6SChristoph Hellwig 		if ((cap & (1 << i)) == 0)
1520aecec8b6SChristoph Hellwig 			continue;
1521aecec8b6SChristoph Hellwig 		if (readl(hpriv->mmio + ahci_remap_dcc(i))
1522aecec8b6SChristoph Hellwig 				!= PCI_CLASS_STORAGE_EXPRESS)
1523aecec8b6SChristoph Hellwig 			continue;
1524aecec8b6SChristoph Hellwig 
1525aecec8b6SChristoph Hellwig 		/* We've found a remapped device */
1526894fba7fSKai-Heng Feng 		hpriv->remapped_nvme++;
1527aecec8b6SChristoph Hellwig 	}
1528aecec8b6SChristoph Hellwig 
1529894fba7fSKai-Heng Feng 	if (!hpriv->remapped_nvme)
1530aecec8b6SChristoph Hellwig 		return;
1531aecec8b6SChristoph Hellwig 
1532894fba7fSKai-Heng Feng 	dev_warn(&pdev->dev, "Found %u remapped NVMe devices.\n",
1533894fba7fSKai-Heng Feng 		 hpriv->remapped_nvme);
1534f723fa4eSChristoph Hellwig 	dev_warn(&pdev->dev,
1535f723fa4eSChristoph Hellwig 		 "Switch your BIOS from RAID to AHCI mode to use them.\n");
1536f723fa4eSChristoph Hellwig 
1537f723fa4eSChristoph Hellwig 	/*
1538f723fa4eSChristoph Hellwig 	 * Don't rely on the msi-x capability in the remap case,
1539f723fa4eSChristoph Hellwig 	 * share the legacy interrupt across ahci and remapped devices.
1540f723fa4eSChristoph Hellwig 	 */
1541f723fa4eSChristoph Hellwig 	hpriv->flags |= AHCI_HFLAG_NO_MSI;
1542aecec8b6SChristoph Hellwig }
1543aecec8b6SChristoph Hellwig 
15440b9e2988SChristoph Hellwig static int ahci_get_irq_vector(struct ata_host *host, int port)
1545ee2aad42SRobert Richter {
15460b9e2988SChristoph Hellwig 	return pci_irq_vector(to_pci_dev(host->dev), port);
1547ee2aad42SRobert Richter }
1548ee2aad42SRobert Richter 
1549a1c82311SRobert Richter static int ahci_init_msi(struct pci_dev *pdev, unsigned int n_ports,
15507b92b4f6SAlexander Gordeev 			struct ahci_host_priv *hpriv)
15515ca72c4fSAlexander Gordeev {
15520b9e2988SChristoph Hellwig 	int nvec;
15535ca72c4fSAlexander Gordeev 
15547b92b4f6SAlexander Gordeev 	if (hpriv->flags & AHCI_HFLAG_NO_MSI)
1555a1c82311SRobert Richter 		return -ENODEV;
15567b92b4f6SAlexander Gordeev 
15575ca72c4fSAlexander Gordeev 	/*
15587b92b4f6SAlexander Gordeev 	 * If number of MSIs is less than number of ports then Sharing Last
15597b92b4f6SAlexander Gordeev 	 * Message mode could be enforced. In this case assume that advantage
15607b92b4f6SAlexander Gordeev 	 * of multipe MSIs is negated and use single MSI mode instead.
15615ca72c4fSAlexander Gordeev 	 */
156217a51f12SChristoph Hellwig 	if (n_ports > 1) {
15630b9e2988SChristoph Hellwig 		nvec = pci_alloc_irq_vectors(pdev, n_ports, INT_MAX,
15640b9e2988SChristoph Hellwig 				PCI_IRQ_MSIX | PCI_IRQ_MSI);
15650b9e2988SChristoph Hellwig 		if (nvec > 0) {
15660b9e2988SChristoph Hellwig 			if (!(readl(hpriv->mmio + HOST_CTL) & HOST_MRSM)) {
15670b9e2988SChristoph Hellwig 				hpriv->get_irq_vector = ahci_get_irq_vector;
1568c3ebd6a9SAlexander Gordeev 				hpriv->flags |= AHCI_HFLAG_MULTI_MSI;
156921bfd1aaSRobert Richter 				return nvec;
1570a1c82311SRobert Richter 			}
1571a1c82311SRobert Richter 
1572d684a90dSDan Williams 			/*
157317a51f12SChristoph Hellwig 			 * Fallback to single MSI mode if the controller
157417a51f12SChristoph Hellwig 			 * enforced MRSM mode.
1575d684a90dSDan Williams 			 */
157617a51f12SChristoph Hellwig 			printk(KERN_INFO
157717a51f12SChristoph Hellwig 				"ahci: MRSM is on, fallback to single MSI\n");
15780b9e2988SChristoph Hellwig 			pci_free_irq_vectors(pdev);
15790b9e2988SChristoph Hellwig 		}
1580a478b097SChristoph Hellwig 	}
1581d684a90dSDan Williams 
15820b9e2988SChristoph Hellwig 	/*
15830b9e2988SChristoph Hellwig 	 * If the host is not capable of supporting per-port vectors, fall
15840b9e2988SChristoph Hellwig 	 * back to single MSI before finally attempting single MSI-X.
15850b9e2988SChristoph Hellwig 	 */
15860b9e2988SChristoph Hellwig 	nvec = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSI);
15870b9e2988SChristoph Hellwig 	if (nvec == 1)
1588a1c82311SRobert Richter 		return nvec;
15890b9e2988SChristoph Hellwig 	return pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSIX);
15905ca72c4fSAlexander Gordeev }
15915ca72c4fSAlexander Gordeev 
1592b1a9585cSSrinivas Pandruvada static void ahci_update_initial_lpm_policy(struct ata_port *ap,
1593b1a9585cSSrinivas Pandruvada 					   struct ahci_host_priv *hpriv)
1594b1a9585cSSrinivas Pandruvada {
1595b1a9585cSSrinivas Pandruvada 	int policy = CONFIG_SATA_MOBILE_LPM_POLICY;
1596b1a9585cSSrinivas Pandruvada 
1597b1a9585cSSrinivas Pandruvada 
1598b1a9585cSSrinivas Pandruvada 	/* Ignore processing for non mobile platforms */
1599b1a9585cSSrinivas Pandruvada 	if (!(hpriv->flags & AHCI_HFLAG_IS_MOBILE))
1600b1a9585cSSrinivas Pandruvada 		return;
1601b1a9585cSSrinivas Pandruvada 
1602b1a9585cSSrinivas Pandruvada 	/* user modified policy via module param */
1603b1a9585cSSrinivas Pandruvada 	if (mobile_lpm_policy != -1) {
1604b1a9585cSSrinivas Pandruvada 		policy = mobile_lpm_policy;
1605b1a9585cSSrinivas Pandruvada 		goto update_policy;
1606b1a9585cSSrinivas Pandruvada 	}
1607b1a9585cSSrinivas Pandruvada 
1608b1a9585cSSrinivas Pandruvada #ifdef CONFIG_ACPI
1609b1a9585cSSrinivas Pandruvada 	if (policy > ATA_LPM_MED_POWER &&
1610b1a9585cSSrinivas Pandruvada 	    (acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0)) {
1611b1a9585cSSrinivas Pandruvada 		if (hpriv->cap & HOST_CAP_PART)
1612b1a9585cSSrinivas Pandruvada 			policy = ATA_LPM_MIN_POWER_WITH_PARTIAL;
1613b1a9585cSSrinivas Pandruvada 		else if (hpriv->cap & HOST_CAP_SSC)
1614b1a9585cSSrinivas Pandruvada 			policy = ATA_LPM_MIN_POWER;
1615b1a9585cSSrinivas Pandruvada 	}
1616b1a9585cSSrinivas Pandruvada #endif
1617b1a9585cSSrinivas Pandruvada 
1618b1a9585cSSrinivas Pandruvada update_policy:
1619b1a9585cSSrinivas Pandruvada 	if (policy >= ATA_LPM_UNKNOWN && policy <= ATA_LPM_MIN_POWER)
1620b1a9585cSSrinivas Pandruvada 		ap->target_lpm_policy = policy;
1621b1a9585cSSrinivas Pandruvada }
1622b1a9585cSSrinivas Pandruvada 
1623c312ef17SDan Williams static void ahci_intel_pcs_quirk(struct pci_dev *pdev, struct ahci_host_priv *hpriv)
1624c312ef17SDan Williams {
1625c312ef17SDan Williams 	const struct pci_device_id *id = pci_match_id(ahci_pci_tbl, pdev);
1626c312ef17SDan Williams 	u16 tmp16;
1627c312ef17SDan Williams 
1628c312ef17SDan Williams 	/*
1629c312ef17SDan Williams 	 * Only apply the 6-port PCS quirk for known legacy platforms.
1630c312ef17SDan Williams 	 */
1631c312ef17SDan Williams 	if (!id || id->vendor != PCI_VENDOR_ID_INTEL)
1632c312ef17SDan Williams 		return;
163309d6ac8dSDan Williams 
163409d6ac8dSDan Williams 	/* Skip applying the quirk on Denverton and beyond */
163509d6ac8dSDan Williams 	if (((enum board_ids) id->driver_data) >= board_ahci_pcs7)
1636c312ef17SDan Williams 		return;
1637c312ef17SDan Williams 
1638c312ef17SDan Williams 	/*
1639c312ef17SDan Williams 	 * port_map is determined from PORTS_IMPL PCI register which is
1640c312ef17SDan Williams 	 * implemented as write or write-once register.  If the register
1641c312ef17SDan Williams 	 * isn't programmed, ahci automatically generates it from number
1642c312ef17SDan Williams 	 * of ports, which is good enough for PCS programming. It is
1643c312ef17SDan Williams 	 * otherwise expected that platform firmware enables the ports
1644c312ef17SDan Williams 	 * before the OS boots.
1645c312ef17SDan Williams 	 */
1646c312ef17SDan Williams 	pci_read_config_word(pdev, PCS_6, &tmp16);
1647c312ef17SDan Williams 	if ((tmp16 & hpriv->port_map) != hpriv->port_map) {
1648c312ef17SDan Williams 		tmp16 |= hpriv->port_map;
1649c312ef17SDan Williams 		pci_write_config_word(pdev, PCS_6, tmp16);
1650c312ef17SDan Williams 	}
1651c312ef17SDan Williams }
1652c312ef17SDan Williams 
1653894fba7fSKai-Heng Feng static ssize_t remapped_nvme_show(struct device *dev,
1654894fba7fSKai-Heng Feng 				  struct device_attribute *attr,
1655894fba7fSKai-Heng Feng 				  char *buf)
1656894fba7fSKai-Heng Feng {
1657894fba7fSKai-Heng Feng 	struct ata_host *host = dev_get_drvdata(dev);
1658894fba7fSKai-Heng Feng 	struct ahci_host_priv *hpriv = host->private_data;
1659894fba7fSKai-Heng Feng 
1660*179a0282SDamien Le Moal 	return sysfs_emit(buf, "%u\n", hpriv->remapped_nvme);
1661894fba7fSKai-Heng Feng }
1662894fba7fSKai-Heng Feng 
1663894fba7fSKai-Heng Feng static DEVICE_ATTR_RO(remapped_nvme);
1664894fba7fSKai-Heng Feng 
1665c6fd2807SJeff Garzik static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
1666c6fd2807SJeff Garzik {
1667e297d99eSTejun Heo 	unsigned int board_id = ent->driver_data;
1668e297d99eSTejun Heo 	struct ata_port_info pi = ahci_port_info[board_id];
16694447d351STejun Heo 	const struct ata_port_info *ppi[] = { &pi, NULL };
167024dc5f33STejun Heo 	struct device *dev = &pdev->dev;
1671c6fd2807SJeff Garzik 	struct ahci_host_priv *hpriv;
16724447d351STejun Heo 	struct ata_host *host;
1673c3ebd6a9SAlexander Gordeev 	int n_ports, i, rc;
1674318893e1SAlessandro Rubini 	int ahci_pci_bar = AHCI_PCI_BAR_STANDARD;
1675c6fd2807SJeff Garzik 
1676c6fd2807SJeff Garzik 	VPRINTK("ENTER\n");
1677c6fd2807SJeff Garzik 
1678b429dd59SJustin P. Mattock 	WARN_ON((int)ATA_MAX_QUEUE > AHCI_MAX_CMDS);
1679c6fd2807SJeff Garzik 
168006296a1eSJoe Perches 	ata_print_version_once(&pdev->dev, DRV_VERSION);
1681c6fd2807SJeff Garzik 
16825b66c829SAlan Cox 	/* The AHCI driver can only drive the SATA ports, the PATA driver
16835b66c829SAlan Cox 	   can drive them all so if both drivers are selected make sure
16845b66c829SAlan Cox 	   AHCI stays out of the way */
16855b66c829SAlan Cox 	if (pdev->vendor == PCI_VENDOR_ID_MARVELL && !marvell_enable)
16865b66c829SAlan Cox 		return -ENODEV;
16875b66c829SAlan Cox 
1688cb85696dSJames Laird 	/* Apple BIOS on MCP89 prevents us using AHCI */
1689cb85696dSJames Laird 	if (is_mcp89_apple(pdev))
1690cb85696dSJames Laird 		ahci_mcp89_apple_enable(pdev);
1691c6353b45STejun Heo 
16927a02267eSMark Nelson 	/* Promise's PDC42819 is a SAS/SATA controller that has an AHCI mode.
16937a02267eSMark Nelson 	 * At the moment, we can only use the AHCI mode. Let the users know
16947a02267eSMark Nelson 	 * that for SAS drives they're out of luck.
16957a02267eSMark Nelson 	 */
16967a02267eSMark Nelson 	if (pdev->vendor == PCI_VENDOR_ID_PROMISE)
1697a44fec1fSJoe Perches 		dev_info(&pdev->dev,
1698a44fec1fSJoe Perches 			 "PDC42819 can only drive SATA devices with this driver\n");
16997a02267eSMark Nelson 
1700b7ae128dSRobert Richter 	/* Some devices use non-standard BARs */
1701318893e1SAlessandro Rubini 	if (pdev->vendor == PCI_VENDOR_ID_STMICRO && pdev->device == 0xCC06)
1702318893e1SAlessandro Rubini 		ahci_pci_bar = AHCI_PCI_BAR_STA2X11;
17037f9c9f8eSHugh Daschbach 	else if (pdev->vendor == 0x1c44 && pdev->device == 0x8000)
17047f9c9f8eSHugh Daschbach 		ahci_pci_bar = AHCI_PCI_BAR_ENMOTUS;
1705b1314e3fSRadha Mohan Chintakuntla 	else if (pdev->vendor == PCI_VENDOR_ID_CAVIUM) {
1706b1314e3fSRadha Mohan Chintakuntla 		if (pdev->device == 0xa01c)
1707b7ae128dSRobert Richter 			ahci_pci_bar = AHCI_PCI_BAR_CAVIUM;
1708b1314e3fSRadha Mohan Chintakuntla 		if (pdev->device == 0xa084)
1709b1314e3fSRadha Mohan Chintakuntla 			ahci_pci_bar = AHCI_PCI_BAR_CAVIUM_GEN5;
1710e49bd683STiezhu Yang 	} else if (pdev->vendor == PCI_VENDOR_ID_LOONGSON) {
1711e49bd683STiezhu Yang 		if (pdev->device == 0x7a08)
1712e49bd683STiezhu Yang 			ahci_pci_bar = AHCI_PCI_BAR_LOONGSON;
1713b1314e3fSRadha Mohan Chintakuntla 	}
1714318893e1SAlessandro Rubini 
17154447d351STejun Heo 	/* acquire resources */
171624dc5f33STejun Heo 	rc = pcim_enable_device(pdev);
1717c6fd2807SJeff Garzik 	if (rc)
1718c6fd2807SJeff Garzik 		return rc;
1719c6fd2807SJeff Garzik 
1720c4f7792cSTejun Heo 	if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
1721c4f7792cSTejun Heo 	    (pdev->device == 0x2652 || pdev->device == 0x2653)) {
1722c4f7792cSTejun Heo 		u8 map;
1723c4f7792cSTejun Heo 
1724c4f7792cSTejun Heo 		/* ICH6s share the same PCI ID for both piix and ahci
1725c4f7792cSTejun Heo 		 * modes.  Enabling ahci mode while MAP indicates
1726c4f7792cSTejun Heo 		 * combined mode is a bad idea.  Yield to ata_piix.
1727c4f7792cSTejun Heo 		 */
1728c4f7792cSTejun Heo 		pci_read_config_byte(pdev, ICH_MAP, &map);
1729c4f7792cSTejun Heo 		if (map & 0x3) {
1730a44fec1fSJoe Perches 			dev_info(&pdev->dev,
1731a44fec1fSJoe Perches 				 "controller is in combined mode, can't enable AHCI mode\n");
1732c4f7792cSTejun Heo 			return -ENODEV;
1733c4f7792cSTejun Heo 		}
1734c4f7792cSTejun Heo 	}
1735c4f7792cSTejun Heo 
17366fec8871SPaul Bolle 	/* AHCI controllers often implement SFF compatible interface.
17376fec8871SPaul Bolle 	 * Grab all PCI BARs just in case.
17386fec8871SPaul Bolle 	 */
17396fec8871SPaul Bolle 	rc = pcim_iomap_regions_request_all(pdev, 1 << ahci_pci_bar, DRV_NAME);
17406fec8871SPaul Bolle 	if (rc == -EBUSY)
17416fec8871SPaul Bolle 		pcim_pin_device(pdev);
17426fec8871SPaul Bolle 	if (rc)
17436fec8871SPaul Bolle 		return rc;
17446fec8871SPaul Bolle 
174524dc5f33STejun Heo 	hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
174624dc5f33STejun Heo 	if (!hpriv)
174724dc5f33STejun Heo 		return -ENOMEM;
1748417a1a6dSTejun Heo 	hpriv->flags |= (unsigned long)pi.private_data;
1749417a1a6dSTejun Heo 
1750e297d99eSTejun Heo 	/* MCP65 revision A1 and A2 can't do MSI */
1751e297d99eSTejun Heo 	if (board_id == board_ahci_mcp65 &&
1752e297d99eSTejun Heo 	    (pdev->revision == 0xa1 || pdev->revision == 0xa2))
1753e297d99eSTejun Heo 		hpriv->flags |= AHCI_HFLAG_NO_MSI;
1754e297d99eSTejun Heo 
1755e427fe04SShane Huang 	/* SB800 does NOT need the workaround to ignore SERR_INTERNAL */
1756e427fe04SShane Huang 	if (board_id == board_ahci_sb700 && pdev->revision >= 0x40)
1757e427fe04SShane Huang 		hpriv->flags &= ~AHCI_HFLAG_IGN_SERR_INTERNAL;
1758e427fe04SShane Huang 
17592fcad9d2STejun Heo 	/* only some SB600s can do 64bit DMA */
17602fcad9d2STejun Heo 	if (ahci_sb600_enable_64bit(pdev))
17612fcad9d2STejun Heo 		hpriv->flags &= ~AHCI_HFLAG_32BIT_ONLY;
176258a09b38SShane Huang 
1763318893e1SAlessandro Rubini 	hpriv->mmio = pcim_iomap_table(pdev)[ahci_pci_bar];
1764d8993349SAnton Vorontsov 
1765aecec8b6SChristoph Hellwig 	/* detect remapped nvme devices */
1766aecec8b6SChristoph Hellwig 	ahci_remap_check(pdev, ahci_pci_bar, hpriv);
1767aecec8b6SChristoph Hellwig 
1768894fba7fSKai-Heng Feng 	sysfs_add_file_to_group(&pdev->dev.kobj,
1769894fba7fSKai-Heng Feng 				&dev_attr_remapped_nvme.attr,
1770894fba7fSKai-Heng Feng 				NULL);
1771894fba7fSKai-Heng Feng 
17720cf4a7d6SJacob Pan 	/* must set flag prior to save config in order to take effect */
17730cf4a7d6SJacob Pan 	if (ahci_broken_devslp(pdev))
17740cf4a7d6SJacob Pan 		hpriv->flags |= AHCI_HFLAG_NO_DEVSLP;
17750cf4a7d6SJacob Pan 
1776d243bed3STirumalesh Chalamarla #ifdef CONFIG_ARM64
1777234e6d2cSXingui Yang 	if (pdev->vendor == PCI_VENDOR_ID_HUAWEI &&
1778234e6d2cSXingui Yang 	    pdev->device == 0xa235 &&
1779234e6d2cSXingui Yang 	    pdev->revision < 0x30)
1780234e6d2cSXingui Yang 		hpriv->flags |= AHCI_HFLAG_NO_SXS;
1781234e6d2cSXingui Yang 
1782d243bed3STirumalesh Chalamarla 	if (pdev->vendor == 0x177d && pdev->device == 0xa01c)
1783d243bed3STirumalesh Chalamarla 		hpriv->irq_handler = ahci_thunderx_irq_handler;
1784d243bed3STirumalesh Chalamarla #endif
1785d243bed3STirumalesh Chalamarla 
17864447d351STejun Heo 	/* save initial config */
1787394d6e53SAnton Vorontsov 	ahci_pci_save_initial_config(pdev, hpriv);
1788c6fd2807SJeff Garzik 
1789c312ef17SDan Williams 	/*
1790c312ef17SDan Williams 	 * If platform firmware failed to enable ports, try to enable
1791c312ef17SDan Williams 	 * them here.
1792c312ef17SDan Williams 	 */
1793c312ef17SDan Williams 	ahci_intel_pcs_quirk(pdev, hpriv);
1794c312ef17SDan Williams 
17954447d351STejun Heo 	/* prepare host */
1796453d3131SRobert Hancock 	if (hpriv->cap & HOST_CAP_NCQ) {
1797453d3131SRobert Hancock 		pi.flags |= ATA_FLAG_NCQ;
179883f2b963STejun Heo 		/*
179983f2b963STejun Heo 		 * Auto-activate optimization is supposed to be
180083f2b963STejun Heo 		 * supported on all AHCI controllers indicating NCQ
180183f2b963STejun Heo 		 * capability, but it seems to be broken on some
180283f2b963STejun Heo 		 * chipsets including NVIDIAs.
180383f2b963STejun Heo 		 */
180483f2b963STejun Heo 		if (!(hpriv->flags & AHCI_HFLAG_NO_FPDMA_AA))
1805453d3131SRobert Hancock 			pi.flags |= ATA_FLAG_FPDMA_AA;
180640fb59e7SMarc Carino 
180740fb59e7SMarc Carino 		/*
180840fb59e7SMarc Carino 		 * All AHCI controllers should be forward-compatible
180940fb59e7SMarc Carino 		 * with the new auxiliary field. This code should be
181040fb59e7SMarc Carino 		 * conditionalized if any buggy AHCI controllers are
181140fb59e7SMarc Carino 		 * encountered.
181240fb59e7SMarc Carino 		 */
181340fb59e7SMarc Carino 		pi.flags |= ATA_FLAG_FPDMA_AUX;
1814453d3131SRobert Hancock 	}
18154447d351STejun Heo 
18167d50b60bSTejun Heo 	if (hpriv->cap & HOST_CAP_PMP)
18177d50b60bSTejun Heo 		pi.flags |= ATA_FLAG_PMP;
18187d50b60bSTejun Heo 
18190cbb0e77SAnton Vorontsov 	ahci_set_em_messages(hpriv, &pi);
182018f7ba4cSKristen Carlson Accardi 
18211fd68434SRafael J. Wysocki 	if (ahci_broken_system_poweroff(pdev)) {
18221fd68434SRafael J. Wysocki 		pi.flags |= ATA_FLAG_NO_POWEROFF_SPINDOWN;
18231fd68434SRafael J. Wysocki 		dev_info(&pdev->dev,
18241fd68434SRafael J. Wysocki 			"quirky BIOS, skipping spindown on poweroff\n");
18251fd68434SRafael J. Wysocki 	}
18261fd68434SRafael J. Wysocki 
1827240630e6SHans de Goede 	if (ahci_broken_lpm(pdev)) {
1828240630e6SHans de Goede 		pi.flags |= ATA_FLAG_NO_LPM;
1829240630e6SHans de Goede 		dev_warn(&pdev->dev,
1830240630e6SHans de Goede 			 "BIOS update required for Link Power Management support\n");
1831240630e6SHans de Goede 	}
1832240630e6SHans de Goede 
18339b10ae86STejun Heo 	if (ahci_broken_suspend(pdev)) {
18349b10ae86STejun Heo 		hpriv->flags |= AHCI_HFLAG_NO_SUSPEND;
1835a44fec1fSJoe Perches 		dev_warn(&pdev->dev,
18369b10ae86STejun Heo 			 "BIOS update required for suspend/resume\n");
18379b10ae86STejun Heo 	}
18389b10ae86STejun Heo 
18395594639aSTejun Heo 	if (ahci_broken_online(pdev)) {
18405594639aSTejun Heo 		hpriv->flags |= AHCI_HFLAG_SRST_TOUT_IS_OFFLINE;
18415594639aSTejun Heo 		dev_info(&pdev->dev,
18425594639aSTejun Heo 			 "online status unreliable, applying workaround\n");
18435594639aSTejun Heo 	}
18445594639aSTejun Heo 
18458bfd1743SSui Chen 
18468bfd1743SSui Chen 	/* Acer SA5-271 workaround modifies private_data */
18478bfd1743SSui Chen 	acer_sa5_271_workaround(hpriv, pdev);
18488bfd1743SSui Chen 
1849837f5f8fSTejun Heo 	/* CAP.NP sometimes indicate the index of the last enabled
1850837f5f8fSTejun Heo 	 * port, at other times, that of the last possible port, so
1851837f5f8fSTejun Heo 	 * determining the maximum port number requires looking at
1852837f5f8fSTejun Heo 	 * both CAP.NP and port_map.
1853837f5f8fSTejun Heo 	 */
1854837f5f8fSTejun Heo 	n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map));
1855837f5f8fSTejun Heo 
1856837f5f8fSTejun Heo 	host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);
18574447d351STejun Heo 	if (!host)
18584447d351STejun Heo 		return -ENOMEM;
18594447d351STejun Heo 	host->private_data = hpriv;
18600b9e2988SChristoph Hellwig 
18610b9e2988SChristoph Hellwig 	if (ahci_init_msi(pdev, n_ports, hpriv) < 0) {
18620b9e2988SChristoph Hellwig 		/* legacy intx interrupts */
18630b9e2988SChristoph Hellwig 		pci_intx(pdev, 1);
18640b9e2988SChristoph Hellwig 	}
18650ce57f8aSChristoph Hellwig 	hpriv->irq = pci_irq_vector(pdev, 0);
186621bfd1aaSRobert Richter 
1867f3d7f23fSArjan van de Ven 	if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss)
1868886ad09fSArjan van de Ven 		host->flags |= ATA_HOST_PARALLEL_SCAN;
1869f3d7f23fSArjan van de Ven 	else
1870d2782d96SJingoo Han 		dev_info(&pdev->dev, "SSS flag set, parallel bus scan disabled\n");
1871886ad09fSArjan van de Ven 
187218f7ba4cSKristen Carlson Accardi 	if (pi.flags & ATA_FLAG_EM)
187318f7ba4cSKristen Carlson Accardi 		ahci_reset_em(host);
187418f7ba4cSKristen Carlson Accardi 
18754447d351STejun Heo 	for (i = 0; i < host->n_ports; i++) {
18764447d351STejun Heo 		struct ata_port *ap = host->ports[i];
18774447d351STejun Heo 
1878318893e1SAlessandro Rubini 		ata_port_pbar_desc(ap, ahci_pci_bar, -1, "abar");
1879318893e1SAlessandro Rubini 		ata_port_pbar_desc(ap, ahci_pci_bar,
1880cbcdd875STejun Heo 				   0x100 + ap->port_no * 0x80, "port");
1881cbcdd875STejun Heo 
188218f7ba4cSKristen Carlson Accardi 		/* set enclosure management message type */
188318f7ba4cSKristen Carlson Accardi 		if (ap->flags & ATA_FLAG_EM)
1884008dbd61SHarry Zhang 			ap->em_message_type = hpriv->em_msg_type;
188518f7ba4cSKristen Carlson Accardi 
1886b1a9585cSSrinivas Pandruvada 		ahci_update_initial_lpm_policy(ap, hpriv);
188718f7ba4cSKristen Carlson Accardi 
1888dab632e8SJeff Garzik 		/* disabled/not-implemented port */
1889350756f6STejun Heo 		if (!(hpriv->port_map & (1 << i)))
1890dab632e8SJeff Garzik 			ap->ops = &ata_dummy_port_ops;
18914447d351STejun Heo 	}
1892c6fd2807SJeff Garzik 
1893edc93052STejun Heo 	/* apply workaround for ASUS P5W DH Deluxe mainboard */
1894edc93052STejun Heo 	ahci_p5wdh_workaround(host);
1895edc93052STejun Heo 
1896f80ae7e4STejun Heo 	/* apply gtf filter quirk */
1897f80ae7e4STejun Heo 	ahci_gtf_filter_workaround(host);
1898f80ae7e4STejun Heo 
1899c6fd2807SJeff Garzik 	/* initialize adapter */
19004447d351STejun Heo 	rc = ahci_configure_dma_masks(pdev, hpriv->cap & HOST_CAP_64);
1901c6fd2807SJeff Garzik 	if (rc)
190224dc5f33STejun Heo 		return rc;
1903c6fd2807SJeff Garzik 
1904c312ef17SDan Williams 	rc = ahci_reset_controller(host);
19054447d351STejun Heo 	if (rc)
19064447d351STejun Heo 		return rc;
1907c6fd2807SJeff Garzik 
1908781d6550SAnton Vorontsov 	ahci_pci_init_controller(host);
1909439fcaecSAnton Vorontsov 	ahci_pci_print_info(host);
1910c6fd2807SJeff Garzik 
19114447d351STejun Heo 	pci_set_master(pdev);
19125ca72c4fSAlexander Gordeev 
191302e53293SMika Westerberg 	rc = ahci_host_activate(host, &ahci_sht);
191402e53293SMika Westerberg 	if (rc)
191502e53293SMika Westerberg 		return rc;
191602e53293SMika Westerberg 
191702e53293SMika Westerberg 	pm_runtime_put_noidle(&pdev->dev);
191802e53293SMika Westerberg 	return 0;
191902e53293SMika Westerberg }
192002e53293SMika Westerberg 
192110a663a1SPrabhakar Kushwaha static void ahci_shutdown_one(struct pci_dev *pdev)
192210a663a1SPrabhakar Kushwaha {
192310a663a1SPrabhakar Kushwaha 	ata_pci_shutdown_one(pdev);
192410a663a1SPrabhakar Kushwaha }
192510a663a1SPrabhakar Kushwaha 
192602e53293SMika Westerberg static void ahci_remove_one(struct pci_dev *pdev)
192702e53293SMika Westerberg {
1928894fba7fSKai-Heng Feng 	sysfs_remove_file_from_group(&pdev->dev.kobj,
1929894fba7fSKai-Heng Feng 				     &dev_attr_remapped_nvme.attr,
1930894fba7fSKai-Heng Feng 				     NULL);
193102e53293SMika Westerberg 	pm_runtime_get_noresume(&pdev->dev);
193202e53293SMika Westerberg 	ata_pci_remove_one(pdev);
1933c6fd2807SJeff Garzik }
1934c6fd2807SJeff Garzik 
19352fc75da0SAxel Lin module_pci_driver(ahci_pci_driver);
1936c6fd2807SJeff Garzik 
1937c6fd2807SJeff Garzik MODULE_AUTHOR("Jeff Garzik");
1938c6fd2807SJeff Garzik MODULE_DESCRIPTION("AHCI SATA low-level driver");
1939c6fd2807SJeff Garzik MODULE_LICENSE("GPL");
1940c6fd2807SJeff Garzik MODULE_DEVICE_TABLE(pci, ahci_pci_tbl);
1941c6fd2807SJeff Garzik MODULE_VERSION(DRV_VERSION);
1942