xref: /openbmc/linux/drivers/ata/ahci.c (revision 837f5f8fb98d4357d49e9631c9ee2815f3c328ca)
1c6fd2807SJeff Garzik /*
2c6fd2807SJeff Garzik  *  ahci.c - AHCI SATA support
3c6fd2807SJeff Garzik  *
4c6fd2807SJeff Garzik  *  Maintained by:  Jeff Garzik <jgarzik@pobox.com>
5c6fd2807SJeff Garzik  *    		    Please ALWAYS copy linux-ide@vger.kernel.org
6c6fd2807SJeff Garzik  *		    on emails.
7c6fd2807SJeff Garzik  *
8c6fd2807SJeff Garzik  *  Copyright 2004-2005 Red Hat, Inc.
9c6fd2807SJeff Garzik  *
10c6fd2807SJeff Garzik  *
11c6fd2807SJeff Garzik  *  This program is free software; you can redistribute it and/or modify
12c6fd2807SJeff Garzik  *  it under the terms of the GNU General Public License as published by
13c6fd2807SJeff Garzik  *  the Free Software Foundation; either version 2, or (at your option)
14c6fd2807SJeff Garzik  *  any later version.
15c6fd2807SJeff Garzik  *
16c6fd2807SJeff Garzik  *  This program is distributed in the hope that it will be useful,
17c6fd2807SJeff Garzik  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
18c6fd2807SJeff Garzik  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19c6fd2807SJeff Garzik  *  GNU General Public License for more details.
20c6fd2807SJeff Garzik  *
21c6fd2807SJeff Garzik  *  You should have received a copy of the GNU General Public License
22c6fd2807SJeff Garzik  *  along with this program; see the file COPYING.  If not, write to
23c6fd2807SJeff Garzik  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
24c6fd2807SJeff Garzik  *
25c6fd2807SJeff Garzik  *
26c6fd2807SJeff Garzik  * libata documentation is available via 'make {ps|pdf}docs',
27c6fd2807SJeff Garzik  * as Documentation/DocBook/libata.*
28c6fd2807SJeff Garzik  *
29c6fd2807SJeff Garzik  * AHCI hardware documentation:
30c6fd2807SJeff Garzik  * http://www.intel.com/technology/serialata/pdf/rev1_0.pdf
31c6fd2807SJeff Garzik  * http://www.intel.com/technology/serialata/pdf/rev1_1.pdf
32c6fd2807SJeff Garzik  *
33c6fd2807SJeff Garzik  */
34c6fd2807SJeff Garzik 
35c6fd2807SJeff Garzik #include <linux/kernel.h>
36c6fd2807SJeff Garzik #include <linux/module.h>
37c6fd2807SJeff Garzik #include <linux/pci.h>
38c6fd2807SJeff Garzik #include <linux/init.h>
39c6fd2807SJeff Garzik #include <linux/blkdev.h>
40c6fd2807SJeff Garzik #include <linux/delay.h>
41c6fd2807SJeff Garzik #include <linux/interrupt.h>
42c6fd2807SJeff Garzik #include <linux/dma-mapping.h>
43c6fd2807SJeff Garzik #include <linux/device.h>
44edc93052STejun Heo #include <linux/dmi.h>
45c6fd2807SJeff Garzik #include <scsi/scsi_host.h>
46c6fd2807SJeff Garzik #include <scsi/scsi_cmnd.h>
47c6fd2807SJeff Garzik #include <linux/libata.h>
48c6fd2807SJeff Garzik 
49c6fd2807SJeff Garzik #define DRV_NAME	"ahci"
507d50b60bSTejun Heo #define DRV_VERSION	"3.0"
51c6fd2807SJeff Garzik 
5231556594SKristen Carlson Accardi static int ahci_enable_alpm(struct ata_port *ap,
5331556594SKristen Carlson Accardi 		enum link_pm policy);
5431556594SKristen Carlson Accardi static void ahci_disable_alpm(struct ata_port *ap);
55c6fd2807SJeff Garzik 
56c6fd2807SJeff Garzik enum {
57c6fd2807SJeff Garzik 	AHCI_PCI_BAR		= 5,
58648a88beSTejun Heo 	AHCI_MAX_PORTS		= 32,
59c6fd2807SJeff Garzik 	AHCI_MAX_SG		= 168, /* hardware max is 64K */
60c6fd2807SJeff Garzik 	AHCI_DMA_BOUNDARY	= 0xffffffff,
61be5d8218SJens Axboe 	AHCI_USE_CLUSTERING	= 1,
62c6fd2807SJeff Garzik 	AHCI_MAX_CMDS		= 32,
63c6fd2807SJeff Garzik 	AHCI_CMD_SZ		= 32,
64c6fd2807SJeff Garzik 	AHCI_CMD_SLOT_SZ	= AHCI_MAX_CMDS * AHCI_CMD_SZ,
65c6fd2807SJeff Garzik 	AHCI_RX_FIS_SZ		= 256,
66c6fd2807SJeff Garzik 	AHCI_CMD_TBL_CDB	= 0x40,
67c6fd2807SJeff Garzik 	AHCI_CMD_TBL_HDR_SZ	= 0x80,
68c6fd2807SJeff Garzik 	AHCI_CMD_TBL_SZ		= AHCI_CMD_TBL_HDR_SZ + (AHCI_MAX_SG * 16),
69c6fd2807SJeff Garzik 	AHCI_CMD_TBL_AR_SZ	= AHCI_CMD_TBL_SZ * AHCI_MAX_CMDS,
70c6fd2807SJeff Garzik 	AHCI_PORT_PRIV_DMA_SZ	= AHCI_CMD_SLOT_SZ + AHCI_CMD_TBL_AR_SZ +
71c6fd2807SJeff Garzik 				  AHCI_RX_FIS_SZ,
72c6fd2807SJeff Garzik 	AHCI_IRQ_ON_SG		= (1 << 31),
73c6fd2807SJeff Garzik 	AHCI_CMD_ATAPI		= (1 << 5),
74c6fd2807SJeff Garzik 	AHCI_CMD_WRITE		= (1 << 6),
75c6fd2807SJeff Garzik 	AHCI_CMD_PREFETCH	= (1 << 7),
76c6fd2807SJeff Garzik 	AHCI_CMD_RESET		= (1 << 8),
77c6fd2807SJeff Garzik 	AHCI_CMD_CLR_BUSY	= (1 << 10),
78c6fd2807SJeff Garzik 
79c6fd2807SJeff Garzik 	RX_FIS_D2H_REG		= 0x40,	/* offset of D2H Register FIS data */
800291f95fSTejun Heo 	RX_FIS_SDB		= 0x58, /* offset of SDB FIS data */
81c6fd2807SJeff Garzik 	RX_FIS_UNK		= 0x60, /* offset of Unknown FIS data */
82c6fd2807SJeff Garzik 
83c6fd2807SJeff Garzik 	board_ahci		= 0,
847a234affSTejun Heo 	board_ahci_vt8251	= 1,
857a234affSTejun Heo 	board_ahci_ign_iferr	= 2,
867a234affSTejun Heo 	board_ahci_sb600	= 3,
877a234affSTejun Heo 	board_ahci_mv		= 4,
88c6fd2807SJeff Garzik 
89c6fd2807SJeff Garzik 	/* global controller registers */
90c6fd2807SJeff Garzik 	HOST_CAP		= 0x00, /* host capabilities */
91c6fd2807SJeff Garzik 	HOST_CTL		= 0x04, /* global host control */
92c6fd2807SJeff Garzik 	HOST_IRQ_STAT		= 0x08, /* interrupt status */
93c6fd2807SJeff Garzik 	HOST_PORTS_IMPL		= 0x0c, /* bitmap of implemented ports */
94c6fd2807SJeff Garzik 	HOST_VERSION		= 0x10, /* AHCI spec. version compliancy */
95c6fd2807SJeff Garzik 
96c6fd2807SJeff Garzik 	/* HOST_CTL bits */
97c6fd2807SJeff Garzik 	HOST_RESET		= (1 << 0),  /* reset controller; self-clear */
98c6fd2807SJeff Garzik 	HOST_IRQ_EN		= (1 << 1),  /* global IRQ enable */
99c6fd2807SJeff Garzik 	HOST_AHCI_EN		= (1 << 31), /* AHCI enabled */
100c6fd2807SJeff Garzik 
101c6fd2807SJeff Garzik 	/* HOST_CAP bits */
102c6fd2807SJeff Garzik 	HOST_CAP_SSC		= (1 << 14), /* Slumber capable */
1037d50b60bSTejun Heo 	HOST_CAP_PMP		= (1 << 17), /* Port Multiplier support */
104c6fd2807SJeff Garzik 	HOST_CAP_CLO		= (1 << 24), /* Command List Override support */
10531556594SKristen Carlson Accardi 	HOST_CAP_ALPM		= (1 << 26), /* Aggressive Link PM support */
106c6fd2807SJeff Garzik 	HOST_CAP_SSS		= (1 << 27), /* Staggered Spin-up */
107203ef6c4STejun Heo 	HOST_CAP_SNTF		= (1 << 29), /* SNotification register */
108c6fd2807SJeff Garzik 	HOST_CAP_NCQ		= (1 << 30), /* Native Command Queueing */
109c6fd2807SJeff Garzik 	HOST_CAP_64		= (1 << 31), /* PCI DAC (64-bit DMA) support */
110c6fd2807SJeff Garzik 
111c6fd2807SJeff Garzik 	/* registers for each SATA port */
112c6fd2807SJeff Garzik 	PORT_LST_ADDR		= 0x00, /* command list DMA addr */
113c6fd2807SJeff Garzik 	PORT_LST_ADDR_HI	= 0x04, /* command list DMA addr hi */
114c6fd2807SJeff Garzik 	PORT_FIS_ADDR		= 0x08, /* FIS rx buf addr */
115c6fd2807SJeff Garzik 	PORT_FIS_ADDR_HI	= 0x0c, /* FIS rx buf addr hi */
116c6fd2807SJeff Garzik 	PORT_IRQ_STAT		= 0x10, /* interrupt status */
117c6fd2807SJeff Garzik 	PORT_IRQ_MASK		= 0x14, /* interrupt enable/disable mask */
118c6fd2807SJeff Garzik 	PORT_CMD		= 0x18, /* port command */
119c6fd2807SJeff Garzik 	PORT_TFDATA		= 0x20,	/* taskfile data */
120c6fd2807SJeff Garzik 	PORT_SIG		= 0x24,	/* device TF signature */
121c6fd2807SJeff Garzik 	PORT_CMD_ISSUE		= 0x38, /* command issue */
122c6fd2807SJeff Garzik 	PORT_SCR_STAT		= 0x28, /* SATA phy register: SStatus */
123c6fd2807SJeff Garzik 	PORT_SCR_CTL		= 0x2c, /* SATA phy register: SControl */
124c6fd2807SJeff Garzik 	PORT_SCR_ERR		= 0x30, /* SATA phy register: SError */
125c6fd2807SJeff Garzik 	PORT_SCR_ACT		= 0x34, /* SATA phy register: SActive */
126203ef6c4STejun Heo 	PORT_SCR_NTF		= 0x3c, /* SATA phy register: SNotification */
127c6fd2807SJeff Garzik 
128c6fd2807SJeff Garzik 	/* PORT_IRQ_{STAT,MASK} bits */
129c6fd2807SJeff Garzik 	PORT_IRQ_COLD_PRES	= (1 << 31), /* cold presence detect */
130c6fd2807SJeff Garzik 	PORT_IRQ_TF_ERR		= (1 << 30), /* task file error */
131c6fd2807SJeff Garzik 	PORT_IRQ_HBUS_ERR	= (1 << 29), /* host bus fatal error */
132c6fd2807SJeff Garzik 	PORT_IRQ_HBUS_DATA_ERR	= (1 << 28), /* host bus data error */
133c6fd2807SJeff Garzik 	PORT_IRQ_IF_ERR		= (1 << 27), /* interface fatal error */
134c6fd2807SJeff Garzik 	PORT_IRQ_IF_NONFATAL	= (1 << 26), /* interface non-fatal error */
135c6fd2807SJeff Garzik 	PORT_IRQ_OVERFLOW	= (1 << 24), /* xfer exhausted available S/G */
136c6fd2807SJeff Garzik 	PORT_IRQ_BAD_PMP	= (1 << 23), /* incorrect port multiplier */
137c6fd2807SJeff Garzik 
138c6fd2807SJeff Garzik 	PORT_IRQ_PHYRDY		= (1 << 22), /* PhyRdy changed */
139c6fd2807SJeff Garzik 	PORT_IRQ_DEV_ILCK	= (1 << 7), /* device interlock */
140c6fd2807SJeff Garzik 	PORT_IRQ_CONNECT	= (1 << 6), /* port connect change status */
141c6fd2807SJeff Garzik 	PORT_IRQ_SG_DONE	= (1 << 5), /* descriptor processed */
142c6fd2807SJeff Garzik 	PORT_IRQ_UNK_FIS	= (1 << 4), /* unknown FIS rx'd */
143c6fd2807SJeff Garzik 	PORT_IRQ_SDB_FIS	= (1 << 3), /* Set Device Bits FIS rx'd */
144c6fd2807SJeff Garzik 	PORT_IRQ_DMAS_FIS	= (1 << 2), /* DMA Setup FIS rx'd */
145c6fd2807SJeff Garzik 	PORT_IRQ_PIOS_FIS	= (1 << 1), /* PIO Setup FIS rx'd */
146c6fd2807SJeff Garzik 	PORT_IRQ_D2H_REG_FIS	= (1 << 0), /* D2H Register FIS rx'd */
147c6fd2807SJeff Garzik 
148c6fd2807SJeff Garzik 	PORT_IRQ_FREEZE		= PORT_IRQ_HBUS_ERR |
149c6fd2807SJeff Garzik 				  PORT_IRQ_IF_ERR |
150c6fd2807SJeff Garzik 				  PORT_IRQ_CONNECT |
151c6fd2807SJeff Garzik 				  PORT_IRQ_PHYRDY |
1527d50b60bSTejun Heo 				  PORT_IRQ_UNK_FIS |
1537d50b60bSTejun Heo 				  PORT_IRQ_BAD_PMP,
154c6fd2807SJeff Garzik 	PORT_IRQ_ERROR		= PORT_IRQ_FREEZE |
155c6fd2807SJeff Garzik 				  PORT_IRQ_TF_ERR |
156c6fd2807SJeff Garzik 				  PORT_IRQ_HBUS_DATA_ERR,
157c6fd2807SJeff Garzik 	DEF_PORT_IRQ		= PORT_IRQ_ERROR | PORT_IRQ_SG_DONE |
158c6fd2807SJeff Garzik 				  PORT_IRQ_SDB_FIS | PORT_IRQ_DMAS_FIS |
159c6fd2807SJeff Garzik 				  PORT_IRQ_PIOS_FIS | PORT_IRQ_D2H_REG_FIS,
160c6fd2807SJeff Garzik 
161c6fd2807SJeff Garzik 	/* PORT_CMD bits */
16231556594SKristen Carlson Accardi 	PORT_CMD_ASP		= (1 << 27), /* Aggressive Slumber/Partial */
16331556594SKristen Carlson Accardi 	PORT_CMD_ALPE		= (1 << 26), /* Aggressive Link PM enable */
164c6fd2807SJeff Garzik 	PORT_CMD_ATAPI		= (1 << 24), /* Device is ATAPI */
1657d50b60bSTejun Heo 	PORT_CMD_PMP		= (1 << 17), /* PMP attached */
166c6fd2807SJeff Garzik 	PORT_CMD_LIST_ON	= (1 << 15), /* cmd list DMA engine running */
167c6fd2807SJeff Garzik 	PORT_CMD_FIS_ON		= (1 << 14), /* FIS DMA engine running */
168c6fd2807SJeff Garzik 	PORT_CMD_FIS_RX		= (1 << 4), /* Enable FIS receive DMA engine */
169c6fd2807SJeff Garzik 	PORT_CMD_CLO		= (1 << 3), /* Command list override */
170c6fd2807SJeff Garzik 	PORT_CMD_POWER_ON	= (1 << 2), /* Power up device */
171c6fd2807SJeff Garzik 	PORT_CMD_SPIN_UP	= (1 << 1), /* Spin up device */
172c6fd2807SJeff Garzik 	PORT_CMD_START		= (1 << 0), /* Enable port DMA engine */
173c6fd2807SJeff Garzik 
174c6fd2807SJeff Garzik 	PORT_CMD_ICC_MASK	= (0xf << 28), /* i/f ICC state mask */
175c6fd2807SJeff Garzik 	PORT_CMD_ICC_ACTIVE	= (0x1 << 28), /* Put i/f in active state */
176c6fd2807SJeff Garzik 	PORT_CMD_ICC_PARTIAL	= (0x2 << 28), /* Put i/f in partial state */
177c6fd2807SJeff Garzik 	PORT_CMD_ICC_SLUMBER	= (0x6 << 28), /* Put i/f in slumber state */
178c6fd2807SJeff Garzik 
179417a1a6dSTejun Heo 	/* hpriv->flags bits */
180417a1a6dSTejun Heo 	AHCI_HFLAG_NO_NCQ		= (1 << 0),
181417a1a6dSTejun Heo 	AHCI_HFLAG_IGN_IRQ_IF_ERR	= (1 << 1), /* ignore IRQ_IF_ERR */
182417a1a6dSTejun Heo 	AHCI_HFLAG_IGN_SERR_INTERNAL	= (1 << 2), /* ignore SERR_INTERNAL */
183417a1a6dSTejun Heo 	AHCI_HFLAG_32BIT_ONLY		= (1 << 3), /* force 32bit */
184417a1a6dSTejun Heo 	AHCI_HFLAG_MV_PATA		= (1 << 4), /* PATA port */
185417a1a6dSTejun Heo 	AHCI_HFLAG_NO_MSI		= (1 << 5), /* no PCI MSI */
1866949b914STejun Heo 	AHCI_HFLAG_NO_PMP		= (1 << 6), /* no PMP */
18731556594SKristen Carlson Accardi 	AHCI_HFLAG_NO_HOTPLUG		= (1 << 7), /* ignore PxSERR.DIAG.N */
188417a1a6dSTejun Heo 
189c6fd2807SJeff Garzik 	/* ap->flags bits */
1901188c0d8STejun Heo 
1911188c0d8STejun Heo 	AHCI_FLAG_COMMON		= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
1921188c0d8STejun Heo 					  ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
19331556594SKristen Carlson Accardi 					  ATA_FLAG_ACPI_SATA | ATA_FLAG_AN |
19431556594SKristen Carlson Accardi 					  ATA_FLAG_IPM,
1950c88758bSTejun Heo 	AHCI_LFLAG_COMMON		= ATA_LFLAG_SKIP_D2H_BSY,
196c4f7792cSTejun Heo 
197c4f7792cSTejun Heo 	ICH_MAP				= 0x90, /* ICH MAP register */
198c6fd2807SJeff Garzik };
199c6fd2807SJeff Garzik 
200c6fd2807SJeff Garzik struct ahci_cmd_hdr {
2014ca4e439SAl Viro 	__le32			opts;
2024ca4e439SAl Viro 	__le32			status;
2034ca4e439SAl Viro 	__le32			tbl_addr;
2044ca4e439SAl Viro 	__le32			tbl_addr_hi;
2054ca4e439SAl Viro 	__le32			reserved[4];
206c6fd2807SJeff Garzik };
207c6fd2807SJeff Garzik 
208c6fd2807SJeff Garzik struct ahci_sg {
2094ca4e439SAl Viro 	__le32			addr;
2104ca4e439SAl Viro 	__le32			addr_hi;
2114ca4e439SAl Viro 	__le32			reserved;
2124ca4e439SAl Viro 	__le32			flags_size;
213c6fd2807SJeff Garzik };
214c6fd2807SJeff Garzik 
215c6fd2807SJeff Garzik struct ahci_host_priv {
216417a1a6dSTejun Heo 	unsigned int		flags;		/* AHCI_HFLAG_* */
217d447df14STejun Heo 	u32			cap;		/* cap to use */
218d447df14STejun Heo 	u32			port_map;	/* port map to use */
219d447df14STejun Heo 	u32			saved_cap;	/* saved initial cap */
220d447df14STejun Heo 	u32			saved_port_map;	/* saved initial port_map */
221c6fd2807SJeff Garzik };
222c6fd2807SJeff Garzik 
223c6fd2807SJeff Garzik struct ahci_port_priv {
2247d50b60bSTejun Heo 	struct ata_link		*active_link;
225c6fd2807SJeff Garzik 	struct ahci_cmd_hdr	*cmd_slot;
226c6fd2807SJeff Garzik 	dma_addr_t		cmd_slot_dma;
227c6fd2807SJeff Garzik 	void			*cmd_tbl;
228c6fd2807SJeff Garzik 	dma_addr_t		cmd_tbl_dma;
229c6fd2807SJeff Garzik 	void			*rx_fis;
230c6fd2807SJeff Garzik 	dma_addr_t		rx_fis_dma;
2310291f95fSTejun Heo 	/* for NCQ spurious interrupt analysis */
2320291f95fSTejun Heo 	unsigned int		ncq_saw_d2h:1;
2330291f95fSTejun Heo 	unsigned int		ncq_saw_dmas:1;
234afb2d552STejun Heo 	unsigned int		ncq_saw_sdb:1;
235a7384925SKristen Carlson Accardi 	u32 			intr_mask;	/* interrupts to enable */
236c6fd2807SJeff Garzik };
237c6fd2807SJeff Garzik 
238da3dbb17STejun Heo static int ahci_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
239da3dbb17STejun Heo static int ahci_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
240c6fd2807SJeff Garzik static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
241c6fd2807SJeff Garzik static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc);
242c6fd2807SJeff Garzik static void ahci_irq_clear(struct ata_port *ap);
243c6fd2807SJeff Garzik static int ahci_port_start(struct ata_port *ap);
244c6fd2807SJeff Garzik static void ahci_port_stop(struct ata_port *ap);
245c6fd2807SJeff Garzik static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
246c6fd2807SJeff Garzik static void ahci_qc_prep(struct ata_queued_cmd *qc);
247c6fd2807SJeff Garzik static u8 ahci_check_status(struct ata_port *ap);
248c6fd2807SJeff Garzik static void ahci_freeze(struct ata_port *ap);
249c6fd2807SJeff Garzik static void ahci_thaw(struct ata_port *ap);
2507d50b60bSTejun Heo static void ahci_pmp_attach(struct ata_port *ap);
2517d50b60bSTejun Heo static void ahci_pmp_detach(struct ata_port *ap);
252c6fd2807SJeff Garzik static void ahci_error_handler(struct ata_port *ap);
253ad616ffbSTejun Heo static void ahci_vt8251_error_handler(struct ata_port *ap);
254edc93052STejun Heo static void ahci_p5wdh_error_handler(struct ata_port *ap);
255c6fd2807SJeff Garzik static void ahci_post_internal_cmd(struct ata_queued_cmd *qc);
256df69c9c5SJeff Garzik static int ahci_port_resume(struct ata_port *ap);
257dab632e8SJeff Garzik static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl);
258dab632e8SJeff Garzik static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
259dab632e8SJeff Garzik 			       u32 opts);
260438ac6d5STejun Heo #ifdef CONFIG_PM
261c6fd2807SJeff Garzik static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg);
262c6fd2807SJeff Garzik static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg);
263c6fd2807SJeff Garzik static int ahci_pci_device_resume(struct pci_dev *pdev);
264438ac6d5STejun Heo #endif
265c6fd2807SJeff Garzik 
26631556594SKristen Carlson Accardi static struct class_device_attribute *ahci_shost_attrs[] = {
26731556594SKristen Carlson Accardi 	&class_device_attr_link_power_management_policy,
26831556594SKristen Carlson Accardi 	NULL
26931556594SKristen Carlson Accardi };
27031556594SKristen Carlson Accardi 
271c6fd2807SJeff Garzik static struct scsi_host_template ahci_sht = {
272c6fd2807SJeff Garzik 	.module			= THIS_MODULE,
273c6fd2807SJeff Garzik 	.name			= DRV_NAME,
274c6fd2807SJeff Garzik 	.ioctl			= ata_scsi_ioctl,
275c6fd2807SJeff Garzik 	.queuecommand		= ata_scsi_queuecmd,
276c6fd2807SJeff Garzik 	.change_queue_depth	= ata_scsi_change_queue_depth,
277c6fd2807SJeff Garzik 	.can_queue		= AHCI_MAX_CMDS - 1,
278c6fd2807SJeff Garzik 	.this_id		= ATA_SHT_THIS_ID,
279c6fd2807SJeff Garzik 	.sg_tablesize		= AHCI_MAX_SG,
280c6fd2807SJeff Garzik 	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
281c6fd2807SJeff Garzik 	.emulated		= ATA_SHT_EMULATED,
282c6fd2807SJeff Garzik 	.use_clustering		= AHCI_USE_CLUSTERING,
283c6fd2807SJeff Garzik 	.proc_name		= DRV_NAME,
284c6fd2807SJeff Garzik 	.dma_boundary		= AHCI_DMA_BOUNDARY,
285c6fd2807SJeff Garzik 	.slave_configure	= ata_scsi_slave_config,
286c6fd2807SJeff Garzik 	.slave_destroy		= ata_scsi_slave_destroy,
287c6fd2807SJeff Garzik 	.bios_param		= ata_std_bios_param,
28831556594SKristen Carlson Accardi 	.shost_attrs		= ahci_shost_attrs,
289c6fd2807SJeff Garzik };
290c6fd2807SJeff Garzik 
291c6fd2807SJeff Garzik static const struct ata_port_operations ahci_ops = {
292c6fd2807SJeff Garzik 	.check_status		= ahci_check_status,
293c6fd2807SJeff Garzik 	.check_altstatus	= ahci_check_status,
294c6fd2807SJeff Garzik 	.dev_select		= ata_noop_dev_select,
295c6fd2807SJeff Garzik 
296c6fd2807SJeff Garzik 	.tf_read		= ahci_tf_read,
297c6fd2807SJeff Garzik 
2987d50b60bSTejun Heo 	.qc_defer		= sata_pmp_qc_defer_cmd_switch,
299c6fd2807SJeff Garzik 	.qc_prep		= ahci_qc_prep,
300c6fd2807SJeff Garzik 	.qc_issue		= ahci_qc_issue,
301c6fd2807SJeff Garzik 
302c6fd2807SJeff Garzik 	.irq_clear		= ahci_irq_clear,
303c6fd2807SJeff Garzik 
304c6fd2807SJeff Garzik 	.scr_read		= ahci_scr_read,
305c6fd2807SJeff Garzik 	.scr_write		= ahci_scr_write,
306c6fd2807SJeff Garzik 
307c6fd2807SJeff Garzik 	.freeze			= ahci_freeze,
308c6fd2807SJeff Garzik 	.thaw			= ahci_thaw,
309c6fd2807SJeff Garzik 
310c6fd2807SJeff Garzik 	.error_handler		= ahci_error_handler,
311c6fd2807SJeff Garzik 	.post_internal_cmd	= ahci_post_internal_cmd,
312c6fd2807SJeff Garzik 
3137d50b60bSTejun Heo 	.pmp_attach		= ahci_pmp_attach,
3147d50b60bSTejun Heo 	.pmp_detach		= ahci_pmp_detach,
3157d50b60bSTejun Heo 
316438ac6d5STejun Heo #ifdef CONFIG_PM
317c6fd2807SJeff Garzik 	.port_suspend		= ahci_port_suspend,
318c6fd2807SJeff Garzik 	.port_resume		= ahci_port_resume,
319438ac6d5STejun Heo #endif
32031556594SKristen Carlson Accardi 	.enable_pm		= ahci_enable_alpm,
32131556594SKristen Carlson Accardi 	.disable_pm		= ahci_disable_alpm,
322c6fd2807SJeff Garzik 
323c6fd2807SJeff Garzik 	.port_start		= ahci_port_start,
324c6fd2807SJeff Garzik 	.port_stop		= ahci_port_stop,
325c6fd2807SJeff Garzik };
326c6fd2807SJeff Garzik 
327ad616ffbSTejun Heo static const struct ata_port_operations ahci_vt8251_ops = {
328ad616ffbSTejun Heo 	.check_status		= ahci_check_status,
329ad616ffbSTejun Heo 	.check_altstatus	= ahci_check_status,
330ad616ffbSTejun Heo 	.dev_select		= ata_noop_dev_select,
331ad616ffbSTejun Heo 
332ad616ffbSTejun Heo 	.tf_read		= ahci_tf_read,
333ad616ffbSTejun Heo 
3347d50b60bSTejun Heo 	.qc_defer		= sata_pmp_qc_defer_cmd_switch,
335ad616ffbSTejun Heo 	.qc_prep		= ahci_qc_prep,
336ad616ffbSTejun Heo 	.qc_issue		= ahci_qc_issue,
337ad616ffbSTejun Heo 
338ad616ffbSTejun Heo 	.irq_clear		= ahci_irq_clear,
339ad616ffbSTejun Heo 
340ad616ffbSTejun Heo 	.scr_read		= ahci_scr_read,
341ad616ffbSTejun Heo 	.scr_write		= ahci_scr_write,
342ad616ffbSTejun Heo 
343ad616ffbSTejun Heo 	.freeze			= ahci_freeze,
344ad616ffbSTejun Heo 	.thaw			= ahci_thaw,
345ad616ffbSTejun Heo 
346ad616ffbSTejun Heo 	.error_handler		= ahci_vt8251_error_handler,
347ad616ffbSTejun Heo 	.post_internal_cmd	= ahci_post_internal_cmd,
348ad616ffbSTejun Heo 
3497d50b60bSTejun Heo 	.pmp_attach		= ahci_pmp_attach,
3507d50b60bSTejun Heo 	.pmp_detach		= ahci_pmp_detach,
3517d50b60bSTejun Heo 
352438ac6d5STejun Heo #ifdef CONFIG_PM
353ad616ffbSTejun Heo 	.port_suspend		= ahci_port_suspend,
354ad616ffbSTejun Heo 	.port_resume		= ahci_port_resume,
355438ac6d5STejun Heo #endif
356ad616ffbSTejun Heo 
357ad616ffbSTejun Heo 	.port_start		= ahci_port_start,
358ad616ffbSTejun Heo 	.port_stop		= ahci_port_stop,
359ad616ffbSTejun Heo };
360ad616ffbSTejun Heo 
361edc93052STejun Heo static const struct ata_port_operations ahci_p5wdh_ops = {
362edc93052STejun Heo 	.check_status		= ahci_check_status,
363edc93052STejun Heo 	.check_altstatus	= ahci_check_status,
364edc93052STejun Heo 	.dev_select		= ata_noop_dev_select,
365edc93052STejun Heo 
366edc93052STejun Heo 	.tf_read		= ahci_tf_read,
367edc93052STejun Heo 
368edc93052STejun Heo 	.qc_defer		= sata_pmp_qc_defer_cmd_switch,
369edc93052STejun Heo 	.qc_prep		= ahci_qc_prep,
370edc93052STejun Heo 	.qc_issue		= ahci_qc_issue,
371edc93052STejun Heo 
372edc93052STejun Heo 	.irq_clear		= ahci_irq_clear,
373edc93052STejun Heo 
374edc93052STejun Heo 	.scr_read		= ahci_scr_read,
375edc93052STejun Heo 	.scr_write		= ahci_scr_write,
376edc93052STejun Heo 
377edc93052STejun Heo 	.freeze			= ahci_freeze,
378edc93052STejun Heo 	.thaw			= ahci_thaw,
379edc93052STejun Heo 
380edc93052STejun Heo 	.error_handler		= ahci_p5wdh_error_handler,
381edc93052STejun Heo 	.post_internal_cmd	= ahci_post_internal_cmd,
382edc93052STejun Heo 
383edc93052STejun Heo 	.pmp_attach		= ahci_pmp_attach,
384edc93052STejun Heo 	.pmp_detach		= ahci_pmp_detach,
385edc93052STejun Heo 
386edc93052STejun Heo #ifdef CONFIG_PM
387edc93052STejun Heo 	.port_suspend		= ahci_port_suspend,
388edc93052STejun Heo 	.port_resume		= ahci_port_resume,
389edc93052STejun Heo #endif
390edc93052STejun Heo 
391edc93052STejun Heo 	.port_start		= ahci_port_start,
392edc93052STejun Heo 	.port_stop		= ahci_port_stop,
393edc93052STejun Heo };
394edc93052STejun Heo 
395417a1a6dSTejun Heo #define AHCI_HFLAGS(flags)	.private_data	= (void *)(flags)
396417a1a6dSTejun Heo 
397c6fd2807SJeff Garzik static const struct ata_port_info ahci_port_info[] = {
398c6fd2807SJeff Garzik 	/* board_ahci */
399c6fd2807SJeff Garzik 	{
4001188c0d8STejun Heo 		.flags		= AHCI_FLAG_COMMON,
4010c88758bSTejun Heo 		.link_flags	= AHCI_LFLAG_COMMON,
402c6fd2807SJeff Garzik 		.pio_mask	= 0x1f, /* pio0-4 */
403469248abSJeff Garzik 		.udma_mask	= ATA_UDMA6,
404c6fd2807SJeff Garzik 		.port_ops	= &ahci_ops,
405c6fd2807SJeff Garzik 	},
406c6fd2807SJeff Garzik 	/* board_ahci_vt8251 */
407c6fd2807SJeff Garzik 	{
4086949b914STejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_PMP),
409417a1a6dSTejun Heo 		.flags		= AHCI_FLAG_COMMON,
4100c88758bSTejun Heo 		.link_flags	= AHCI_LFLAG_COMMON | ATA_LFLAG_HRST_TO_RESUME,
411c6fd2807SJeff Garzik 		.pio_mask	= 0x1f, /* pio0-4 */
412469248abSJeff Garzik 		.udma_mask	= ATA_UDMA6,
413ad616ffbSTejun Heo 		.port_ops	= &ahci_vt8251_ops,
414c6fd2807SJeff Garzik 	},
41541669553STejun Heo 	/* board_ahci_ign_iferr */
41641669553STejun Heo 	{
417417a1a6dSTejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_IGN_IRQ_IF_ERR),
418417a1a6dSTejun Heo 		.flags		= AHCI_FLAG_COMMON,
4190c88758bSTejun Heo 		.link_flags	= AHCI_LFLAG_COMMON,
42041669553STejun Heo 		.pio_mask	= 0x1f, /* pio0-4 */
421469248abSJeff Garzik 		.udma_mask	= ATA_UDMA6,
42241669553STejun Heo 		.port_ops	= &ahci_ops,
42341669553STejun Heo 	},
42455a61604SConke Hu 	/* board_ahci_sb600 */
42555a61604SConke Hu 	{
426417a1a6dSTejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_IGN_SERR_INTERNAL |
4276949b914STejun Heo 				 AHCI_HFLAG_32BIT_ONLY | AHCI_HFLAG_NO_PMP),
428417a1a6dSTejun Heo 		.flags		= AHCI_FLAG_COMMON,
4290c88758bSTejun Heo 		.link_flags	= AHCI_LFLAG_COMMON,
43055a61604SConke Hu 		.pio_mask	= 0x1f, /* pio0-4 */
431469248abSJeff Garzik 		.udma_mask	= ATA_UDMA6,
43255a61604SConke Hu 		.port_ops	= &ahci_ops,
43355a61604SConke Hu 	},
434cd70c266SJeff Garzik 	/* board_ahci_mv */
435cd70c266SJeff Garzik 	{
436417a1a6dSTejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_MSI |
437417a1a6dSTejun Heo 				 AHCI_HFLAG_MV_PATA),
438cd70c266SJeff Garzik 		.flags		= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
439417a1a6dSTejun Heo 				  ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA,
4400c88758bSTejun Heo 		.link_flags	= AHCI_LFLAG_COMMON,
441cd70c266SJeff Garzik 		.pio_mask	= 0x1f, /* pio0-4 */
442cd70c266SJeff Garzik 		.udma_mask	= ATA_UDMA6,
443cd70c266SJeff Garzik 		.port_ops	= &ahci_ops,
444cd70c266SJeff Garzik 	},
445c6fd2807SJeff Garzik };
446c6fd2807SJeff Garzik 
447c6fd2807SJeff Garzik static const struct pci_device_id ahci_pci_tbl[] = {
448c6fd2807SJeff Garzik 	/* Intel */
44954bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2652), board_ahci }, /* ICH6 */
45054bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2653), board_ahci }, /* ICH6M */
45154bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c1), board_ahci }, /* ICH7 */
45254bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c5), board_ahci }, /* ICH7M */
45354bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c3), board_ahci }, /* ICH7R */
45482490c09STejun Heo 	{ PCI_VDEVICE(AL, 0x5288), board_ahci_ign_iferr }, /* ULi M5288 */
45554bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2681), board_ahci }, /* ESB2 */
45654bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2682), board_ahci }, /* ESB2 */
45754bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2683), board_ahci }, /* ESB2 */
45854bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c6), board_ahci }, /* ICH7-M DH */
4597a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2821), board_ahci }, /* ICH8 */
4607a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2822), board_ahci }, /* ICH8 */
4617a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2824), board_ahci }, /* ICH8 */
4627a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2829), board_ahci }, /* ICH8M */
4637a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x282a), board_ahci }, /* ICH8M */
4647a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2922), board_ahci }, /* ICH9 */
4657a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2923), board_ahci }, /* ICH9 */
4667a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2924), board_ahci }, /* ICH9 */
4677a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2925), board_ahci }, /* ICH9 */
4687a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2927), board_ahci }, /* ICH9 */
4697a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2929), board_ahci }, /* ICH9M */
4707a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x292a), board_ahci }, /* ICH9M */
4717a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x292b), board_ahci }, /* ICH9M */
4727a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x292c), board_ahci }, /* ICH9M */
4737a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x292f), board_ahci }, /* ICH9M */
4747a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x294d), board_ahci }, /* ICH9 */
4757a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x294e), board_ahci }, /* ICH9M */
476d4155e6fSJason Gaston 	{ PCI_VDEVICE(INTEL, 0x502a), board_ahci }, /* Tolapai */
477d4155e6fSJason Gaston 	{ PCI_VDEVICE(INTEL, 0x502b), board_ahci }, /* Tolapai */
47816ad1ad9SJason Gaston 	{ PCI_VDEVICE(INTEL, 0x3a05), board_ahci }, /* ICH10 */
47916ad1ad9SJason Gaston 	{ PCI_VDEVICE(INTEL, 0x3a25), board_ahci }, /* ICH10 */
480c6fd2807SJeff Garzik 
481e34bb370STejun Heo 	/* JMicron 360/1/3/5/6, match class to avoid IDE function */
482e34bb370STejun Heo 	{ PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
483e34bb370STejun Heo 	  PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci_ign_iferr },
484c6fd2807SJeff Garzik 
485c6fd2807SJeff Garzik 	/* ATI */
486c65ec1c2SConke Hu 	{ PCI_VDEVICE(ATI, 0x4380), board_ahci_sb600 }, /* ATI SB600 */
487c69c0892Shenry su 	{ PCI_VDEVICE(ATI, 0x4390), board_ahci_sb600 }, /* ATI SB700/800 */
488c69c0892Shenry su 	{ PCI_VDEVICE(ATI, 0x4391), board_ahci_sb600 }, /* ATI SB700/800 */
489c69c0892Shenry su 	{ PCI_VDEVICE(ATI, 0x4392), board_ahci_sb600 }, /* ATI SB700/800 */
490c69c0892Shenry su 	{ PCI_VDEVICE(ATI, 0x4393), board_ahci_sb600 }, /* ATI SB700/800 */
491c69c0892Shenry su 	{ PCI_VDEVICE(ATI, 0x4394), board_ahci_sb600 }, /* ATI SB700/800 */
492c69c0892Shenry su 	{ PCI_VDEVICE(ATI, 0x4395), board_ahci_sb600 }, /* ATI SB700/800 */
493c6fd2807SJeff Garzik 
494c6fd2807SJeff Garzik 	/* VIA */
49554bb3a94SJeff Garzik 	{ PCI_VDEVICE(VIA, 0x3349), board_ahci_vt8251 }, /* VIA VT8251 */
496bf335542STejun Heo 	{ PCI_VDEVICE(VIA, 0x6287), board_ahci_vt8251 }, /* VIA VT8251 */
497c6fd2807SJeff Garzik 
498c6fd2807SJeff Garzik 	/* NVIDIA */
49954bb3a94SJeff Garzik 	{ PCI_VDEVICE(NVIDIA, 0x044c), board_ahci },		/* MCP65 */
50054bb3a94SJeff Garzik 	{ PCI_VDEVICE(NVIDIA, 0x044d), board_ahci },		/* MCP65 */
50154bb3a94SJeff Garzik 	{ PCI_VDEVICE(NVIDIA, 0x044e), board_ahci },		/* MCP65 */
50254bb3a94SJeff Garzik 	{ PCI_VDEVICE(NVIDIA, 0x044f), board_ahci },		/* MCP65 */
5036fbf5ba4SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x045c), board_ahci },		/* MCP65 */
5046fbf5ba4SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x045d), board_ahci },		/* MCP65 */
5056fbf5ba4SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x045e), board_ahci },		/* MCP65 */
5066fbf5ba4SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x045f), board_ahci },		/* MCP65 */
5076fbf5ba4SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0550), board_ahci },		/* MCP67 */
5086fbf5ba4SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0551), board_ahci },		/* MCP67 */
5096fbf5ba4SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0552), board_ahci },		/* MCP67 */
5106fbf5ba4SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0553), board_ahci },		/* MCP67 */
511895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0554), board_ahci },		/* MCP67 */
512895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0555), board_ahci },		/* MCP67 */
513895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0556), board_ahci },		/* MCP67 */
514895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0557), board_ahci },		/* MCP67 */
515895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0558), board_ahci },		/* MCP67 */
516895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0559), board_ahci },		/* MCP67 */
517895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x055a), board_ahci },		/* MCP67 */
518895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x055b), board_ahci },		/* MCP67 */
5190522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x07f0), board_ahci },		/* MCP73 */
5200522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x07f1), board_ahci },		/* MCP73 */
5210522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x07f2), board_ahci },		/* MCP73 */
5220522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x07f3), board_ahci },		/* MCP73 */
5230522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x07f4), board_ahci },		/* MCP73 */
5240522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x07f5), board_ahci },		/* MCP73 */
5250522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x07f6), board_ahci },		/* MCP73 */
5260522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x07f7), board_ahci },		/* MCP73 */
5270522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x07f8), board_ahci },		/* MCP73 */
5280522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x07f9), board_ahci },		/* MCP73 */
5290522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x07fa), board_ahci },		/* MCP73 */
5300522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x07fb), board_ahci },		/* MCP73 */
5310522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad0), board_ahci },		/* MCP77 */
5320522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad1), board_ahci },		/* MCP77 */
5330522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad2), board_ahci },		/* MCP77 */
5340522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad3), board_ahci },		/* MCP77 */
5350522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad4), board_ahci },		/* MCP77 */
5360522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad5), board_ahci },		/* MCP77 */
5370522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad6), board_ahci },		/* MCP77 */
5380522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad7), board_ahci },		/* MCP77 */
5390522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad8), board_ahci },		/* MCP77 */
5400522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad9), board_ahci },		/* MCP77 */
5410522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ada), board_ahci },		/* MCP77 */
5420522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0adb), board_ahci },		/* MCP77 */
5436ba86958Speerchen 	{ PCI_VDEVICE(NVIDIA, 0x0ab4), board_ahci },		/* MCP79 */
5446ba86958Speerchen 	{ PCI_VDEVICE(NVIDIA, 0x0ab5), board_ahci },		/* MCP79 */
5456ba86958Speerchen 	{ PCI_VDEVICE(NVIDIA, 0x0ab6), board_ahci },		/* MCP79 */
5466ba86958Speerchen 	{ PCI_VDEVICE(NVIDIA, 0x0ab7), board_ahci },		/* MCP79 */
5477100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ab8), board_ahci },		/* MCP79 */
5487100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ab9), board_ahci },		/* MCP79 */
5497100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0aba), board_ahci },		/* MCP79 */
5507100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0abb), board_ahci },		/* MCP79 */
5517100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0abc), board_ahci },		/* MCP79 */
5527100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0abd), board_ahci },		/* MCP79 */
5537100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0abe), board_ahci },		/* MCP79 */
5547100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0abf), board_ahci },		/* MCP79 */
555c6fd2807SJeff Garzik 
556c6fd2807SJeff Garzik 	/* SiS */
55754bb3a94SJeff Garzik 	{ PCI_VDEVICE(SI, 0x1184), board_ahci }, /* SiS 966 */
55854bb3a94SJeff Garzik 	{ PCI_VDEVICE(SI, 0x1185), board_ahci }, /* SiS 966 */
55954bb3a94SJeff Garzik 	{ PCI_VDEVICE(SI, 0x0186), board_ahci }, /* SiS 968 */
560c6fd2807SJeff Garzik 
561cd70c266SJeff Garzik 	/* Marvell */
562cd70c266SJeff Garzik 	{ PCI_VDEVICE(MARVELL, 0x6145), board_ahci_mv },	/* 6145 */
563cd70c266SJeff Garzik 
564415ae2b5SJeff Garzik 	/* Generic, PCI class code for AHCI */
565415ae2b5SJeff Garzik 	{ PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
566c9f89475SConke Hu 	  PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci },
567415ae2b5SJeff Garzik 
568c6fd2807SJeff Garzik 	{ }	/* terminate list */
569c6fd2807SJeff Garzik };
570c6fd2807SJeff Garzik 
571c6fd2807SJeff Garzik 
572c6fd2807SJeff Garzik static struct pci_driver ahci_pci_driver = {
573c6fd2807SJeff Garzik 	.name			= DRV_NAME,
574c6fd2807SJeff Garzik 	.id_table		= ahci_pci_tbl,
575c6fd2807SJeff Garzik 	.probe			= ahci_init_one,
57624dc5f33STejun Heo 	.remove			= ata_pci_remove_one,
577438ac6d5STejun Heo #ifdef CONFIG_PM
578c6fd2807SJeff Garzik 	.suspend		= ahci_pci_device_suspend,
579c6fd2807SJeff Garzik 	.resume			= ahci_pci_device_resume,
580438ac6d5STejun Heo #endif
581c6fd2807SJeff Garzik };
582c6fd2807SJeff Garzik 
583c6fd2807SJeff Garzik 
58498fa4b60STejun Heo static inline int ahci_nr_ports(u32 cap)
58598fa4b60STejun Heo {
58698fa4b60STejun Heo 	return (cap & 0x1f) + 1;
58798fa4b60STejun Heo }
58898fa4b60STejun Heo 
589dab632e8SJeff Garzik static inline void __iomem *__ahci_port_base(struct ata_host *host,
590dab632e8SJeff Garzik 					     unsigned int port_no)
591dab632e8SJeff Garzik {
592dab632e8SJeff Garzik 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
593dab632e8SJeff Garzik 
594dab632e8SJeff Garzik 	return mmio + 0x100 + (port_no * 0x80);
595dab632e8SJeff Garzik }
596dab632e8SJeff Garzik 
5974447d351STejun Heo static inline void __iomem *ahci_port_base(struct ata_port *ap)
598c6fd2807SJeff Garzik {
599dab632e8SJeff Garzik 	return __ahci_port_base(ap->host, ap->port_no);
600c6fd2807SJeff Garzik }
601c6fd2807SJeff Garzik 
602b710a1f4STejun Heo static void ahci_enable_ahci(void __iomem *mmio)
603b710a1f4STejun Heo {
604b710a1f4STejun Heo 	u32 tmp;
605b710a1f4STejun Heo 
606b710a1f4STejun Heo 	/* turn on AHCI_EN */
607b710a1f4STejun Heo 	tmp = readl(mmio + HOST_CTL);
608b710a1f4STejun Heo 	if (!(tmp & HOST_AHCI_EN)) {
609b710a1f4STejun Heo 		tmp |= HOST_AHCI_EN;
610b710a1f4STejun Heo 		writel(tmp, mmio + HOST_CTL);
611b710a1f4STejun Heo 		tmp = readl(mmio + HOST_CTL);	/* flush && sanity check */
612b710a1f4STejun Heo 		WARN_ON(!(tmp & HOST_AHCI_EN));
613b710a1f4STejun Heo 	}
614b710a1f4STejun Heo }
615b710a1f4STejun Heo 
616d447df14STejun Heo /**
617d447df14STejun Heo  *	ahci_save_initial_config - Save and fixup initial config values
6184447d351STejun Heo  *	@pdev: target PCI device
6194447d351STejun Heo  *	@hpriv: host private area to store config values
620d447df14STejun Heo  *
621d447df14STejun Heo  *	Some registers containing configuration info might be setup by
622d447df14STejun Heo  *	BIOS and might be cleared on reset.  This function saves the
623d447df14STejun Heo  *	initial values of those registers into @hpriv such that they
624d447df14STejun Heo  *	can be restored after controller reset.
625d447df14STejun Heo  *
626d447df14STejun Heo  *	If inconsistent, config values are fixed up by this function.
627d447df14STejun Heo  *
628d447df14STejun Heo  *	LOCKING:
629d447df14STejun Heo  *	None.
630d447df14STejun Heo  */
6314447d351STejun Heo static void ahci_save_initial_config(struct pci_dev *pdev,
6324447d351STejun Heo 				     struct ahci_host_priv *hpriv)
633d447df14STejun Heo {
6344447d351STejun Heo 	void __iomem *mmio = pcim_iomap_table(pdev)[AHCI_PCI_BAR];
635d447df14STejun Heo 	u32 cap, port_map;
63617199b18STejun Heo 	int i;
637d447df14STejun Heo 
638b710a1f4STejun Heo 	/* make sure AHCI mode is enabled before accessing CAP */
639b710a1f4STejun Heo 	ahci_enable_ahci(mmio);
640b710a1f4STejun Heo 
641d447df14STejun Heo 	/* Values prefixed with saved_ are written back to host after
642d447df14STejun Heo 	 * reset.  Values without are used for driver operation.
643d447df14STejun Heo 	 */
644d447df14STejun Heo 	hpriv->saved_cap = cap = readl(mmio + HOST_CAP);
645d447df14STejun Heo 	hpriv->saved_port_map = port_map = readl(mmio + HOST_PORTS_IMPL);
646d447df14STejun Heo 
647274c1fdeSTejun Heo 	/* some chips have errata preventing 64bit use */
648417a1a6dSTejun Heo 	if ((cap & HOST_CAP_64) && (hpriv->flags & AHCI_HFLAG_32BIT_ONLY)) {
649c7a42156STejun Heo 		dev_printk(KERN_INFO, &pdev->dev,
650c7a42156STejun Heo 			   "controller can't do 64bit DMA, forcing 32bit\n");
651c7a42156STejun Heo 		cap &= ~HOST_CAP_64;
652c7a42156STejun Heo 	}
653c7a42156STejun Heo 
654417a1a6dSTejun Heo 	if ((cap & HOST_CAP_NCQ) && (hpriv->flags & AHCI_HFLAG_NO_NCQ)) {
655274c1fdeSTejun Heo 		dev_printk(KERN_INFO, &pdev->dev,
656274c1fdeSTejun Heo 			   "controller can't do NCQ, turning off CAP_NCQ\n");
657274c1fdeSTejun Heo 		cap &= ~HOST_CAP_NCQ;
658274c1fdeSTejun Heo 	}
659274c1fdeSTejun Heo 
6606949b914STejun Heo 	if ((cap && HOST_CAP_PMP) && (hpriv->flags & AHCI_HFLAG_NO_PMP)) {
6616949b914STejun Heo 		dev_printk(KERN_INFO, &pdev->dev,
6626949b914STejun Heo 			   "controller can't do PMP, turning off CAP_PMP\n");
6636949b914STejun Heo 		cap &= ~HOST_CAP_PMP;
6646949b914STejun Heo 	}
6656949b914STejun Heo 
666cd70c266SJeff Garzik 	/*
667cd70c266SJeff Garzik 	 * Temporary Marvell 6145 hack: PATA port presence
668cd70c266SJeff Garzik 	 * is asserted through the standard AHCI port
669cd70c266SJeff Garzik 	 * presence register, as bit 4 (counting from 0)
670cd70c266SJeff Garzik 	 */
671417a1a6dSTejun Heo 	if (hpriv->flags & AHCI_HFLAG_MV_PATA) {
672cd70c266SJeff Garzik 		dev_printk(KERN_ERR, &pdev->dev,
673cd70c266SJeff Garzik 			   "MV_AHCI HACK: port_map %x -> %x\n",
674cd70c266SJeff Garzik 			   hpriv->port_map,
675cd70c266SJeff Garzik 			   hpriv->port_map & 0xf);
676cd70c266SJeff Garzik 
677cd70c266SJeff Garzik 		port_map &= 0xf;
678cd70c266SJeff Garzik 	}
679cd70c266SJeff Garzik 
68017199b18STejun Heo 	/* cross check port_map and cap.n_ports */
6817a234affSTejun Heo 	if (port_map) {
682*837f5f8fSTejun Heo 		int map_ports = 0;
68317199b18STejun Heo 
684*837f5f8fSTejun Heo 		for (i = 0; i < AHCI_MAX_PORTS; i++)
685*837f5f8fSTejun Heo 			if (port_map & (1 << i))
686*837f5f8fSTejun Heo 				map_ports++;
68717199b18STejun Heo 
688*837f5f8fSTejun Heo 		/* If PI has more ports than n_ports, whine, clear
689*837f5f8fSTejun Heo 		 * port_map and let it be generated from n_ports.
69017199b18STejun Heo 		 */
691*837f5f8fSTejun Heo 		if (map_ports > ahci_nr_ports(cap)) {
6924447d351STejun Heo 			dev_printk(KERN_WARNING, &pdev->dev,
693*837f5f8fSTejun Heo 				   "implemented port map (0x%x) contains more "
694*837f5f8fSTejun Heo 				   "ports than nr_ports (%u), using nr_ports\n",
695*837f5f8fSTejun Heo 				   port_map, ahci_nr_ports(cap));
6967a234affSTejun Heo 			port_map = 0;
6977a234affSTejun Heo 		}
6987a234affSTejun Heo 	}
6997a234affSTejun Heo 
70017199b18STejun Heo 	/* fabricate port_map from cap.nr_ports */
7017a234affSTejun Heo 	if (!port_map) {
70217199b18STejun Heo 		port_map = (1 << ahci_nr_ports(cap)) - 1;
7037a234affSTejun Heo 		dev_printk(KERN_WARNING, &pdev->dev,
7047a234affSTejun Heo 			   "forcing PORTS_IMPL to 0x%x\n", port_map);
7057a234affSTejun Heo 
7067a234affSTejun Heo 		/* write the fixed up value to the PI register */
7077a234affSTejun Heo 		hpriv->saved_port_map = port_map;
70817199b18STejun Heo 	}
70917199b18STejun Heo 
710d447df14STejun Heo 	/* record values to use during operation */
711d447df14STejun Heo 	hpriv->cap = cap;
712d447df14STejun Heo 	hpriv->port_map = port_map;
713d447df14STejun Heo }
714d447df14STejun Heo 
715d447df14STejun Heo /**
716d447df14STejun Heo  *	ahci_restore_initial_config - Restore initial config
7174447d351STejun Heo  *	@host: target ATA host
718d447df14STejun Heo  *
719d447df14STejun Heo  *	Restore initial config stored by ahci_save_initial_config().
720d447df14STejun Heo  *
721d447df14STejun Heo  *	LOCKING:
722d447df14STejun Heo  *	None.
723d447df14STejun Heo  */
7244447d351STejun Heo static void ahci_restore_initial_config(struct ata_host *host)
725d447df14STejun Heo {
7264447d351STejun Heo 	struct ahci_host_priv *hpriv = host->private_data;
7274447d351STejun Heo 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
7284447d351STejun Heo 
729d447df14STejun Heo 	writel(hpriv->saved_cap, mmio + HOST_CAP);
730d447df14STejun Heo 	writel(hpriv->saved_port_map, mmio + HOST_PORTS_IMPL);
731d447df14STejun Heo 	(void) readl(mmio + HOST_PORTS_IMPL);	/* flush */
732d447df14STejun Heo }
733d447df14STejun Heo 
734203ef6c4STejun Heo static unsigned ahci_scr_offset(struct ata_port *ap, unsigned int sc_reg)
735c6fd2807SJeff Garzik {
736203ef6c4STejun Heo 	static const int offset[] = {
737203ef6c4STejun Heo 		[SCR_STATUS]		= PORT_SCR_STAT,
738203ef6c4STejun Heo 		[SCR_CONTROL]		= PORT_SCR_CTL,
739203ef6c4STejun Heo 		[SCR_ERROR]		= PORT_SCR_ERR,
740203ef6c4STejun Heo 		[SCR_ACTIVE]		= PORT_SCR_ACT,
741203ef6c4STejun Heo 		[SCR_NOTIFICATION]	= PORT_SCR_NTF,
742203ef6c4STejun Heo 	};
743203ef6c4STejun Heo 	struct ahci_host_priv *hpriv = ap->host->private_data;
744c6fd2807SJeff Garzik 
745203ef6c4STejun Heo 	if (sc_reg < ARRAY_SIZE(offset) &&
746203ef6c4STejun Heo 	    (sc_reg != SCR_NOTIFICATION || (hpriv->cap & HOST_CAP_SNTF)))
747203ef6c4STejun Heo 		return offset[sc_reg];
748da3dbb17STejun Heo 	return 0;
749c6fd2807SJeff Garzik }
750c6fd2807SJeff Garzik 
751203ef6c4STejun Heo static int ahci_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
752c6fd2807SJeff Garzik {
753203ef6c4STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
754203ef6c4STejun Heo 	int offset = ahci_scr_offset(ap, sc_reg);
755c6fd2807SJeff Garzik 
756203ef6c4STejun Heo 	if (offset) {
757203ef6c4STejun Heo 		*val = readl(port_mmio + offset);
758203ef6c4STejun Heo 		return 0;
759203ef6c4STejun Heo 	}
760da3dbb17STejun Heo 	return -EINVAL;
761c6fd2807SJeff Garzik }
762c6fd2807SJeff Garzik 
763203ef6c4STejun Heo static int ahci_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
764203ef6c4STejun Heo {
765203ef6c4STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
766203ef6c4STejun Heo 	int offset = ahci_scr_offset(ap, sc_reg);
767203ef6c4STejun Heo 
768203ef6c4STejun Heo 	if (offset) {
769203ef6c4STejun Heo 		writel(val, port_mmio + offset);
770da3dbb17STejun Heo 		return 0;
771c6fd2807SJeff Garzik 	}
772203ef6c4STejun Heo 	return -EINVAL;
773203ef6c4STejun Heo }
774c6fd2807SJeff Garzik 
7754447d351STejun Heo static void ahci_start_engine(struct ata_port *ap)
776c6fd2807SJeff Garzik {
7774447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
778c6fd2807SJeff Garzik 	u32 tmp;
779c6fd2807SJeff Garzik 
780c6fd2807SJeff Garzik 	/* start DMA */
781c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_CMD);
782c6fd2807SJeff Garzik 	tmp |= PORT_CMD_START;
783c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_CMD);
784c6fd2807SJeff Garzik 	readl(port_mmio + PORT_CMD); /* flush */
785c6fd2807SJeff Garzik }
786c6fd2807SJeff Garzik 
7874447d351STejun Heo static int ahci_stop_engine(struct ata_port *ap)
788c6fd2807SJeff Garzik {
7894447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
790c6fd2807SJeff Garzik 	u32 tmp;
791c6fd2807SJeff Garzik 
792c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_CMD);
793c6fd2807SJeff Garzik 
794c6fd2807SJeff Garzik 	/* check if the HBA is idle */
795c6fd2807SJeff Garzik 	if ((tmp & (PORT_CMD_START | PORT_CMD_LIST_ON)) == 0)
796c6fd2807SJeff Garzik 		return 0;
797c6fd2807SJeff Garzik 
798c6fd2807SJeff Garzik 	/* setting HBA to idle */
799c6fd2807SJeff Garzik 	tmp &= ~PORT_CMD_START;
800c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_CMD);
801c6fd2807SJeff Garzik 
802c6fd2807SJeff Garzik 	/* wait for engine to stop. This could be as long as 500 msec */
803c6fd2807SJeff Garzik 	tmp = ata_wait_register(port_mmio + PORT_CMD,
804c6fd2807SJeff Garzik 				PORT_CMD_LIST_ON, PORT_CMD_LIST_ON, 1, 500);
805c6fd2807SJeff Garzik 	if (tmp & PORT_CMD_LIST_ON)
806c6fd2807SJeff Garzik 		return -EIO;
807c6fd2807SJeff Garzik 
808c6fd2807SJeff Garzik 	return 0;
809c6fd2807SJeff Garzik }
810c6fd2807SJeff Garzik 
8114447d351STejun Heo static void ahci_start_fis_rx(struct ata_port *ap)
812c6fd2807SJeff Garzik {
8134447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
8144447d351STejun Heo 	struct ahci_host_priv *hpriv = ap->host->private_data;
8154447d351STejun Heo 	struct ahci_port_priv *pp = ap->private_data;
816c6fd2807SJeff Garzik 	u32 tmp;
817c6fd2807SJeff Garzik 
818c6fd2807SJeff Garzik 	/* set FIS registers */
8194447d351STejun Heo 	if (hpriv->cap & HOST_CAP_64)
8204447d351STejun Heo 		writel((pp->cmd_slot_dma >> 16) >> 16,
8214447d351STejun Heo 		       port_mmio + PORT_LST_ADDR_HI);
8224447d351STejun Heo 	writel(pp->cmd_slot_dma & 0xffffffff, port_mmio + PORT_LST_ADDR);
823c6fd2807SJeff Garzik 
8244447d351STejun Heo 	if (hpriv->cap & HOST_CAP_64)
8254447d351STejun Heo 		writel((pp->rx_fis_dma >> 16) >> 16,
8264447d351STejun Heo 		       port_mmio + PORT_FIS_ADDR_HI);
8274447d351STejun Heo 	writel(pp->rx_fis_dma & 0xffffffff, port_mmio + PORT_FIS_ADDR);
828c6fd2807SJeff Garzik 
829c6fd2807SJeff Garzik 	/* enable FIS reception */
830c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_CMD);
831c6fd2807SJeff Garzik 	tmp |= PORT_CMD_FIS_RX;
832c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_CMD);
833c6fd2807SJeff Garzik 
834c6fd2807SJeff Garzik 	/* flush */
835c6fd2807SJeff Garzik 	readl(port_mmio + PORT_CMD);
836c6fd2807SJeff Garzik }
837c6fd2807SJeff Garzik 
8384447d351STejun Heo static int ahci_stop_fis_rx(struct ata_port *ap)
839c6fd2807SJeff Garzik {
8404447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
841c6fd2807SJeff Garzik 	u32 tmp;
842c6fd2807SJeff Garzik 
843c6fd2807SJeff Garzik 	/* disable FIS reception */
844c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_CMD);
845c6fd2807SJeff Garzik 	tmp &= ~PORT_CMD_FIS_RX;
846c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_CMD);
847c6fd2807SJeff Garzik 
848c6fd2807SJeff Garzik 	/* wait for completion, spec says 500ms, give it 1000 */
849c6fd2807SJeff Garzik 	tmp = ata_wait_register(port_mmio + PORT_CMD, PORT_CMD_FIS_ON,
850c6fd2807SJeff Garzik 				PORT_CMD_FIS_ON, 10, 1000);
851c6fd2807SJeff Garzik 	if (tmp & PORT_CMD_FIS_ON)
852c6fd2807SJeff Garzik 		return -EBUSY;
853c6fd2807SJeff Garzik 
854c6fd2807SJeff Garzik 	return 0;
855c6fd2807SJeff Garzik }
856c6fd2807SJeff Garzik 
8574447d351STejun Heo static void ahci_power_up(struct ata_port *ap)
858c6fd2807SJeff Garzik {
8594447d351STejun Heo 	struct ahci_host_priv *hpriv = ap->host->private_data;
8604447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
861c6fd2807SJeff Garzik 	u32 cmd;
862c6fd2807SJeff Garzik 
863c6fd2807SJeff Garzik 	cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK;
864c6fd2807SJeff Garzik 
865c6fd2807SJeff Garzik 	/* spin up device */
8664447d351STejun Heo 	if (hpriv->cap & HOST_CAP_SSS) {
867c6fd2807SJeff Garzik 		cmd |= PORT_CMD_SPIN_UP;
868c6fd2807SJeff Garzik 		writel(cmd, port_mmio + PORT_CMD);
869c6fd2807SJeff Garzik 	}
870c6fd2807SJeff Garzik 
871c6fd2807SJeff Garzik 	/* wake up link */
872c6fd2807SJeff Garzik 	writel(cmd | PORT_CMD_ICC_ACTIVE, port_mmio + PORT_CMD);
873c6fd2807SJeff Garzik }
874c6fd2807SJeff Garzik 
87531556594SKristen Carlson Accardi static void ahci_disable_alpm(struct ata_port *ap)
87631556594SKristen Carlson Accardi {
87731556594SKristen Carlson Accardi 	struct ahci_host_priv *hpriv = ap->host->private_data;
87831556594SKristen Carlson Accardi 	void __iomem *port_mmio = ahci_port_base(ap);
87931556594SKristen Carlson Accardi 	u32 cmd;
88031556594SKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
88131556594SKristen Carlson Accardi 
88231556594SKristen Carlson Accardi 	/* IPM bits should be disabled by libata-core */
88331556594SKristen Carlson Accardi 	/* get the existing command bits */
88431556594SKristen Carlson Accardi 	cmd = readl(port_mmio + PORT_CMD);
88531556594SKristen Carlson Accardi 
88631556594SKristen Carlson Accardi 	/* disable ALPM and ASP */
88731556594SKristen Carlson Accardi 	cmd &= ~PORT_CMD_ASP;
88831556594SKristen Carlson Accardi 	cmd &= ~PORT_CMD_ALPE;
88931556594SKristen Carlson Accardi 
89031556594SKristen Carlson Accardi 	/* force the interface back to active */
89131556594SKristen Carlson Accardi 	cmd |= PORT_CMD_ICC_ACTIVE;
89231556594SKristen Carlson Accardi 
89331556594SKristen Carlson Accardi 	/* write out new cmd value */
89431556594SKristen Carlson Accardi 	writel(cmd, port_mmio + PORT_CMD);
89531556594SKristen Carlson Accardi 	cmd = readl(port_mmio + PORT_CMD);
89631556594SKristen Carlson Accardi 
89731556594SKristen Carlson Accardi 	/* wait 10ms to be sure we've come out of any low power state */
89831556594SKristen Carlson Accardi 	msleep(10);
89931556594SKristen Carlson Accardi 
90031556594SKristen Carlson Accardi 	/* clear out any PhyRdy stuff from interrupt status */
90131556594SKristen Carlson Accardi 	writel(PORT_IRQ_PHYRDY, port_mmio + PORT_IRQ_STAT);
90231556594SKristen Carlson Accardi 
90331556594SKristen Carlson Accardi 	/* go ahead and clean out PhyRdy Change from Serror too */
90431556594SKristen Carlson Accardi 	ahci_scr_write(ap, SCR_ERROR, ((1 << 16) | (1 << 18)));
90531556594SKristen Carlson Accardi 
90631556594SKristen Carlson Accardi 	/*
90731556594SKristen Carlson Accardi  	 * Clear flag to indicate that we should ignore all PhyRdy
90831556594SKristen Carlson Accardi  	 * state changes
90931556594SKristen Carlson Accardi  	 */
91031556594SKristen Carlson Accardi 	hpriv->flags &= ~AHCI_HFLAG_NO_HOTPLUG;
91131556594SKristen Carlson Accardi 
91231556594SKristen Carlson Accardi 	/*
91331556594SKristen Carlson Accardi  	 * Enable interrupts on Phy Ready.
91431556594SKristen Carlson Accardi  	 */
91531556594SKristen Carlson Accardi 	pp->intr_mask |= PORT_IRQ_PHYRDY;
91631556594SKristen Carlson Accardi 	writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
91731556594SKristen Carlson Accardi 
91831556594SKristen Carlson Accardi 	/*
91931556594SKristen Carlson Accardi  	 * don't change the link pm policy - we can be called
92031556594SKristen Carlson Accardi  	 * just to turn of link pm temporarily
92131556594SKristen Carlson Accardi  	 */
92231556594SKristen Carlson Accardi }
92331556594SKristen Carlson Accardi 
92431556594SKristen Carlson Accardi static int ahci_enable_alpm(struct ata_port *ap,
92531556594SKristen Carlson Accardi 	enum link_pm policy)
92631556594SKristen Carlson Accardi {
92731556594SKristen Carlson Accardi 	struct ahci_host_priv *hpriv = ap->host->private_data;
92831556594SKristen Carlson Accardi 	void __iomem *port_mmio = ahci_port_base(ap);
92931556594SKristen Carlson Accardi 	u32 cmd;
93031556594SKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
93131556594SKristen Carlson Accardi 	u32 asp;
93231556594SKristen Carlson Accardi 
93331556594SKristen Carlson Accardi 	/* Make sure the host is capable of link power management */
93431556594SKristen Carlson Accardi 	if (!(hpriv->cap & HOST_CAP_ALPM))
93531556594SKristen Carlson Accardi 		return -EINVAL;
93631556594SKristen Carlson Accardi 
93731556594SKristen Carlson Accardi 	switch (policy) {
93831556594SKristen Carlson Accardi 	case MAX_PERFORMANCE:
93931556594SKristen Carlson Accardi 	case NOT_AVAILABLE:
94031556594SKristen Carlson Accardi 		/*
94131556594SKristen Carlson Accardi  		 * if we came here with NOT_AVAILABLE,
94231556594SKristen Carlson Accardi  		 * it just means this is the first time we
94331556594SKristen Carlson Accardi  		 * have tried to enable - default to max performance,
94431556594SKristen Carlson Accardi  		 * and let the user go to lower power modes on request.
94531556594SKristen Carlson Accardi  		 */
94631556594SKristen Carlson Accardi 		ahci_disable_alpm(ap);
94731556594SKristen Carlson Accardi 		return 0;
94831556594SKristen Carlson Accardi 	case MIN_POWER:
94931556594SKristen Carlson Accardi 		/* configure HBA to enter SLUMBER */
95031556594SKristen Carlson Accardi 		asp = PORT_CMD_ASP;
95131556594SKristen Carlson Accardi 		break;
95231556594SKristen Carlson Accardi 	case MEDIUM_POWER:
95331556594SKristen Carlson Accardi 		/* configure HBA to enter PARTIAL */
95431556594SKristen Carlson Accardi 		asp = 0;
95531556594SKristen Carlson Accardi 		break;
95631556594SKristen Carlson Accardi 	default:
95731556594SKristen Carlson Accardi 		return -EINVAL;
95831556594SKristen Carlson Accardi 	}
95931556594SKristen Carlson Accardi 
96031556594SKristen Carlson Accardi 	/*
96131556594SKristen Carlson Accardi  	 * Disable interrupts on Phy Ready. This keeps us from
96231556594SKristen Carlson Accardi  	 * getting woken up due to spurious phy ready interrupts
96331556594SKristen Carlson Accardi 	 * TBD - Hot plug should be done via polling now, is
96431556594SKristen Carlson Accardi 	 * that even supported?
96531556594SKristen Carlson Accardi  	 */
96631556594SKristen Carlson Accardi 	pp->intr_mask &= ~PORT_IRQ_PHYRDY;
96731556594SKristen Carlson Accardi 	writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
96831556594SKristen Carlson Accardi 
96931556594SKristen Carlson Accardi 	/*
97031556594SKristen Carlson Accardi  	 * Set a flag to indicate that we should ignore all PhyRdy
97131556594SKristen Carlson Accardi  	 * state changes since these can happen now whenever we
97231556594SKristen Carlson Accardi  	 * change link state
97331556594SKristen Carlson Accardi  	 */
97431556594SKristen Carlson Accardi 	hpriv->flags |= AHCI_HFLAG_NO_HOTPLUG;
97531556594SKristen Carlson Accardi 
97631556594SKristen Carlson Accardi 	/* get the existing command bits */
97731556594SKristen Carlson Accardi 	cmd = readl(port_mmio + PORT_CMD);
97831556594SKristen Carlson Accardi 
97931556594SKristen Carlson Accardi 	/*
98031556594SKristen Carlson Accardi  	 * Set ASP based on Policy
98131556594SKristen Carlson Accardi  	 */
98231556594SKristen Carlson Accardi 	cmd |= asp;
98331556594SKristen Carlson Accardi 
98431556594SKristen Carlson Accardi 	/*
98531556594SKristen Carlson Accardi  	 * Setting this bit will instruct the HBA to aggressively
98631556594SKristen Carlson Accardi  	 * enter a lower power link state when it's appropriate and
98731556594SKristen Carlson Accardi  	 * based on the value set above for ASP
98831556594SKristen Carlson Accardi  	 */
98931556594SKristen Carlson Accardi 	cmd |= PORT_CMD_ALPE;
99031556594SKristen Carlson Accardi 
99131556594SKristen Carlson Accardi 	/* write out new cmd value */
99231556594SKristen Carlson Accardi 	writel(cmd, port_mmio + PORT_CMD);
99331556594SKristen Carlson Accardi 	cmd = readl(port_mmio + PORT_CMD);
99431556594SKristen Carlson Accardi 
99531556594SKristen Carlson Accardi 	/* IPM bits should be set by libata-core */
99631556594SKristen Carlson Accardi 	return 0;
99731556594SKristen Carlson Accardi }
99831556594SKristen Carlson Accardi 
999438ac6d5STejun Heo #ifdef CONFIG_PM
10004447d351STejun Heo static void ahci_power_down(struct ata_port *ap)
1001c6fd2807SJeff Garzik {
10024447d351STejun Heo 	struct ahci_host_priv *hpriv = ap->host->private_data;
10034447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
1004c6fd2807SJeff Garzik 	u32 cmd, scontrol;
1005c6fd2807SJeff Garzik 
10064447d351STejun Heo 	if (!(hpriv->cap & HOST_CAP_SSS))
100707c53dacSTejun Heo 		return;
1008c6fd2807SJeff Garzik 
100907c53dacSTejun Heo 	/* put device into listen mode, first set PxSCTL.DET to 0 */
1010c6fd2807SJeff Garzik 	scontrol = readl(port_mmio + PORT_SCR_CTL);
1011c6fd2807SJeff Garzik 	scontrol &= ~0xf;
1012c6fd2807SJeff Garzik 	writel(scontrol, port_mmio + PORT_SCR_CTL);
1013c6fd2807SJeff Garzik 
1014c6fd2807SJeff Garzik 	/* then set PxCMD.SUD to 0 */
101507c53dacSTejun Heo 	cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK;
1016c6fd2807SJeff Garzik 	cmd &= ~PORT_CMD_SPIN_UP;
1017c6fd2807SJeff Garzik 	writel(cmd, port_mmio + PORT_CMD);
1018c6fd2807SJeff Garzik }
1019438ac6d5STejun Heo #endif
1020c6fd2807SJeff Garzik 
1021df69c9c5SJeff Garzik static void ahci_start_port(struct ata_port *ap)
1022c6fd2807SJeff Garzik {
1023c6fd2807SJeff Garzik 	/* enable FIS reception */
10244447d351STejun Heo 	ahci_start_fis_rx(ap);
1025c6fd2807SJeff Garzik 
1026c6fd2807SJeff Garzik 	/* enable DMA */
10274447d351STejun Heo 	ahci_start_engine(ap);
1028c6fd2807SJeff Garzik }
1029c6fd2807SJeff Garzik 
10304447d351STejun Heo static int ahci_deinit_port(struct ata_port *ap, const char **emsg)
1031c6fd2807SJeff Garzik {
1032c6fd2807SJeff Garzik 	int rc;
1033c6fd2807SJeff Garzik 
1034c6fd2807SJeff Garzik 	/* disable DMA */
10354447d351STejun Heo 	rc = ahci_stop_engine(ap);
1036c6fd2807SJeff Garzik 	if (rc) {
1037c6fd2807SJeff Garzik 		*emsg = "failed to stop engine";
1038c6fd2807SJeff Garzik 		return rc;
1039c6fd2807SJeff Garzik 	}
1040c6fd2807SJeff Garzik 
1041c6fd2807SJeff Garzik 	/* disable FIS reception */
10424447d351STejun Heo 	rc = ahci_stop_fis_rx(ap);
1043c6fd2807SJeff Garzik 	if (rc) {
1044c6fd2807SJeff Garzik 		*emsg = "failed stop FIS RX";
1045c6fd2807SJeff Garzik 		return rc;
1046c6fd2807SJeff Garzik 	}
1047c6fd2807SJeff Garzik 
1048c6fd2807SJeff Garzik 	return 0;
1049c6fd2807SJeff Garzik }
1050c6fd2807SJeff Garzik 
10514447d351STejun Heo static int ahci_reset_controller(struct ata_host *host)
1052c6fd2807SJeff Garzik {
10534447d351STejun Heo 	struct pci_dev *pdev = to_pci_dev(host->dev);
105449f29090STejun Heo 	struct ahci_host_priv *hpriv = host->private_data;
10554447d351STejun Heo 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
1056d447df14STejun Heo 	u32 tmp;
1057c6fd2807SJeff Garzik 
10583cc3eb11SJeff Garzik 	/* we must be in AHCI mode, before using anything
10593cc3eb11SJeff Garzik 	 * AHCI-specific, such as HOST_RESET.
10603cc3eb11SJeff Garzik 	 */
1061b710a1f4STejun Heo 	ahci_enable_ahci(mmio);
10623cc3eb11SJeff Garzik 
10633cc3eb11SJeff Garzik 	/* global controller reset */
1064b710a1f4STejun Heo 	tmp = readl(mmio + HOST_CTL);
1065c6fd2807SJeff Garzik 	if ((tmp & HOST_RESET) == 0) {
1066c6fd2807SJeff Garzik 		writel(tmp | HOST_RESET, mmio + HOST_CTL);
1067c6fd2807SJeff Garzik 		readl(mmio + HOST_CTL); /* flush */
1068c6fd2807SJeff Garzik 	}
1069c6fd2807SJeff Garzik 
1070c6fd2807SJeff Garzik 	/* reset must complete within 1 second, or
1071c6fd2807SJeff Garzik 	 * the hardware should be considered fried.
1072c6fd2807SJeff Garzik 	 */
1073c6fd2807SJeff Garzik 	ssleep(1);
1074c6fd2807SJeff Garzik 
1075c6fd2807SJeff Garzik 	tmp = readl(mmio + HOST_CTL);
1076c6fd2807SJeff Garzik 	if (tmp & HOST_RESET) {
10774447d351STejun Heo 		dev_printk(KERN_ERR, host->dev,
1078c6fd2807SJeff Garzik 			   "controller reset failed (0x%x)\n", tmp);
1079c6fd2807SJeff Garzik 		return -EIO;
1080c6fd2807SJeff Garzik 	}
1081c6fd2807SJeff Garzik 
108298fa4b60STejun Heo 	/* turn on AHCI mode */
1083b710a1f4STejun Heo 	ahci_enable_ahci(mmio);
108498fa4b60STejun Heo 
1085d447df14STejun Heo 	/* some registers might be cleared on reset.  restore initial values */
10864447d351STejun Heo 	ahci_restore_initial_config(host);
1087c6fd2807SJeff Garzik 
1088c6fd2807SJeff Garzik 	if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
1089c6fd2807SJeff Garzik 		u16 tmp16;
1090c6fd2807SJeff Garzik 
1091c6fd2807SJeff Garzik 		/* configure PCS */
1092c6fd2807SJeff Garzik 		pci_read_config_word(pdev, 0x92, &tmp16);
109349f29090STejun Heo 		if ((tmp16 & hpriv->port_map) != hpriv->port_map) {
109449f29090STejun Heo 			tmp16 |= hpriv->port_map;
1095c6fd2807SJeff Garzik 			pci_write_config_word(pdev, 0x92, tmp16);
1096c6fd2807SJeff Garzik 		}
109749f29090STejun Heo 	}
1098c6fd2807SJeff Garzik 
1099c6fd2807SJeff Garzik 	return 0;
1100c6fd2807SJeff Garzik }
1101c6fd2807SJeff Garzik 
11022bcd866bSJeff Garzik static void ahci_port_init(struct pci_dev *pdev, struct ata_port *ap,
11032bcd866bSJeff Garzik 			   int port_no, void __iomem *mmio,
11042bcd866bSJeff Garzik 			   void __iomem *port_mmio)
1105c6fd2807SJeff Garzik {
1106c6fd2807SJeff Garzik 	const char *emsg = NULL;
11072bcd866bSJeff Garzik 	int rc;
11082bcd866bSJeff Garzik 	u32 tmp;
1109c6fd2807SJeff Garzik 
1110c6fd2807SJeff Garzik 	/* make sure port is not active */
11114447d351STejun Heo 	rc = ahci_deinit_port(ap, &emsg);
1112c6fd2807SJeff Garzik 	if (rc)
1113c6fd2807SJeff Garzik 		dev_printk(KERN_WARNING, &pdev->dev,
1114c6fd2807SJeff Garzik 			   "%s (%d)\n", emsg, rc);
1115c6fd2807SJeff Garzik 
1116c6fd2807SJeff Garzik 	/* clear SError */
1117c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_SCR_ERR);
1118c6fd2807SJeff Garzik 	VPRINTK("PORT_SCR_ERR 0x%x\n", tmp);
1119c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_SCR_ERR);
1120c6fd2807SJeff Garzik 
1121c6fd2807SJeff Garzik 	/* clear port IRQ */
1122c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_IRQ_STAT);
1123c6fd2807SJeff Garzik 	VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp);
1124c6fd2807SJeff Garzik 	if (tmp)
1125c6fd2807SJeff Garzik 		writel(tmp, port_mmio + PORT_IRQ_STAT);
1126c6fd2807SJeff Garzik 
11272bcd866bSJeff Garzik 	writel(1 << port_no, mmio + HOST_IRQ_STAT);
11282bcd866bSJeff Garzik }
11292bcd866bSJeff Garzik 
11302bcd866bSJeff Garzik static void ahci_init_controller(struct ata_host *host)
11312bcd866bSJeff Garzik {
1132417a1a6dSTejun Heo 	struct ahci_host_priv *hpriv = host->private_data;
11332bcd866bSJeff Garzik 	struct pci_dev *pdev = to_pci_dev(host->dev);
11342bcd866bSJeff Garzik 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
11352bcd866bSJeff Garzik 	int i;
1136cd70c266SJeff Garzik 	void __iomem *port_mmio;
11372bcd866bSJeff Garzik 	u32 tmp;
11382bcd866bSJeff Garzik 
1139417a1a6dSTejun Heo 	if (hpriv->flags & AHCI_HFLAG_MV_PATA) {
1140cd70c266SJeff Garzik 		port_mmio = __ahci_port_base(host, 4);
1141cd70c266SJeff Garzik 
1142cd70c266SJeff Garzik 		writel(0, port_mmio + PORT_IRQ_MASK);
1143cd70c266SJeff Garzik 
1144cd70c266SJeff Garzik 		/* clear port IRQ */
1145cd70c266SJeff Garzik 		tmp = readl(port_mmio + PORT_IRQ_STAT);
1146cd70c266SJeff Garzik 		VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp);
1147cd70c266SJeff Garzik 		if (tmp)
1148cd70c266SJeff Garzik 			writel(tmp, port_mmio + PORT_IRQ_STAT);
1149cd70c266SJeff Garzik 	}
1150cd70c266SJeff Garzik 
11512bcd866bSJeff Garzik 	for (i = 0; i < host->n_ports; i++) {
11522bcd866bSJeff Garzik 		struct ata_port *ap = host->ports[i];
11532bcd866bSJeff Garzik 
1154cd70c266SJeff Garzik 		port_mmio = ahci_port_base(ap);
11552bcd866bSJeff Garzik 		if (ata_port_is_dummy(ap))
11562bcd866bSJeff Garzik 			continue;
11572bcd866bSJeff Garzik 
11582bcd866bSJeff Garzik 		ahci_port_init(pdev, ap, i, mmio, port_mmio);
1159c6fd2807SJeff Garzik 	}
1160c6fd2807SJeff Garzik 
1161c6fd2807SJeff Garzik 	tmp = readl(mmio + HOST_CTL);
1162c6fd2807SJeff Garzik 	VPRINTK("HOST_CTL 0x%x\n", tmp);
1163c6fd2807SJeff Garzik 	writel(tmp | HOST_IRQ_EN, mmio + HOST_CTL);
1164c6fd2807SJeff Garzik 	tmp = readl(mmio + HOST_CTL);
1165c6fd2807SJeff Garzik 	VPRINTK("HOST_CTL 0x%x\n", tmp);
1166c6fd2807SJeff Garzik }
1167c6fd2807SJeff Garzik 
1168c6fd2807SJeff Garzik static unsigned int ahci_dev_classify(struct ata_port *ap)
1169c6fd2807SJeff Garzik {
11704447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
1171c6fd2807SJeff Garzik 	struct ata_taskfile tf;
1172c6fd2807SJeff Garzik 	u32 tmp;
1173c6fd2807SJeff Garzik 
1174c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_SIG);
1175c6fd2807SJeff Garzik 	tf.lbah		= (tmp >> 24)	& 0xff;
1176c6fd2807SJeff Garzik 	tf.lbam		= (tmp >> 16)	& 0xff;
1177c6fd2807SJeff Garzik 	tf.lbal		= (tmp >> 8)	& 0xff;
1178c6fd2807SJeff Garzik 	tf.nsect	= (tmp)		& 0xff;
1179c6fd2807SJeff Garzik 
1180c6fd2807SJeff Garzik 	return ata_dev_classify(&tf);
1181c6fd2807SJeff Garzik }
1182c6fd2807SJeff Garzik 
1183c6fd2807SJeff Garzik static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
1184c6fd2807SJeff Garzik 			       u32 opts)
1185c6fd2807SJeff Garzik {
1186c6fd2807SJeff Garzik 	dma_addr_t cmd_tbl_dma;
1187c6fd2807SJeff Garzik 
1188c6fd2807SJeff Garzik 	cmd_tbl_dma = pp->cmd_tbl_dma + tag * AHCI_CMD_TBL_SZ;
1189c6fd2807SJeff Garzik 
1190c6fd2807SJeff Garzik 	pp->cmd_slot[tag].opts = cpu_to_le32(opts);
1191c6fd2807SJeff Garzik 	pp->cmd_slot[tag].status = 0;
1192c6fd2807SJeff Garzik 	pp->cmd_slot[tag].tbl_addr = cpu_to_le32(cmd_tbl_dma & 0xffffffff);
1193c6fd2807SJeff Garzik 	pp->cmd_slot[tag].tbl_addr_hi = cpu_to_le32((cmd_tbl_dma >> 16) >> 16);
1194c6fd2807SJeff Garzik }
1195c6fd2807SJeff Garzik 
1196d2e75dffSTejun Heo static int ahci_kick_engine(struct ata_port *ap, int force_restart)
1197c6fd2807SJeff Garzik {
11980d5ff566STejun Heo 	void __iomem *port_mmio = ap->ioaddr.cmd_addr;
1199cca3974eSJeff Garzik 	struct ahci_host_priv *hpriv = ap->host->private_data;
1200c6fd2807SJeff Garzik 	u32 tmp;
1201d2e75dffSTejun Heo 	int busy, rc;
1202c6fd2807SJeff Garzik 
1203d2e75dffSTejun Heo 	/* do we need to kick the port? */
1204d2e75dffSTejun Heo 	busy = ahci_check_status(ap) & (ATA_BUSY | ATA_DRQ);
1205d2e75dffSTejun Heo 	if (!busy && !force_restart)
1206d2e75dffSTejun Heo 		return 0;
1207c6fd2807SJeff Garzik 
1208d2e75dffSTejun Heo 	/* stop engine */
1209d2e75dffSTejun Heo 	rc = ahci_stop_engine(ap);
1210d2e75dffSTejun Heo 	if (rc)
1211d2e75dffSTejun Heo 		goto out_restart;
1212d2e75dffSTejun Heo 
1213d2e75dffSTejun Heo 	/* need to do CLO? */
1214d2e75dffSTejun Heo 	if (!busy) {
1215d2e75dffSTejun Heo 		rc = 0;
1216d2e75dffSTejun Heo 		goto out_restart;
1217d2e75dffSTejun Heo 	}
1218d2e75dffSTejun Heo 
1219d2e75dffSTejun Heo 	if (!(hpriv->cap & HOST_CAP_CLO)) {
1220d2e75dffSTejun Heo 		rc = -EOPNOTSUPP;
1221d2e75dffSTejun Heo 		goto out_restart;
1222d2e75dffSTejun Heo 	}
1223d2e75dffSTejun Heo 
1224d2e75dffSTejun Heo 	/* perform CLO */
1225c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_CMD);
1226c6fd2807SJeff Garzik 	tmp |= PORT_CMD_CLO;
1227c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_CMD);
1228c6fd2807SJeff Garzik 
1229d2e75dffSTejun Heo 	rc = 0;
1230c6fd2807SJeff Garzik 	tmp = ata_wait_register(port_mmio + PORT_CMD,
1231c6fd2807SJeff Garzik 				PORT_CMD_CLO, PORT_CMD_CLO, 1, 500);
1232c6fd2807SJeff Garzik 	if (tmp & PORT_CMD_CLO)
1233d2e75dffSTejun Heo 		rc = -EIO;
1234c6fd2807SJeff Garzik 
1235d2e75dffSTejun Heo 	/* restart engine */
1236d2e75dffSTejun Heo  out_restart:
1237d2e75dffSTejun Heo 	ahci_start_engine(ap);
1238d2e75dffSTejun Heo 	return rc;
1239c6fd2807SJeff Garzik }
1240c6fd2807SJeff Garzik 
124191c4a2e0STejun Heo static int ahci_exec_polled_cmd(struct ata_port *ap, int pmp,
124291c4a2e0STejun Heo 				struct ata_taskfile *tf, int is_cmd, u16 flags,
124391c4a2e0STejun Heo 				unsigned long timeout_msec)
124491c4a2e0STejun Heo {
124591c4a2e0STejun Heo 	const u32 cmd_fis_len = 5; /* five dwords */
124691c4a2e0STejun Heo 	struct ahci_port_priv *pp = ap->private_data;
124791c4a2e0STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
124891c4a2e0STejun Heo 	u8 *fis = pp->cmd_tbl;
124991c4a2e0STejun Heo 	u32 tmp;
125091c4a2e0STejun Heo 
125191c4a2e0STejun Heo 	/* prep the command */
125291c4a2e0STejun Heo 	ata_tf_to_fis(tf, pmp, is_cmd, fis);
125391c4a2e0STejun Heo 	ahci_fill_cmd_slot(pp, 0, cmd_fis_len | flags | (pmp << 12));
125491c4a2e0STejun Heo 
125591c4a2e0STejun Heo 	/* issue & wait */
125691c4a2e0STejun Heo 	writel(1, port_mmio + PORT_CMD_ISSUE);
125791c4a2e0STejun Heo 
125891c4a2e0STejun Heo 	if (timeout_msec) {
125991c4a2e0STejun Heo 		tmp = ata_wait_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x1,
126091c4a2e0STejun Heo 					1, timeout_msec);
126191c4a2e0STejun Heo 		if (tmp & 0x1) {
126291c4a2e0STejun Heo 			ahci_kick_engine(ap, 1);
126391c4a2e0STejun Heo 			return -EBUSY;
126491c4a2e0STejun Heo 		}
126591c4a2e0STejun Heo 	} else
126691c4a2e0STejun Heo 		readl(port_mmio + PORT_CMD_ISSUE);	/* flush */
126791c4a2e0STejun Heo 
126891c4a2e0STejun Heo 	return 0;
126991c4a2e0STejun Heo }
127091c4a2e0STejun Heo 
1271cc0680a5STejun Heo static int ahci_do_softreset(struct ata_link *link, unsigned int *class,
1272a9cf5e85STejun Heo 			     int pmp, unsigned long deadline)
1273c6fd2807SJeff Garzik {
1274cc0680a5STejun Heo 	struct ata_port *ap = link->ap;
1275c6fd2807SJeff Garzik 	const char *reason = NULL;
12762cbb79ebSTejun Heo 	unsigned long now, msecs;
1277c6fd2807SJeff Garzik 	struct ata_taskfile tf;
1278c6fd2807SJeff Garzik 	int rc;
1279c6fd2807SJeff Garzik 
1280c6fd2807SJeff Garzik 	DPRINTK("ENTER\n");
1281c6fd2807SJeff Garzik 
1282cc0680a5STejun Heo 	if (ata_link_offline(link)) {
1283c6fd2807SJeff Garzik 		DPRINTK("PHY reports no device\n");
1284c6fd2807SJeff Garzik 		*class = ATA_DEV_NONE;
1285c6fd2807SJeff Garzik 		return 0;
1286c6fd2807SJeff Garzik 	}
1287c6fd2807SJeff Garzik 
1288c6fd2807SJeff Garzik 	/* prepare for SRST (AHCI-1.1 10.4.1) */
1289d2e75dffSTejun Heo 	rc = ahci_kick_engine(ap, 1);
1290994056d7STejun Heo 	if (rc && rc != -EOPNOTSUPP)
1291cc0680a5STejun Heo 		ata_link_printk(link, KERN_WARNING,
1292994056d7STejun Heo 				"failed to reset engine (errno=%d)\n", rc);
1293c6fd2807SJeff Garzik 
1294cc0680a5STejun Heo 	ata_tf_init(link->device, &tf);
1295c6fd2807SJeff Garzik 
1296c6fd2807SJeff Garzik 	/* issue the first D2H Register FIS */
12972cbb79ebSTejun Heo 	msecs = 0;
12982cbb79ebSTejun Heo 	now = jiffies;
12992cbb79ebSTejun Heo 	if (time_after(now, deadline))
13002cbb79ebSTejun Heo 		msecs = jiffies_to_msecs(deadline - now);
13012cbb79ebSTejun Heo 
1302c6fd2807SJeff Garzik 	tf.ctl |= ATA_SRST;
1303a9cf5e85STejun Heo 	if (ahci_exec_polled_cmd(ap, pmp, &tf, 0,
130491c4a2e0STejun Heo 				 AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY, msecs)) {
1305c6fd2807SJeff Garzik 		rc = -EIO;
1306c6fd2807SJeff Garzik 		reason = "1st FIS failed";
1307c6fd2807SJeff Garzik 		goto fail;
1308c6fd2807SJeff Garzik 	}
1309c6fd2807SJeff Garzik 
1310c6fd2807SJeff Garzik 	/* spec says at least 5us, but be generous and sleep for 1ms */
1311c6fd2807SJeff Garzik 	msleep(1);
1312c6fd2807SJeff Garzik 
1313c6fd2807SJeff Garzik 	/* issue the second D2H Register FIS */
1314c6fd2807SJeff Garzik 	tf.ctl &= ~ATA_SRST;
1315a9cf5e85STejun Heo 	ahci_exec_polled_cmd(ap, pmp, &tf, 0, 0, 0);
1316c6fd2807SJeff Garzik 
131788ff6eafSTejun Heo 	/* wait a while before checking status */
131888ff6eafSTejun Heo 	ata_wait_after_reset(ap, deadline);
1319c6fd2807SJeff Garzik 
1320d4b2bab4STejun Heo 	rc = ata_wait_ready(ap, deadline);
13219b89391cSTejun Heo 	/* link occupied, -ENODEV too is an error */
13229b89391cSTejun Heo 	if (rc) {
1323c6fd2807SJeff Garzik 		reason = "device not ready";
1324c6fd2807SJeff Garzik 		goto fail;
1325c6fd2807SJeff Garzik 	}
1326c6fd2807SJeff Garzik 	*class = ahci_dev_classify(ap);
1327c6fd2807SJeff Garzik 
1328c6fd2807SJeff Garzik 	DPRINTK("EXIT, class=%u\n", *class);
1329c6fd2807SJeff Garzik 	return 0;
1330c6fd2807SJeff Garzik 
1331c6fd2807SJeff Garzik  fail:
1332cc0680a5STejun Heo 	ata_link_printk(link, KERN_ERR, "softreset failed (%s)\n", reason);
1333c6fd2807SJeff Garzik 	return rc;
1334c6fd2807SJeff Garzik }
1335c6fd2807SJeff Garzik 
1336cc0680a5STejun Heo static int ahci_softreset(struct ata_link *link, unsigned int *class,
1337a9cf5e85STejun Heo 			  unsigned long deadline)
1338a9cf5e85STejun Heo {
13397d50b60bSTejun Heo 	int pmp = 0;
13407d50b60bSTejun Heo 
13417d50b60bSTejun Heo 	if (link->ap->flags & ATA_FLAG_PMP)
13427d50b60bSTejun Heo 		pmp = SATA_PMP_CTRL_PORT;
13437d50b60bSTejun Heo 
13447d50b60bSTejun Heo 	return ahci_do_softreset(link, class, pmp, deadline);
1345a9cf5e85STejun Heo }
1346a9cf5e85STejun Heo 
1347cc0680a5STejun Heo static int ahci_hardreset(struct ata_link *link, unsigned int *class,
1348d4b2bab4STejun Heo 			  unsigned long deadline)
1349c6fd2807SJeff Garzik {
1350cc0680a5STejun Heo 	struct ata_port *ap = link->ap;
1351c6fd2807SJeff Garzik 	struct ahci_port_priv *pp = ap->private_data;
1352c6fd2807SJeff Garzik 	u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
1353c6fd2807SJeff Garzik 	struct ata_taskfile tf;
1354c6fd2807SJeff Garzik 	int rc;
1355c6fd2807SJeff Garzik 
1356c6fd2807SJeff Garzik 	DPRINTK("ENTER\n");
1357c6fd2807SJeff Garzik 
13584447d351STejun Heo 	ahci_stop_engine(ap);
1359c6fd2807SJeff Garzik 
1360c6fd2807SJeff Garzik 	/* clear D2H reception area to properly wait for D2H FIS */
1361cc0680a5STejun Heo 	ata_tf_init(link->device, &tf);
1362dfd7a3dbSTejun Heo 	tf.command = 0x80;
13639977126cSTejun Heo 	ata_tf_to_fis(&tf, 0, 0, d2h_fis);
1364c6fd2807SJeff Garzik 
1365cc0680a5STejun Heo 	rc = sata_std_hardreset(link, class, deadline);
1366c6fd2807SJeff Garzik 
13674447d351STejun Heo 	ahci_start_engine(ap);
1368c6fd2807SJeff Garzik 
1369cc0680a5STejun Heo 	if (rc == 0 && ata_link_online(link))
1370c6fd2807SJeff Garzik 		*class = ahci_dev_classify(ap);
13717d50b60bSTejun Heo 	if (rc != -EAGAIN && *class == ATA_DEV_UNKNOWN)
1372c6fd2807SJeff Garzik 		*class = ATA_DEV_NONE;
1373c6fd2807SJeff Garzik 
1374c6fd2807SJeff Garzik 	DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
1375c6fd2807SJeff Garzik 	return rc;
1376c6fd2807SJeff Garzik }
1377c6fd2807SJeff Garzik 
1378cc0680a5STejun Heo static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
1379d4b2bab4STejun Heo 				 unsigned long deadline)
1380ad616ffbSTejun Heo {
1381cc0680a5STejun Heo 	struct ata_port *ap = link->ap;
1382da3dbb17STejun Heo 	u32 serror;
1383ad616ffbSTejun Heo 	int rc;
1384ad616ffbSTejun Heo 
1385ad616ffbSTejun Heo 	DPRINTK("ENTER\n");
1386ad616ffbSTejun Heo 
13874447d351STejun Heo 	ahci_stop_engine(ap);
1388ad616ffbSTejun Heo 
1389cc0680a5STejun Heo 	rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context),
1390d4b2bab4STejun Heo 				 deadline);
1391ad616ffbSTejun Heo 
1392ad616ffbSTejun Heo 	/* vt8251 needs SError cleared for the port to operate */
1393da3dbb17STejun Heo 	ahci_scr_read(ap, SCR_ERROR, &serror);
1394da3dbb17STejun Heo 	ahci_scr_write(ap, SCR_ERROR, serror);
1395ad616ffbSTejun Heo 
13964447d351STejun Heo 	ahci_start_engine(ap);
1397ad616ffbSTejun Heo 
1398ad616ffbSTejun Heo 	DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
1399ad616ffbSTejun Heo 
1400ad616ffbSTejun Heo 	/* vt8251 doesn't clear BSY on signature FIS reception,
1401ad616ffbSTejun Heo 	 * request follow-up softreset.
1402ad616ffbSTejun Heo 	 */
1403ad616ffbSTejun Heo 	return rc ?: -EAGAIN;
1404ad616ffbSTejun Heo }
1405ad616ffbSTejun Heo 
1406edc93052STejun Heo static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
1407edc93052STejun Heo 				unsigned long deadline)
1408edc93052STejun Heo {
1409edc93052STejun Heo 	struct ata_port *ap = link->ap;
1410edc93052STejun Heo 	struct ahci_port_priv *pp = ap->private_data;
1411edc93052STejun Heo 	u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
1412edc93052STejun Heo 	struct ata_taskfile tf;
1413edc93052STejun Heo 	int rc;
1414edc93052STejun Heo 
1415edc93052STejun Heo 	ahci_stop_engine(ap);
1416edc93052STejun Heo 
1417edc93052STejun Heo 	/* clear D2H reception area to properly wait for D2H FIS */
1418edc93052STejun Heo 	ata_tf_init(link->device, &tf);
1419edc93052STejun Heo 	tf.command = 0x80;
1420edc93052STejun Heo 	ata_tf_to_fis(&tf, 0, 0, d2h_fis);
1421edc93052STejun Heo 
1422edc93052STejun Heo 	rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context),
1423edc93052STejun Heo 				 deadline);
1424edc93052STejun Heo 
1425edc93052STejun Heo 	ahci_start_engine(ap);
1426edc93052STejun Heo 
1427edc93052STejun Heo 	if (rc || ata_link_offline(link))
1428edc93052STejun Heo 		return rc;
1429edc93052STejun Heo 
1430edc93052STejun Heo 	/* spec mandates ">= 2ms" before checking status */
1431edc93052STejun Heo 	msleep(150);
1432edc93052STejun Heo 
1433edc93052STejun Heo 	/* The pseudo configuration device on SIMG4726 attached to
1434edc93052STejun Heo 	 * ASUS P5W-DH Deluxe doesn't send signature FIS after
1435edc93052STejun Heo 	 * hardreset if no device is attached to the first downstream
1436edc93052STejun Heo 	 * port && the pseudo device locks up on SRST w/ PMP==0.  To
1437edc93052STejun Heo 	 * work around this, wait for !BSY only briefly.  If BSY isn't
1438edc93052STejun Heo 	 * cleared, perform CLO and proceed to IDENTIFY (achieved by
1439edc93052STejun Heo 	 * ATA_LFLAG_NO_SRST and ATA_LFLAG_ASSUME_ATA).
1440edc93052STejun Heo 	 *
1441edc93052STejun Heo 	 * Wait for two seconds.  Devices attached to downstream port
1442edc93052STejun Heo 	 * which can't process the following IDENTIFY after this will
1443edc93052STejun Heo 	 * have to be reset again.  For most cases, this should
1444edc93052STejun Heo 	 * suffice while making probing snappish enough.
1445edc93052STejun Heo 	 */
1446edc93052STejun Heo 	rc = ata_wait_ready(ap, jiffies + 2 * HZ);
1447edc93052STejun Heo 	if (rc)
1448edc93052STejun Heo 		ahci_kick_engine(ap, 0);
1449edc93052STejun Heo 
1450edc93052STejun Heo 	return 0;
1451edc93052STejun Heo }
1452edc93052STejun Heo 
1453cc0680a5STejun Heo static void ahci_postreset(struct ata_link *link, unsigned int *class)
1454c6fd2807SJeff Garzik {
1455cc0680a5STejun Heo 	struct ata_port *ap = link->ap;
14564447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
1457c6fd2807SJeff Garzik 	u32 new_tmp, tmp;
1458c6fd2807SJeff Garzik 
1459cc0680a5STejun Heo 	ata_std_postreset(link, class);
1460c6fd2807SJeff Garzik 
1461c6fd2807SJeff Garzik 	/* Make sure port's ATAPI bit is set appropriately */
1462c6fd2807SJeff Garzik 	new_tmp = tmp = readl(port_mmio + PORT_CMD);
1463c6fd2807SJeff Garzik 	if (*class == ATA_DEV_ATAPI)
1464c6fd2807SJeff Garzik 		new_tmp |= PORT_CMD_ATAPI;
1465c6fd2807SJeff Garzik 	else
1466c6fd2807SJeff Garzik 		new_tmp &= ~PORT_CMD_ATAPI;
1467c6fd2807SJeff Garzik 	if (new_tmp != tmp) {
1468c6fd2807SJeff Garzik 		writel(new_tmp, port_mmio + PORT_CMD);
1469c6fd2807SJeff Garzik 		readl(port_mmio + PORT_CMD); /* flush */
1470c6fd2807SJeff Garzik 	}
1471c6fd2807SJeff Garzik }
1472c6fd2807SJeff Garzik 
14737d50b60bSTejun Heo static int ahci_pmp_softreset(struct ata_link *link, unsigned int *class,
14747d50b60bSTejun Heo 			      unsigned long deadline)
14757d50b60bSTejun Heo {
14767d50b60bSTejun Heo 	return ahci_do_softreset(link, class, link->pmp, deadline);
14777d50b60bSTejun Heo }
14787d50b60bSTejun Heo 
1479c6fd2807SJeff Garzik static u8 ahci_check_status(struct ata_port *ap)
1480c6fd2807SJeff Garzik {
14810d5ff566STejun Heo 	void __iomem *mmio = ap->ioaddr.cmd_addr;
1482c6fd2807SJeff Garzik 
1483c6fd2807SJeff Garzik 	return readl(mmio + PORT_TFDATA) & 0xFF;
1484c6fd2807SJeff Garzik }
1485c6fd2807SJeff Garzik 
1486c6fd2807SJeff Garzik static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
1487c6fd2807SJeff Garzik {
1488c6fd2807SJeff Garzik 	struct ahci_port_priv *pp = ap->private_data;
1489c6fd2807SJeff Garzik 	u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
1490c6fd2807SJeff Garzik 
1491c6fd2807SJeff Garzik 	ata_tf_from_fis(d2h_fis, tf);
1492c6fd2807SJeff Garzik }
1493c6fd2807SJeff Garzik 
1494c6fd2807SJeff Garzik static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl)
1495c6fd2807SJeff Garzik {
1496c6fd2807SJeff Garzik 	struct scatterlist *sg;
1497ff2aeb1eSTejun Heo 	struct ahci_sg *ahci_sg = cmd_tbl + AHCI_CMD_TBL_HDR_SZ;
1498ff2aeb1eSTejun Heo 	unsigned int si;
1499c6fd2807SJeff Garzik 
1500c6fd2807SJeff Garzik 	VPRINTK("ENTER\n");
1501c6fd2807SJeff Garzik 
1502c6fd2807SJeff Garzik 	/*
1503c6fd2807SJeff Garzik 	 * Next, the S/G list.
1504c6fd2807SJeff Garzik 	 */
1505ff2aeb1eSTejun Heo 	for_each_sg(qc->sg, sg, qc->n_elem, si) {
1506c6fd2807SJeff Garzik 		dma_addr_t addr = sg_dma_address(sg);
1507c6fd2807SJeff Garzik 		u32 sg_len = sg_dma_len(sg);
1508c6fd2807SJeff Garzik 
1509ff2aeb1eSTejun Heo 		ahci_sg[si].addr = cpu_to_le32(addr & 0xffffffff);
1510ff2aeb1eSTejun Heo 		ahci_sg[si].addr_hi = cpu_to_le32((addr >> 16) >> 16);
1511ff2aeb1eSTejun Heo 		ahci_sg[si].flags_size = cpu_to_le32(sg_len - 1);
1512c6fd2807SJeff Garzik 	}
1513c6fd2807SJeff Garzik 
1514ff2aeb1eSTejun Heo 	return si;
1515c6fd2807SJeff Garzik }
1516c6fd2807SJeff Garzik 
1517c6fd2807SJeff Garzik static void ahci_qc_prep(struct ata_queued_cmd *qc)
1518c6fd2807SJeff Garzik {
1519c6fd2807SJeff Garzik 	struct ata_port *ap = qc->ap;
1520c6fd2807SJeff Garzik 	struct ahci_port_priv *pp = ap->private_data;
1521405e66b3STejun Heo 	int is_atapi = ata_is_atapi(qc->tf.protocol);
1522c6fd2807SJeff Garzik 	void *cmd_tbl;
1523c6fd2807SJeff Garzik 	u32 opts;
1524c6fd2807SJeff Garzik 	const u32 cmd_fis_len = 5; /* five dwords */
1525c6fd2807SJeff Garzik 	unsigned int n_elem;
1526c6fd2807SJeff Garzik 
1527c6fd2807SJeff Garzik 	/*
1528c6fd2807SJeff Garzik 	 * Fill in command table information.  First, the header,
1529c6fd2807SJeff Garzik 	 * a SATA Register - Host to Device command FIS.
1530c6fd2807SJeff Garzik 	 */
1531c6fd2807SJeff Garzik 	cmd_tbl = pp->cmd_tbl + qc->tag * AHCI_CMD_TBL_SZ;
1532c6fd2807SJeff Garzik 
15337d50b60bSTejun Heo 	ata_tf_to_fis(&qc->tf, qc->dev->link->pmp, 1, cmd_tbl);
1534c6fd2807SJeff Garzik 	if (is_atapi) {
1535c6fd2807SJeff Garzik 		memset(cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32);
1536c6fd2807SJeff Garzik 		memcpy(cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb, qc->dev->cdb_len);
1537c6fd2807SJeff Garzik 	}
1538c6fd2807SJeff Garzik 
1539c6fd2807SJeff Garzik 	n_elem = 0;
1540c6fd2807SJeff Garzik 	if (qc->flags & ATA_QCFLAG_DMAMAP)
1541c6fd2807SJeff Garzik 		n_elem = ahci_fill_sg(qc, cmd_tbl);
1542c6fd2807SJeff Garzik 
1543c6fd2807SJeff Garzik 	/*
1544c6fd2807SJeff Garzik 	 * Fill in command slot information.
1545c6fd2807SJeff Garzik 	 */
15467d50b60bSTejun Heo 	opts = cmd_fis_len | n_elem << 16 | (qc->dev->link->pmp << 12);
1547c6fd2807SJeff Garzik 	if (qc->tf.flags & ATA_TFLAG_WRITE)
1548c6fd2807SJeff Garzik 		opts |= AHCI_CMD_WRITE;
1549c6fd2807SJeff Garzik 	if (is_atapi)
1550c6fd2807SJeff Garzik 		opts |= AHCI_CMD_ATAPI | AHCI_CMD_PREFETCH;
1551c6fd2807SJeff Garzik 
1552c6fd2807SJeff Garzik 	ahci_fill_cmd_slot(pp, qc->tag, opts);
1553c6fd2807SJeff Garzik }
1554c6fd2807SJeff Garzik 
1555c6fd2807SJeff Garzik static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
1556c6fd2807SJeff Garzik {
1557417a1a6dSTejun Heo 	struct ahci_host_priv *hpriv = ap->host->private_data;
1558c6fd2807SJeff Garzik 	struct ahci_port_priv *pp = ap->private_data;
15597d50b60bSTejun Heo 	struct ata_eh_info *host_ehi = &ap->link.eh_info;
15607d50b60bSTejun Heo 	struct ata_link *link = NULL;
15617d50b60bSTejun Heo 	struct ata_queued_cmd *active_qc;
15627d50b60bSTejun Heo 	struct ata_eh_info *active_ehi;
1563c6fd2807SJeff Garzik 	u32 serror;
1564c6fd2807SJeff Garzik 
15657d50b60bSTejun Heo 	/* determine active link */
15667d50b60bSTejun Heo 	ata_port_for_each_link(link, ap)
15677d50b60bSTejun Heo 		if (ata_link_active(link))
15687d50b60bSTejun Heo 			break;
15697d50b60bSTejun Heo 	if (!link)
15707d50b60bSTejun Heo 		link = &ap->link;
15717d50b60bSTejun Heo 
15727d50b60bSTejun Heo 	active_qc = ata_qc_from_tag(ap, link->active_tag);
15737d50b60bSTejun Heo 	active_ehi = &link->eh_info;
15747d50b60bSTejun Heo 
15757d50b60bSTejun Heo 	/* record irq stat */
15767d50b60bSTejun Heo 	ata_ehi_clear_desc(host_ehi);
15777d50b60bSTejun Heo 	ata_ehi_push_desc(host_ehi, "irq_stat 0x%08x", irq_stat);
1578c6fd2807SJeff Garzik 
1579c6fd2807SJeff Garzik 	/* AHCI needs SError cleared; otherwise, it might lock up */
1580da3dbb17STejun Heo 	ahci_scr_read(ap, SCR_ERROR, &serror);
1581c6fd2807SJeff Garzik 	ahci_scr_write(ap, SCR_ERROR, serror);
15827d50b60bSTejun Heo 	host_ehi->serror |= serror;
1583c6fd2807SJeff Garzik 
158441669553STejun Heo 	/* some controllers set IRQ_IF_ERR on device errors, ignore it */
1585417a1a6dSTejun Heo 	if (hpriv->flags & AHCI_HFLAG_IGN_IRQ_IF_ERR)
158641669553STejun Heo 		irq_stat &= ~PORT_IRQ_IF_ERR;
158741669553STejun Heo 
158855a61604SConke Hu 	if (irq_stat & PORT_IRQ_TF_ERR) {
15897d50b60bSTejun Heo 		/* If qc is active, charge it; otherwise, the active
15907d50b60bSTejun Heo 		 * link.  There's no active qc on NCQ errors.  It will
15917d50b60bSTejun Heo 		 * be determined by EH by reading log page 10h.
15927d50b60bSTejun Heo 		 */
15937d50b60bSTejun Heo 		if (active_qc)
15947d50b60bSTejun Heo 			active_qc->err_mask |= AC_ERR_DEV;
15957d50b60bSTejun Heo 		else
15967d50b60bSTejun Heo 			active_ehi->err_mask |= AC_ERR_DEV;
15977d50b60bSTejun Heo 
1598417a1a6dSTejun Heo 		if (hpriv->flags & AHCI_HFLAG_IGN_SERR_INTERNAL)
15997d50b60bSTejun Heo 			host_ehi->serror &= ~SERR_INTERNAL;
1600c6fd2807SJeff Garzik 	}
1601c6fd2807SJeff Garzik 
1602c6fd2807SJeff Garzik 	if (irq_stat & PORT_IRQ_UNK_FIS) {
1603c6fd2807SJeff Garzik 		u32 *unk = (u32 *)(pp->rx_fis + RX_FIS_UNK);
1604c6fd2807SJeff Garzik 
16057d50b60bSTejun Heo 		active_ehi->err_mask |= AC_ERR_HSM;
16067d50b60bSTejun Heo 		active_ehi->action |= ATA_EH_SOFTRESET;
16077d50b60bSTejun Heo 		ata_ehi_push_desc(active_ehi,
16087d50b60bSTejun Heo 				  "unknown FIS %08x %08x %08x %08x" ,
1609c6fd2807SJeff Garzik 				  unk[0], unk[1], unk[2], unk[3]);
1610c6fd2807SJeff Garzik 	}
1611c6fd2807SJeff Garzik 
16127d50b60bSTejun Heo 	if (ap->nr_pmp_links && (irq_stat & PORT_IRQ_BAD_PMP)) {
16137d50b60bSTejun Heo 		active_ehi->err_mask |= AC_ERR_HSM;
16147d50b60bSTejun Heo 		active_ehi->action |= ATA_EH_SOFTRESET;
16157d50b60bSTejun Heo 		ata_ehi_push_desc(active_ehi, "incorrect PMP");
16167d50b60bSTejun Heo 	}
1617c6fd2807SJeff Garzik 
16187d50b60bSTejun Heo 	if (irq_stat & (PORT_IRQ_HBUS_ERR | PORT_IRQ_HBUS_DATA_ERR)) {
16197d50b60bSTejun Heo 		host_ehi->err_mask |= AC_ERR_HOST_BUS;
16207d50b60bSTejun Heo 		host_ehi->action |= ATA_EH_SOFTRESET;
16217d50b60bSTejun Heo 		ata_ehi_push_desc(host_ehi, "host bus error");
16227d50b60bSTejun Heo 	}
16237d50b60bSTejun Heo 
16247d50b60bSTejun Heo 	if (irq_stat & PORT_IRQ_IF_ERR) {
16257d50b60bSTejun Heo 		host_ehi->err_mask |= AC_ERR_ATA_BUS;
16267d50b60bSTejun Heo 		host_ehi->action |= ATA_EH_SOFTRESET;
16277d50b60bSTejun Heo 		ata_ehi_push_desc(host_ehi, "interface fatal error");
16287d50b60bSTejun Heo 	}
16297d50b60bSTejun Heo 
16307d50b60bSTejun Heo 	if (irq_stat & (PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY)) {
16317d50b60bSTejun Heo 		ata_ehi_hotplugged(host_ehi);
16327d50b60bSTejun Heo 		ata_ehi_push_desc(host_ehi, "%s",
16337d50b60bSTejun Heo 			irq_stat & PORT_IRQ_CONNECT ?
16347d50b60bSTejun Heo 			"connection status changed" : "PHY RDY changed");
16357d50b60bSTejun Heo 	}
16367d50b60bSTejun Heo 
16377d50b60bSTejun Heo 	/* okay, let's hand over to EH */
1638c6fd2807SJeff Garzik 
1639c6fd2807SJeff Garzik 	if (irq_stat & PORT_IRQ_FREEZE)
1640c6fd2807SJeff Garzik 		ata_port_freeze(ap);
1641c6fd2807SJeff Garzik 	else
1642c6fd2807SJeff Garzik 		ata_port_abort(ap);
1643c6fd2807SJeff Garzik }
1644c6fd2807SJeff Garzik 
1645df69c9c5SJeff Garzik static void ahci_port_intr(struct ata_port *ap)
1646c6fd2807SJeff Garzik {
16474447d351STejun Heo 	void __iomem *port_mmio = ap->ioaddr.cmd_addr;
16489af5c9c9STejun Heo 	struct ata_eh_info *ehi = &ap->link.eh_info;
16490291f95fSTejun Heo 	struct ahci_port_priv *pp = ap->private_data;
16505f226c6bSTejun Heo 	struct ahci_host_priv *hpriv = ap->host->private_data;
1651b06ce3e5STejun Heo 	int resetting = !!(ap->pflags & ATA_PFLAG_RESETTING);
1652c6fd2807SJeff Garzik 	u32 status, qc_active;
1653459ad688STejun Heo 	int rc;
1654c6fd2807SJeff Garzik 
1655c6fd2807SJeff Garzik 	status = readl(port_mmio + PORT_IRQ_STAT);
1656c6fd2807SJeff Garzik 	writel(status, port_mmio + PORT_IRQ_STAT);
1657c6fd2807SJeff Garzik 
1658b06ce3e5STejun Heo 	/* ignore BAD_PMP while resetting */
1659b06ce3e5STejun Heo 	if (unlikely(resetting))
1660b06ce3e5STejun Heo 		status &= ~PORT_IRQ_BAD_PMP;
1661b06ce3e5STejun Heo 
166231556594SKristen Carlson Accardi 	/* If we are getting PhyRdy, this is
166331556594SKristen Carlson Accardi  	 * just a power state change, we should
166431556594SKristen Carlson Accardi  	 * clear out this, plus the PhyRdy/Comm
166531556594SKristen Carlson Accardi  	 * Wake bits from Serror
166631556594SKristen Carlson Accardi  	 */
166731556594SKristen Carlson Accardi 	if ((hpriv->flags & AHCI_HFLAG_NO_HOTPLUG) &&
166831556594SKristen Carlson Accardi 		(status & PORT_IRQ_PHYRDY)) {
166931556594SKristen Carlson Accardi 		status &= ~PORT_IRQ_PHYRDY;
167031556594SKristen Carlson Accardi 		ahci_scr_write(ap, SCR_ERROR, ((1 << 16) | (1 << 18)));
167131556594SKristen Carlson Accardi 	}
167231556594SKristen Carlson Accardi 
1673c6fd2807SJeff Garzik 	if (unlikely(status & PORT_IRQ_ERROR)) {
1674c6fd2807SJeff Garzik 		ahci_error_intr(ap, status);
1675c6fd2807SJeff Garzik 		return;
1676c6fd2807SJeff Garzik 	}
1677c6fd2807SJeff Garzik 
16782f294968SKristen Carlson Accardi 	if (status & PORT_IRQ_SDB_FIS) {
16795f226c6bSTejun Heo 		/* If SNotification is available, leave notification
16805f226c6bSTejun Heo 		 * handling to sata_async_notification().  If not,
16815f226c6bSTejun Heo 		 * emulate it by snooping SDB FIS RX area.
16825f226c6bSTejun Heo 		 *
16835f226c6bSTejun Heo 		 * Snooping FIS RX area is probably cheaper than
16845f226c6bSTejun Heo 		 * poking SNotification but some constrollers which
16855f226c6bSTejun Heo 		 * implement SNotification, ICH9 for example, don't
16865f226c6bSTejun Heo 		 * store AN SDB FIS into receive area.
16875f226c6bSTejun Heo 		 */
16885f226c6bSTejun Heo 		if (hpriv->cap & HOST_CAP_SNTF)
16895f226c6bSTejun Heo 			sata_async_notification(ap);
16905f226c6bSTejun Heo 		else {
16915f226c6bSTejun Heo 			/* If the 'N' bit in word 0 of the FIS is set,
16925f226c6bSTejun Heo 			 * we just received asynchronous notification.
16935f226c6bSTejun Heo 			 * Tell libata about it.
16942f294968SKristen Carlson Accardi 			 */
16952f294968SKristen Carlson Accardi 			const __le32 *f = pp->rx_fis + RX_FIS_SDB;
16962f294968SKristen Carlson Accardi 			u32 f0 = le32_to_cpu(f[0]);
16972f294968SKristen Carlson Accardi 
16987d77b247STejun Heo 			if (f0 & (1 << 15))
16997d77b247STejun Heo 				sata_async_notification(ap);
17002f294968SKristen Carlson Accardi 		}
17015f226c6bSTejun Heo 	}
17022f294968SKristen Carlson Accardi 
17037d50b60bSTejun Heo 	/* pp->active_link is valid iff any command is in flight */
17047d50b60bSTejun Heo 	if (ap->qc_active && pp->active_link->sactive)
1705c6fd2807SJeff Garzik 		qc_active = readl(port_mmio + PORT_SCR_ACT);
1706c6fd2807SJeff Garzik 	else
1707c6fd2807SJeff Garzik 		qc_active = readl(port_mmio + PORT_CMD_ISSUE);
1708c6fd2807SJeff Garzik 
1709c6fd2807SJeff Garzik 	rc = ata_qc_complete_multiple(ap, qc_active, NULL);
1710b06ce3e5STejun Heo 
1711459ad688STejun Heo 	/* while resetting, invalid completions are expected */
1712459ad688STejun Heo 	if (unlikely(rc < 0 && !resetting)) {
1713c6fd2807SJeff Garzik 		ehi->err_mask |= AC_ERR_HSM;
1714c6fd2807SJeff Garzik 		ehi->action |= ATA_EH_SOFTRESET;
1715c6fd2807SJeff Garzik 		ata_port_freeze(ap);
1716c6fd2807SJeff Garzik 	}
1717c6fd2807SJeff Garzik }
1718c6fd2807SJeff Garzik 
1719c6fd2807SJeff Garzik static void ahci_irq_clear(struct ata_port *ap)
1720c6fd2807SJeff Garzik {
1721c6fd2807SJeff Garzik 	/* TODO */
1722c6fd2807SJeff Garzik }
1723c6fd2807SJeff Garzik 
17247d12e780SDavid Howells static irqreturn_t ahci_interrupt(int irq, void *dev_instance)
1725c6fd2807SJeff Garzik {
1726cca3974eSJeff Garzik 	struct ata_host *host = dev_instance;
1727c6fd2807SJeff Garzik 	struct ahci_host_priv *hpriv;
1728c6fd2807SJeff Garzik 	unsigned int i, handled = 0;
1729c6fd2807SJeff Garzik 	void __iomem *mmio;
1730c6fd2807SJeff Garzik 	u32 irq_stat, irq_ack = 0;
1731c6fd2807SJeff Garzik 
1732c6fd2807SJeff Garzik 	VPRINTK("ENTER\n");
1733c6fd2807SJeff Garzik 
1734cca3974eSJeff Garzik 	hpriv = host->private_data;
17350d5ff566STejun Heo 	mmio = host->iomap[AHCI_PCI_BAR];
1736c6fd2807SJeff Garzik 
1737c6fd2807SJeff Garzik 	/* sigh.  0xffffffff is a valid return from h/w */
1738c6fd2807SJeff Garzik 	irq_stat = readl(mmio + HOST_IRQ_STAT);
1739c6fd2807SJeff Garzik 	irq_stat &= hpriv->port_map;
1740c6fd2807SJeff Garzik 	if (!irq_stat)
1741c6fd2807SJeff Garzik 		return IRQ_NONE;
1742c6fd2807SJeff Garzik 
1743cca3974eSJeff Garzik 	spin_lock(&host->lock);
1744c6fd2807SJeff Garzik 
1745cca3974eSJeff Garzik 	for (i = 0; i < host->n_ports; i++) {
1746c6fd2807SJeff Garzik 		struct ata_port *ap;
1747c6fd2807SJeff Garzik 
1748c6fd2807SJeff Garzik 		if (!(irq_stat & (1 << i)))
1749c6fd2807SJeff Garzik 			continue;
1750c6fd2807SJeff Garzik 
1751cca3974eSJeff Garzik 		ap = host->ports[i];
1752c6fd2807SJeff Garzik 		if (ap) {
1753df69c9c5SJeff Garzik 			ahci_port_intr(ap);
1754c6fd2807SJeff Garzik 			VPRINTK("port %u\n", i);
1755c6fd2807SJeff Garzik 		} else {
1756c6fd2807SJeff Garzik 			VPRINTK("port %u (no irq)\n", i);
1757c6fd2807SJeff Garzik 			if (ata_ratelimit())
1758cca3974eSJeff Garzik 				dev_printk(KERN_WARNING, host->dev,
1759c6fd2807SJeff Garzik 					"interrupt on disabled port %u\n", i);
1760c6fd2807SJeff Garzik 		}
1761c6fd2807SJeff Garzik 
1762c6fd2807SJeff Garzik 		irq_ack |= (1 << i);
1763c6fd2807SJeff Garzik 	}
1764c6fd2807SJeff Garzik 
1765c6fd2807SJeff Garzik 	if (irq_ack) {
1766c6fd2807SJeff Garzik 		writel(irq_ack, mmio + HOST_IRQ_STAT);
1767c6fd2807SJeff Garzik 		handled = 1;
1768c6fd2807SJeff Garzik 	}
1769c6fd2807SJeff Garzik 
1770cca3974eSJeff Garzik 	spin_unlock(&host->lock);
1771c6fd2807SJeff Garzik 
1772c6fd2807SJeff Garzik 	VPRINTK("EXIT\n");
1773c6fd2807SJeff Garzik 
1774c6fd2807SJeff Garzik 	return IRQ_RETVAL(handled);
1775c6fd2807SJeff Garzik }
1776c6fd2807SJeff Garzik 
1777c6fd2807SJeff Garzik static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc)
1778c6fd2807SJeff Garzik {
1779c6fd2807SJeff Garzik 	struct ata_port *ap = qc->ap;
17804447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
17817d50b60bSTejun Heo 	struct ahci_port_priv *pp = ap->private_data;
17827d50b60bSTejun Heo 
17837d50b60bSTejun Heo 	/* Keep track of the currently active link.  It will be used
17847d50b60bSTejun Heo 	 * in completion path to determine whether NCQ phase is in
17857d50b60bSTejun Heo 	 * progress.
17867d50b60bSTejun Heo 	 */
17877d50b60bSTejun Heo 	pp->active_link = qc->dev->link;
1788c6fd2807SJeff Garzik 
1789c6fd2807SJeff Garzik 	if (qc->tf.protocol == ATA_PROT_NCQ)
1790c6fd2807SJeff Garzik 		writel(1 << qc->tag, port_mmio + PORT_SCR_ACT);
1791c6fd2807SJeff Garzik 	writel(1 << qc->tag, port_mmio + PORT_CMD_ISSUE);
1792c6fd2807SJeff Garzik 	readl(port_mmio + PORT_CMD_ISSUE);	/* flush */
1793c6fd2807SJeff Garzik 
1794c6fd2807SJeff Garzik 	return 0;
1795c6fd2807SJeff Garzik }
1796c6fd2807SJeff Garzik 
1797c6fd2807SJeff Garzik static void ahci_freeze(struct ata_port *ap)
1798c6fd2807SJeff Garzik {
17994447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
1800c6fd2807SJeff Garzik 
1801c6fd2807SJeff Garzik 	/* turn IRQ off */
1802c6fd2807SJeff Garzik 	writel(0, port_mmio + PORT_IRQ_MASK);
1803c6fd2807SJeff Garzik }
1804c6fd2807SJeff Garzik 
1805c6fd2807SJeff Garzik static void ahci_thaw(struct ata_port *ap)
1806c6fd2807SJeff Garzik {
18070d5ff566STejun Heo 	void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
18084447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
1809c6fd2807SJeff Garzik 	u32 tmp;
1810a7384925SKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
1811c6fd2807SJeff Garzik 
1812c6fd2807SJeff Garzik 	/* clear IRQ */
1813c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_IRQ_STAT);
1814c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_IRQ_STAT);
1815a718728fSTejun Heo 	writel(1 << ap->port_no, mmio + HOST_IRQ_STAT);
1816c6fd2807SJeff Garzik 
18171c954a4dSTejun Heo 	/* turn IRQ back on */
18181c954a4dSTejun Heo 	writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
1819c6fd2807SJeff Garzik }
1820c6fd2807SJeff Garzik 
1821c6fd2807SJeff Garzik static void ahci_error_handler(struct ata_port *ap)
1822c6fd2807SJeff Garzik {
1823c6fd2807SJeff Garzik 	if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
1824c6fd2807SJeff Garzik 		/* restart engine */
18254447d351STejun Heo 		ahci_stop_engine(ap);
18264447d351STejun Heo 		ahci_start_engine(ap);
1827c6fd2807SJeff Garzik 	}
1828c6fd2807SJeff Garzik 
1829c6fd2807SJeff Garzik 	/* perform recovery */
18307d50b60bSTejun Heo 	sata_pmp_do_eh(ap, ata_std_prereset, ahci_softreset,
18317d50b60bSTejun Heo 		       ahci_hardreset, ahci_postreset,
18327d50b60bSTejun Heo 		       sata_pmp_std_prereset, ahci_pmp_softreset,
18337d50b60bSTejun Heo 		       sata_pmp_std_hardreset, sata_pmp_std_postreset);
1834c6fd2807SJeff Garzik }
1835c6fd2807SJeff Garzik 
1836ad616ffbSTejun Heo static void ahci_vt8251_error_handler(struct ata_port *ap)
1837ad616ffbSTejun Heo {
1838ad616ffbSTejun Heo 	if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
1839ad616ffbSTejun Heo 		/* restart engine */
18404447d351STejun Heo 		ahci_stop_engine(ap);
18414447d351STejun Heo 		ahci_start_engine(ap);
1842ad616ffbSTejun Heo 	}
1843ad616ffbSTejun Heo 
1844ad616ffbSTejun Heo 	/* perform recovery */
1845ad616ffbSTejun Heo 	ata_do_eh(ap, ata_std_prereset, ahci_softreset, ahci_vt8251_hardreset,
1846ad616ffbSTejun Heo 		  ahci_postreset);
1847ad616ffbSTejun Heo }
1848ad616ffbSTejun Heo 
1849edc93052STejun Heo static void ahci_p5wdh_error_handler(struct ata_port *ap)
1850edc93052STejun Heo {
1851edc93052STejun Heo 	if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
1852edc93052STejun Heo 		/* restart engine */
1853edc93052STejun Heo 		ahci_stop_engine(ap);
1854edc93052STejun Heo 		ahci_start_engine(ap);
1855edc93052STejun Heo 	}
1856edc93052STejun Heo 
1857edc93052STejun Heo 	/* perform recovery */
1858edc93052STejun Heo 	ata_do_eh(ap, ata_std_prereset, ahci_softreset, ahci_p5wdh_hardreset,
1859edc93052STejun Heo 		  ahci_postreset);
1860edc93052STejun Heo }
1861edc93052STejun Heo 
1862c6fd2807SJeff Garzik static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
1863c6fd2807SJeff Garzik {
1864c6fd2807SJeff Garzik 	struct ata_port *ap = qc->ap;
1865c6fd2807SJeff Garzik 
1866c6fd2807SJeff Garzik 	/* make DMA engine forget about the failed command */
1867d2e75dffSTejun Heo 	if (qc->flags & ATA_QCFLAG_FAILED)
1868d2e75dffSTejun Heo 		ahci_kick_engine(ap, 1);
1869c6fd2807SJeff Garzik }
1870c6fd2807SJeff Garzik 
18717d50b60bSTejun Heo static void ahci_pmp_attach(struct ata_port *ap)
18727d50b60bSTejun Heo {
18737d50b60bSTejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
18741c954a4dSTejun Heo 	struct ahci_port_priv *pp = ap->private_data;
18757d50b60bSTejun Heo 	u32 cmd;
18767d50b60bSTejun Heo 
18777d50b60bSTejun Heo 	cmd = readl(port_mmio + PORT_CMD);
18787d50b60bSTejun Heo 	cmd |= PORT_CMD_PMP;
18797d50b60bSTejun Heo 	writel(cmd, port_mmio + PORT_CMD);
18801c954a4dSTejun Heo 
18811c954a4dSTejun Heo 	pp->intr_mask |= PORT_IRQ_BAD_PMP;
18821c954a4dSTejun Heo 	writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
18837d50b60bSTejun Heo }
18847d50b60bSTejun Heo 
18857d50b60bSTejun Heo static void ahci_pmp_detach(struct ata_port *ap)
18867d50b60bSTejun Heo {
18877d50b60bSTejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
18881c954a4dSTejun Heo 	struct ahci_port_priv *pp = ap->private_data;
18897d50b60bSTejun Heo 	u32 cmd;
18907d50b60bSTejun Heo 
18917d50b60bSTejun Heo 	cmd = readl(port_mmio + PORT_CMD);
18927d50b60bSTejun Heo 	cmd &= ~PORT_CMD_PMP;
18937d50b60bSTejun Heo 	writel(cmd, port_mmio + PORT_CMD);
18941c954a4dSTejun Heo 
18951c954a4dSTejun Heo 	pp->intr_mask &= ~PORT_IRQ_BAD_PMP;
18961c954a4dSTejun Heo 	writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
18977d50b60bSTejun Heo }
18987d50b60bSTejun Heo 
1899028a2596SAlexey Dobriyan static int ahci_port_resume(struct ata_port *ap)
1900028a2596SAlexey Dobriyan {
1901028a2596SAlexey Dobriyan 	ahci_power_up(ap);
1902028a2596SAlexey Dobriyan 	ahci_start_port(ap);
1903028a2596SAlexey Dobriyan 
19047d50b60bSTejun Heo 	if (ap->nr_pmp_links)
19057d50b60bSTejun Heo 		ahci_pmp_attach(ap);
19067d50b60bSTejun Heo 	else
19077d50b60bSTejun Heo 		ahci_pmp_detach(ap);
19087d50b60bSTejun Heo 
1909028a2596SAlexey Dobriyan 	return 0;
1910028a2596SAlexey Dobriyan }
1911028a2596SAlexey Dobriyan 
1912438ac6d5STejun Heo #ifdef CONFIG_PM
1913c6fd2807SJeff Garzik static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg)
1914c6fd2807SJeff Garzik {
1915c6fd2807SJeff Garzik 	const char *emsg = NULL;
1916c6fd2807SJeff Garzik 	int rc;
1917c6fd2807SJeff Garzik 
19184447d351STejun Heo 	rc = ahci_deinit_port(ap, &emsg);
19198e16f941STejun Heo 	if (rc == 0)
19204447d351STejun Heo 		ahci_power_down(ap);
19218e16f941STejun Heo 	else {
1922c6fd2807SJeff Garzik 		ata_port_printk(ap, KERN_ERR, "%s (%d)\n", emsg, rc);
1923df69c9c5SJeff Garzik 		ahci_start_port(ap);
1924c6fd2807SJeff Garzik 	}
1925c6fd2807SJeff Garzik 
1926c6fd2807SJeff Garzik 	return rc;
1927c6fd2807SJeff Garzik }
1928c6fd2807SJeff Garzik 
1929c6fd2807SJeff Garzik static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
1930c6fd2807SJeff Garzik {
1931cca3974eSJeff Garzik 	struct ata_host *host = dev_get_drvdata(&pdev->dev);
19320d5ff566STejun Heo 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
1933c6fd2807SJeff Garzik 	u32 ctl;
1934c6fd2807SJeff Garzik 
1935c6fd2807SJeff Garzik 	if (mesg.event == PM_EVENT_SUSPEND) {
1936c6fd2807SJeff Garzik 		/* AHCI spec rev1.1 section 8.3.3:
1937c6fd2807SJeff Garzik 		 * Software must disable interrupts prior to requesting a
1938c6fd2807SJeff Garzik 		 * transition of the HBA to D3 state.
1939c6fd2807SJeff Garzik 		 */
1940c6fd2807SJeff Garzik 		ctl = readl(mmio + HOST_CTL);
1941c6fd2807SJeff Garzik 		ctl &= ~HOST_IRQ_EN;
1942c6fd2807SJeff Garzik 		writel(ctl, mmio + HOST_CTL);
1943c6fd2807SJeff Garzik 		readl(mmio + HOST_CTL); /* flush */
1944c6fd2807SJeff Garzik 	}
1945c6fd2807SJeff Garzik 
1946c6fd2807SJeff Garzik 	return ata_pci_device_suspend(pdev, mesg);
1947c6fd2807SJeff Garzik }
1948c6fd2807SJeff Garzik 
1949c6fd2807SJeff Garzik static int ahci_pci_device_resume(struct pci_dev *pdev)
1950c6fd2807SJeff Garzik {
1951cca3974eSJeff Garzik 	struct ata_host *host = dev_get_drvdata(&pdev->dev);
1952c6fd2807SJeff Garzik 	int rc;
1953c6fd2807SJeff Garzik 
1954553c4aa6STejun Heo 	rc = ata_pci_device_do_resume(pdev);
1955553c4aa6STejun Heo 	if (rc)
1956553c4aa6STejun Heo 		return rc;
1957c6fd2807SJeff Garzik 
1958c6fd2807SJeff Garzik 	if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
19594447d351STejun Heo 		rc = ahci_reset_controller(host);
1960c6fd2807SJeff Garzik 		if (rc)
1961c6fd2807SJeff Garzik 			return rc;
1962c6fd2807SJeff Garzik 
19634447d351STejun Heo 		ahci_init_controller(host);
1964c6fd2807SJeff Garzik 	}
1965c6fd2807SJeff Garzik 
1966cca3974eSJeff Garzik 	ata_host_resume(host);
1967c6fd2807SJeff Garzik 
1968c6fd2807SJeff Garzik 	return 0;
1969c6fd2807SJeff Garzik }
1970438ac6d5STejun Heo #endif
1971c6fd2807SJeff Garzik 
1972c6fd2807SJeff Garzik static int ahci_port_start(struct ata_port *ap)
1973c6fd2807SJeff Garzik {
1974cca3974eSJeff Garzik 	struct device *dev = ap->host->dev;
1975c6fd2807SJeff Garzik 	struct ahci_port_priv *pp;
1976c6fd2807SJeff Garzik 	void *mem;
1977c6fd2807SJeff Garzik 	dma_addr_t mem_dma;
1978c6fd2807SJeff Garzik 	int rc;
1979c6fd2807SJeff Garzik 
198024dc5f33STejun Heo 	pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
1981c6fd2807SJeff Garzik 	if (!pp)
1982c6fd2807SJeff Garzik 		return -ENOMEM;
1983c6fd2807SJeff Garzik 
1984c6fd2807SJeff Garzik 	rc = ata_pad_alloc(ap, dev);
198524dc5f33STejun Heo 	if (rc)
1986c6fd2807SJeff Garzik 		return rc;
1987c6fd2807SJeff Garzik 
198824dc5f33STejun Heo 	mem = dmam_alloc_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, &mem_dma,
198924dc5f33STejun Heo 				  GFP_KERNEL);
199024dc5f33STejun Heo 	if (!mem)
1991c6fd2807SJeff Garzik 		return -ENOMEM;
1992c6fd2807SJeff Garzik 	memset(mem, 0, AHCI_PORT_PRIV_DMA_SZ);
1993c6fd2807SJeff Garzik 
1994c6fd2807SJeff Garzik 	/*
1995c6fd2807SJeff Garzik 	 * First item in chunk of DMA memory: 32-slot command table,
1996c6fd2807SJeff Garzik 	 * 32 bytes each in size
1997c6fd2807SJeff Garzik 	 */
1998c6fd2807SJeff Garzik 	pp->cmd_slot = mem;
1999c6fd2807SJeff Garzik 	pp->cmd_slot_dma = mem_dma;
2000c6fd2807SJeff Garzik 
2001c6fd2807SJeff Garzik 	mem += AHCI_CMD_SLOT_SZ;
2002c6fd2807SJeff Garzik 	mem_dma += AHCI_CMD_SLOT_SZ;
2003c6fd2807SJeff Garzik 
2004c6fd2807SJeff Garzik 	/*
2005c6fd2807SJeff Garzik 	 * Second item: Received-FIS area
2006c6fd2807SJeff Garzik 	 */
2007c6fd2807SJeff Garzik 	pp->rx_fis = mem;
2008c6fd2807SJeff Garzik 	pp->rx_fis_dma = mem_dma;
2009c6fd2807SJeff Garzik 
2010c6fd2807SJeff Garzik 	mem += AHCI_RX_FIS_SZ;
2011c6fd2807SJeff Garzik 	mem_dma += AHCI_RX_FIS_SZ;
2012c6fd2807SJeff Garzik 
2013c6fd2807SJeff Garzik 	/*
2014c6fd2807SJeff Garzik 	 * Third item: data area for storing a single command
2015c6fd2807SJeff Garzik 	 * and its scatter-gather table
2016c6fd2807SJeff Garzik 	 */
2017c6fd2807SJeff Garzik 	pp->cmd_tbl = mem;
2018c6fd2807SJeff Garzik 	pp->cmd_tbl_dma = mem_dma;
2019c6fd2807SJeff Garzik 
2020a7384925SKristen Carlson Accardi 	/*
2021a7384925SKristen Carlson Accardi 	 * Save off initial list of interrupts to be enabled.
2022a7384925SKristen Carlson Accardi 	 * This could be changed later
2023a7384925SKristen Carlson Accardi 	 */
2024a7384925SKristen Carlson Accardi 	pp->intr_mask = DEF_PORT_IRQ;
2025a7384925SKristen Carlson Accardi 
2026c6fd2807SJeff Garzik 	ap->private_data = pp;
2027c6fd2807SJeff Garzik 
2028df69c9c5SJeff Garzik 	/* engage engines, captain */
2029df69c9c5SJeff Garzik 	return ahci_port_resume(ap);
2030c6fd2807SJeff Garzik }
2031c6fd2807SJeff Garzik 
2032c6fd2807SJeff Garzik static void ahci_port_stop(struct ata_port *ap)
2033c6fd2807SJeff Garzik {
2034c6fd2807SJeff Garzik 	const char *emsg = NULL;
2035c6fd2807SJeff Garzik 	int rc;
2036c6fd2807SJeff Garzik 
2037c6fd2807SJeff Garzik 	/* de-initialize port */
20384447d351STejun Heo 	rc = ahci_deinit_port(ap, &emsg);
2039c6fd2807SJeff Garzik 	if (rc)
2040c6fd2807SJeff Garzik 		ata_port_printk(ap, KERN_WARNING, "%s (%d)\n", emsg, rc);
2041c6fd2807SJeff Garzik }
2042c6fd2807SJeff Garzik 
20434447d351STejun Heo static int ahci_configure_dma_masks(struct pci_dev *pdev, int using_dac)
2044c6fd2807SJeff Garzik {
2045c6fd2807SJeff Garzik 	int rc;
2046c6fd2807SJeff Garzik 
2047c6fd2807SJeff Garzik 	if (using_dac &&
2048c6fd2807SJeff Garzik 	    !pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
2049c6fd2807SJeff Garzik 		rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
2050c6fd2807SJeff Garzik 		if (rc) {
2051c6fd2807SJeff Garzik 			rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
2052c6fd2807SJeff Garzik 			if (rc) {
2053c6fd2807SJeff Garzik 				dev_printk(KERN_ERR, &pdev->dev,
2054c6fd2807SJeff Garzik 					   "64-bit DMA enable failed\n");
2055c6fd2807SJeff Garzik 				return rc;
2056c6fd2807SJeff Garzik 			}
2057c6fd2807SJeff Garzik 		}
2058c6fd2807SJeff Garzik 	} else {
2059c6fd2807SJeff Garzik 		rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
2060c6fd2807SJeff Garzik 		if (rc) {
2061c6fd2807SJeff Garzik 			dev_printk(KERN_ERR, &pdev->dev,
2062c6fd2807SJeff Garzik 				   "32-bit DMA enable failed\n");
2063c6fd2807SJeff Garzik 			return rc;
2064c6fd2807SJeff Garzik 		}
2065c6fd2807SJeff Garzik 		rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
2066c6fd2807SJeff Garzik 		if (rc) {
2067c6fd2807SJeff Garzik 			dev_printk(KERN_ERR, &pdev->dev,
2068c6fd2807SJeff Garzik 				   "32-bit consistent DMA enable failed\n");
2069c6fd2807SJeff Garzik 			return rc;
2070c6fd2807SJeff Garzik 		}
2071c6fd2807SJeff Garzik 	}
2072c6fd2807SJeff Garzik 	return 0;
2073c6fd2807SJeff Garzik }
2074c6fd2807SJeff Garzik 
20754447d351STejun Heo static void ahci_print_info(struct ata_host *host)
2076c6fd2807SJeff Garzik {
20774447d351STejun Heo 	struct ahci_host_priv *hpriv = host->private_data;
20784447d351STejun Heo 	struct pci_dev *pdev = to_pci_dev(host->dev);
20794447d351STejun Heo 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
2080c6fd2807SJeff Garzik 	u32 vers, cap, impl, speed;
2081c6fd2807SJeff Garzik 	const char *speed_s;
2082c6fd2807SJeff Garzik 	u16 cc;
2083c6fd2807SJeff Garzik 	const char *scc_s;
2084c6fd2807SJeff Garzik 
2085c6fd2807SJeff Garzik 	vers = readl(mmio + HOST_VERSION);
2086c6fd2807SJeff Garzik 	cap = hpriv->cap;
2087c6fd2807SJeff Garzik 	impl = hpriv->port_map;
2088c6fd2807SJeff Garzik 
2089c6fd2807SJeff Garzik 	speed = (cap >> 20) & 0xf;
2090c6fd2807SJeff Garzik 	if (speed == 1)
2091c6fd2807SJeff Garzik 		speed_s = "1.5";
2092c6fd2807SJeff Garzik 	else if (speed == 2)
2093c6fd2807SJeff Garzik 		speed_s = "3";
2094c6fd2807SJeff Garzik 	else
2095c6fd2807SJeff Garzik 		speed_s = "?";
2096c6fd2807SJeff Garzik 
2097c6fd2807SJeff Garzik 	pci_read_config_word(pdev, 0x0a, &cc);
2098c9f89475SConke Hu 	if (cc == PCI_CLASS_STORAGE_IDE)
2099c6fd2807SJeff Garzik 		scc_s = "IDE";
2100c9f89475SConke Hu 	else if (cc == PCI_CLASS_STORAGE_SATA)
2101c6fd2807SJeff Garzik 		scc_s = "SATA";
2102c9f89475SConke Hu 	else if (cc == PCI_CLASS_STORAGE_RAID)
2103c6fd2807SJeff Garzik 		scc_s = "RAID";
2104c6fd2807SJeff Garzik 	else
2105c6fd2807SJeff Garzik 		scc_s = "unknown";
2106c6fd2807SJeff Garzik 
2107c6fd2807SJeff Garzik 	dev_printk(KERN_INFO, &pdev->dev,
2108c6fd2807SJeff Garzik 		"AHCI %02x%02x.%02x%02x "
2109c6fd2807SJeff Garzik 		"%u slots %u ports %s Gbps 0x%x impl %s mode\n"
2110c6fd2807SJeff Garzik 		,
2111c6fd2807SJeff Garzik 
2112c6fd2807SJeff Garzik 		(vers >> 24) & 0xff,
2113c6fd2807SJeff Garzik 		(vers >> 16) & 0xff,
2114c6fd2807SJeff Garzik 		(vers >> 8) & 0xff,
2115c6fd2807SJeff Garzik 		vers & 0xff,
2116c6fd2807SJeff Garzik 
2117c6fd2807SJeff Garzik 		((cap >> 8) & 0x1f) + 1,
2118c6fd2807SJeff Garzik 		(cap & 0x1f) + 1,
2119c6fd2807SJeff Garzik 		speed_s,
2120c6fd2807SJeff Garzik 		impl,
2121c6fd2807SJeff Garzik 		scc_s);
2122c6fd2807SJeff Garzik 
2123c6fd2807SJeff Garzik 	dev_printk(KERN_INFO, &pdev->dev,
2124c6fd2807SJeff Garzik 		"flags: "
2125203ef6c4STejun Heo 		"%s%s%s%s%s%s%s"
2126c6fd2807SJeff Garzik 		"%s%s%s%s%s%s%s\n"
2127c6fd2807SJeff Garzik 		,
2128c6fd2807SJeff Garzik 
2129c6fd2807SJeff Garzik 		cap & (1 << 31) ? "64bit " : "",
2130c6fd2807SJeff Garzik 		cap & (1 << 30) ? "ncq " : "",
2131203ef6c4STejun Heo 		cap & (1 << 29) ? "sntf " : "",
2132c6fd2807SJeff Garzik 		cap & (1 << 28) ? "ilck " : "",
2133c6fd2807SJeff Garzik 		cap & (1 << 27) ? "stag " : "",
2134c6fd2807SJeff Garzik 		cap & (1 << 26) ? "pm " : "",
2135c6fd2807SJeff Garzik 		cap & (1 << 25) ? "led " : "",
2136c6fd2807SJeff Garzik 
2137c6fd2807SJeff Garzik 		cap & (1 << 24) ? "clo " : "",
2138c6fd2807SJeff Garzik 		cap & (1 << 19) ? "nz " : "",
2139c6fd2807SJeff Garzik 		cap & (1 << 18) ? "only " : "",
2140c6fd2807SJeff Garzik 		cap & (1 << 17) ? "pmp " : "",
2141c6fd2807SJeff Garzik 		cap & (1 << 15) ? "pio " : "",
2142c6fd2807SJeff Garzik 		cap & (1 << 14) ? "slum " : "",
2143c6fd2807SJeff Garzik 		cap & (1 << 13) ? "part " : ""
2144c6fd2807SJeff Garzik 		);
2145c6fd2807SJeff Garzik }
2146c6fd2807SJeff Garzik 
2147edc93052STejun Heo /* On ASUS P5W DH Deluxe, the second port of PCI device 00:1f.2 is
2148edc93052STejun Heo  * hardwired to on-board SIMG 4726.  The chipset is ICH8 and doesn't
2149edc93052STejun Heo  * support PMP and the 4726 either directly exports the device
2150edc93052STejun Heo  * attached to the first downstream port or acts as a hardware storage
2151edc93052STejun Heo  * controller and emulate a single ATA device (can be RAID 0/1 or some
2152edc93052STejun Heo  * other configuration).
2153edc93052STejun Heo  *
2154edc93052STejun Heo  * When there's no device attached to the first downstream port of the
2155edc93052STejun Heo  * 4726, "Config Disk" appears, which is a pseudo ATA device to
2156edc93052STejun Heo  * configure the 4726.  However, ATA emulation of the device is very
2157edc93052STejun Heo  * lame.  It doesn't send signature D2H Reg FIS after the initial
2158edc93052STejun Heo  * hardreset, pukes on SRST w/ PMP==0 and has bunch of other issues.
2159edc93052STejun Heo  *
2160edc93052STejun Heo  * The following function works around the problem by always using
2161edc93052STejun Heo  * hardreset on the port and not depending on receiving signature FIS
2162edc93052STejun Heo  * afterward.  If signature FIS isn't received soon, ATA class is
2163edc93052STejun Heo  * assumed without follow-up softreset.
2164edc93052STejun Heo  */
2165edc93052STejun Heo static void ahci_p5wdh_workaround(struct ata_host *host)
2166edc93052STejun Heo {
2167edc93052STejun Heo 	static struct dmi_system_id sysids[] = {
2168edc93052STejun Heo 		{
2169edc93052STejun Heo 			.ident = "P5W DH Deluxe",
2170edc93052STejun Heo 			.matches = {
2171edc93052STejun Heo 				DMI_MATCH(DMI_SYS_VENDOR,
2172edc93052STejun Heo 					  "ASUSTEK COMPUTER INC"),
2173edc93052STejun Heo 				DMI_MATCH(DMI_PRODUCT_NAME, "P5W DH Deluxe"),
2174edc93052STejun Heo 			},
2175edc93052STejun Heo 		},
2176edc93052STejun Heo 		{ }
2177edc93052STejun Heo 	};
2178edc93052STejun Heo 	struct pci_dev *pdev = to_pci_dev(host->dev);
2179edc93052STejun Heo 
2180edc93052STejun Heo 	if (pdev->bus->number == 0 && pdev->devfn == PCI_DEVFN(0x1f, 2) &&
2181edc93052STejun Heo 	    dmi_check_system(sysids)) {
2182edc93052STejun Heo 		struct ata_port *ap = host->ports[1];
2183edc93052STejun Heo 
2184edc93052STejun Heo 		dev_printk(KERN_INFO, &pdev->dev, "enabling ASUS P5W DH "
2185edc93052STejun Heo 			   "Deluxe on-board SIMG4726 workaround\n");
2186edc93052STejun Heo 
2187edc93052STejun Heo 		ap->ops = &ahci_p5wdh_ops;
2188edc93052STejun Heo 		ap->link.flags |= ATA_LFLAG_NO_SRST | ATA_LFLAG_ASSUME_ATA;
2189edc93052STejun Heo 	}
2190edc93052STejun Heo }
2191edc93052STejun Heo 
2192c6fd2807SJeff Garzik static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
2193c6fd2807SJeff Garzik {
2194c6fd2807SJeff Garzik 	static int printed_version;
21954447d351STejun Heo 	struct ata_port_info pi = ahci_port_info[ent->driver_data];
21964447d351STejun Heo 	const struct ata_port_info *ppi[] = { &pi, NULL };
219724dc5f33STejun Heo 	struct device *dev = &pdev->dev;
2198c6fd2807SJeff Garzik 	struct ahci_host_priv *hpriv;
21994447d351STejun Heo 	struct ata_host *host;
2200*837f5f8fSTejun Heo 	int n_ports, i, rc;
2201c6fd2807SJeff Garzik 
2202c6fd2807SJeff Garzik 	VPRINTK("ENTER\n");
2203c6fd2807SJeff Garzik 
2204c6fd2807SJeff Garzik 	WARN_ON(ATA_MAX_QUEUE > AHCI_MAX_CMDS);
2205c6fd2807SJeff Garzik 
2206c6fd2807SJeff Garzik 	if (!printed_version++)
2207c6fd2807SJeff Garzik 		dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
2208c6fd2807SJeff Garzik 
22094447d351STejun Heo 	/* acquire resources */
221024dc5f33STejun Heo 	rc = pcim_enable_device(pdev);
2211c6fd2807SJeff Garzik 	if (rc)
2212c6fd2807SJeff Garzik 		return rc;
2213c6fd2807SJeff Garzik 
22140d5ff566STejun Heo 	rc = pcim_iomap_regions(pdev, 1 << AHCI_PCI_BAR, DRV_NAME);
22150d5ff566STejun Heo 	if (rc == -EBUSY)
221624dc5f33STejun Heo 		pcim_pin_device(pdev);
22170d5ff566STejun Heo 	if (rc)
221824dc5f33STejun Heo 		return rc;
2219c6fd2807SJeff Garzik 
2220c4f7792cSTejun Heo 	if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
2221c4f7792cSTejun Heo 	    (pdev->device == 0x2652 || pdev->device == 0x2653)) {
2222c4f7792cSTejun Heo 		u8 map;
2223c4f7792cSTejun Heo 
2224c4f7792cSTejun Heo 		/* ICH6s share the same PCI ID for both piix and ahci
2225c4f7792cSTejun Heo 		 * modes.  Enabling ahci mode while MAP indicates
2226c4f7792cSTejun Heo 		 * combined mode is a bad idea.  Yield to ata_piix.
2227c4f7792cSTejun Heo 		 */
2228c4f7792cSTejun Heo 		pci_read_config_byte(pdev, ICH_MAP, &map);
2229c4f7792cSTejun Heo 		if (map & 0x3) {
2230c4f7792cSTejun Heo 			dev_printk(KERN_INFO, &pdev->dev, "controller is in "
2231c4f7792cSTejun Heo 				   "combined mode, can't enable AHCI mode\n");
2232c4f7792cSTejun Heo 			return -ENODEV;
2233c4f7792cSTejun Heo 		}
2234c4f7792cSTejun Heo 	}
2235c4f7792cSTejun Heo 
223624dc5f33STejun Heo 	hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
223724dc5f33STejun Heo 	if (!hpriv)
223824dc5f33STejun Heo 		return -ENOMEM;
2239417a1a6dSTejun Heo 	hpriv->flags |= (unsigned long)pi.private_data;
2240417a1a6dSTejun Heo 
2241417a1a6dSTejun Heo 	if ((hpriv->flags & AHCI_HFLAG_NO_MSI) || pci_enable_msi(pdev))
2242417a1a6dSTejun Heo 		pci_intx(pdev, 1);
2243c6fd2807SJeff Garzik 
22444447d351STejun Heo 	/* save initial config */
2245417a1a6dSTejun Heo 	ahci_save_initial_config(pdev, hpriv);
2246c6fd2807SJeff Garzik 
22474447d351STejun Heo 	/* prepare host */
2248274c1fdeSTejun Heo 	if (hpriv->cap & HOST_CAP_NCQ)
22494447d351STejun Heo 		pi.flags |= ATA_FLAG_NCQ;
22504447d351STejun Heo 
22517d50b60bSTejun Heo 	if (hpriv->cap & HOST_CAP_PMP)
22527d50b60bSTejun Heo 		pi.flags |= ATA_FLAG_PMP;
22537d50b60bSTejun Heo 
2254*837f5f8fSTejun Heo 	/* CAP.NP sometimes indicate the index of the last enabled
2255*837f5f8fSTejun Heo 	 * port, at other times, that of the last possible port, so
2256*837f5f8fSTejun Heo 	 * determining the maximum port number requires looking at
2257*837f5f8fSTejun Heo 	 * both CAP.NP and port_map.
2258*837f5f8fSTejun Heo 	 */
2259*837f5f8fSTejun Heo 	n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map));
2260*837f5f8fSTejun Heo 
2261*837f5f8fSTejun Heo 	host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);
22624447d351STejun Heo 	if (!host)
22634447d351STejun Heo 		return -ENOMEM;
22644447d351STejun Heo 	host->iomap = pcim_iomap_table(pdev);
22654447d351STejun Heo 	host->private_data = hpriv;
22664447d351STejun Heo 
22674447d351STejun Heo 	for (i = 0; i < host->n_ports; i++) {
22684447d351STejun Heo 		struct ata_port *ap = host->ports[i];
22694447d351STejun Heo 		void __iomem *port_mmio = ahci_port_base(ap);
22704447d351STejun Heo 
2271cbcdd875STejun Heo 		ata_port_pbar_desc(ap, AHCI_PCI_BAR, -1, "abar");
2272cbcdd875STejun Heo 		ata_port_pbar_desc(ap, AHCI_PCI_BAR,
2273cbcdd875STejun Heo 				   0x100 + ap->port_no * 0x80, "port");
2274cbcdd875STejun Heo 
227531556594SKristen Carlson Accardi 		/* set initial link pm policy */
227631556594SKristen Carlson Accardi 		ap->pm_policy = NOT_AVAILABLE;
227731556594SKristen Carlson Accardi 
2278dab632e8SJeff Garzik 		/* standard SATA port setup */
2279203ef6c4STejun Heo 		if (hpriv->port_map & (1 << i))
22804447d351STejun Heo 			ap->ioaddr.cmd_addr = port_mmio;
2281dab632e8SJeff Garzik 
2282dab632e8SJeff Garzik 		/* disabled/not-implemented port */
2283dab632e8SJeff Garzik 		else
2284dab632e8SJeff Garzik 			ap->ops = &ata_dummy_port_ops;
22854447d351STejun Heo 	}
2286c6fd2807SJeff Garzik 
2287edc93052STejun Heo 	/* apply workaround for ASUS P5W DH Deluxe mainboard */
2288edc93052STejun Heo 	ahci_p5wdh_workaround(host);
2289edc93052STejun Heo 
2290c6fd2807SJeff Garzik 	/* initialize adapter */
22914447d351STejun Heo 	rc = ahci_configure_dma_masks(pdev, hpriv->cap & HOST_CAP_64);
2292c6fd2807SJeff Garzik 	if (rc)
229324dc5f33STejun Heo 		return rc;
2294c6fd2807SJeff Garzik 
22954447d351STejun Heo 	rc = ahci_reset_controller(host);
22964447d351STejun Heo 	if (rc)
22974447d351STejun Heo 		return rc;
2298c6fd2807SJeff Garzik 
22994447d351STejun Heo 	ahci_init_controller(host);
23004447d351STejun Heo 	ahci_print_info(host);
2301c6fd2807SJeff Garzik 
23024447d351STejun Heo 	pci_set_master(pdev);
23034447d351STejun Heo 	return ata_host_activate(host, pdev->irq, ahci_interrupt, IRQF_SHARED,
23044447d351STejun Heo 				 &ahci_sht);
2305c6fd2807SJeff Garzik }
2306c6fd2807SJeff Garzik 
2307c6fd2807SJeff Garzik static int __init ahci_init(void)
2308c6fd2807SJeff Garzik {
2309c6fd2807SJeff Garzik 	return pci_register_driver(&ahci_pci_driver);
2310c6fd2807SJeff Garzik }
2311c6fd2807SJeff Garzik 
2312c6fd2807SJeff Garzik static void __exit ahci_exit(void)
2313c6fd2807SJeff Garzik {
2314c6fd2807SJeff Garzik 	pci_unregister_driver(&ahci_pci_driver);
2315c6fd2807SJeff Garzik }
2316c6fd2807SJeff Garzik 
2317c6fd2807SJeff Garzik 
2318c6fd2807SJeff Garzik MODULE_AUTHOR("Jeff Garzik");
2319c6fd2807SJeff Garzik MODULE_DESCRIPTION("AHCI SATA low-level driver");
2320c6fd2807SJeff Garzik MODULE_LICENSE("GPL");
2321c6fd2807SJeff Garzik MODULE_DEVICE_TABLE(pci, ahci_pci_tbl);
2322c6fd2807SJeff Garzik MODULE_VERSION(DRV_VERSION);
2323c6fd2807SJeff Garzik 
2324c6fd2807SJeff Garzik module_init(ahci_init);
2325c6fd2807SJeff Garzik module_exit(ahci_exit);
2326